# Conflicts:
#	star_lock/lib/blue/sender_beforeDataManage.dart
#	star_lock/lib/main/lockDetail/doorLockLog/doorLockLog_logic.dart
This commit is contained in:
魏少阳 2024-05-16 13:56:42 +08:00
commit f615616f0e
17 changed files with 431 additions and 162 deletions

View File

@ -712,7 +712,7 @@
"请输入手机号": "Please enter mobile phone number", "请输入手机号": "Please enter mobile phone number",
"家人到家": "Family gets home", "家人到家": "Family gets home",
"添加家人": "Add family", "添加家人": "Add family",
"若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择": "If the lock is not connected to the Internet, in addition to the electronic key, the password, card, fingerprint and other door reminders can not be sent in time, please choose according to your actual situation", "若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择": "If the lock is not connected to the Internet, in addition to the electronic key, the password, card, fingerprint and other door reminders can not be sent in time, please choose according to your actual situation",
"消息提醒": "Message reminder", "消息提醒": "Message reminder",
"开门通知": "Opening notice", "开门通知": "Opening notice",
"N天未开门": "N days without opening the door", "N天未开门": "N days without opening the door",
@ -844,5 +844,14 @@
"钥匙无效": "The key is invalid", "钥匙无效": "The key is invalid",
"操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。": "The operation failed. Please confirm whether the lock is nearby, or restart your phone's Bluetooth and try again.", "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。": "The operation failed. Please confirm whether the lock is nearby, or restart your phone's Bluetooth and try again.",
"如果是全自动锁,请使屏幕变亮": "If it is a fully automatic lock, please make the screen brighter", "如果是全自动锁,请使屏幕变亮": "If it is a fully automatic lock, please make the screen brighter",
"正在尝试闭锁……": "Attempting to lock..." "正在尝试闭锁……": "Attempting to lock...",
"清空记录":"Clear record",
"是否要删除操作记录?":"Do you want to delete the operation record?",
"被删除的记录不能恢复":"The deleted record cannot be restored",
"全部事件":"All events",
"开锁事件":"Unlock event",
"异常事件":"Abnormal event",
"门铃事件":"Doorbell event",
"视频事件":"Video event"
} }

View File

@ -740,7 +740,7 @@
"请输入手机号":"请输入手机号", "请输入手机号":"请输入手机号",
"家人到家":"家人到家", "家人到家":"家人到家",
"添加家人":"添加家人", "添加家人":"添加家人",
"若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择":"若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择", "若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择":"若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择",
"消息提醒":"消息提醒", "消息提醒":"消息提醒",
"开门通知":"开门通知", "开门通知":"开门通知",
"N天未开门":"N天未开门", "N天未开门":"N天未开门",
@ -872,5 +872,13 @@
"钥匙无效": "钥匙无效", "钥匙无效": "钥匙无效",
"操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。": "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。", "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。": "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。",
"如果是全自动锁,请使屏幕变亮": "如果是全自动锁,请使屏幕变亮", "如果是全自动锁,请使屏幕变亮": "如果是全自动锁,请使屏幕变亮",
"正在尝试闭锁……": "正在尝试闭锁……" "正在尝试闭锁……": "正在尝试闭锁……",
"清空记录":"清空记录",
"是否要删除操作记录?":"是否要删除操作记录?",
"被删除的记录不能恢复":"被删除的记录不能恢复",
"全部事件":"全部事件",
"开锁事件":"开锁事件",
"异常事件":"异常事件",
"门铃事件":"门铃事件",
"视频事件":"视频事件"
} }

View File

@ -712,7 +712,7 @@
"请输入手机号": "请输入手机号", "请输入手机号": "请输入手机号",
"家人到家": "家人到家", "家人到家": "家人到家",
"添加家人": "添加家人", "添加家人": "添加家人",
"若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择": "若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择", "若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择": "若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择",
"消息提醒": "消息提醒", "消息提醒": "消息提醒",
"开门通知": "开门通知", "开门通知": "开门通知",
"N天未开门": "N天未开门", "N天未开门": "N天未开门",
@ -842,5 +842,13 @@
"钥匙无效": "钥匙无效", "钥匙无效": "钥匙无效",
"操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。": "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。", "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。": "操作失败,请确认锁是否在附近,或重启手机蓝牙后再试。",
"如果是全自动锁,请使屏幕变亮": "如果是全自动锁,请使屏幕变亮", "如果是全自动锁,请使屏幕变亮": "如果是全自动锁,请使屏幕变亮",
"正在尝试闭锁……": "正在尝试闭锁……" "正在尝试闭锁……": "正在尝试闭锁……",
"清空记录":"清空记录",
"是否要删除操作记录?":"是否要删除操作记录?",
"被删除的记录不能恢复":"被删除的记录不能恢复",
"全部事件":"全部事件",
"开锁事件":"开锁事件",
"异常事件":"异常事件",
"门铃事件":"门铃事件",
"视频事件":"视频事件"
} }

View File

@ -351,4 +351,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 317f9473a5705c6fe4d79d95e81676f248048fdc PODFILE CHECKSUM: 317f9473a5705c6fe4d79d95e81676f248048fdc
COCOAPODS: 1.15.2 COCOAPODS: 1.14.3

View File

@ -696,7 +696,8 @@ class BlueManage {
// if(bluetoothConnectDevice != null && bluetoothConnectDevice!.connectionState == BluetoothConnectionState.connected){ // if(bluetoothConnectDevice != null && bluetoothConnectDevice!.connectionState == BluetoothConnectionState.connected){
connectDeviceMacAddress = ""; connectDeviceMacAddress = "";
if (bluetoothConnectionState == BluetoothConnectionState.connected) { if (bluetoothConnectionState == BluetoothConnectionState.connected) {
await bluetoothConnectDevice!.disconnect(); //
await bluetoothConnectDevice!.disconnect(timeout: 2);
AppLog.log("断开连接成功"); AppLog.log("断开连接成功");
} }
// } // }

View File

@ -1,4 +1,3 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
@ -6,9 +5,9 @@ import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
import 'package:star_lock/main/lockDetail/lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart'; import 'package:star_lock/main/lockDetail/lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart';
import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/eventBusEventManage.dart'; import 'package:star_lock/tools/eventBusEventManage.dart';
import '../../../app_settings/app_settings.dart';
import '../../../blue/blue_manage.dart'; import '../../../blue/blue_manage.dart';
import '../../../blue/io_protocol/io_referEventRecordTime.dart'; import '../../../blue/io_protocol/io_referEventRecordTime.dart';
import '../../../blue/io_reply.dart'; import '../../../blue/io_reply.dart';
@ -26,16 +25,17 @@ class DoorLockLogLogic extends BaseGetXController {
// //
late StreamSubscription<Reply> _replySubscription; late StreamSubscription<Reply> _replySubscription;
void _initReplySubscription() { void _initReplySubscription() {
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) { _replySubscription =
EventBusManager().eventBus!.on<Reply>().listen((reply) {
if (reply is SenderReferEventRecordTimeReply && state.ifCurrentScreen.value == true) { if (reply is SenderReferEventRecordTimeReply &&
state.ifCurrentScreen.value == true) {
_replyReferEventRecordTime(reply); _replyReferEventRecordTime(reply);
} }
}); });
} }
// //
Future<void> _replyReferEventRecordTime(Reply reply) async { Future<void> _replyReferEventRecordTime(Reply reply) async {
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
int status = reply.data[2]; int status = reply.data[2];
switch (status) { switch (status) {
@ -47,7 +47,7 @@ class DoorLockLogLogic extends BaseGetXController {
if (dataLength > 0) { if (dataLength > 0) {
reply.data.removeRange(0, 7); reply.data.removeRange(0, 7);
// 8 // 8
if(reply.data.length < 17){ if (reply.data.length < 17) {
return; return;
} }
var getList = splitList(reply.data, 17); var getList = splitList(reply.data, 17);
@ -59,11 +59,10 @@ class DoorLockLogLogic extends BaseGetXController {
var indexMap = {}; var indexMap = {};
indexMap["type"] = indexList[0].toString(); indexMap["type"] = indexList[0].toString();
if(indexList[0] == 2){ if (indexList[0] == 2) {
var passwordData = indexList.sublist(7, 17); var passwordData = indexList.sublist(7, 17);
var password = utf8String(passwordData); var password = utf8String(passwordData);
indexMap["user"] = password.toString(); indexMap["user"] = password.toString();
}else{
int userNo = (indexList[1]*256) + indexList[2]; int userNo = (indexList[1]*256) + indexList[2];
indexMap["user"] = userNo.toString(); indexMap["user"] = userNo.toString();
} }
@ -71,15 +70,15 @@ class DoorLockLogLogic extends BaseGetXController {
indexMap["success"] = "1"; indexMap["success"] = "1";
int time = ((0xff & indexList[(3)]) << 24 | int time = ((0xff & indexList[(3)]) << 24 |
(0xff & indexList[4]) << 16 | (0xff & indexList[4]) << 16 |
(0xff & indexList[5]) << 8 | (0xff & indexList[5]) << 8 |
(0xFF & indexList[6])); (0xFF & indexList[6]));
indexMap["date"] = "${time * 1000}"; indexMap["date"] = "${time * 1000}";
uploadList.add(indexMap); uploadList.add(indexMap);
} }
lockRecordUploadData(uploadList); lockRecordUploadData(uploadList);
if(dataLength == state.logCountPage){ if (dataLength == state.logCountPage) {
state.ifHaveNext = true; state.ifHaveNext = true;
} }
} }
@ -97,10 +96,11 @@ class DoorLockLogLogic extends BaseGetXController {
// () // ()
Future<void> senderReferEventRecordTime() async { Future<void> senderReferEventRecordTime() async {
showEasyLoading(); showEasyLoading();
showBlueConnetctToastTimer(action: (){ showBlueConnetctToastTimer(action: () {
dismissEasyLoading(); dismissEasyLoading();
}); });
BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionStateState) async { BlueManage().bludSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState connectionStateState) async {
if (connectionStateState == BluetoothConnectionState.connected) { if (connectionStateState == BluetoothConnectionState.connected) {
var privateKey = await Storage.getStringList(saveBluePrivateKey); var privateKey = await Storage.getStringList(saveBluePrivateKey);
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!); List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
@ -122,10 +122,11 @@ class DoorLockLogLogic extends BaseGetXController {
publicKey: getPublicKeyList, publicKey: getPublicKeyList,
privateKey: getPrivateKeyList, privateKey: getPrivateKeyList,
); );
} else if (connectionStateState == BluetoothConnectionState.disconnected) { } else if (connectionStateState ==
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
if(state.ifCurrentScreen.value == true){ if (state.ifCurrentScreen.value == true) {
showBlueConnetctToast(); showBlueConnetctToast();
} }
} }
@ -134,6 +135,7 @@ class DoorLockLogLogic extends BaseGetXController {
// //
void mockNetworkDataRequest() async { void mockNetworkDataRequest() async {
state.lockLogItemList.clear();
DoorLockLogEntity entity = await ApiRepository.to.lockEventList( DoorLockLogEntity entity = await ApiRepository.to.lockEventList(
lockId: state.keyInfos.value.lockId!, lockId: state.keyInfos.value.lockId!,
lockEventType: state.dropdownValue.value, lockEventType: state.dropdownValue.value,
@ -141,9 +143,16 @@ class DoorLockLogLogic extends BaseGetXController {
pageSize: int.parse(pageSize), pageSize: int.parse(pageSize),
startDate: state.startDate.value, startDate: state.startDate.value,
endDate: state.endDate.value); endDate: state.endDate.value);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
state.lockLogItemList.value = entity.data!.itemList!; if (pageNo == 1) {
state.lockLogItemList.value = entity.data!.itemList!;
pageNo++;
} else {
if (entity.data!.itemList!.isNotEmpty) {
state.lockLogItemList.addAll(entity.data!.itemList!);
pageNo++;
}
}
} }
} }
@ -152,15 +161,18 @@ class DoorLockLogLogic extends BaseGetXController {
void _getDoorLockLogListRefreshUIAction() { void _getDoorLockLogListRefreshUIAction() {
_getDoorLockLogListRefreshUIEvent = _getDoorLockLogListRefreshUIEvent =
eventBus.on<DoorLockLogListRefreshUI>().listen((event) { eventBus.on<DoorLockLogListRefreshUI>().listen((event) {
state.currentSelectDate.value = event.getDoorLockLogTime;
// startDate为当天的0点 // startDate为当天的0点
state.startDate.value = DateTime(event.getDoorLockLogTime.year, state.startDate.value = DateTime(
event.getDoorLockLogTime.month, event.getDoorLockLogTime.day) state.currentSelectDate.value.year,
state.currentSelectDate.value.month,
state.currentSelectDate.value.day)
.millisecondsSinceEpoch; .millisecondsSinceEpoch;
// endDate为下一天的0点1 // endDate为下一天的0点1
state.endDate.value = (DateTime( state.endDate.value = (DateTime(
event.getDoorLockLogTime.year, state.currentSelectDate.value.year,
event.getDoorLockLogTime.month, state.currentSelectDate.value.month,
event.getDoorLockLogTime.day + 1) state.currentSelectDate.value.day + 1)
.subtract(const Duration(milliseconds: 1))) .subtract(const Duration(milliseconds: 1)))
.millisecondsSinceEpoch; .millisecondsSinceEpoch;
@ -186,9 +198,9 @@ class DoorLockLogLogic extends BaseGetXController {
.lockRecordUploadData( .lockRecordUploadData(
lockId: state.keyInfos.value.lockId.toString(), records: list); lockId: state.keyInfos.value.lockId.toString(), records: list);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
if(state.ifHaveNext == true){ if (state.ifHaveNext == true) {
getLockRecordLastUploadDataTime(); getLockRecordLastUploadDataTime();
}else{ } else {
pageNo = 1; pageNo = 1;
mockNetworkDataRequest(); mockNetworkDataRequest();
} }
@ -197,10 +209,14 @@ class DoorLockLogLogic extends BaseGetXController {
// //
void clearOperationRecordRequest() async { void clearOperationRecordRequest() async {
KeyOperationRecordEntity entity = KeyOperationRecordEntity entity = await ApiRepository.to
await ApiRepository.to.clearOperationRecord('28'); .clearOperationRecord(
CommonDataManage().currentKeyInfo.lockId.toString());
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
showToast("清除数据成功"); showToast("清除数据成功", something: () {
pageNo = 1;
mockNetworkDataRequest();
});
} }
} }

View File

@ -5,9 +5,11 @@ import 'package:get/get.dart';
import 'package:star_lock/appRouters.dart'; import 'package:star_lock/appRouters.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_logic.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_logic.dart';
import 'package:star_lock/tools/EasyRefreshTool.dart';
import 'package:star_lock/tools/advancedCalendar/src/widget.dart'; import 'package:star_lock/tools/advancedCalendar/src/widget.dart';
import 'package:star_lock/tools/menuItem/xsDropDownWidget.dart'; import 'package:star_lock/tools/menuItem/xsDropDownWidget.dart';
import 'package:star_lock/tools/noData.dart'; import 'package:star_lock/tools/noData.dart';
import 'package:star_lock/tools/showCupertinoAlertView.dart';
import 'package:timelines/timelines.dart'; import 'package:timelines/timelines.dart';
import '../../../app_settings/app_colors.dart'; import '../../../app_settings/app_colors.dart';
@ -26,11 +28,6 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
final logic = Get.put(DoorLockLogLogic()); final logic = Get.put(DoorLockLogLogic());
final state = Get.find<DoorLockLogLogic>().state; final state = Get.find<DoorLockLogLogic>().state;
@override
void initState() {
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -39,6 +36,19 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
barTitle: TranslationLoader.lanKeys!.operatingRecord!.tr, barTitle: TranslationLoader.lanKeys!.operatingRecord!.tr,
haveBack: true, haveBack: true,
backgroundColor: AppColors.mainColor, backgroundColor: AppColors.mainColor,
actionsList: [
TextButton(
onPressed: () {
ShowCupertinoAlertView().showClearOperationRecordAlert(
clearClick: () {
logic.clearOperationRecordRequest();
});
},
child: Text(
'清空记录'.tr,
style: TextStyle(color: Colors.white, fontSize: 24.sp),
)),
],
), ),
body: Column( body: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
@ -52,7 +62,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
endIndent: 30.w, endIndent: 30.w,
), ),
eventDropDownWidget(), eventDropDownWidget(),
Expanded(child: Obx(() => timeLineView(state.lockLogItemList))) Expanded(child: timeLineView())
], ],
), ),
); );
@ -81,19 +91,34 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
highlightColor: Colors.yellow, highlightColor: Colors.yellow,
disabledColor: Colors.grey, disabledColor: Colors.grey,
), ),
child: AdvancedCalendar( child: Stack(
controller: state.calendarControllerCustom, children: [
events: state.events, AdvancedCalendar(
weekLineHeight: 48.0, controller: state.calendarControllerCustom,
startWeekDay: 1, events: state.events,
innerDot: true, weekLineHeight: 48.0,
keepLineSize: true, startWeekDay: 1,
calendarTextStyle: const TextStyle( innerDot: true,
fontSize: 18, keepLineSize: true,
fontWeight: FontWeight.w400, calendarTextStyle: const TextStyle(
height: 1.3125, fontSize: 18,
letterSpacing: 0, fontWeight: FontWeight.w400,
), height: 1.3125,
letterSpacing: 0,
),
),
Positioned(
top: 8.0,
right: 8.0,
child: Obx(() => Text(
'${state.currentSelectDate.value.year}${state.currentSelectDate.value.month}',
style: theme.textTheme.titleMedium!.copyWith(
fontSize: 16,
color: theme.colorScheme.secondary,
),
)),
),
],
), ),
); );
} }
@ -118,77 +143,16 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
} }
// //
Widget timeLineView(List<DoorLockLogDataItem> timelineDataList) { Widget timeLineView() {
return Container( return Container(
margin: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 20.h, top: 20.h), margin: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 20.h, top: 20.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16.w), borderRadius: BorderRadius.circular(16.w),
), ),
child: timelineDataList.isNotEmpty child: Obx(() => state.lockLogItemList.isNotEmpty
? Timeline.tileBuilder( ? Timeline.tileBuilder(
builder: TimelineTileBuilder.fromStyle( builder: _timelineBuilderWidget(),
contentsAlign: ContentsAlign.basic,
itemCount: timelineDataList.length,
contentsBuilder: (context, index) {
DoorLockLogDataItem timelineData = timelineDataList[index];
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
timelineData.operateDate!);
String formattedTime =
'${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
return Padding(
padding: EdgeInsets.only(left: 20.w, top: 20.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$formattedTime ${timelineData.recordTypeName}',
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontSize: 24.sp,
fontWeight: FontWeight.w600,
),
),
SizedBox(
height: 10.h,
),
GestureDetector(
onTap: () {
Get.toNamed(Routers.videoLogDetailPage);
},
child: Stack(
children: [
timelineData.imagesUrl!.isNotEmpty
? Image.network(
timelineData.imagesUrl!,
width: 260.w,
height: 260.h,
)
: Container(),
Positioned(
top: 150.h,
left: 10.w,
child: Image(
image: const AssetImage(
'images/main/icon_lockLog_play.png'),
width: 24.w,
height: 20.w,
),
),
],
),
),
SizedBox(
height: 20.h,
),
],
),
);
},
),
theme: TimelineThemeData( theme: TimelineThemeData(
nodePosition: 0.04, // nodePosition: 0.04, //
connectorTheme: const ConnectorThemeData( connectorTheme: const ConnectorThemeData(
@ -203,7 +167,72 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
), ),
), ),
) )
: NoData(), : NoData()),
);
}
TimelineTileBuilder _timelineBuilderWidget() {
return TimelineTileBuilder.fromStyle(
contentsAlign: ContentsAlign.basic,
itemCount: state.lockLogItemList.length,
contentsBuilder: (context, index) {
DoorLockLogDataItem timelineData = state.lockLogItemList[index];
DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(timelineData.operateDate!);
String formattedTime =
'${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
return Padding(
padding: EdgeInsets.only(left: 20.w, top: 20.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$formattedTime ${timelineData.username!.isNotEmpty ? "${timelineData.username}用" : ""}${timelineData.recordTypeName}',
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontSize: 24.sp,
fontWeight: FontWeight.w600,
),
),
SizedBox(
height: 10.h,
),
GestureDetector(
onTap: () {
Get.toNamed(Routers.videoLogDetailPage);
},
child: Stack(
children: [
timelineData.imagesUrl!.isNotEmpty
? Image.network(
timelineData.imagesUrl!,
width: 260.w,
height: 260.h,
)
: Container(),
Positioned(
top: 150.h,
left: 10.w,
child: Image(
image: const AssetImage(
'images/main/icon_lockLog_play.png'),
width: 24.w,
height: 20.w,
),
),
],
),
),
SizedBox(
height: 20.h,
),
],
),
);
},
); );
} }

View File

@ -17,31 +17,38 @@ class DoorLockLogState {
DateTime(2024, 10, 10), DateTime(2024, 10, 10),
]; ];
final startDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day).millisecondsSinceEpoch.obs; final startDate =
final endDate = (DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day + 1).subtract(const Duration(milliseconds: 1))).millisecondsSinceEpoch.obs; DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day)
.millisecondsSinceEpoch
.obs;
final endDate = (DateTime(
DateTime.now().year, DateTime.now().month, DateTime.now().day + 1)
.subtract(const Duration(milliseconds: 1)))
.millisecondsSinceEpoch
.obs;
var dropdownTitle = '全部事件'.obs; var dropdownTitle = '全部事件'.tr.obs;
var dropdownValue = XSConstantMacro.lockEventTypeAll.obs; var dropdownValue = XSConstantMacro.lockEventTypeAll.obs;
List<DropDownItem> getDropDownItemList = [ List<DropDownItem> getDropDownItemList = [
DropDownItem( DropDownItem(
itemTitle: "全部事件", itemTitle: "全部事件".tr,
itemValue: XSConstantMacro.lockEventTypeAll.toString(), itemValue: XSConstantMacro.lockEventTypeAll.toString(),
isCheked: false), isCheked: false),
DropDownItem( DropDownItem(
itemTitle: "开锁事件", itemTitle: "开锁事件".tr,
itemValue: XSConstantMacro.lockEventTypeOpenDoor.toString(), itemValue: XSConstantMacro.lockEventTypeOpenDoor.toString(),
isCheked: false), isCheked: false),
DropDownItem( DropDownItem(
itemTitle: "异常事件", itemTitle: "异常事件".tr,
itemValue: XSConstantMacro.lockEventTypeAbnormal.toString(), itemValue: XSConstantMacro.lockEventTypeAbnormal.toString(),
isCheked: false), isCheked: false),
DropDownItem( DropDownItem(
itemTitle: "门铃事件", itemTitle: "门铃事件".tr,
itemValue: XSConstantMacro.lockEventTypeDoorbell.toString(), itemValue: XSConstantMacro.lockEventTypeDoorbell.toString(),
isCheked: false), isCheked: false),
DropDownItem( DropDownItem(
itemTitle: "视频事件", itemTitle: "视频事件".tr,
itemValue: XSConstantMacro.lockEventTypeVideo.toString(), itemValue: XSConstantMacro.lockEventTypeVideo.toString(),
isCheked: false), isCheked: false),
]; ];
@ -50,6 +57,7 @@ class DoorLockLogState {
var operateDate = 0; // var operateDate = 0; //
var ifHaveNext = false; // var ifHaveNext = false; //
var logCountPage = 10; // var logCountPage = 10; //
var currentSelectDate = DateTime.now().obs; //
DoorLockLogState() { DoorLockLogState() {
keyInfos.value = Get.arguments["keyInfo"]; keyInfos.value = Get.arguments["keyInfo"];

View File

@ -1,9 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/appRouters.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart'; import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetail/electronicKeyDetail_page.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetail/electronicKeyDetail_page.dart';
import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetail/electronicKeyDetail_state.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetail/electronicKeyDetail_state.dart';
import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity/ElectronicKeyListEntity.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity/ElectronicKeyListEntity.dart';
import 'package:star_lock/mine/valueAddedServices/advancedFunctionRecord/advancedFunctionRecord_entity.dart';
import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/tools/baseGetXController.dart'; import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/showCupertinoAlertView.dart'; import 'package:star_lock/tools/showCupertinoAlertView.dart';
@ -135,16 +137,32 @@ class ElectronicKeyDetailLogic extends BaseGetXController {
Future<void> checkRealNameStatus(int realNameAuthStatus) async { Future<void> checkRealNameStatus(int realNameAuthStatus) async {
// //
if (realNameAuthStatus == 1) { if (realNameAuthStatus == 1) {
if (state.getRealName.value.isEmpty || AdvancedFunctionRecordEntity entity = await ApiRepository.to.keyCheckFace(
state.getIDCardNumber.value.isEmpty) { lockId: CommonDataManage().currentKeyInfo.lockId ?? 0,
ShowCupertinoAlertView() );
.showOpenAuthWithIDCardInfoAlert((idCard, realName) { if (entity.errorCode!.codeIsSuccessful) {
state.getIDCardNumber.value = idCard ?? ''; if (state.getRealName.value.isEmpty ||
state.getRealName.value = realName ?? ''; state.getIDCardNumber.value.isEmpty) {
ShowCupertinoAlertView()
.showOpenAuthWithIDCardInfoAlert((idCard, realName) {
state.getIDCardNumber.value = idCard ?? '';
state.getRealName.value = realName ?? '';
updateRealNameInfoWithAuthStatus(realNameAuthStatus);
});
} else {
updateRealNameInfoWithAuthStatus(realNameAuthStatus); updateRealNameInfoWithAuthStatus(realNameAuthStatus);
}); }
} else { } else if (entity.errorCode == 432) {
updateRealNameInfoWithAuthStatus(realNameAuthStatus); //432--
ShowCupertinoAlertView().showBuyTipWithContentAlert(
titleStr: '实名认证为付费功能,请购买后再使用'.tr,
sureClick: () {
Get.toNamed(Routers.advancedFeaturesWebPage,
arguments: {'isShop': false});
});
} else if (entity.errorCode == 433) {
//
ShowCupertinoAlertView().showContactAdministratorBuyAlert();
} }
} else { } else {
updateRealNameInfoWithAuthStatus(realNameAuthStatus); updateRealNameInfoWithAuthStatus(realNameAuthStatus);
@ -231,17 +249,23 @@ class ElectronicKeyDetailLogic extends BaseGetXController {
var textList = <String>[]; var textList = <String>[];
if (CommonDataManage().currentKeyInfo.keyRight == 1) { if (CommonDataManage().currentKeyInfo.keyRight == 1) {
textList = [ textList = [
state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen ? '取消冻结'.tr : "冻结".tr state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen
? '取消冻结'.tr
: "冻结".tr
]; ];
} else if (CommonDataManage().currentKeyInfo.isLockOwner == 1) { } else if (CommonDataManage().currentKeyInfo.isLockOwner == 1) {
if (state.keyType.value == 1 || state.keyType.value == 2) { if (state.keyType.value == 1 || state.keyType.value == 2) {
textList = [ textList = [
state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen ? '取消冻结'.tr : "冻结".tr, state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen
? '取消冻结'.tr
: "冻结".tr,
state.itemData.value.keyRight == 1 ? '取消授权'.tr : '授权'.tr state.itemData.value.keyRight == 1 ? '取消授权'.tr : '授权'.tr
]; ];
} else if (state.keyType.value == 4) { } else if (state.keyType.value == 4) {
textList = [ textList = [
state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen ? '取消冻结'.tr : "冻结".tr state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen
? '取消冻结'.tr
: "冻结".tr
]; ];
} }
} }
@ -256,7 +280,8 @@ class ElectronicKeyDetailLogic extends BaseGetXController {
chooseCallback: (value) { chooseCallback: (value) {
int index = value; int index = value;
if (index == 0) { if (index == 0) {
if (state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen) { if (state.itemData.value.keyStatus ==
XSConstantMacro.keyStatusFrozen) {
// //
if (state.itemData.value.keyRight == 1) { if (state.itemData.value.keyRight == 1) {
// //
@ -336,13 +361,36 @@ class ElectronicKeyDetailLogic extends BaseGetXController {
return currentController; return currentController;
} }
noModificationAllowedDuringFreeze(){ noModificationAllowedDuringFreeze() {
if(state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen){ if (state.itemData.value.keyStatus == XSConstantMacro.keyStatusFrozen) {
showToast("冻结状态下不允许修改钥匙权限".tr); showToast("冻结状态下不允许修改钥匙权限".tr);
return; return;
} }
} }
//
Future<void> keyCheckFace() async {
AdvancedFunctionRecordEntity entity = await ApiRepository.to.keyCheckFace(
lockId: CommonDataManage().currentKeyInfo.lockId ?? 0,
);
if (entity.errorCode!.codeIsSuccessful) {
//
state.isRequireAuth.value = true;
state.isRealNameAuth.value = true;
} else if (entity.errorCode == 432) {
//432--
ShowCupertinoAlertView().showBuyTipWithContentAlert(
titleStr: '实名认证为付费功能,请购买后再使用'.tr,
sureClick: () {
Get.toNamed(Routers.advancedFeaturesWebPage,
arguments: {'isShop': false});
});
} else if (entity.errorCode == 433) {
//
ShowCupertinoAlertView().showContactAdministratorBuyAlert();
}
}
@override @override
void onReady() { void onReady() {
// TODO: implement onReady // TODO: implement onReady

View File

@ -24,6 +24,7 @@ class ElectronicKeyDetailState {
var isRealNameAuth = false.obs; // 0: 1: var isRealNameAuth = false.obs; // 0: 1:
var getRealName = ''.obs; // var getRealName = ''.obs; //
var getIDCardNumber = ''.obs; // var getIDCardNumber = ''.obs; //
var isRequireAuth = false.obs; //
ElectronicKeyDetailState() { ElectronicKeyDetailState() {
Map map = Get.arguments; Map map = Get.arguments;

View File

@ -48,8 +48,7 @@ class LockEscalationLogic extends BaseGetXController {
// //
Future<void> otaUpdate() async { Future<void> otaUpdate() async {
var status = await PermissionDialog.request( var status = await PermissionDialog.requestStorage();
Permission.storage, '需要访问读写权限才能使用手动升级固件'.tr);
if (status != true) { if (status != true) {
return; return;
} }
@ -69,8 +68,7 @@ class LockEscalationLogic extends BaseGetXController {
} }
String md5Str = md5.convert(otaBin!).toString(); String md5Str = md5.convert(otaBin!).toString();
headJson!['fwMd5'] = md5Str; headJson!['fwMd5'] = md5Str;
ShowTipView().showIosTipWithContentDialog("未避免异常情况,请在门打开时升级".tr, ShowTipView().showIosTipWithContentDialog("未避免异常情况,请在门打开时升级".tr, () async {
() async {
blueOTAUpgrade(headJson!, [0, 0, 0, 0]); blueOTAUpgrade(headJson!, [0, 0, 0, 0]);
EasyLoading.show( EasyLoading.show(
status: '设备连接中...'.tr, maskType: EasyLoadingMaskType.black); status: '设备连接中...'.tr, maskType: EasyLoadingMaskType.black);

View File

@ -72,7 +72,7 @@ class _OpenDoorNotifyPageState extends State<OpenDoorNotifyPage> {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w), margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w),
child: Text( child: Text(
'若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择'.tr, '若锁没有联网,除电子钥匙外,密码、卡、指纹等开门提醒无法及时发送,请根据你的实际情况选择'.tr,
style: TextStyle(color: AppColors.darkGrayTextColor, fontSize: 20.sp), style: TextStyle(color: AppColors.darkGrayTextColor, fontSize: 20.sp),
)); ));
} }

View File

@ -431,8 +431,7 @@ class NearbyLockLogic extends BaseGetXController {
// //
Future<void> otaUpdate() async { Future<void> otaUpdate() async {
var status = await PermissionDialog.request( var status = await PermissionDialog.requestStorage();
Permission.storage, '需要访问读写权限才能使用手动升级固件'.tr);
if (status != true) { if (status != true) {
return; return;
} }

View File

@ -15,8 +15,7 @@ class Header extends StatelessWidget {
this.todayStyle, this.todayStyle,
}) : super(key: key); }) : super(key: key);
static final _dateFormatter = DateFormat().add_yMMMM(); static final _dateFormatter = DateFormat.yM('zh_CN');
// static final _dateFormatter = DateFormat('MM月dd日', 'zh_CN');
final DateTime monthDate; final DateTime monthDate;
final EdgeInsetsGeometry margin; final EdgeInsetsGeometry margin;
final VoidCallback? onPressed; final VoidCallback? onPressed;

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';

View File

@ -364,4 +364,36 @@ class ShowCupertinoAlertView {
}, },
); );
} }
//
void showClearOperationRecordAlert({required Function clearClick}) {
showCupertinoDialog(
context: Get.context!,
builder: (context) {
return CupertinoAlertDialog(
title: Text('是否要删除操作记录?'.tr),
content: Text('被删除的记录不能恢复'.tr),
actions: [
CupertinoDialogAction(
child: Text(
'取消'.tr,
style: TextStyle(color: AppColors.mainColor),
),
onPressed: () {
Get.back();
},
),
CupertinoDialogAction(
child:
Text('删除'.tr, style: TextStyle(color: AppColors.mainColor)),
onPressed: () {
Get.back();
clearClick();
},
),
],
);
},
);
}
} }

View File

@ -32,14 +32,30 @@ class PermissionDialog {
return false; return false;
} }
bool application = true; bool application = true;
Map<Permission, PermissionStatus> statuses = await [ List<Permission> permissions = [
Permission.bluetooth,
Permission.bluetoothScan, Permission.bluetoothScan,
Permission.bluetoothConnect, Permission.bluetoothConnect,
].request(); ];
Future<bool> getPermissionStatus(List<Permission> permissions) async {
bool isGranted = true;
List<PermissionStatus> permissionStatus = [];
for (Permission per in permissions) {
permissionStatus.add(await per.status);
}
for (PermissionStatus per in permissionStatus) {
isGranted = isGranted && per.isGranted;
}
if (GetPlatform.isIOS) {
isGranted = permissionStatus[0].isGranted;
}
return isGranted;
}
Permission permission = Permission.bluetoothScan; Permission permission = Permission.bluetoothScan;
dynamic cache = await Storage.getString(titles[permission]); dynamic cache = await Storage.getString(titles[permission]);
bool isGranted = statuses.values.every((element) => element.isGranted); bool isGranted = await getPermissionStatus(permissions);
if (AppPlatform.isAndroid && !isGranted && cache is! String) { if (GetPlatform.isAndroid && !isGranted && cache is! String) {
application = await showCupertinoDialog( application = await showCupertinoDialog(
context: Get.context!, context: Get.context!,
builder: (context) { builder: (context) {
@ -69,16 +85,19 @@ class PermissionDialog {
if (application) { if (application) {
await Storage.setString(titles[permission], titles[permission]); await Storage.setString(titles[permission], titles[permission]);
} }
} else if (cache is String) { } else if (cache is! String) {
bool isDenied = statuses.values.every((element) => element.isDenied); await Storage.setString(titles[permission], titles[permission]);
if (isDenied) { } else {
bool isGranted = await getPermissionStatus(permissions);
if (!isGranted) {
showSet(permission); showSet(permission);
return false; return false;
} }
} }
if (application) { if (application) {
PermissionStatus status = await permission.request(); await permissions.request();
return status.isGranted; bool isGranted = await getPermissionStatus(permissions);
return isGranted;
} }
return false; return false;
} }
@ -171,6 +190,98 @@ class PermissionDialog {
return false; return false;
} }
//
static Future<bool> requestStorage() async {
if (Get.context == null) {
return false;
}
bool isAndroid33 =
AppPlatform.isAndroid && AppPlatform.getSdkIntValue() >= 33;
//
List<Permission> requestPermission() {
List<Permission> permissions;
if (isAndroid33) {
permissions = [
Permission.mediaLibrary,
Permission.photos,
// Permission.audio,
Permission.videos,
Permission.manageExternalStorage,
];
} else {
permissions = [
Permission.storage,
];
}
return permissions;
}
Future<bool> permissionStatus(List<Permission> permissions) async {
bool isGranted = true;
for (Permission permission in permissions) {
isGranted =
isGranted && (await permission.status) == PermissionStatus.granted;
}
if (isAndroid33) {
// android 33
isGranted = (await Permission.mediaLibrary.status) ==
PermissionStatus.granted ||
(await Permission.manageExternalStorage.status) ==
PermissionStatus.granted;
}
return isGranted;
}
bool application = true;
Permission permission = Permission.photos;
List<Permission> permissions = requestPermission();
dynamic cache = await Storage.getString(titles[permission]);
bool isGranted = await permissionStatus(permissions);
if (AppPlatform.isAndroid && !isGranted && cache is! String) {
application = await showCupertinoDialog(
context: Get.context!,
builder: (context) {
return PopScope(
canPop: false,
child: CupertinoAlertDialog(
title: Text('${'申请'.tr}${titles[permission] ?? ''}${'权限'.tr}'),
content: Text('需要访问读写权限才能使用手动升级固件'.tr),
actions: [
CupertinoDialogAction(
child: Text('不允许'.tr),
onPressed: () {
Get.back(result: false);
},
),
CupertinoDialogAction(
child: Text('允许'.tr),
onPressed: () {
Get.back(result: true);
},
),
],
));
},
);
if (application) {
await Storage.setString(titles[permission], titles[permission]);
}
} else if (cache is String) {
bool isDenied = !(await permissionStatus(permissions));
if (isDenied) {
showSet(permission);
return false;
}
}
if (application) {
Map<Permission, PermissionStatus> statuses = await permissions.request();
bool isGranted = await permissionStatus(statuses.keys.toList());
return isGranted;
}
return false;
}
// //
static Future<bool> request(Permission permission, [String? content]) async { static Future<bool> request(Permission permission, [String? content]) async {
if (Get.context == null) { if (Get.context == null) {