// // BigTruckVC.m // jiaPei // // Created by EchoShacolee on 2018/4/3. // Copyright © 2018年 JCZ. All rights reserved. // /* 中途/首次连接流程: 手机主动发起连接请求指令RequestConnectOrder(包含学员全国统一编号);终端判断回复be020400成功,be020401非当前学员失败 期间由心跳包保持连接 中断心跳包指令be0501... ;app回复 HeartbeatOrder 签退:终端签退通知手机指令:QuitOrder,若手机不在附近 手机会在每5分钟更新学员状态的地方知道自己已被签退 停止计时 本地学时补传:nextWithCurrentStatu 里面根据当前是否准备计时来判断是立即提示补传或者等开始计时后的第一分钟跟随上传 状态接口没300s调一次。1.更新UI 2.检测状态。如果检测到学员在终端已签退。则执行签退相关的操作 状态接口1:getCurrentState 更新训练状态 更新训练过程图片 状态接口2:getStudentTrainInfos 更新训练信息 */ #import "BigTruckVC.h" #import #import //bd计算相关 #import "TileViewController.h" #import "EleMinRecordListVC.h" #import #import "BC_TimerImgView.h" static NSString * const bigCarTableName = @"dcPeriod"; static NSString * const BServiceUUID = @"6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; static NSString * const BCharacteristicUUID_write = @"6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; static NSString * const BCharacteristicUUID_reade = @"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; static NSString * const RequestConnectOrder = @"be0984";//请求连接 static NSString * const HeartbeatOrder = @"be03810000";//心跳回应 static NSString * const QuitOrder = @"be0183";//签退指令 @interface BigTruckVC () { BOOL hasReply; //蓝牙命令已回复 BOOL isVoice; //是否开启语音提醒 默认开启 NSDateFormatter *dateFormatter; NSMutableDictionary *minuteTrainDic;//分钟学时用参数 签到和断线重连时候初始化 分钟学时发送之前更新字典 NSMutableDictionary *gatherTrainDic;//汇总学时用参数 签到和断线重连时候初始化 分钟学时发送之前更新字典 并存本地 短线重连用来恢复计时 //地图定位 CLLocationCoordinate2D myCoordinate;//定位我的位置 NSMutableDictionary *gpsDic; //某个点的信息 CLLocationManager *locationManager;//系统gps NSTimer *timer; NSInteger seconds; //定时器时间 //蓝牙 BOOL dataIsLack;//如果为yes代表数据不完整 需要下次接收到的数据拼接 NSString *lastData;//接收蓝牙数据时 一个数据包分次返回时 之前的数据 NSString *peripheralName;//蓝牙名称 NSString *blueToothOrder;//最新的蓝牙命令 用于蓝牙未回应重新作操作 BOOL isConnectBlueTooth;//是否与蓝牙连接状态 NSInteger disconnectSeconds;//蓝牙断开的时长 //学时相关 NSString *subject; //当前训练科目 NSString *classId; //课堂ID NSString *trainOrderNum;//学时编号用序列 每天置0 NSMutableArray *dataSourceArray; //表的数据源 组成部分:颜色数字+提示字 1为红色失败 2为绿色成功(暂未使用) NSDictionary *bigCarDic;//状态接口返回数据 //UI UIScrollView *mainScrV; //statusLab UILabel *statusLab;//调试用@lee //top UILabel *nameLab; UILabel *coachLab; UILabel *carNum; BC_TimerImgView *topRight; NSMutableArray *trainMsgLabs;//培训信息lab集合 UILabel *trainDetails; //培训照片 UIButton *checkTrainPhotoBtn;//查看培训照片 UIView *tileView;//照片视图 } //蓝牙 @property (nonatomic, strong) CBCentralManager *cbcManager; /** 已连接的外设*/ @property (nonatomic, strong) CBPeripheral *peripheral; /** 要写入的特征值*/ @property (nonatomic, strong) CBCharacteristic *writeCharacteristic; /** 要读的特征值*/ @property (nonatomic, strong) CBCharacteristic *readCharacteristic; @property (nonatomic, strong) UILabel *blueToothLabel; @end @implementation BigTruckVC - (void)viewDidLoad { [super viewDidLoad]; self.title = @"大客/货车计时"; self.view.backgroundColor = backGroundColor; [self customNavigationBar]; //ui [self myInit]; //开启定位(设置允许后台定位) [self setGPSLocationService]; //获取当前状态 [self getCurrentState]; } -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; if (timer == nil) { [locationManager stopUpdatingLocation]; } [self.blueToothLabel removeFromSuperview]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)myInit{ dateFormatter = [NSDateFormatter rq_defaultDateFormatter]; gatherTrainDic = [NSMutableDictionary dictionary]; trainMsgLabs = [NSMutableArray array]; mainScrV = [[UIScrollView alloc]initWithFrame:kFrame]; mainScrV.height -= kNavOffSet; [self.view addSubview:mainScrV]; //下啦刷新 MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ [self getCurrentState]; [mainScrV.mj_header endRefreshing];//这个就放这里吧 }]; mainScrV.mj_header = header; CGFloat x,y,w,h; x = 0; y = 0; h = 100; w = kSize.width; //@lee 调试用状态栏 // { // h = 130; // UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(0, h-30, kSize.width, 30)]; // statusLab = lab; // lab.alpha = .7; // lab.backgroundColor = [UIColor yellowColor]; // [mainScrV addSubview:lab]; // } //topView UIImageView *topView =[[UIImageView alloc]setxywh]; topView.backgroundColor = [UIColor darkGrayColor]; // topView.image = [UIImage imageNamed:@"bigCar_TrainTop"]; [mainScrV addSubview:topView]; x = 20; w = 80; h = 100; y = (h-w)/2; UIImageView *headV = [[UIImageView alloc]initWithFrame:CGRectMake(20, y, w, w)]; headV.layer.masksToBounds = YES; headV.layer.cornerRadius = w/2; [topView addSubview:headV]; NSString *str = defUser.userDict[@"photo"]; if (str == nil) { str = @""; } [headV sd_setImageWithURL:[NSURL URLWithString:str] placeholderImage:[UIImage imageNamed:@"drawer_head.png"]]; x += x+w; h = w/3; w = kSize.width - x - 20; nameLab = [[UILabel alloc]setxywh]; [nameLab setText:defUser.userDict[@"userName"] Font:FontTitle TextColor:[UIColor whiteColor] Alignment:NSTextAlignmentLeft]; [topView addSubview:nameLab]; y += h; coachLab = [[UILabel alloc]setxywh]; [coachLab setText:@"带教教练:" Font:FontTitle TextColor:[UIColor whiteColor] Alignment:NSTextAlignmentLeft]; [topView addSubview:coachLab]; y += h; carNum = [[UILabel alloc]setxywh]; [carNum setText:@"未开始计时" Font:FontTitle TextColor:[UIColor whiteColor] Alignment:NSTextAlignmentLeft]; [topView addSubview:carNum]; topRight = [BC_TimerImgView buttonWithType:UIButtonTypeCustom]; [topRight setTitle:@"计时中" forState:UIControlStateNormal]; [topRight setTitle:@"计时停止" forState:UIControlStateSelected]; [topRight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [topRight setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; [topRight.titleLabel setTextAlignment:NSTextAlignmentCenter]; [topRight.titleLabel setAdjustsFontSizeToFitWidth:YES]; [topRight setImage:[[UIImage imageNamed:@"bigCar_clock"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateNormal]; [topRight setImage:[[UIImage imageNamed:@"bigCar_clock"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateSelected]; topRight.frame = CGRectMake(kSize.width-100, 10, 60, 60*3/2); topRight.alpha = 0; [topView addSubview:topRight]; //培训信息 x = 10; y = topView.height; w = kSize.width; h = 50; UILabel *trainMessageLab = [[UILabel alloc]setxywh]; [trainMessageLab setText:@"培训信息" Font:FontTitle TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; [mainScrV addSubview:trainMessageLab]; w = 110; h = 35; x = kSize.width - w-15; y += (trainMessageLab.height-h)/2; UIButton *checkMinRecordBtn = [UIButton buttonWithType:UIButtonTypeSystem]; checkMinRecordBtn.layer.masksToBounds = YES; checkMinRecordBtn.layer.cornerRadius = 5; checkMinRecordBtn.frame = CGRectMake(x, y, w, h); [checkMinRecordBtn setTitle:@"查看分钟学时" textColor:[UIColor whiteColor] font:FontTitle fotState:UIControlStateNormal]; [checkMinRecordBtn addTarget:self action:@selector(checkMinRecordBtnClick) forControlEvents:UIControlEventTouchUpInside]; checkMinRecordBtn.backgroundColor = defGreen; [mainScrV addSubview:checkMinRecordBtn]; x = 0; y += (trainMessageLab.height-h)/2+h; w = kSize.width; h = 3; [trainMessageLab addViewWithRect:CGRectMake(x, y, w, h) Color:defGreen]; x = 0; y += h+15; w = kSize.width/4; h = 30; CGFloat bd = 15; for (int i=0; i<4; i++) { for (int j=0; j<7; j++) { UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(i%4*w, y+j%7*h, w, h)]; if (j>=5) { lab.frame = CGRectMake(i%4*w, bd+y+j%7*h, w, h); } lab.font = [UIFont scaleSize:Font17]; lab.adjustsFontSizeToFitWidth = YES; lab.textAlignment = NSTextAlignmentCenter; [mainScrV addSubview:lab]; if (j==0) { lab.textColor = kTitleColor; switch (i) { case 0: lab.text = @"培训阶段"; break; case 1: lab.text = @"已完成学时"; break; case 2: lab.text = @"审核状态"; break; case 3: lab.text = @"确认状态"; break; default: break; } }else if (i==0){ lab.textColor = kTitleColor; switch (j) { case 1: lab.text = @"科目一"; break; case 2: lab.text = @"科目二"; break; case 3: lab.text = @"科目三"; break; case 4: lab.text = @"科目四"; break; case 5: lab.text = @"总时长"; break; case 6: [trainMsgLabs addObject:lab]; break; default: break; } }else if (i==1){ lab.textColor = defGreen; switch (j) { case 1: [trainMsgLabs addObject:lab]; break; case 2: [trainMsgLabs addObject:lab]; break; case 3: [trainMsgLabs addObject:lab]; break; case 4: [trainMsgLabs addObject:lab]; break; case 5: lab.textColor = kTitleColor; lab.text = @"有效时长"; break; case 6: lab.textColor = [UIColor cyanColor]; [trainMsgLabs addObject:lab]; break; default: break; } }else if (i==2){ lab.textColor = [UIColor redColor]; switch (j) { case 1: [trainMsgLabs addObject:lab]; break; case 2: [trainMsgLabs addObject:lab]; break; case 3: [trainMsgLabs addObject:lab]; break; case 4: [trainMsgLabs addObject:lab]; break; case 5: lab.textColor = kTitleColor; lab.text = @"无效时长"; break; case 6: [trainMsgLabs addObject:lab]; break; default: break; } } else if (i==3){ lab.textColor = kTitleColor; switch (j) { case 1: [trainMsgLabs addObject:lab]; break; case 2: [trainMsgLabs addObject:lab]; break; case 3: [trainMsgLabs addObject:lab]; break; case 4: [trainMsgLabs addObject:lab]; break; case 5: lab.text = @"待审核时长"; break; case 6: lab.textColor = defGreen; [trainMsgLabs addObject:lab]; break; default: break; } } } } //line CGFloat lineW = 1; for (int i=0; i<9; i++) { //垂直 if (i<5) { UIView *lineVer3 = [[UIView alloc]initWithFrame:CGRectMake(w*i, y, lineW, h*5)]; lineVer3.backgroundColor = [UIColor lightGrayColor]; [mainScrV addSubview:lineVer3]; UIView *lineVer4 = [[UIView alloc]initWithFrame:CGRectMake(w*i, y+h*5+bd, lineW, h*2)]; lineVer4.backgroundColor = [UIColor lightGrayColor]; [mainScrV addSubview:lineVer4]; } //水平 UIView *lineHor = [[UIView alloc]initWithFrame:CGRectMake(0, y+h*i, kSize.width, lineW)]; lineHor.backgroundColor = [UIColor lightGrayColor]; if (i>=6) { lineHor.frame = CGRectMake(0, y+h*(i-1)+bd, kSize.width, lineW); } [mainScrV addSubview:lineHor]; } x = 10; y += 7*h+bd+lineW; w = kSize.width - x - 15; h = 50; trainDetails = [[UILabel alloc]setxywh]; trainDetails.backgroundColor = backGroundColor; [trainDetails setText:@"" Font:Font17 TextColor:contentTextColor Alignment:NSTextAlignmentLeft]; trainDetails.numberOfLines = 0; trainDetails.contentMode = UIViewContentModeCenter; trainDetails.adjustsFontSizeToFitWidth = YES; [mainScrV addSubview:trainDetails]; //培训照片 x = 10; y += h; w = kSize.width; h = 50; UILabel *trainPhotoeLab = [[UILabel alloc]setxywh]; [trainPhotoeLab setText:@"培训照片" Font:FontTitle TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; [mainScrV addSubview:trainPhotoeLab]; w = 110; h = 35; x = kSize.width - w - 15; y += (trainPhotoeLab.height-h)/2; checkTrainPhotoBtn = [UIButton buttonWithType:UIButtonTypeSystem]; checkTrainPhotoBtn.layer.masksToBounds = YES; checkTrainPhotoBtn.layer.cornerRadius = 5; checkTrainPhotoBtn.frame = CGRectMake(x, y, w, h); [checkTrainPhotoBtn setTitle:@"查看更多照片" textColor:[UIColor darkGrayColor] font:FontTitle fotState:UIControlStateNormal]; [checkTrainPhotoBtn addTarget:self action:@selector(checkTrainPhotoBtnClick) forControlEvents:UIControlEventTouchUpInside]; checkTrainPhotoBtn.backgroundColor = [UIColor lightGrayColor]; [mainScrV addSubview:checkTrainPhotoBtn]; x = 0; y += (trainPhotoeLab.height-h)/2+h; w = kSize.width; h = 3; [trainPhotoeLab addViewWithRect:CGRectMake(x, y, w, h) Color:defGreen]; [mainScrV setContentSize:CGSizeMake(0, y+h+20+kSafeAreaBottomHeight)]; } -(void)customNavigationBar{ UIBarButtonItem* backBbi = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"question_pre_checked_icon.png"] style:UIBarButtonItemStylePlain target:self action:@selector(goBackByNavigation)]; [backBbi setTintColor:defGreen]; [self.navigationItem setLeftBarButtonItem:backBbi]; self.navigationController.navigationBar.translucent = NO; } -(void)goBackByNavigation{ if (self.navigationController.presentingViewController) { [self.navigationController dismissViewControllerAnimated:YES completion:nil]; }else{ [self.navigationController popViewControllerAnimated:YES]; } } - (void)checkMinRecordBtnClick{ EleMinRecordListVC *vc = [[EleMinRecordListVC alloc]init]; vc.stuID = defUser.userDict[@"outId"]; vc.classId = gatherTrainDic[@"classId"]; [self navPushHideTabbarToVC:vc]; } - (void)checkTrainPhotoBtnClick{ NSArray *dataImgs = bigCarDic[@"picList"]; if (dataImgs.count == 0) { return; } TileViewController *vc = [[TileViewController alloc]initWithImageNames:dataImgs]; [self navPushHideTabbarToVC:vc]; } - (void)nextWithCurrentStatu:(NSString *)statu{ myDelegate.dcTrainType = statu; [self getGatherTrainDic];//这一步可以拿到登录接口返回并存储的claaid等课时相关信息 //这里做补传学时的操作,如果不继续计时,就补传学时 if (![statu isEqualToString:@"0"]) { classId = gatherTrainDic[@"classId"]; NSArray *minuteTrainArray = [DB_Helper quearyTrainWithClassId:classId type:bigCarTableName]; if (minuteTrainArray.count != 0) { UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:@"提醒" message:@"检测到本地有未上传学时,是否现在补传学时" preferredStyle:UIAlertControllerStyleAlert]; [alertFind addAction:[UIAlertAction actionWithTitle:@"否" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [alertFind addAction:[UIAlertAction actionWithTitle:@"是" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [self uploadAppTrainPlWithSignOut:YES]; }]]; [self presentViewController:alertFind animated:true completion:nil]; return; } } //获取到状态 /* Type 定义 0 成功获取终端信息 1 学员还未在终端签到 2 学员签到的记录没有绑定终端 3 学员签到记录绑定的终端没有找到终端 4 学员签到记录的终端不在线 5 连接的终端非车载计时终端 6 未找到带教教练 */ if ([statu isEqualToString:@"0"]) {//成功获取终端信息 终端签到过就有 //UI NSString *coach = bigCarDic[@"CoachName"]; if (coach && coach.length > 0) { coachLab.text = [NSString stringWithFormat:@"带教教练:%@",coach]; } carNum.text = bigCarDic[@"TDI_TRAIN_CAR_LICNUM"]; [self refreshTrainPhotos]; [self getStudentTrainInfos];//获取训练信息 peripheralName = bigCarDic[@"TDI_TRAIN_CAR_LICNUM"]; classId = bigCarDic[@"ClassId"]; [gatherTrainDic setValue:bigCarDic[@"ClassId"] forKey:@"classId"]; //保存至本地 可以用于断线重连 [gatherTrainDic setValue:@"0" forKey:@"isOver"]; [self saveGatherTrainDic]; [self searchBlueTooth];//搜索蓝牙进行连接 }else if([statu isEqualToString:@"1"]){//学员还未在终端器签到 5分钟检测到被签退 if (timer) { [self uploadAppTrainPlWithSignOut:YES]; [self refreshTrainPhotos]; [self getStudentTrainInfos]; return; } UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:@"提醒" message:@"当前暂未检测到终端签到信息;如需计时,请在终端签到" preferredStyle:UIAlertControllerStyleAlert]; [alertFind addAction:[UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [alertFind addAction:[UIAlertAction actionWithTitle:@"终端已签到" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [self getCurrentState]; }]]; [self presentViewController:alertFind animated:true completion:nil]; }else if ([statu isEqualToString:@"2"]) {//学员签到的记录没有绑定终端 showMsgByAlert(self, @"学员签到的记录没有绑定终端"); }else if ([statu isEqualToString:@"3"]) {//学员签到记录绑定的终端没有找到终端 showMsgByAlert(self, @"学员签到记录绑定的终端没有找到终端"); }else if ([statu isEqualToString:@"4"]) {//学员签到记录的终端不在线 showMsgByAlert(self, @"学员签到记录的终端不在线"); }else if ([statu isEqualToString:@"5"]) {//连接的终端非车载计时终端 showMsgByAlert(self, @"连接的终端非车载计时终端"); }else if ([statu isEqualToString:@"6"]) {//未找到带教教练 showMsgByAlert(self, @"未找到带教教练"); } } #pragma mark - 添加本地通知 -(void)addLocalNotificationWithAudio:(NSString *)audioName{ //定义本地通知对象 UILocalNotification *notification = [[UILocalNotification alloc]init]; //设置调用时间 notification.fireDate = [NSDate date]; //设置通知属性 NSString *bodyString = @"优易学车提醒您"; if ([audioName isEqualToString:@"dc_blueToothDisconnect.mp3"]) { bodyString = @"车宰设备已断开,计时停止"; }else if ([audioName isEqualToString:@"dc_blueToothConnect.mp3"]) { bodyString = @"车宰设备连接成功,恢复计时"; } notification.alertBody = bodyString; //通知主体 notification.applicationIconBadgeNumber = 1;//应用程序图标右上角显示的消息数 notification.alertAction = @"打开应用"; //待机界面的滑动动作提示 notification.soundName = audioName;//收到通知时播放的声音,默认消息声音 // 通知参数 NSDictionary *userDict = [NSDictionary dictionaryWithObjectsAndKeys:@"nothing",@"BigTruckTrainVC", nil]; notification.userInfo = userDict; //调用通知 [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } #pragma mark - 本地数据读取 - (void)saveGatherTrainDic { NSString *filePath = [Tools getPathWithFileName:@"BigCarTrainDic.plist"]; [gatherTrainDic writeToFile:filePath atomically:YES]; } - (void)getGatherTrainDic { NSString *filePath = [Tools getPathWithFileName:@"BigCarTrainDic.plist"]; if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { gatherTrainDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath]; } } #pragma mark gps定位相关 -(void)setGPSLocationService{ //实例化manager locationManager=[[CLLocationManager alloc]init]; //设置代理 locationManager.delegate=self; //设置定位精度 //定位要求的精度越高、属性distanceFilter的值越小,应用程序的耗电量就越大。 locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters; //定位距离 locationManager.distanceFilter=50; //这里定位只是为了使其后台运行 //申请定位许可,iOS8以后特有 /** 由于IOS8中定位的授权机制改变 需要进行手动授权 * 获取授权认证,两个方法: * [self.locationManager requestWhenInUseAuthorization]; * [self.locationManager requestAlwaysAuthorization]; */ if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [locationManager requestAlwaysAuthorization]; } if ([[UIDevice currentDevice].systemVersion floatValue] > 9) { /** iOS9新特性:将允许出现这种场景:同一app中多个location manager:一些只能在前台定位,另一些可在后台定位(并可随时禁止其后台定位)。 */ [locationManager setAllowsBackgroundLocationUpdates:YES]; } //开始定位 [locationManager startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{ /* kCLErrorDenied,//访问位置或范围已被用户拒绝 kCLErrorNetwork,//一般,与网络相关的错误 */ NSLog(@"位置访问失败"); UIAlertView *alert =[[UIAlertView alloc]initWithTitle:@"温馨提示" message:@"请在iPhone的“设置”-“隐私”-“定位服务”功能中,找到“优易学车”打开位置访问权限" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil]; [alert show]; [locationManager stopUpdatingLocation]; } //- (void)locationManager:(CLLocationManager *)manager // didUpdateToLocation:(CLLocation *)newLocation // fromLocation:(CLLocation *)oldLocation //{ // //打印出经度和纬度 // CLLocationCoordinate2D coordinate = newLocation.coordinate; // NSDictionary *testdic =BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_GPS);//转换GPS坐标至百度坐标(加密后的坐标) // //解密加密后的坐标字典 // CLLocationCoordinate2D baiduCoor = BMKCoorDictionaryDecode(testdic);//转换后的百度坐标 // myCoordinate = baiduCoor; // // [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; // NSString *strDate = [dateFormatter stringFromDate:newLocation.timestamp]; // // //暂时未用到 // gpsDic = [NSMutableDictionary dictionaryWithDictionary:@{ // @"latitude":[NSString stringWithFormat:@"%f",baiduCoor.latitude], // @"longitude":[NSString stringWithFormat:@"%f",baiduCoor.longitude], // @"altitude":[NSString stringWithFormat:@"%.2f",newLocation.altitude], // @"timestamp":strDate, // }]; //} - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations { CLLocation *loctaion = [locations firstObject]; CLLocationCoordinate2D coordinate = loctaion.coordinate; myCoordinate = BMKCoordTrans(coordinate, BMK_COORDTYPE_GPS, BMK_COORDTYPE_BD09LL);//转换GPS坐标至百度坐标(加密后的坐标) [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *strDate = [dateFormatter stringFromDate:loctaion.timestamp]; //暂时未用到 gpsDic = [NSMutableDictionary dictionaryWithDictionary:@{ @"latitude":[NSString stringWithFormat:@"%f",myCoordinate.latitude], @"longitude":[NSString stringWithFormat:@"%f",myCoordinate.longitude], @"altitude":[NSString stringWithFormat:@"%.2f",loctaion.altitude], @"timestamp":strDate, }]; } #pragma mark 蓝牙相关 - (void)addBlueToothLabelWithContent:(NSString *)string mp3:(NSString *)audioStr{ if (!self.blueToothLabel.superview) { [[UIApplication sharedApplication].keyWindow addSubview:self.blueToothLabel]; } self.blueToothLabel.text = string; if(audioStr){ if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:audioStr]; }else { [Tools playAudioWithString:string]; } } } - (void)removeBlueToothLabel { if (_blueToothLabel) { [_blueToothLabel removeFromSuperview]; } } -(UIView *)blueToothLabel { if (!_blueToothLabel) { _blueToothLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, (kSize.height - 90)/2.0, kSize.width - 60, 80)]; _blueToothLabel.numberOfLines = 0; _blueToothLabel.backgroundColor = backGroundColor; [_blueToothLabel setBoardWid:5 Color:contentTextColor]; [_blueToothLabel setText:@"" Font:24 TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; } return _blueToothLabel; } - (void)closeBlueTooth { if (peripheralName.length > 0) { //断开连接 if (self.peripheral) { [self.cbcManager cancelPeripheralConnection:self.peripheral]; } self.peripheral.delegate = nil; self.peripheral = nil; self.writeCharacteristic = nil; self.readCharacteristic = nil; self.cbcManager = nil; } } - (void)searchBlueTooth { blueToothOrder = @""; if (!_cbcManager) { _cbcManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; } } //只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态 - (void)centralManagerDidUpdateState:(CBCentralManager *)central { switch (central.state) { case 0: //状态未知 //NSLog(@"CBCentralManagerStateUnknown"); break; case 1: //连接断开 即将重置 //NSLog(@"CBCentralManagerStateResetting"); break; case 2: //该平台不支持蓝牙 //NSLog(@"CBCentralManagerStateUnsupported"); break; case 3: //未授权蓝牙使用 hovertree.com //NSLog(@"CBCentralManagerStateUnauthorized"); { [self removeBlueToothLabel]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"请在“设置”中打开蓝牙访问权限" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; [alert show]; } break; case 4: { //蓝牙未开启 //NSLog(@"CBCentralManagerStatePoweredOff"); if (peripheralName.length > 0) { showMsgByAlert(self, @"请打开手机蓝牙"); [Tools playAudioWithString:@"请打开手机蓝牙"]; } } break; case 5: { //蓝牙已开启 //NSLog(@"CBCentralManagerStatePoweredOn"); if (peripheralName.length < 1) { return; } // 搜索外设 if (self.peripheral) { return; } // 搜索成功之后,会调用找到外设的代理方法 [self addBlueToothLabelWithContent:[NSString stringWithFormat:@"正在连接终端设备 %@ 请稍候",peripheralName] mp3:nil]; [self.cbcManager scanForPeripheralsWithServices:nil // 通过某些服务筛选外设 options:nil]; // dict,条件 } break; default: break; } } // 发现外设后调用的方法 - (void)centralManager:(CBCentralManager *)central // 中心管理者 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设 advertisementData:(NSDictionary *)advertisementData // 外设携带的数据 RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度 { NSLog(@"搜索到的外设----><>%@----><>%@",peripheral.name,peripheralName); //如果蓝牙名称和二维码中的一致 就可以连接了 最好能关闭蓝牙的扫描 if ([peripheral.name isEqualToString:peripheralName]) { self.peripheral = peripheral; [self.cbcManager stopScan]; [_cbcManager connectPeripheral:self.peripheral options:nil]; } } // 中心管理者连接外设成功 - (void)centralManager:(CBCentralManager *)central // 中心管理者 didConnectPeripheral:(CBPeripheral *)peripheral // 外设 { NSLog(@"%s, line = %d, %@=连接成功", __FUNCTION__, __LINE__, peripheral.name); _blueToothLabel.text = @"连接成功"; dispatch_time_t zz = dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC); dispatch_after(zz, dispatch_get_main_queue(), ^{ [self removeBlueToothLabel]; }); // 连接成功之后,可以进行服务和特征的发现 // 设置外设的代理 self.peripheral.delegate = self; // 外设发现服务,传nil代表不过滤 [self.peripheral discoverServices:@[ [CBUUID UUIDWithString:BServiceUUID] ]]; isConnectBlueTooth = YES; disconnectSeconds = 0; //因为断开重连也需要验证 所以就不。。。 // if (myDelegate.isBackgroundTask) { // [self addLocalNotificationWithAudio:@"dc_blueToothConnect.mp3"]; // }else { // [Tools playAudioWithString:@"已成功连接车宰设备"]; // } } // 外设连接失败 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { isConnectBlueTooth = NO; NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name); [self addBlueToothLabelWithContent:@"终端设备连接失败!正在尝试重新连接" mp3:nil]; if (self.peripheral) { [_cbcManager connectPeripheral:self.peripheral options:nil]; } } // 丢失连接 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { isConnectBlueTooth = NO; NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name); if (self.cbcManager && self.peripheral) { [self.cbcManager connectPeripheral:self.peripheral options:nil]; //断开链接后在timerun里面每5s发起一次蓝牙连接请求。 并且seconds不自增 } if (timer) { ShowMsg(@"车载设备已断开,计时停止"); topRight.selected = YES; topRight.alpha = 1.0; if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"dc_blueToothDisconnect.mp3"]; }else { [Tools playAudioWithString:@"车宰设备已断开,计时停止"]; } } } //查找服务的所有特征 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { if (error) { NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]); [self addBlueToothLabelWithContent:@"蓝牙服务搜索失败" mp3:nil]; return; } //NSLog(@"services---><>%@",peripheral.services); //服务并不是我们的目标,也没有实际意义。我们需要用的是服务下的特征,查询(每一个服务下的若干)特征 for (CBService *service in peripheral.services) { NSLog(@"Service found with UUID: %@", service.UUID); // Discovers the characteristics for a given service if ([service.UUID isEqual:[CBUUID UUIDWithString:BServiceUUID]]) { //搜索特性 [self.peripheral discoverCharacteristics:nil forService:service]; } } } // 发现外设服务里的特征的时候调用的代理方法(这个是比较重要的方法,你在这里可以通过事先知道UUID找到你需要的特征,订阅特征,或者这里写入数据给特征也可以) - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (error) { NSLog(@"搜索特性失败 characteristic: %@", [error localizedDescription]); [self addBlueToothLabelWithContent:@"蓝牙服务特征搜索失败" mp3:nil]; return; } /* 这里经过测试 读写全用UUID为FFE1的特征 这样收到的蓝牙回复 没有很多的多余的数据 */ for (CBCharacteristic *cha in service.characteristics) { if ([cha.UUID isEqual:[CBUUID UUIDWithString:BCharacteristicUUID_reade]]) { // NSLog(@"读取特征-->>>%@",cha); self.readCharacteristic = cha; [peripheral setNotifyValue:YES forCharacteristic:cha]; // [peripheral readValueForCharacteristic:cha]; /* 最后还有一个重要的补充,当我们已经找到了我们感兴趣的characteristic后,他的value并不一定通过1方法或者2方法就可以接收的,就算可以接收,有时候只能用1,有时候只能用2。 这牵扯到characteristic的一个property 当为read(0x02)的时候,我们用1方法可以查看,用2就会出错。当为notify(0x10)的时候我们就得用2方法。其他就不说明了,比如write就只能写value······ typedef enum { CBCharacteristicPropertyBroadcast = 0x01, CBCharacteristicPropertyRead = 0x02, CBCharacteristicPropertyWriteWithoutResponse = 0x04, CBCharacteristicPropertyWrite = 0x08, CBCharacteristicPropertyNotify = 0x10, CBCharacteristicPropertyIndicate = 0x20, CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40, CBCharacteristicPropertyExtendedProperties = 0x80, CBCharacteristicPropertyNotifyEncryptionRequired = 0x100, CBCharacteristicPropertyIndicateEncryptionRequired = 0x200, } CBCharacteristicProperties; 所以当我们想查看value的时候,先了解一下这个characteristic的property,看是不是能让我们读的。怎么查看?找BLE外设的设备厂商或者查看外设的说明书。 推荐将value经常变化的characteristic的property设为notify */ } if ([cha.UUID isEqual:[CBUUID UUIDWithString:BCharacteristicUUID_write]]) { // NSLog(@"写入特征-->>>%@",cha);//0x04对应的是CBCharacteristicPropertyWriteWithoutResponse || 0x0A对应的是CBCharacteristicPropertyNotify self.writeCharacteristic = cha; //重新连接/开始连接都需要发这个验证 blueToothOrder = [NSString stringWithFormat:@"%@%@",RequestConnectOrder,defUser.userDict[@"stuNum"]]; [self sendBlueToothOrder]; } } } - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { if (error) { NSLog(@"Error changing notification state: %@", error.localizedDescription); // [self addBlueToothLabelWithContent:@"蓝牙服务特征状态异常" mp3:nil]; return; } // Exits if it's not the transfer characteristic if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:BCharacteristicUUID_reade]]) { return; } // Notification has started if (characteristic.isNotifying) { NSLog(@"Notification began on %@", characteristic); NSLog(@"%@",characteristic.value); NSLog(@"%@",[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]); [peripheral readValueForCharacteristic:characteristic]; } else { // Notification has stopped NSLog(@"Notification stopped on %@. Disconnecting", characteristic); } } // 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if ([characteristic isEqual:self.readCharacteristic] ) { NSString *hexString = [Tools convertDataToHexStr:characteristic.value]; NSLog(@"hexString---><>%@",hexString); if ([hexString containsString:@"be0204"]) { hasReply = YES; NSString *result = [hexString substringFromIndex:hexString.length-2]; if ([result isEqualToString:@"00"]) { //连接成功,可以开始培训 if (timer) {//表示是蓝牙断开重连 topRight.selected = NO; if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"dc_blueToothConnect.mp3"]; }else { [Tools playAudioWithString:@"车宰设备连接成功,恢复计时"]; } }else{ [Tools playAudioWithString:@"连接成功,开始计时"]; [self beginTimer]; } }else if ([result isEqualToString:@"01"]){ showMsgByAlert(self, @"非当前训练学员,连接失败"); [Tools playAudioWithString:@"非当前训练学员,连接失败"]; [self closeBlueTooth]; } return; } if ([hexString containsString:@"be0501"]) {//心跳回应 blueToothOrder = HeartbeatOrder; [self sendBlueToothOrder]; } if ([hexString containsString:@"be0103"]) {//签退通知 //这个回复没意义。终端签退即签退 // blueToothOrder = QuitOrder; // [self sendBlueToothOrder]; if (timer) { [timer invalidate]; timer = nil; } [self uploadAppTrainPlWithSignOut:YES]; } } } -(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error{ if (error) { NSLog(@"写入数据失败:%@",error); [self addBlueToothLabelWithContent:@"蓝牙连接异常,指令发送失败" mp3:nil]; }else{ NSLog(@"写入数据成功-->: %@",blueToothOrder); } } #pragma mark - 蓝牙写入数据 - (void)sendBlueToothOrder{ dataIsLack = NO; lastData = nil; hasReply = NO; if (blueToothOrder && blueToothOrder.length != 0) { [self.peripheral writeValue:[Tools convertHexStrToData:blueToothOrder] forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse]; } if ([blueToothOrder containsString:RequestConnectOrder]) {//可能刚开始连上的时候 接受不到消息 dispatch_time_t zz = dispatch_time(DISPATCH_TIME_NOW, 2* NSEC_PER_SEC); dispatch_after(zz, dispatch_get_main_queue(), ^{ if (hasReply == NO) { [self sendBlueToothOrder]; } }); } } #pragma mark 教学信息更新 -(void)reloadDetailLabWithDic:(NSDictionary *)dic{ //更新UI展示内容 int i=0; for (UILabel *lab in trainMsgLabs) { switch (i) {//按从上往下 从左往右 1+5+5 case 0: lab.text = [self getTimeByMinString:dic[@"totalTime"]]; break; case 1: lab.text = [self getTimeByMinString:dic[@"ONE"]]; break; case 2: lab.text = [self getTimeByMinString:dic[@"TWO"]]; break; case 3: lab.text = [self getTimeByMinString:dic[@"THREE"]]; break; case 4: lab.text = [self getTimeByMinString:dic[@"FOUR"]]; break; case 5: lab.text = [self getTimeByMinString:dic[@"vaildTime"]]; break; case 6: { NSArray *arr = [self getStrAndColorByStatus:dic[@"ONESTATUS"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 7: { NSArray *arr = [self getStrAndColorByStatus:dic[@"TWOSTATUS"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 8: { NSArray *arr = [self getStrAndColorByStatus:dic[@"THREESTATUS"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 9: { NSArray *arr = [self getStrAndColorByStatus:dic[@"FOURSTATUS"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 10: lab.text = [self getTimeByMinString:dic[@"noVaildTime"]]; break; case 11: { NSArray *arr = [self getSureStrAndColorByStatus:dic[@"CHECKONE"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 12: { NSArray *arr = [self getSureStrAndColorByStatus:dic[@"CHECKTWO"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 13: { NSArray *arr = [self getSureStrAndColorByStatus:dic[@"CHECKTHREE"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 14: { NSArray *arr = [self getSureStrAndColorByStatus:dic[@"CHECKFOUR"]]; lab.text = arr[1]; lab.textColor = arr[0]; } break; case 15: lab.text = [self getTimeByMinString:dic[@"notAuditTime"]]; break; default: break; } i++; } NSInteger totalTime = [[NSString stringWithFormat:@"%@",dic[@"totalTime"]] integerValue]; trainDetails.text = [NSString stringWithFormat:@"当前培训过程中,车辆平均速度为%.2fKm/h,行驶总里程为%.2fKm,有效学时占比为%.1f%%",[dic[@"avgSpeed"] floatValue],[dic[@"totalMile"] floatValue]/1000.0, totalTime==0 ? 0 : [dic[@"vaildTime"] floatValue]/[dic[@"totalTime"] floatValue]*100]; } -(NSString *)getTimeByMinString:(NSString *)minStr{ NSInteger min = [minStr integerValue]; NSInteger h = min/60; NSInteger m = min%60; if (h != 0) { return [NSString stringWithFormat:@"%ld小时%ld分钟",h,m]; } return [NSString stringWithFormat:@"%ld分钟",m]; } -(NSArray *)getStrAndColorByStatus:(NSString *)status{ NSString *stateString = status; UIColor *color = [UIColor blackColor]; switch ([stateString intValue]) { case 0: stateString = @"不允许送审"; color = [UIColor redColor]; break; case 1: stateString = @"允许送审"; color = contentTextColor; break; case 2: stateString = @"审核通过"; color = contentTextColor; break; case 3: stateString = @"退回"; color = [UIColor redColor]; break; case 4: stateString = @"待审核"; color = [UIColor darkGrayColor]; break; default: stateString = @"<未知>"; color = [UIColor lightTextColor]; break; } return @[color,stateString]; } -(NSArray *)getSureStrAndColorByStatus:(NSString *)status{ NSString *stateString = status; UIColor *color = [UIColor blackColor]; switch ([stateString intValue]) { case 0: stateString = @"未确认"; color = contentTextColor; break; case 1: stateString = @"已确认"; color = contentTextColor; break; default: stateString = @"<未知>"; color = [UIColor lightTextColor]; break; } return @[color,stateString]; } -(void)refreshTrainPhotos{ CGFloat tileView_H = 0; if (tileView) { [tileView removeFromSuperview]; [[self.childViewControllers lastObject] removeFromParentViewController]; tileView_H = tileView.height+30;//30 是下边留的空白 } NSArray *dataImgs = bigCarDic[@"picList"]; if (dataImgs.count == 0) { return; } [checkTrainPhotoBtn setTitle:@"查看更多照片" textColor:[UIColor whiteColor] font:FontTitle fotState:UIControlStateNormal]; checkTrainPhotoBtn.backgroundColor = defGreen; NSArray *imgs = dataImgs.count>4?[dataImgs subarrayWithRange:NSMakeRange(0, 4)]:dataImgs; TileViewController *vc = [[TileViewController alloc]initWithImageNames:imgs]; CGFloat h = kSize.width/2*3/4*(dataImgs.count/2>2 ? 2:dataImgs.count); vc.view.frame = CGRectMake(0, mainScrV.contentSize.height-kSafeAreaBottomHeight-20-tileView_H, kSize.width, h); [self addChildViewController:vc]; [mainScrV addSubview:vc.view]; tileView = vc.view; [mainScrV setContentSize:CGSizeMake(0, mainScrV.contentSize.height+30+h-tileView_H)];//50=30+20 } #pragma mark -开始计时 - (void)beginTimer { [DB_Helper deleteAllTrainWithType:bigCarTableName]; [self getClassId];//获取classId [gatherTrainDic setObject:classId forKey:@"classId"]; //classId minuteTrainDic = [NSMutableDictionary dictionary]; [minuteTrainDic setValue:classId forKey:@"classId"]; seconds = 0; disconnectSeconds = 0; topRight.alpha = 1; timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerRun) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];//处理UI交互阻塞计时 myDelegate.dcPeriodVC = self; } - (void)timerRun { NSLog(@"timerRuning"); statusLab.text = @"timerRuning"; if (!isConnectBlueTooth && peripheralName.length > 0) {//计时过程中蓝牙断开连接 disconnectSeconds ++; //外设重连 if (disconnectSeconds%5 == 0) { if (_cbcManager && self.peripheral) { [_cbcManager connectPeripheral:self.peripheral options:nil]; NSLog(@"蓝牙断开每5s重新发起连接"); statusLab.text = @"蓝牙断开每5s重新发起连接"; } } //重新扫描间隔10 持续3 if (disconnectSeconds%10 == 0) { if (!_cbcManager.isScanning) { [self.cbcManager scanForPeripheralsWithServices:nil // 通过某些服务筛选外设 options:nil]; // dict,条件 } }else if (disconnectSeconds%3 == 0) { if (_cbcManager.isScanning) { [self.cbcManager stopScan]; } } return; } topRight.alpha = seconds%2; NSLog(@"timerRuning: %ld",seconds); statusLab.text = [statusLab.text stringByAppendingString:[NSString stringWithFormat:@"%ld",seconds]]; //计时器 seconds++; // NSLog(@"%d---->%@",seconds,blueToothOrder); if (seconds%30 == 0) { //这个点就当前时间 [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; [minuteTrainDic setValue:classId forKey:@"classId"]; //{lng:121.595793,lat:41.961311,crTime:'2017-01-01 00:00:00'} NSDictionary *dic = @{ @"lng":[NSString stringWithFormat:@"%f",myCoordinate.longitude], @"lat":[NSString stringWithFormat:@"%f",myCoordinate.latitude], @"crTime":dateString}; NSString *gpsStr = [self getJsonStringWithObj:dic]; [minuteTrainDic setValue:gpsStr forKey:@"gps"]; NSLog(@"存入的字典: %@",minuteTrainDic); [DB_Helper saveTrainWithDic:minuteTrainDic type:bigCarTableName]; [self uploadAppTrainPlWithSignOut:NO]; } if (seconds%300 == 0) { [self getCurrentState];//刷新UI 里面有用到计时器状态判断是否是训练中 不会走开始训练的那些处理 } } - (void)getClassId { if (classId && classId.length > 0) { return; } //将之前的学时全部清空 // [DB_Helper deleteAllTrainWithType:bigCarTableName]; // //classId // NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970]*1000; //// NSString *timeString = [[[[NSString stringWithFormat:@"%f",timeInterval] substringFromIndex:1] componentsSeparatedByString:@"."] firstObject]; //// NSInteger redomNum = arc4random()%8999 + 1000; //// classId = [NSString stringWithFormat:@"%d%@",(int)redomNum,timeString]; // NSString *timeString = [[[NSString stringWithFormat:@"%f",timeInterval] componentsSeparatedByString:@"."] lastObject]; // timeString = [timeString substringFromIndex:timeString.length-10]; // classId = timeString; } - (void)closeTimer{ [gatherTrainDic setValue:@"1" forKey:@"isOver"]; [gatherTrainDic removeObjectForKey:@"classId"]; [self saveGatherTrainDic]; [DB_Helper deleteAllTrainWithType:bigCarTableName]; [dataSourceArray removeAllObjects]; //先关闭定时器 if (timer.isValid) { [timer invalidate]; timer = nil; } myDelegate.dcPeriodVC = nil; myDelegate.dcTrainType = @"1"; [Tools playAudioWithString:@"本次计时结束"]; coachLab.text = @"带教教练:"; carNum.text = @"已签退"; topRight.alpha = 0; } #pragma mark - 转json字符串 - (NSString *)getJsonStringWithObj:(NSObject *)jsonObj{ NSError *error = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonObj options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = nil; if ([jsonData length] != 0 && error == nil){ // 使用这个方法的返回,我们就可以得到想要的JSON串 jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; }else{ ShowMsg(@"数据错误,请重试!"); } return jsonString; } #pragma mark - 网络请求 //获取当前训练状态 -(void)getCurrentState { [MBProgressHUD showMessage:@"正在获取当前训练状态" toView:self.view]; //这个主要目的是为了更新本地学时编号等数据 [LoginViewController getCurrentStateWithCompleteBlock:^(NSDictionary *root) { [MBProgressHUD hideHUDForView:self.view animated:NO]; if (!root) { ShowMsg(@"请求失败"); return; } if ([root[@"code"] isEqualToString:@"0"]) { bigCarDic = root[@"body"][@"bigCar"]; if (timer && [bigCarDic[@"TYPE"] isEqualToString:@"0"]) {//训练中 //刷新UI [self refreshTrainPhotos]; [self getStudentTrainInfos]; return; } NSArray *arr = @[@"科目一",@"科目二",@"科目三",@"科目四"]; int subject = [[NSString stringWithFormat:@"%@",root[@"body"][@"subject"]] intValue]; if (subject <= 4) { nameLab.text = [NSString stringWithFormat:@"%@ %@",[nameLab.text componentsSeparatedByString:@" "][0],arr[subject-1]]; } else { nameLab.text = [NSString stringWithFormat:@"%@ %@",[nameLab.text componentsSeparatedByString:@" "][0],@"科目错误"]; } //获取到状态下一步 [self nextWithCurrentStatu:root[@"body"][@"bigCar"][@"TYPE"]]; }else{ ShowMsg(root[@"msg"]); } }]; } - (void)getStudentTrainInfos { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } //查询学员签到列表 科目传空 查全部 NSMutableArray *arr = [NSMutableArray array]; [arr addPro:@"coachId" Value:bigCarDic[@"CoachId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]]; NSString* method = @"getStudentTrainInfos"; [MBProgressHUD showMessage:@"正在获取计时信息" toView:self.view]; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary *root) { [MBProgressHUD hideHUDForView:self.view]; if (!root) { ShowMsg(@"请求失败"); return ; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); return; } [self reloadDetailLabWithDic:root[@"body"]]; }]; } //上传分钟学时(批量) - (void)uploadAppTrainPlWithSignOut:(BOOL)isSignOut { NSArray *minuteTrainArray = [DB_Helper quearyTrainWithClassId:classId type:bigCarTableName]; if (isSignOut) { if (minuteTrainArray.count == 0) { [self closeTimer]; return; } } if (![Util connectedToNetWork]) { if (isVoice) { [Tools playAudioWithString:@"无网络连接,学时上传失败"]; } if (isSignOut) { [self showReUpLoad]; return; } [dateFormatter setDateFormat:@"HH:mm"]; NSString *timeString = [dateFormatter stringFromDate:[NSDate date]]; [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 学时上传失败!",timeString]]; return; } NSMutableArray *mArr = [NSMutableArray new];; for (NSDictionary *dic in minuteTrainArray) { NSData *responseObject = [dic[@"gps"] dataUsingEncoding:NSUTF8StringEncoding]; if (responseObject == nil) { return; } NSDictionary *gpsDic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil]; NSMutableDictionary * csDic = [NSMutableDictionary new]; [csDic setObject:gpsDic[@"lng"] forKey:@"lng"]; [csDic setObject:gpsDic[@"lat"] forKey:@"lat"]; [csDic setObject:gpsDic[@"crTime"] forKey:@"crTime"]; [mArr addObject:csDic]; } NSString *jsonString = [self getJsonStringWithObj:mArr]; NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"stuOutId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]]; [arr addPro:@"classId" Value:gatherTrainDic[@"classId"]]; [arr addPro:@"gpsList" Value:jsonString]; [arr addPro:@"lng" Value:[NSString stringWithFormat:@"%f",myCoordinate.longitude]]; [arr addPro:@"lat" Value:[NSString stringWithFormat:@"%f",myCoordinate.latitude]]; NSString* method = @"uploadStuGps"; if (isSignOut) { [MBProgressHUD showMessage:@"正在补传学时" toView:self.view]; } [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (isSignOut) { [MBProgressHUD hideHUDForView:self.view animated:YES]; } [self.view setUserInteractionEnabled:YES]; [dateFormatter setDateFormat:@"HH:mm"]; NSString *timeString = [dateFormatter stringFromDate:[NSDate date]]; if (!root) { if (isSignOut) { [gatherTrainDic setObject:@"2" forKey:@"isOver"]; [self saveGatherTrainDic];//保存至本地 可以用于断线重连 [self showReUpLoad];//重新上传选择 } if (isVoice) { [Tools playAudioWithString:@"学时上传失败!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 学时上传失败!",timeString]]; return ; } if ([root[@"code"] isEqualToString:@"1"]) { if (isSignOut) { [gatherTrainDic setObject:@"2" forKey:@"isOver"]; [self saveGatherTrainDic];//保存至本地 [self showReUpLoad];//重新上传选择 } if (isVoice) { [Tools playAudioWithString:[NSString stringWithFormat:@"%@,学时上传失败!",root[@"body"]]]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 学时上传失败!",timeString]]; return; } // ShowMsg(@"调试:位置上传成功一次"); //msg = 上传位置成功;1;1;0;0, 后面的分别表示xx时间 if (isVoice) { [Tools playAudioWithString:@"学时上传成功!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"0%@ 学时上传成功!",timeString]]; [DB_Helper deleteTrainWithClassId:gatherTrainDic[@"classId"] type:bigCarTableName]; //计时结束 if (isSignOut) { [DB_Helper deleteAllTrainWithType:bigCarTableName]; [self closeTimer]; } }]; } //重新上传选择 - (void)showReUpLoad{ UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:@"提醒" message:@"学时补传失败,已保存至手机。您可以选择立即或稍后重新上传" preferredStyle:UIAlertControllerStyleAlert]; [alertFind addAction:[UIAlertAction actionWithTitle:@"现在上传" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { [self uploadAppTrainPlWithSignOut:YES]; }]]; [alertFind addAction:[UIAlertAction actionWithTitle:@"以后补传" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { }]]; [self presentViewController:alertFind animated:true completion:nil]; } @end