1,操作记录完善部分缺失UI布局

2,新增操作记录读取记录功能
3,新增PopupMenuButton组件及公用弹窗
4,修复我的设置、锁设置—锁需联网标识 关联锁详情页面问题
This commit is contained in:
Daisy 2024-06-15 17:20:55 +08:00
parent 7b59e9056a
commit 738c9e19b4
8 changed files with 175 additions and 84 deletions

View File

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
@ -58,24 +57,24 @@ class DoorLockLogLogic extends BaseGetXController {
var indexList = getList[i];
// AppLog.log("indexList:$indexList");
var indexMap = {};
indexMap["type"] = indexList[0].toString();
indexMap['type'] = indexList[0].toString();
int operateDate = 0;
if (indexList[0] == 2) {
var passwordData = indexList.sublist(7, 17);
var password = utf8String(passwordData);
indexMap["user"] = password.toString();
}else {
indexMap['user'] = password.toString();
} else {
int userNo = (indexList[1] * 256) + indexList[2];
indexMap["user"] = userNo.toString();
indexMap['user'] = userNo.toString();
}
indexMap["success"] = "1";
indexMap['success'] = '1';
int time = ((0xff & indexList[(3)]) << 24 |
(0xff & indexList[4]) << 16 |
(0xff & indexList[5]) << 8 |
(0xFF & indexList[6]));
indexMap["date"] = "${time * 1000}";
indexMap['date'] = '${time * 1000}';
uploadList.add(indexMap);
if (i == getList.length - 1) {
@ -141,13 +140,13 @@ class DoorLockLogLogic extends BaseGetXController {
}
//
void mockNetworkDataRequest({required bool isRefresh}) async {
Future<void> mockNetworkDataRequest({required bool isRefresh}) async {
//
if (isRefresh) {
state.lockLogItemList.clear();
pageNo = 1;
}
DoorLockLogEntity entity = await ApiRepository.to.lockEventList(
final DoorLockLogEntity entity = await ApiRepository.to.lockEventList(
lockId: state.keyInfos.value.lockId!,
lockEventType: state.dropdownValue.value,
pageNo: pageNo,
@ -165,8 +164,9 @@ class DoorLockLogLogic extends BaseGetXController {
///
StreamSubscription? _getDoorLockLogListRefreshUIEvent;
void _getDoorLockLogListRefreshUIAction() {
_getDoorLockLogListRefreshUIEvent =
eventBus.on<DoorLockLogListRefreshUI>().listen((event) {
_getDoorLockLogListRefreshUIEvent = eventBus
.on<DoorLockLogListRefreshUI>()
.listen((DoorLockLogListRefreshUI event) {
state.currentSelectDate.value = event.getDoorLockLogTime;
// startDate为当天的0点
state.startDate.value = DateTime(
@ -175,11 +175,11 @@ class DoorLockLogLogic extends BaseGetXController {
state.currentSelectDate.value.day)
.millisecondsSinceEpoch;
// endDate为下一天的0点1
state.endDate.value = (DateTime(
state.currentSelectDate.value.year,
state.currentSelectDate.value.month,
state.currentSelectDate.value.day + 1)
.subtract(const Duration(milliseconds: 1)))
state.endDate.value = DateTime(
state.currentSelectDate.value.year,
state.currentSelectDate.value.month,
state.currentSelectDate.value.day + 1)
.subtract(const Duration(milliseconds: 1))
.millisecondsSinceEpoch;
pageNo = 1;
@ -188,9 +188,9 @@ class DoorLockLogLogic extends BaseGetXController {
}
//
void getLockRecordLastUploadDataTime() async {
LockOperatingRecordGetLastRecordTimeEntity entity = await ApiRepository.to
.getLockRecordLastUploadDataTime(
Future<void> getLockRecordLastUploadDataTime() async {
final LockOperatingRecordGetLastRecordTimeEntity entity =
await ApiRepository.to.getLockRecordLastUploadDataTime(
lockId: state.keyInfos.value.lockId.toString());
if (entity.errorCode!.codeIsSuccessful) {
state.operateDate = entity.data!.operateDate! ~/ 1000;
@ -199,8 +199,8 @@ class DoorLockLogLogic extends BaseGetXController {
}
//
void lockRecordUploadData(List list) async {
KeyOperationRecordEntity entity = await ApiRepository.to
Future<void> lockRecordUploadData(List list) async {
final KeyOperationRecordEntity entity = await ApiRepository.to
.lockRecordUploadData(
lockId: state.keyInfos.value.lockId.toString(), records: list);
if (entity.errorCode!.codeIsSuccessful) {
@ -213,12 +213,12 @@ class DoorLockLogLogic extends BaseGetXController {
}
//
void clearOperationRecordRequest() async {
KeyOperationRecordEntity entity = await ApiRepository.to
Future<void> clearOperationRecordRequest() async {
final KeyOperationRecordEntity entity = await ApiRepository.to
.clearOperationRecord(
CommonDataManage().currentKeyInfo.lockId.toString());
if (entity.errorCode!.codeIsSuccessful) {
showToast("清除数据成功", something: () {
showToast('清除数据成功', something: () {
pageNo = 1;
mockNetworkDataRequest(isRefresh: true);
});

View File

@ -5,12 +5,14 @@ import 'package:get/get.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_logic.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
import 'package:star_lock/tools/EasyRefreshTool.dart';
import 'package:star_lock/tools/advancedCalendar/src/widget.dart';
import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/menuItem/xsDropDownWidget.dart';
import 'package:star_lock/tools/noData.dart';
import 'package:star_lock/tools/showCupertinoAlertView.dart';
import 'package:star_lock/tools/showTipView.dart';
import 'package:timelines/timelines.dart';
import '../../../app_settings/app_colors.dart';
@ -26,8 +28,8 @@ class DoorLockLogPage extends StatefulWidget {
}
class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
final logic = Get.put(DoorLockLogLogic());
final state = Get.find<DoorLockLogLogic>().state;
final DoorLockLogLogic logic = Get.put(DoorLockLogLogic());
final DoorLockLogState state = Get.find<DoorLockLogLogic>().state;
@override
Widget build(BuildContext context) {
@ -37,22 +39,45 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
barTitle: TranslationLoader.lanKeys!.operatingRecord!.tr,
haveBack: true,
backgroundColor: AppColors.mainColor,
actionsList: [
actionsList: <Widget>[
Visibility(
visible: CommonDataManage().currentKeyInfo.isLockOwner == 1
? true
: false,
child: TextButton(
onPressed: () {
ShowCupertinoAlertView().showClearOperationRecordAlert(
clearClick: () {
logic.clearOperationRecordRequest();
});
},
child: Text(
'清空记录'.tr,
style: TextStyle(color: Colors.white, fontSize: 24.sp),
))),
visible: CommonDataManage().currentKeyInfo.isLockOwner == 1,
child: GestureDetector(
child: Image.asset(
'images/icon_tips_Q.png',
width: 34.w,
height: 32.w,
color: Colors.white,
),
onTap: () {
ShowTipView().showSureAlertDialog(
'1.锁没有联网密码、IC卡、指纹等开门记录无法实时上传可以点击右上角按钮然后读取记录。\n2.只能保留一定时间内的记录,如果您需要保留历史记录,可以点击右上角按钮,然后导出记录',
tipTitle: '看不到操作记录,可能原因有',
sureStr: '我知道了');
},
)),
Visibility(
visible: CommonDataManage().currentKeyInfo.isLockOwner == 1,
child: PopupMenuButton<String>(
onSelected: _onMenuItemSelected,
color: Colors.black,
itemBuilder: (BuildContext context) {
return <PopupMenuEntry<String>>[
_buildCustomPopupMenuItem('读取记录'),
const PopupMenuDivider(),
_buildCustomPopupMenuItem('清空记录'),
const PopupMenuDivider(),
_buildCustomPopupMenuItem('导出记录'),
];
},
icon: Image.asset(
'images/icon_bar_more.png',
height: 30.h,
width: 10.w,
),
offset: Offset(0, 70.h), //
),
),
],
),
body: Column(
@ -73,9 +98,47 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
);
}
//
PopupMenuItem<String> _buildCustomPopupMenuItem(String value) {
return PopupMenuItem<String>(
value: value,
height: 46.h,
child: SizedBox(
height: 46.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(value, style: TextStyle(color: Colors.white, fontSize: 22.sp)),
],
),
),
);
}
void _onMenuItemSelected(String value) {
switch (value) {
case '读取记录':
{
logic.mockNetworkDataRequest(isRefresh: true);
}
break;
case '清空记录':
{
ShowCupertinoAlertView().showClearOperationRecordAlert(
clearClick: () {
logic.clearOperationRecordRequest();
});
}
break;
case '导出记录':
{}
break;
}
}
//
Widget topAdvancedCalendarWidget() {
final theme = Theme.of(context);
final ThemeData theme = Theme.of(context);
return Theme(
data: theme.copyWith(
textTheme: theme.textTheme.copyWith(
@ -134,7 +197,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
margin: EdgeInsets.only(top: 20.h, left: 30.w, bottom: 10.h, right: 20.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
children: <Widget>[
Obx(() => XSDropDownWidget(
items: state.getDropDownItemList,
value: state.dropdownTitle.value,
@ -187,11 +250,11 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
return TimelineTileBuilder.fromStyle(
contentsAlign: ContentsAlign.basic,
itemCount: state.lockLogItemList.length,
contentsBuilder: (context, index) {
DoorLockLogDataItem timelineData = state.lockLogItemList[index];
DateTime dateTime =
contentsBuilder: (BuildContext context, int index) {
final DoorLockLogDataItem timelineData = state.lockLogItemList[index];
final DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(timelineData.operateDate!);
String formattedTime =
final String formattedTime =
'${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
return Padding(
@ -199,7 +262,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
children: <Widget>[
Text(
'$formattedTime ${timelineData.username!.isNotEmpty ? "${timelineData.username}用" : ""}${timelineData.recordTypeName}',
textAlign: TextAlign.left,
@ -217,14 +280,15 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
Get.toNamed(Routers.videoLogDetailPage);
},
child: Stack(
children: [
timelineData.imagesUrl!.isNotEmpty
? Image.network(
timelineData.imagesUrl!,
width: 260.w,
height: 260.h,
)
: Container(),
children: <Widget>[
if (timelineData.imagesUrl!.isNotEmpty)
Image.network(
timelineData.imagesUrl!,
width: 260.w,
height: 260.h,
)
else
Container(),
Positioned(
top: 150.h,
left: 10.w,
@ -293,7 +357,9 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
void didPushNext() {
super.didPushNext();
logic.cancelBlueConnetctToastTimer();
if (EasyLoading.isShow) EasyLoading.dismiss(animation: true);
if (EasyLoading.isShow) {
EasyLoading.dismiss(animation: true);
}
state.ifCurrentScreen.value = false;
}
}

View File

@ -350,18 +350,20 @@ class LockDetailLogic extends BaseGetXController {
//
Future<void> getServerDatetime() async {
final GetServerDatetimeEntity entity =
await ApiRepository.to.getServerDatetimeData(isUnShowLoading:true);
await ApiRepository.to.getServerDatetimeData(isUnShowLoading: true);
if (entity.errorCode!.codeIsSuccessful) {
state.differentialTime = entity.data!.date! ~/ 1000 - DateTime.now().millisecondsSinceEpoch ~/ 1000;
}else{
state.differentialTime = entity.data!.date! ~/ 1000 -
DateTime.now().millisecondsSinceEpoch ~/ 1000;
} else {
state.isHaveNetwork = false;
}
}
int getUTCNetTime() {
if(state.isHaveNetwork){
return DateTime.now().millisecondsSinceEpoch ~/ 1000 + state.differentialTime;
}else{
if (state.isHaveNetwork) {
return DateTime.now().millisecondsSinceEpoch ~/ 1000 +
state.differentialTime;
} else {
return 0;
}
}
@ -474,10 +476,10 @@ class LockDetailLogic extends BaseGetXController {
// state.keyInfos.value.electricQuantity = int.parse(event.setResult);
final int electricQuantity =
int.tryParse(event.setResult['electricQuantity']) ?? 0;
state.electricQuantity.value =electricQuantity;
state.electricQuantity.value = electricQuantity;
state.keyInfos.value.electricQuantity = electricQuantity;
state.keyInfos.value.electricQuantityDate =
event.setResult['uploadElectricQuantityDate'];
event.setResult['uploadElectricQuantityDate'];
} else if (event.type == 5) {
// 5
state.keyInfos.value.lockSetting!.remoteUnlock =
@ -536,6 +538,13 @@ class LockDetailLogic extends BaseGetXController {
state.LockSetChangeSetRefreshLockDetailWithTypeSubscription = eventBus
.on<LockSetChangeSetRefreshLockDetailWithType>()
.listen((LockSetChangeSetRefreshLockDetailWithType event) {
//
if (event.type == 1) {
state.isOpenLockNeedOnline.value = int.parse(event.setResult);
state.keyInfos.value.lockSetting!.appUnlockOnline =
int.parse(event.setResult);
state.isOpenLockNeedOnline.refresh();
}
if (event.type == 4) {
final int electricQuantity =
int.tryParse(event.setResult['electricQuantity']) ?? 0;

View File

@ -776,18 +776,18 @@ class _LockDetailPageState extends State<LockDetailPage>
child: Image.asset('images/main/icon_lockDetail_needNetwork.png',
width: 24.w,
height: 20.w,
color: state.keyInfos.value.appUnlockOnline == 1
color: state.isOpenLockNeedOnline.value == 1
? AppColors.mainColor
: AppColors.btnDisableColor),
),
SizedBox(width: 6.w),
Text(
'手机需联网',
style: TextStyle(
fontSize: 20.sp,
color: state.keyInfos.value.appUnlockOnline == 1
? AppColors.mainColor
: AppColors.btnDisableColor),
Obx(
() => Text('手机需联网',
style: TextStyle(
fontSize: 20.sp,
color: state.isOpenLockNeedOnline.value == 1
? AppColors.mainColor
: AppColors.btnDisableColor)),
),
if (add) ...<Widget>[
const Spacer(),

View File

@ -5,6 +5,7 @@ import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:star_lock/login/login/entity/LoginEntity.dart';
import 'package:star_lock/main/lockMian/entity/lockListInfo_entity.dart';
import 'package:star_lock/main/lockMian/lockMain/lockMain_logic.dart';
import 'package:star_lock/tools/showTipView.dart';
import '../../../../blue/blue_manage.dart';
@ -596,7 +597,8 @@ class LockSetLogic extends BaseGetXController {
final bool isXHJ = F.isXHJ;
final bool isOnlyOneData = state.isOnlyOneData.value == true;
await Future<dynamic>.delayed(const Duration(milliseconds: 200)).then((e) {
await Future<dynamic>.delayed(const Duration(milliseconds: 200))
.then((e) {
if (isXHJ) {
Get.close(3);
} else {

View File

@ -1,15 +1,20 @@
import 'package:get/get.dart';
import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_logic.dart';
import 'package:star_lock/main/lockMian/lockMain/lockMain_logic.dart';
import '../../../network/api_repository.dart';
import '../../../tools/baseGetXController.dart';
import 'appUnlockNeedMobileNetworkingLock_state.dart';
import 'selectLockListEntity.dart';
class AppUnlockNeedMobileNetworkingLockLogic extends BaseGetXController{
final AppUnlockNeedMobileNetworkingLockState state = AppUnlockNeedMobileNetworkingLockState();
class AppUnlockNeedMobileNetworkingLockLogic extends BaseGetXController {
final AppUnlockNeedMobileNetworkingLockState state =
AppUnlockNeedMobileNetworkingLockState();
//
Future<SelectLockListEntity> mockNetworkDataRequest() async {
final SelectLockListEntity entity = await ApiRepository.to.selectLockList(searchStr: state.searchController.text);
final SelectLockListEntity entity = await ApiRepository.to
.selectLockList(searchStr: state.searchController.text);
List<LockItemData> dataList = <LockItemData>[];
if (entity.errorCode!.codeIsSuccessful) {
dataList = entity.data!.list!;
@ -27,9 +32,14 @@ class AppUnlockNeedMobileNetworkingLockLogic extends BaseGetXController{
//APP开锁时需手机联网的锁
Future<void> setAppUnlockMustOnlineRequest() async {
final SelectLockListEntity entity =
await ApiRepository.to.setAppUnlockMustOnline(state.selectLockIdList);
await ApiRepository.to.setAppUnlockMustOnline(state.selectLockIdList);
if (entity.errorCode!.codeIsSuccessful) {
showToast('操作成功');
//--
if (Get.isRegistered<LockMainLogic>()) {
Get.find<LockMainLogic>().getStarLockInfo();
}
}
}
@ -44,5 +54,4 @@ class AppUnlockNeedMobileNetworkingLockLogic extends BaseGetXController{
void onInit() {
super.onInit();
}
}
}

View File

@ -102,7 +102,8 @@ class BaseProvider extends GetConnect with Api {
EasyLoading.showToast('数据不存在', duration: 2000.milliseconds);
break;
case 434: //
ShowTipView().showSureBtnTipsAlert(T['errorMsg']);
ShowTipView()
.showSureBtnTipsAlert(tipsText: T['errorMsg'], sureText: '确定');
break;
}
}

View File

@ -23,7 +23,8 @@ class ShowTipView {
content: Text(contentStr),
actions: <Widget>[
CupertinoDialogAction(
child: Text(sureStr ?? TranslationLoader.lanKeys!.sure!.tr),
child: Text(sureStr ?? TranslationLoader.lanKeys!.sure!.tr,
style: TextStyle(color: AppColors.mainColor)),
onPressed: Get.back,
),
],
@ -93,7 +94,9 @@ class ShowTipView {
);
}
void showTFViewAlertDialog(TextEditingController controller, String title, String tipTitle, Function sureClick, {List<TextInputFormatter>? inputFormatters, bool? isShowSuffixIcon}) {
void showTFViewAlertDialog(TextEditingController controller, String title,
String tipTitle, Function sureClick,
{List<TextInputFormatter>? inputFormatters, bool? isShowSuffixIcon}) {
//
showDialog(
context: Get.context!,
@ -122,7 +125,8 @@ class ShowTipView {
}
//
void showSureBtnTipsAlert(String tipsText) {
void showSureBtnTipsAlert(
{required String tipsText, required String sureText}) {
showCupertinoDialog(
context: Get.context!,
builder: (BuildContext context) {