123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import 'dart:async';
- import 'dart:io';
- import 'package:geolocation/models/position.dart';
- import 'package:get/get.dart';
- import 'package:o2oa_all_platform/common/extension/index.dart';
- import '../api/index.dart';
- import '../models/index.dart';
- import '../utils/index.dart';
- import '../widgets/index.dart';
- import 'shared_preference_service.dart';
- /// 极速打卡功能
- class FastCheckInService {
- // 单例
- static final FastCheckInService instance = FastCheckInService._internal();
- factory FastCheckInService() => instance;
- FastCheckInService._internal();
- // 定时器
- Timer? _timer;
- /// geolocator 定位
- GeolocatorHelper? _geoHelper;
- /// 当前定位信息
- GeoPosition? _myPosition;
- // 上班是否开启极速打卡
- bool _onDutyFastCheckInEnable = false;
- // 下班是否开启极速打卡
- bool _offDutyFastCheckInEnable = false;
- // 是否正在运行中
- bool _isRunning = false;
- // 运行时间 超过 2 分钟就结束
- int _runningTime = 0;
- // 工作地点
- final List<WorkPlaceList> _workplaceList = [];
- WorkPlaceList? _nearLeastWorkplace; // 最近的打卡地点
- bool _isInCheckInPositionRange = false; // 最近的打卡地点是否在打卡范围内
- AttendanceV2Record? _currentCheckItem; // 当前打卡对象
- bool _isPosting = false;
- /// 开始运行极速打卡
- void start() async {
- if (!Platform.isAndroid && !Platform.isIOS) return;
- if (_isRunning) return;
- OLogger.i('开始极速打卡!');
- _isRunning = true;
- final config = await AttendanceAssembleControlService.to.config();
- if (config != null &&
- (config.onDutyFastCheckInEnable == true ||
- config.offDutyFastCheckInEnable == true)) {
- _onDutyFastCheckInEnable = config.onDutyFastCheckInEnable ?? false;
- _offDutyFastCheckInEnable = config.offDutyFastCheckInEnable ?? false;
- _startTimer();
- _loadPreCheckInData();
- } else {
- OLogger.d('没有配置极速打卡!');
- _isRunning = false;
- }
- }
- /// 结束运行极速打卡
- void stop() {
- OLogger.i('结束极速打卡!');
- _timer?.cancel();
- _timer = null;
- _geoHelper?.stopLocation();
- _geoHelper = null;
- _myPosition = null;
- _nearLeastWorkplace = null;
- _currentCheckItem = null;
- _runningTime = 0;
- _isRunning = false;
- }
- /// 开始定位
- void _startLocation() async {
- // 初始化定位程序
- _geoHelper = GeolocatorHelper(callback: (position){
- _myPosition = position;
- _calNearestWorkplace();
- });
- _geoHelper?.startLocation();
- }
- /// 开始计时 2 分钟 没有运行结束就 stop
- void _startTimer() {
- /// 间隔5秒
- _timer = Timer.periodic(const Duration(milliseconds: 5000), (timer) {
- _runningTime += 5000;
- if (_runningTime >= 2 * 60 * 1000) {
- stop();
- }
- });
- }
- /// 获取打卡初始化数据
- /// 先判断数据业务 除了 固定班制 排班制 其他不进行自动打卡
- void _loadPreCheckInData() async {
- final data = await AttendanceAssembleControlService.to.loadPreCheckInData();
- if (data == null) {
- stop();
- return;
- }
- bool needCheck = data.canCheckIn ?? false; //今天是否还需要打卡
- if (needCheck) {
- // 打卡记录
- final checkItemList = data.checkItemList ?? [];
- // 是否最后一条已经打卡过的数据
- _currentCheckItem = checkItemList
- .firstWhereOrNull((element) => element.checkInResult == 'PreCheckIn');
- // 固定班制 排班制 并且有班次 id 才能进行极速打卡
- if (_currentCheckItem != null &&
- _currentCheckItem?.shiftId?.isNotEmpty == true &&
- (_currentCheckItem?.groupCheckType == "1" ||
- _currentCheckItem?.groupCheckType == "3")) {
- needCheck = true;
- } else {
- needCheck = false;
- }
- }
- // 如果不能打卡了 就结束
- if (!needCheck) {
- OLogger.i("今天无需打卡, 全部停止。");
- stop();
- } else {
- // 开始启动定位
- _startLocation();
- // 开始查询工作场所数据
- if (data.workPlaceList != null && data.workPlaceList!.isNotEmpty) {
- _workplaceList
- ..clear()
- ..addAll(data.workPlaceList!);
- // 计算最近的打卡地点
- _calNearestWorkplace();
- }
- _tryCheckIn();
- }
- }
- /// 尝试极速打卡
- void _tryCheckIn() {
- if (_myPosition == null || _workplaceList.isEmpty) {
- OLogger.e('可能还未定位到。。。。');
- return;
- }
- if (_nearLeastWorkplace != null &&
- _currentCheckItem != null &&
- _isInCheckInPositionRange) {
- // 上班打卡
- if ((_currentCheckItem?.checkInType == 'OnDuty' &&
- _onDutyFastCheckInEnable) ||
- (_currentCheckItem?.checkInType == 'OffDuty' &&
- _offDutyFastCheckInEnable)) {
- // 是否在打卡限制时间内
- final dutyTime = _currentCheckItem?.preDutyTime ?? '';
- final preBeforeTime = _currentCheckItem?.preDutyTimeBeforeLimit ?? '';
- final preAfterTime = _currentCheckItem?.preDutyTimeAfterLimit ?? '';
- if (!_checkLimitTime(_currentCheckItem?.checkInType ?? '', dutyTime,
- preBeforeTime, preAfterTime)) {
- OLogger.e("不在限制时间内!!!!");
- return;
- }
- _postCheckIn(_currentCheckItem!, _nearLeastWorkplace!.id!);
- } else {
- OLogger.i("当前打卡类型:${_currentCheckItem?.checkInType} 不允许极速打卡!");
- stop();
- }
- }
- }
- // 打卡
- void _postCheckIn(AttendanceV2Record record, String workPlaceId) async {
- if (_isPosting) return;
- _isPosting = true;
- var post = CheckPost(
- recordId: record.id,
- checkInType: record.checkInType,
- workPlaceId: workPlaceId,
- fieldWork: false,
- signDescription: '',
- latitude: '${_myPosition!.latitude}',
- longitude: '${_myPosition!.longitude}',
- recordAddress: '${_myPosition!.address}',
- sourceType: 'FAST_CHECK');
- var deviceType = SharedPreferenceService.to
- .getString(SharedPreferenceService.currentDeviceTypeKey);
- post.sourceDevice = deviceType;
- final iddata =
- await AttendanceAssembleControlService.to.checkInPostV2(post);
- if (iddata != null) {
- OLogger.i('极速打卡成功!');
- // 发送通知
- O2OverlayEntryDialog.instance.openFastCheckInDialog(
- 'attendance_fast_checkin_notify_title'.tr,
- 'attendance_fast_checkin_notify_content'
- .trArgs([(iddata.recordDate ?? '')]));
- stop();
- }
- _isPosting = false;
- }
- /// 是否有打卡时间限制
- bool _checkLimitTime(String checkInType, String dutyTime,
- String preDutyTimeBeforeLimit, String preDutyTimeAfterLimit) {
- final now = DateTime.now();
- final today = now.ymd();
- final dutyTimeDate = DateTime.tryParse('$today $dutyTime:00');
- if (dutyTimeDate == null) {
- OLogger.e('时间解析出差,$today $dutyTime');
- return false;
- }
- // 极速打卡开始时间
- var fastCheckInBeforeLimit = dutyTimeDate;
- if (checkInType == 'OnDuty') {
- //上班前一个小时
- fastCheckInBeforeLimit = dutyTimeDate.addMinutes(-60);
- }
- // 极速打卡结束时间
- var fastCheckInAfterLimit = dutyTimeDate.addMinutes(60); // 下班后1个小时
- if (checkInType == 'OnDuty') {
- fastCheckInAfterLimit = dutyTimeDate;
- }
- if (preDutyTimeBeforeLimit.isNotEmpty) {
- final beforeTime = DateTime.tryParse("$today $preDutyTimeBeforeLimit:00");
- if (beforeTime != null && fastCheckInBeforeLimit.isBefore(beforeTime)) {
- fastCheckInBeforeLimit = beforeTime;
- }
- }
- if (preDutyTimeAfterLimit.isNotEmpty) {
- final afterTime = DateTime.tryParse("$today $preDutyTimeAfterLimit:00");
- if (afterTime != null && fastCheckInAfterLimit.isAfter(afterTime)) {
- fastCheckInAfterLimit = afterTime;
- }
- }
- OLogger.d(
- "打卡时间,$dutyTimeDate 极速打卡开始时间:$fastCheckInBeforeLimit 极速打卡结束时间: $fastCheckInAfterLimit");
- if (fastCheckInBeforeLimit.isBefore(now) &&
- fastCheckInAfterLimit.isAfter(now)) {
- return true;
- }
- return false;
- }
- /// 计算最近的打卡地点
- void _calNearestWorkplace() async {
- if (_myPosition == null) {
- OLogger.e('还没有定位成功!');
- return;
- }
- _isInCheckInPositionRange = false;
- if (_workplaceList.isNotEmpty) {
- for (final workplace in _workplaceList) {
- OLogger.d('工作地点: ${workplace.latitude} ${workplace.longitude}');
- double startLatitude = _myPosition?.latitude ?? 0;
- double startLongitude = _myPosition?.longitude ?? 0;
- final lngLat = workplace.getLngLat();
- double endLatitude = lngLat[1];
- double endLongitude = lngLat[0];
- if (startLatitude != 0 && startLongitude != 0 && endLatitude != 0 && endLongitude != 0) {
- OLogger.d('坐标 workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
- final distance = _geoHelper?.distanceInMeters(startLatitude, startLongitude, endLatitude, endLongitude) ?? 0;
- int range = workplace.errorRange ?? 100; // 默认 100 米
- OLogger.d('距离计算:$distance $range');
- if (distance != 0 && distance <= range) {
- // 找到了范围内的打卡地点
- _nearLeastWorkplace = workplace;
- _isInCheckInPositionRange = true;
- _tryCheckIn();
- break;
- }
- } else {
- OLogger.e(' 错误的坐标 workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
- }
- }
- OLogger.d('找到最近的打卡点? ${_nearLeastWorkplace?.placeName ?? '无'}');
- }
- }
- }
|