a,领锁,点击+号时,如果获取网络时间失败,不进入下一页,提示必须联网 b. 开锁时:有网络时间则同步,无网络则不同步时间 c. 同步时间功能:必须有网才同步时间,确定和通通锁不一致 2、修改登录、注册、修改密码选择跟当前ip不是用一个国家的时候,弹窗提示
527 lines
17 KiB
Dart
Executable File
527 lines
17 KiB
Dart
Executable File
import 'package:flutter/material.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:star_lock/main/lockDetail/checkingIn/checkingInDetail/checkingInDetail_state.dart';
|
||
|
||
import '../../../../app_settings/app_colors.dart';
|
||
import '../../../../tools/titleAppBar.dart';
|
||
import '../../../../translations/trans_lib.dart';
|
||
import 'checkingInDetail_logic.dart';
|
||
|
||
class CheckingInDetailPage extends StatefulWidget {
|
||
const CheckingInDetailPage({Key? key}) : super(key: key);
|
||
|
||
@override
|
||
_CheckingInDetailPageState createState() => _CheckingInDetailPageState();
|
||
}
|
||
|
||
class _CheckingInDetailPageState extends State<CheckingInDetailPage> {
|
||
final CheckingInDetailLogic logic = Get.put(CheckingInDetailLogic());
|
||
final CheckingInDetailState state = Get.find<CheckingInDetailLogic>().state;
|
||
|
||
int _year = DateTime.now().year;
|
||
int _month = DateTime.now().month;
|
||
int _day = DateTime.now().day;
|
||
final List<CalendarModel> _datas = <CalendarModel>[];
|
||
final List<CalendarModel> _listDatas = <CalendarModel>[];
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
|
||
//设置默认当前月日期
|
||
_setDatas(year: _year, month: _month);
|
||
|
||
logic.getCheckInDetailData((){
|
||
//设置模拟数据,日历月事件,可根据接口返回的结果
|
||
_loadAttendanceMonthRecord('$_year-$_month');
|
||
});
|
||
|
||
//设置模拟数据,日历月事件,可根据接口返回的结果
|
||
// _loadAttendanceMonthRecord("$_year-$_month");
|
||
//日历日事件
|
||
// _loadAttendanceDayRecord("$_year-$_month-$_day");
|
||
}
|
||
|
||
//加载月历事件,请求接口
|
||
_loadAttendanceMonthRecord(String dateTime) async {
|
||
// 显示的上个月的天数
|
||
final int placeholderDays = _getPlaceholderDays(year: _year, month: _month);
|
||
// 当月多少天
|
||
final int currentMonthDays = _getCurrentMonthDays(year: _year, month: _month);
|
||
|
||
setState(() {
|
||
// 因为_datas这个月上个月都包含的都有 遍历把本月的赋值
|
||
for (int i = 0; i < _datas.length; i++) {
|
||
// 因为i从0开始 所以i>=上个月的天数 且小于上个月跟本月天数之和
|
||
if((i >= placeholderDays) && (i < (placeholderDays + currentMonthDays))){
|
||
_datas[i].workType = state.monthListData[i-placeholderDays].colorType.toString();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
//加载日事件,请求接口
|
||
_loadAttendanceDayRecord(String dateTime) async {
|
||
//可根据接口返回的内容在日历下面打卡信息或者其余内容
|
||
state.checkDate.value = DateTime.parse(dateTime).millisecondsSinceEpoch;
|
||
logic.getCheckInDetailData((){
|
||
//设置模拟数据,日历月事件,可根据接口返回的结果
|
||
_loadAttendanceMonthRecord('$_year-$_month');
|
||
});
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: TitleAppBar(
|
||
barTitle: state.staffName.value,
|
||
haveBack: true,
|
||
backgroundColor: AppColors.mainColor),
|
||
body: SingleChildScrollView(
|
||
child: Column(
|
||
children: <Widget>[
|
||
Container(
|
||
// margin: EdgeInsets.all(20.sp),
|
||
decoration: BoxDecoration(
|
||
//设置颜色
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.all(Radius.circular(12.r)),
|
||
//设置四周边框
|
||
),
|
||
child: Column(
|
||
children: <Widget>[
|
||
_yearHeader(),
|
||
SizedBox(height: 10.h),
|
||
_weekHeader(),
|
||
_everyDay(),
|
||
_bottomStatisticsWidget()
|
||
],
|
||
),
|
||
),
|
||
|
||
//下面可以添加日事件中的信息,例如打卡信息
|
||
Container(),
|
||
],
|
||
)));
|
||
}
|
||
|
||
//头部年
|
||
Widget _yearHeader() {
|
||
return Container(
|
||
height: 30,
|
||
margin: const EdgeInsets.only(top: 10),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: <Widget>[
|
||
GestureDetector(
|
||
onTap: _lastMonth,
|
||
child: Image(width: 50.w, height: 30.w, image: const AssetImage('images/icon_left_black.png'),),
|
||
),
|
||
SizedBox(width: 60.w,),
|
||
Text('$_year-$_month', style: TextStyle(fontSize: 28.sp, color: Colors.black, fontWeight: FontWeight.w500)),
|
||
SizedBox(width: 60.w),
|
||
GestureDetector(
|
||
onTap: _nextMonth,
|
||
child: Image(width: 50.w, height: 30.w, image: const AssetImage('images/icon_right_black.png')),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
//中部周
|
||
Widget _weekHeader() {
|
||
final List<String> array = <String>[
|
||
TranslationLoader.lanKeys!.mondayShort!.tr,
|
||
TranslationLoader.lanKeys!.tuesdayShort!.tr,
|
||
TranslationLoader.lanKeys!.wednesdayShort!.tr,
|
||
TranslationLoader.lanKeys!.thursdayShort!.tr,
|
||
TranslationLoader.lanKeys!.fridayShort!.tr,
|
||
TranslationLoader.lanKeys!.saturdayShort!.tr,
|
||
TranslationLoader.lanKeys!.sundayShort!.tr
|
||
];
|
||
return SizedBox(
|
||
height: 50.h,
|
||
child: GridView.builder(
|
||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||
itemCount: array.length,
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||
//横轴元素个数
|
||
crossAxisCount: 7,
|
||
//纵轴间距
|
||
// mainAxisSpacing: ScreenUtil().setHeight(10),
|
||
// 横轴间距
|
||
// crossAxisSpacing: ScreenUtil().setWidth(15),
|
||
//子组件宽高长度比例
|
||
childAspectRatio: 2),
|
||
itemBuilder: (BuildContext context, int index) {
|
||
return Container(
|
||
alignment: Alignment.center,
|
||
child: Text(
|
||
array[index],
|
||
style: TextStyle(
|
||
color:
|
||
// index == 5 || index == 6
|
||
// ? const Color(0xFFC4C8D0) :
|
||
const Color(0xFF3C3E43),
|
||
fontSize: 26.sp),
|
||
));
|
||
},
|
||
),
|
||
);
|
||
}
|
||
|
||
//底部日
|
||
Widget _everyDay() {
|
||
return GridView.builder(
|
||
padding: EdgeInsets.only(left: 10.sp, top: 10.sp, right: 10.sp),
|
||
itemCount: _getRowsForMonthYear(year: _year, month: _month) * 7,
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||
//横轴元素个数
|
||
crossAxisCount: 7,
|
||
// //纵轴间距
|
||
// mainAxisSpacing: ScreenUtil().setHeight(10),
|
||
// // 横轴间距
|
||
// crossAxisSpacing: ScreenUtil().setWidth(10),
|
||
//子组件宽高长度比例
|
||
childAspectRatio: 1),
|
||
itemBuilder: (BuildContext context, int index) {
|
||
Color backColor = Colors.white;
|
||
// Color textColor = const Color(0xFFFFFFFF);
|
||
if(_datas[index].workType == '1'){
|
||
// 迟到
|
||
backColor = const Color(0xFFE83523);
|
||
}else if( _datas[index].workType == '2'){
|
||
// 早退
|
||
backColor = const Color(0xFFEDB459);
|
||
}else if( _datas[index].workType == '3'){
|
||
// 未打卡
|
||
backColor = const Color(0xFF666666);
|
||
}
|
||
return GestureDetector(
|
||
onTap: () {
|
||
// setState(() {
|
||
// if (_datas[index].month == _month) {
|
||
// //判断点击的是否是当月日期,只对当前月点击的日期做处理
|
||
// for (int i = 0; i < _datas.length; i++) {
|
||
// if (i == index) {
|
||
// //切换至选中的日期
|
||
// _day = _datas[i].day!;
|
||
// _datas[i].isSelect = true;
|
||
//
|
||
// //加载选中的日期事件
|
||
// _loadAttendanceDayRecord(
|
||
// "${_datas[i].year}-${_datas[i].month}-${_datas[i].day}");
|
||
// } else {
|
||
// _datas[i].isSelect = false;
|
||
// }
|
||
// }
|
||
// } else {
|
||
// //不是当月的不做处理
|
||
// // _datas[index].is_select=false;
|
||
// }
|
||
// });
|
||
},
|
||
child: Column(
|
||
children: <Widget>[
|
||
Container(
|
||
width: 40.w,
|
||
height: 40.w,
|
||
//设置底部背景
|
||
decoration: BoxDecoration(
|
||
color: backColor,
|
||
shape: BoxShape.circle,
|
||
),
|
||
child: Center(
|
||
child: Text(
|
||
//不是当前月不显示值
|
||
_datas[index].month == _month
|
||
? _datas[index].day.toString()
|
||
: '',
|
||
textAlign: TextAlign.center,
|
||
//设置选中字体颜色 休息的颜色都是黑色 其余的都是白色因为有背景色
|
||
style: (int.parse(_datas[index].workType!) > 0)
|
||
? TextStyle(
|
||
fontSize: 24.sp, color: const Color(0xFFFFFFFF))
|
||
: TextStyle(
|
||
fontSize: 24.sp,
|
||
color: Colors.black),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 5),
|
||
//设置底部小圆点,非当前月的不显示,设置为透明,其余的根据状态判断显示
|
||
// _datas[index].month == _month &&
|
||
// _datas[index].workType != "" &&
|
||
// _datas[index].workType != "0"
|
||
// ? Container(
|
||
// height: 6.0,
|
||
// width: 6.0,
|
||
// decoration: BoxDecoration(
|
||
// shape: BoxShape.circle,
|
||
// color: _datas[index].workType == "1"
|
||
// ? const Color(0xFFF48835)
|
||
// : const Color(0xFF2C91F6)),
|
||
// )
|
||
// : Container(),
|
||
],
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Widget _bottomStatisticsWidget() {
|
||
return Column(
|
||
children: <Widget>[
|
||
Row(
|
||
children: <Widget>[
|
||
Container(
|
||
width: 1.sw,
|
||
// height: 40.h,
|
||
padding: EdgeInsets.only(left: 50.w, top: 5.h, bottom: 5.h),
|
||
color: Colors.grey,
|
||
child: Text(
|
||
'月统计'.tr,
|
||
style: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: 26.sp,
|
||
fontWeight: FontWeight.w500),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
_bottomStatisticsItemWidget(const Color(0xFFE83523), '迟到'.tr, state.lateTimes.value),
|
||
_bottomStatisticsItemWidget(const Color(0xFFEDB459), '早退'.tr, state.earlyTimes.value),
|
||
_bottomStatisticsItemWidget(const Color(0xFF666666), '未打卡'.tr, state.noPunchTimes.value),
|
||
],
|
||
);
|
||
}
|
||
|
||
Widget _bottomStatisticsItemWidget(
|
||
Color color,
|
||
String leftTitel,
|
||
String rightTitle,
|
||
) {
|
||
return Column(
|
||
children: <Widget>[
|
||
Container(
|
||
// height: 70.h,
|
||
padding:
|
||
EdgeInsets.only(left: 20.w, right: 10.w, top: 20.w, bottom: 20.w),
|
||
child: Row(
|
||
children: <Widget>[
|
||
SizedBox(width: 20.w),
|
||
Container(
|
||
width: 30.w,
|
||
height: 30.w,
|
||
decoration: BoxDecoration(
|
||
color: color,
|
||
borderRadius: BorderRadius.all(Radius.circular(30.h))),
|
||
),
|
||
SizedBox(width: 20.w),
|
||
Expanded(
|
||
child: Text(leftTitel,
|
||
style: TextStyle(
|
||
fontSize: 24.sp, fontWeight: FontWeight.w500))),
|
||
SizedBox(width: 20.w),
|
||
Text(rightTitle,
|
||
textAlign: TextAlign.end,
|
||
style:
|
||
TextStyle(fontSize: 24.sp, fontWeight: FontWeight.w500)),
|
||
SizedBox(width: 10.w),
|
||
],
|
||
),
|
||
),
|
||
Container(
|
||
height: 0.5.h,
|
||
color: Colors.grey,
|
||
)
|
||
],
|
||
);
|
||
}
|
||
|
||
// 获取行数
|
||
int _getRowsForMonthYear({int? year, int? month}) {
|
||
// 当前月天数
|
||
final int currentMonthDays = _getCurrentMonthDays(year: year, month: month);
|
||
// 这个月1号前面有几天
|
||
final int placeholderDays = _getPlaceholderDays(year: year, month: month);
|
||
|
||
int rows = (currentMonthDays + placeholderDays) ~/ 7;
|
||
|
||
final int remainder = (currentMonthDays + placeholderDays) % 7;
|
||
if (remainder > 0) {
|
||
rows = rows + 1;
|
||
}
|
||
return rows;
|
||
}
|
||
|
||
// 得到这个月的第一天是星期几
|
||
int _getPlaceholderDays({int? year, int? month}) {
|
||
return DateTime(year!, month!).weekday - 1 % 7;
|
||
}
|
||
|
||
// 获取当前月份天数
|
||
int _getCurrentMonthDays({int? year, int? month}) {
|
||
if (month == 2) {
|
||
//判断2月份是闰年月还是平年
|
||
if (((year! % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
|
||
return 29;
|
||
} else {
|
||
return 28;
|
||
}
|
||
} else if (month == 1 ||
|
||
month == 3 ||
|
||
month == 5 ||
|
||
month == 7 ||
|
||
month == 8 ||
|
||
month == 10 ||
|
||
month == 12) {
|
||
return 31;
|
||
} else {
|
||
return 30;
|
||
}
|
||
}
|
||
|
||
/// 获取展示信息
|
||
_setDatas({int? year, int? month}) {
|
||
/// 上个月占位
|
||
int? lastYear = year;
|
||
int lastMonth = month! - 1;
|
||
if (month == 1) {
|
||
lastYear = (year! - 1)!;
|
||
lastMonth = 12;
|
||
}
|
||
|
||
final int placeholderDays = _getPlaceholderDays(year: year, month: month);
|
||
final int lastMonthDays = _getCurrentMonthDays(year: lastYear, month: lastMonth);
|
||
final int firstDay = lastMonthDays - placeholderDays;
|
||
for (int i = 0; i < placeholderDays; i++) {
|
||
_datas.add(CalendarModel(
|
||
year: lastYear,
|
||
month: lastMonth,
|
||
day: firstDay + i + 1,
|
||
isSelect: false,
|
||
workType: '0'));
|
||
}
|
||
|
||
/// 本月显示
|
||
final int currentMonthDays = _getCurrentMonthDays(year: year, month: month);
|
||
for (int i = 0; i < currentMonthDays; i++) {
|
||
if (i == _day - 1) {
|
||
_datas.add(CalendarModel(
|
||
year: year,
|
||
month: month,
|
||
day: i + 1,
|
||
isSelect: true,
|
||
workType: '0'));
|
||
} else {
|
||
_datas.add(CalendarModel(
|
||
year: year,
|
||
month: month,
|
||
day: i + 1,
|
||
isSelect: false,
|
||
workType: '0'));
|
||
}
|
||
}
|
||
|
||
/// 下个月占位
|
||
int? nextYear = year;
|
||
int nextMonth = month + 1;
|
||
if (month == 12) {
|
||
nextYear = year! + 1;
|
||
nextMonth = 1;
|
||
}
|
||
final int nextPlaceholderDays =
|
||
_getPlaceholderDays(year: nextYear, month: nextMonth);
|
||
for (int i = 0; i < 7 - nextPlaceholderDays; i++) {
|
||
_datas.add(CalendarModel(
|
||
year: nextYear,
|
||
month: nextMonth,
|
||
day: i + 1,
|
||
isSelect: false,
|
||
workType: '0'));
|
||
}
|
||
}
|
||
|
||
// 上月
|
||
_lastMonth() {
|
||
setState(() {
|
||
if (_month == 1) {
|
||
_year = _year - 1;
|
||
_month = 12;
|
||
} else {
|
||
_month = _month - 1;
|
||
}
|
||
_day = 1; //查看上一个月时,默认选中的为第一天
|
||
_datas.clear();
|
||
_setDatas(year: _year, month: _month);
|
||
//更新月历事件
|
||
// _loadAttendanceMonthRecord("$_year-$_month");
|
||
//更新日事件
|
||
_loadAttendanceDayRecord("$_year-${_month.toString().padLeft(2,'0')}-${_day.toString().padLeft(2,'0')}");
|
||
});
|
||
}
|
||
|
||
// 下月
|
||
_nextMonth() {
|
||
if (_month == 12) {
|
||
//当前月是12月,下一个月就是下一年
|
||
if (DateTime.now().year >= _year + 1) {
|
||
//判断下一年是否大于当前年
|
||
_setNextMonthData();
|
||
}
|
||
} else {
|
||
//当前月不是12月,还处于当前年
|
||
if (DateTime.now().month >= _month + 1) {
|
||
//判断下一个月是否超过当前月,超过当前月不做操作
|
||
_setNextMonthData();
|
||
}
|
||
}
|
||
}
|
||
|
||
//设置下个月的数据
|
||
_setNextMonthData() {
|
||
setState(() {
|
||
if (_month == 12) {
|
||
_year = _year + 1;
|
||
_month = 1;
|
||
} else {
|
||
_month = _month + 1;
|
||
}
|
||
if (_month == DateTime.now().month) {
|
||
//如果下个月时当前月,默认选中当天
|
||
_day = DateTime.now().day;
|
||
} else {
|
||
//如果不是当前月,默认选中第一天
|
||
_day = 1;
|
||
}
|
||
_datas.clear();
|
||
_setDatas(year: _year, month: _month);
|
||
//更新月历事件
|
||
_loadAttendanceMonthRecord('$_year-$_month');
|
||
//更新日事件
|
||
// _loadAttendanceDayRecord("$_year-$_month-$_day");
|
||
_loadAttendanceDayRecord("$_year-${_month.toString().padLeft(2,'0')}-${_day.toString().padLeft(2,'0')}");
|
||
});
|
||
}
|
||
}
|
||
|
||
//日历bean
|
||
class CalendarModel {
|
||
|
||
CalendarModel(
|
||
{this.year, this.month, this.day, this.isSelect, this.workType});
|
||
int? year;
|
||
int? month;
|
||
int? day;
|
||
String? workType = ''; //日期事件,0休息,1迟到,2早退,3未打卡
|
||
bool? isSelect = false;
|
||
}
|