// // ViewController.m // JSJPCoach // // Created by apple on 2017/3/10. // Copyright © 2017年 Danson. All rights reserved. // #import "ViewController.h" #import "PersonalVC.h" #import "PeriodVC.h" #import "ExploreVC.h" #import "ModelVC.h" #import "PeriodStuCell.h" #import "DES3Util.h" #import "LoginVC.h" #import "BindVC.h" #import "STButton.h" #import "MBProgressHUD+Add.h" #import "MJRefresh.h" #import //引入地图功能所有的头文件 #import //引入定位功能所有的头文件 //蓝牙 #import typedef NS_ENUM(NSInteger, RQCoachSignStatus) { /// 未带教 RQCoachSignStatusNone = 0, /// 手机实操 RQCoachSignStatusPhoneActual = 1, /// 模拟 RQCoachSignStatussSimulation = 2, /// 实操终端 RQCoachSignStatusTerminalActual = 3, /// 集中训练 RQCoachSignStatusCentralizedTraining = 4, /// 预约 RQCoachSignStatusSubscribe = 5, }; @interface ViewController () { UITextField *BindNumberField; UITextField *RegistField; UIView *btnBar; //分段选择器下方的滚动条。 UIButton *periodBtn; UIButton *modelBtn; UIButton *overBtn; UIView *periodView; UITableView *periodTableView; UIScrollView *noticeScroll; UILabel *allTimeLabel, *valueTimeLabel, *invalidTimeLabel, *waitTimeLabel; CGFloat periodViewH; CGPoint lastOffset; //保存scroll主页面。最后一次滚动的offset NSMutableArray *stuListArray; NSMutableArray *uploadGPSArray; //注意事项 UIView *noticeView; UIButton *isForeverBtn; //计时 NSTimer *timer; UILabel *timerLabel; UIImageView *scanImgView; UIView *scanView;//二维码页面 NSDictionary *stuSignInDic; BOOL isAfterDelay; BOOL isOverScan; int timeI; BOOL isSignInState; BOOL isTerminal;//是否在终端实操计时 //上传位置定时器 NSTimer *uploadGpsTimer; CLLocationCoordinate2D myLocation;//实操用 CLLocationCoordinate2D coachLocation;//模拟用 NSInteger uploadCount; //蓝牙 NSMutableArray *peripheralArray; NSString *peripheralName; BOOL isNeed;//如果为yes代表数据不完整 需要下次接收到的数据拼接 NSString *lastData;//前边包的数据 NSString *carUUID; BOOL isJudgeCarUUID;//如果不判断 教练直接签到计时 如果判断 就获取车架号 } @property (assign, readwrite, nonatomic) RQCoachSignStatus coachSignStatus; @property(nonatomic,strong)BMKLocationManager *locationManager; @property(nonatomic,strong)UIScrollView *mainScroll; /**分段选择器的按钮 */ @property(nonatomic,strong)NSMutableArray *segBtnArray; /**用于使scroll和按钮联动 */ @property(nonatomic,assign)NSInteger pageIndex; //蓝牙 @property (nonatomic, strong) CBCentralManager *cbcManager; /** 已连接的外设*/ @property (nonatomic, strong) CBPeripheral *peripheral; /** 要写入的特征值*/ @property (nonatomic, strong) CBCharacteristic *writeCharacteristic; /** 要读的特征值*/ @property (nonatomic, strong) CBCharacteristic *readCharacteristic; @property (nonatomic, strong) UITableView *blueTableView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIImageView *backImageView = [[UIImageView alloc] initWithFrame:kFrame]; backImageView.image = [UIImage imageNamed:@"bgImage"]; [self.view addSubview:backImageView]; UIImageView *statusImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kSize.width, kStatusHeight + kSegmentHeight)]; statusImageView.backgroundColor = RGB_COLOR(7, 11, 24); [backImageView addSubview:statusImageView]; periodViewH = [defUser.userDict[@"cityId"] isEqualToString:@"3503"]? 0 : (kSize.height-kSafeAreaBottomHeight)/6.0; _pageIndex = 1; self.periodType = 3;//2018/9/18 默认为模拟带教 isSignInState = NO; isTerminal = NO; stuListArray = [NSMutableArray array]; uploadGPSArray = [NSMutableArray array]; isJudgeCarUUID = YES; if ([[NSString stringWithFormat:@"%@",defUser.userDict[@"isJudge"]] isEqualToString:@"0"]) { isJudgeCarUUID = NO; } peripheralName = @"NONAME"; //选择框 NSArray *segTitleArray = @[@"我",@"预约",@"发现"]; CGFloat segW = kSize.width/(segTitleArray.count); _segBtnArray = [NSMutableArray arrayWithCapacity:3]; for (int i = 0; i<3; i ++) { UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(segW*i,kStatusHeight,segW,kSegmentHeight)]; if (i == 1) { [button setImage:[UIImage imageNamed:@"carIcon"] forState:UIControlStateNormal]; [button setImage:[[UIImage imageNamed:@"carIcon"] tint:defGreen] forState:UIControlStateSelected]; [button setImageEdgeInsets:UIEdgeInsetsMake(2, (segW - 40)/2.0, 2, (segW - 40)/2.0)]; button.selected = YES; }else{ [button setTitle:[segTitleArray objectAtIndex:i] forState:UIControlStateNormal]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button setTitleColor:defGreen forState:UIControlStateSelected]; [button.titleLabel setFont:[UIFont scaleSize:Font18]]; } [button addTarget:self action:@selector(segSelected:) forControlEvents:UIControlEventTouchUpInside]; [button setTag:i]; [self.view addSubview:button]; [_segBtnArray addObject:button]; } btnBar = [[UIView alloc] initWithFrame:CGRectMake(segW + 20, kStatusHeight + kSegmentHeight - 3, segW - 40, 3)]; [btnBar setBackgroundColor:defGreen]; [self.view addSubview:btnBar]; //mainScroll CGFloat mainScrH = kSize.height - kNavOffSet - periodViewH - kSafeAreaBottomHeight; _mainScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, kNavOffSet, kSize.width, mainScrH)]; _mainScroll.delegate = self; [_mainScroll setShowsHorizontalScrollIndicator:NO]; [self.view addSubview:_mainScroll]; PersonalVC *personalVC = [[PersonalVC alloc] initWithScrFrame:CGRectMake(0, 0, kSize.width, mainScrH)]; [self addChildViewController:personalVC]; [_mainScroll addSubview:personalVC.view]; PeriodVC *periodVC = [[PeriodVC alloc] init]; periodVC.view.frame = CGRectMake(kSize.width, 0, kSize.width, mainScrH); [self addChildViewController:periodVC]; [_mainScroll addSubview:periodVC.view]; periodView = periodVC.view; [self resetPeriodView]; ExploreVC * exploreVC = [[ExploreVC alloc] initWithScrFrame:CGRectMake(kSize.width*2, 0, kSize.width, mainScrH)]; [self addChildViewController:exploreVC]; [_mainScroll addSubview:exploreVC.view]; NSLog(@"%@",_mainScroll.subviews); [_mainScroll setContentSize:CGSizeMake(kSize.width * 3, 0)]; [_mainScroll setContentOffset:CGPointMake(kSize.width, _mainScroll.contentOffset.y) animated:NO]; [_mainScroll setPagingEnabled:YES]; [_mainScroll setDecelerationRate:.2]; //用于使scroll快速完成减速 //底部按钮 3、4、5 tag CGFloat x, y, w, h; y = kSize.height - periodViewH - kSafeAreaBottomHeight; h = periodViewH - 20; if (h > 80) { h = 80; y += (periodViewH - 100)/2.0; } w = h; x = kSize.width/2.0 - w/2.0; periodBtn = [UIButton buttonWithType:UIButtonTypeCustom]; periodBtn.frame = setDIYFrame; [periodBtn setRound]; periodBtn.backgroundColor = defGreen; [periodBtn setTitle:@"带教" textColor:[UIColor whiteColor] font:Font18 fotState:UIControlStateNormal]; [periodBtn setTitle:@"带教中" textColor:[UIColor whiteColor] font:Font18 fotState:UIControlStateSelected]; [periodBtn target:self Tag:3]; [self.view addSubview:periodBtn]; periodBtn.hidden = [defUser.userDict[@"cityId"] isEqualToString:@"3503"]; x = 20; w = w/1.46; y += (h - w)/2 + 5; h = w; modelBtn = [UIButton buttonWithType:UIButtonTypeCustom]; modelBtn.frame = setDIYFrame; [modelBtn setRound]; modelBtn.backgroundColor = RGB_COLOR(145, 160, 175); [modelBtn setTitle:@"模式" textColor:[UIColor blackColor] font:Font16 fotState:UIControlStateNormal]; [modelBtn target:self Tag:4]; //@lee-mark:暂时移除模式 [self.view addSubview:modelBtn]; modelBtn.hidden = [defUser.userDict[@"cityId"] isEqualToString:@"3503"]; x = kSize.width - w - 20; overBtn = [UIButton buttonWithType:UIButtonTypeCustom]; overBtn.frame = setDIYFrame; [overBtn setRound]; overBtn.backgroundColor = RGB_COLOR(145, 160, 175); [overBtn setTitle:@"结束" textColor:newTitleColor font:Font16 fotState:UIControlStateNormal]; [overBtn target:self Tag:5]; [self.view addSubview:overBtn]; [RACObserve(defUser, isLogin) subscribeNext:^(id _Nullable x) { [self updateData]; }]; [RACObserve(self, periodType) subscribeNext:^(id _Nullable x) { if (self.periodType != 0) {//选择过模式了0.0 for (UIView *view in periodView.subviews) { if ([view isKindOfClass:[UILabel class]]) { UILabel *label = (UILabel *)view; if ([label.text containsString:@"带教类型"]) { if (self.periodType == 3) { label.text = @"带教类型:模拟"; }else{ switch (self.coachSignStatus) { case RQCoachSignStatusTerminalActual: label.text = [NSString stringWithFormat:@"带教类型:实操终端"]; break; default: { self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"]; NSString *subject = [self.periodDic[@"subject"] isEqualToString:@"2"] ? @"科二实操" : @"科三实操"; label.text = [NSString stringWithFormat:@"带教类型:%@",subject]; break; } } } } if ([label.text containsString:@"价格"]) { if (self.periodType == 3) { label.text = @"价格:免费"; }else{ switch (self.coachSignStatus) { case RQCoachSignStatusTerminalActual: label.text = @""; break; default: { NSString *priceString = self.periodDic[@"price"]; if ([priceString containsString:@"免费"]) { priceString = @"价格:免费"; }else{ priceString = [NSString stringWithFormat:@"价格:%@元/时",priceString]; } label.text = priceString; } break; } } } } } } }]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navigationController.navigationBarHidden = YES; [self updateData]; } - (void)updateData { //如果登陆过之后 要更新信息 if (defUser.isLogin && defUser.userDict[@"outId"] && defUser.userDict[@"cityId"]) { // [self getCoachSignForTrain];//判断是否签到按钮 [self getCoachSignStatus];//获取是否有带教学员 }else { periodBtn.selected = NO; isTerminal = NO; overBtn.hidden = YES; } } -(void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; self.navigationController.navigationBarHidden = NO; } /** 调用时间:确定带教成功 有学员列表 或者恢复带教 有学员列表 模拟有点特殊 没有学员列表也可以是带教中 只要生成了二维码就调这个接口 要做的事情:更改底部按钮状态 初始化计时页面 开启位置上传 */ - (void)initPeriodBar { periodBtn.selected = YES; overBtn.hidden = NO; //初始化计时面板 if (periodView) { for (UIView *view in periodView.subviews) { [view removeFromSuperview]; } } CGFloat x,y,w,h; w = kSize.width; if (self.periodType == 3) {//模拟 x = y = 20; w -= 2*x; h = 30; UILabel *label = [[UILabel alloc] setxywh]; [label setText:@"带教类型:模拟" Font:Font16 TextColor:newTitleColor]; [periodView addSubview:label]; y += h + 10; label = [[UILabel alloc] setxywh]; [label setText:@"带教学员:" Font:Font16 TextColor:newTitleColor]; [periodView addSubview:label]; x = 0; y += h; h = _mainScroll.height - y; w = kSize.width; periodTableView = [[UITableView alloc] initWithFrame:setDIYFrame style:UITableViewStylePlain]; periodTableView.backgroundColor = [UIColor clearColor]; periodTableView.delegate = self; periodTableView.dataSource = self; periodTableView.rowHeight = 80; [periodView addSubview:periodTableView]; periodTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ [self getCoachSignStatus]; [self getCoachSignStuRecordsMnWithIsOver:YES]; }]; }else{ x = 10; y = 20; w -= 2*x; h = 30; // UILabel *label = [[UILabel alloc] setxywh]; // [label setText:@"带教信息" Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentCenter]; // [periodView addSubview:label]; self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"]; NSString *subject = @"科二实操"; if ([self.periodDic isKindOfClass:[NSDictionary class]]) { subject = [self.periodDic[@"subject"] isEqualToString:@"2"] ? @"科二实操" : @"科三实操"; } UILabel *label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"带教类型:%@",subject] Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentLeft]; [periodView addSubview:label]; NSString *priceString = self.periodDic[@"price"]; if ([priceString containsString:@"免费"]) { priceString = @"价格:免费"; }else{ priceString = [NSString stringWithFormat:@"价格:%@元/时",priceString]; } label = [[UILabel alloc] setxywh]; [label setText:priceString Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentRight]; [periodView addSubview:label]; y += h; label = [[UILabel alloc] setxywh]; [label setText:@"带教学员:" Font:Font16 TextColor:newTitleColor]; [periodView addSubview:label]; x = 0; y += h; w = kSize.width; h = 80; UIView *view = [[UIView alloc] setxywh]; [periodView addSubview:view]; PeriodStuCell *cell = [[PeriodStuCell alloc] initWithFrame:CGRectMake(0, 0, w, h)]; cell.nameLabel.text = stuSignInDic[@"TSO_NAME"]; if ([stuSignInDic[@"TSO_PHONE"] length] > 0) { NSMutableAttributedString *abs = [[NSMutableAttributedString alloc]initWithString:stuSignInDic[@"TSO_PHONE"]]; [abs beginEditing]; //字体大小 [abs addAttribute:NSFontAttributeName value:[UIFont scaleSize:Font17] range:NSMakeRange(0, [stuSignInDic[@"TSO_PHONE"] length])]; //字体颜色 [abs addAttribute:NSForegroundColorAttributeName value:canClickColor range:NSMakeRange(0, [stuSignInDic[@"TSO_PHONE"] length])]; //下划线 [abs addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, [stuSignInDic[@"TSO_PHONE"] length])]; cell.telLabel.attributedText = abs; }else{ cell.telLabel.text = stuSignInDic[@"TSO_PHONE"]; } cell.imgPath = stuSignInDic[@"TSO_PHOTO_PATH"]; [view addSubview:cell]; y += h; h = 25; w = kSize.width/4.0; NSArray *titles = @[@"总时长",@"有效时长",@"无效时长",@"待审核"]; NSArray *colors = @[newTitleColor,[UIColor greenColor],[UIColor redColor],defGreen]; NSMutableArray *labels = [NSMutableArray arrayWithCapacity:4]; for (int i = 0; i < 4; i ++) { label = [[UILabel alloc] initWithFrame:CGRectMake(i*w, y, w, h)]; label.backgroundColor = [UIColor colorWithWhite:.7 alpha:.2]; [label setText:titles[i] Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentCenter]; [periodView addSubview:label]; label = [[UILabel alloc] initWithFrame:CGRectMake(i*w, y + h, w, h)]; [label setText:@"0分钟" Font:Font16 TextColor:colors[i] Alignment:NSTextAlignmentCenter]; [periodView addSubview:label]; [labels addObject:label]; if (i != 0) { [label addViewWithRect:CGRectMake(i*w, y, 1, 2*h) Color:newBackGroundColor]; } } allTimeLabel = labels[0]; valueTimeLabel = labels[1]; invalidTimeLabel = labels[2]; waitTimeLabel = labels[3]; // [allTimeLabel addViewWithRect:CGRectMake(20, y, kSize.width - 40, 1) Color:newBackGroundColor]; [allTimeLabel addViewWithRect:CGRectMake(20, y + 2*h - 1, kSize.width - 40, 1) Color:newBackGroundColor]; y += 2*h; w = kSize.width; h = _mainScroll.height - y + 1; periodTableView = [[UITableView alloc] initWithFrame:setDIYFrame style:UITableViewStylePlain]; periodTableView.backgroundColor = [UIColor clearColor]; periodTableView.delegate = self; periodTableView.dataSource = self; periodTableView.separatorStyle = UITableViewCellSeparatorStyleNone; [periodView addSubview:periodTableView]; //开启后台上传位置 // [self beginUploadCoachGPS]; myDelegate.isPeriodIng = YES; } } /** 将periodView置回未计时状态 */ - (void)resetPeriodView { if (periodView) { for (UIView *view in periodView.subviews) { [view removeFromSuperview]; } } //在这里将上传位置信息全清空 [uploadGPSArray removeAllObjects]; self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"]; NSString *subject = @"科二实操"; if ([self.periodDic isKindOfClass:[NSDictionary class]]) { subject = [self.periodDic[@"subject"] isEqualToString:@"2"] ? @"科二实操" : @"科三实操"; } UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 30, kSize.width - 40, 30)]; [label setText:[NSString stringWithFormat:@"带教类型:%@",subject] Font:Font18 TextColor:newTitleColor]; [periodView addSubview:label]; label = [[UILabel alloc] initWithFrame:CGRectMake(20, 60, kSize.width - 40, 30)]; [label setText:@"价格:免费" Font:Font18 TextColor:newTitleColor]; [periodView addSubview:label]; NSString *title = @"查看注意事项"; CGFloat w = [title sizeForFont:Font17].width + 10; UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(kSize.width - w - 20, 60, w, 30)]; [button setTitle:@"查看注意事项" textColor:defGreen font:Font17 fotState:UIControlStateNormal]; [button setTitle:@"隐藏注意事项" textColor:defGreen font:Font17 fotState:UIControlStateSelected]; [button target:self Tag:8]; [periodView addSubview:button]; [button addViewWithRect:CGRectMake(kSize.width - w - 20, 85, w, 1) Color:defGreen]; CGFloat y = 120; CGFloat h = kSize.width/3.0 - 10; UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, y, kSize.width - 40, h)]; imageView.image = [UIImage imageNamed:@"periodStep.png"]; [imageView borderCornorRadios:5]; [periodView addSubview:imageView]; NSString *string = @"教练您好:\n 本系统采用分钟学时的方法计算学时,所以请您在带教的过程中注意以下几点: \n\n1、确保您的手机能正常联网,3G以上网络能给您带来更好的效果 \n\n2、带教过程中,规定不允许离开训练场和打电话,系统会实时采集您的位置,用于学员分钟学时有效性判断,请确保网络正常连接,系统允许临时接电话,默认15分钟内,具体按管理部门规定,如果超过规定时间,学员的分钟学时全部无效 \n\n3、如果您选择计时收费,请确认您已经选择好了培训科目和培训价格,否则系统无法进行计费训练 \n\n4、培训结束后,学员可以对您的带教进行评价或投诉,一旦发生投诉,系统将会上传至省监管平台,将会影响您的信誉 \n\n5、为确保学员分钟学时有效,请确保您跟学员的位置在规定范围内,否则学员分钟学时无效 \n\n6、如果是收费训练,在训练结束后,可以在我的订单中选择收款,生成二维码,学员扫码支付成功后,学员学时有效,请提醒您的学员及时支付,否则,学时将不会计入有效学时"; CGFloat noticeH = [string heightForWid:kSize.width - 40 Font:Font17] + 10; y += h + 10; noticeScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, y, kSize.width, _mainScroll.height - y)]; [periodView addSubview:noticeScroll]; noticeScroll.contentSize = CGSizeMake(kSize.width, noticeH + 30); UILabel *noticeLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, kSize.width - 40, noticeH)]; [noticeLabel setText:string Font:Font17 TextColor:backGroundColor]; noticeLabel.numberOfLines = 0; [noticeScroll addSubview:noticeLabel]; noticeScroll.hidden = YES; } - (void)initNoticeView { noticeView = [[UIView alloc] initWithFrame:kFrame]; noticeView.backgroundColor = [UIColor colorWithWhite:.01 alpha:.4]; [[UIApplication sharedApplication].keyWindow addSubview:noticeView]; NSString *noticeString = @"教练您好:\n\n 本系统采用分钟学时的方法计算学时,所以请您在带教的过程中注意以下几点: \n\n1、确保您的手机能正常联网,3G以上网络能给您带来更好的效果 \n\n2、带教过程中,规定不允许离开训练场和打电话,系统会实时采集您的位置,用于学员分钟学时有效性判断,请确保网络正常连接,系统允许临时接电话,默认15分钟内,具体按管理部门规定,如果超过规定时间,学员的分钟学时全部无效 \n\n3、如果您选择计时收费,请确认您已经选择好了培训科目和培训价格,否则系统无法进行计费训练 \n\n4、培训结束后,学员可以对您的带教进行评价或投诉,一旦发生投诉,系统将会上传至省监管平台,将会影响您的信誉 \n\n5、为确保学员分钟学时有效,请确保您跟学员的位置在规定范围内,否则学员分钟学时无效 \n\n6、如果是收费训练,在训练结束后,可以在我的订单中选择收款,生成二维码,学员扫码支付成功后,学员学时有效,请提醒您的学员及时支付,否则,学时将不会计入有效学时"; CGFloat noticeH = [noticeString heightForWid:kSize.width - 80 Font:Font17] + 10; UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(20, kNavOffSet, kSize.width - 40, kSize.height - kNavOffSet - 100)]; scrollView.contentSize = CGSizeMake(kSize.width - 40, noticeH + 50); scrollView.backgroundColor = newBackGroundColor; [noticeView addSubview:scrollView]; [scrollView addViewWithRect:CGRectMake(20, scrollView.y + scrollView.height, scrollView.width, 1)]; UILabel *noticeLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, kSize.width - 80, noticeH)]; noticeLabel.numberOfLines = 0; [noticeLabel setText:noticeString Font:Font17 TextColor:newTitleColor]; [scrollView addSubview:noticeLabel]; UIView *btnView = [[UIView alloc] initWithFrame:CGRectMake(20, scrollView.y + scrollView.height + 1, scrollView.width, 40)]; btnView.backgroundColor = newBackGroundColor; [noticeView addSubview:btnView]; NSArray *titles = @[@"不再显示",@"不同意",@"同意"]; CGFloat w = scrollView.width/4.0; for (int i = 0; i < 3; i ++) { UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; if (i == 0) { btn.frame = CGRectMake(0, 0, 2*w, 40); }else{ btn.frame = CGRectMake(w + i*w, 0, w, 40); } [btn setTitle:titles[i] textColor:newTitleColor font:Font18 fotState:UIControlStateNormal]; [btn target:self Tag:20 + i]; [btnView addSubview:btn]; if (i == 0) { isForeverBtn = btn; } } [isForeverBtn addViewWithRect:CGRectMake(2*w - 1, 0, 1, 40) Color:newSubTitleColor]; [isForeverBtn addViewWithRect:CGRectMake(3*w - 1, 0, 1, 40) Color:newSubTitleColor]; } - (void)btnClick:(UIButton *)sender { if (!defUser.isLogin) { [LoginVC loginFromVC:self]; return ; } //3 带教 4 模式。 5结束 if (sender.tag == 3) { if (isTerminal) { //正在终端带教中 ShowMsg(@"正在终端带教学员,无法进行此操作"); [Tools playAudioWithString:@"正在终端带教学员,请在终端投屏中查看带教信息"]; return; } if (![sender isKindOfClass:[STButton class]]) { //注意事项 if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"isShowNotice"] isKindOfClass:[NSString class]]) { if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"isShowNotice"] isEqualToString:@"doNotShowNotice"]) { [self initNoticeView]; return; } }else{ [self initNoticeView]; return; } } //判断是否绑定(取消绑定IMIE) // if ([defUser.userDict[@"city"] isEqualToString:@"3503"]) { // // }else { // if ([defUser.userDict[@"imei"] length] > 0) { // if (![defUser.userDict[@"imei"] isEqualToString:[Tools getIDFV]]) { // ShowMsg(@"账号与绑定手机不匹配,请用本人手机带教学员"); // [Tools playAudioWithString:@"账号与绑定手机不匹配,请用本人手机带教学员"]; // return; // } // }else{ // [self goToBindVC]; // return; // } // } //判断是否注册车辆 [self doTeach]; return; } if (sender.tag == 4) { //判断是否可以选择模式 带教中 不能选择模式 if (periodBtn.selected) { ShowMsg(@"正在带教中,不能进行此操作"); return; } ModelVC *vc = [[ModelVC alloc] init]; vc.superVC = self; vc.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:vc animated:YES completion:^{ [Tools playAudioWithString:@"请选择带教模式"]; }]; return; } if (sender.tag == 5) { if (self.periodType == 3) { [self getCoachSignStuRecordsMnWithIsOver:YES]; }else if (self.periodType == 2) { ModelVC *vc = [[ModelVC alloc] init]; vc.modelPageType = RQModelPageTypeSubscribe; vc.superVC = self; [vc initWithCoachOrderBlock:^(NSDictionary *dic) { self.periodDic = dic; [self makeOverScanView]; }]; vc.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:vc animated:YES completion:^{ [Tools playAudioWithString:@"请选择预约学员"]; }]; }else{ // 取消判断IMEI // if ([defUser.userDict[@"imei"] length] > 0) { // if (![defUser.userDict[@"imei"] isEqualToString:[Tools getIDFV]]) { // ShowMsg(@"账号与绑定手机不匹配,请用本人手机带教学员"); // [Tools playAudioWithString:@"账号与绑定手机不匹配,请用本人手机带教学员"]; // return; // } // } [self makeOverScanView]; } return; } //更新二维码 if (sender.tag == 7) { NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [formatter stringFromDate:effectiveDate]; NSString *scanString = @""; if (self.periodType == 1) { //实时 scanString = [NSString stringWithFormat:@"#JSDTMO#;signIn;%@;%@;%@;%@;%@;%@;%@;NOMACADRESS;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],_periodDic[@"price"],_periodDic[@"subject"],defUser.userDict[@"mobile"],defUser.userDict[@"devnum"],peripheralName,dateString];//参数分别是 type 教练outID 教练姓名 价格 科目 电话号码 终端设备号 蓝牙名称 有效时间 } if (self.periodType == 2) { //预约 scanString = [NSString stringWithFormat:@"#JSDTMO#;planSignIn;%@;%@;%@;%@;%@;%@;%@;NOMACADRESS;%@;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],_periodDic[@"userId"],_periodDic[@"rid"],defUser.userDict[@"mobile"],defUser.userDict[@"devnum"],peripheralName,dateString,defUser.userDict[@"id"]];//参数分别是 type教练outID 教练姓名 学生ID 预约ID 电话号码 终端设备号 蓝牙名称 有效时间 教练ID } if (self.periodType == 3) { //模拟 scanString = [NSString stringWithFormat:@"#JSDTMO#;imitSignIn;%@;%@;%f;%f;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],coachLocation.longitude,coachLocation.latitude,dateString];//标识符 type 教练outID 教练名字 教练经度 教练纬度 有效时间 } if (isOverScan) { scanString = [NSString stringWithFormat:@"#JSDTMO#;signOut;%@;%@;%@",defUser.userDict[@"outId"],[stuSignInDic objectForKey:@"TSO_ID"],dateString];//参数分别是 type 教练outID 学生outID 有效时间 } //NSLog(@"加密前---><>%@",scanString); scanString = [DES3Util encrypt:scanString]; scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString]; //NSLog(@"加密后--><>%@",scanString); UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f]; qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)]; scanImgView.image = qrcode; //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来 timeI = 600; if (self.periodType == 3) { if (timer) { //如果存在 置为空 [timer invalidate]; timer = nil; } timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInImitate) userInfo:nil repeats:YES]; }else{ if (timer) { //如果存在 置为空 [timer invalidate]; timer = nil; } timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES]; } return; } if (sender.tag == 8) {//显示 隐藏 sender.selected = !sender.selected; if (sender.selected) { } noticeScroll.hidden = sender.selected ? NO : YES; //ShowMsg([NSString stringWithFormat:@"%@",sender.selected ? @"显示流程图":@"隐藏流程图"]); } if (sender.tag == 9) {//取消蓝牙连接 取消计时 [self closeBlueTooth]; return; } if (sender.tag == 20) {//是否还要显示 sender.selected = !sender.selected; if (sender.selected) { sender.backgroundColor = defGreen; }else{ sender.backgroundColor = [UIColor clearColor]; } } if (sender.tag == 21) { [noticeView removeFromSuperview]; } if (sender.tag == 22) { if (isForeverBtn.selected) { //不再显示 本地存个字段 [[NSUserDefaults standardUserDefaults] setValue:@"doNotShowNotice" forKey:@"isShowNotice"]; } [noticeView removeFromSuperview]; //重新回到tag==3的触发事件中 STButton *st = [[STButton alloc] init]; st.tag = 3; [self btnClick:st]; } } - (void)goToBindVC { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"您的账号还未绑定手机,绑定后当前手机只能用于当前帐号带教学员" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"去绑定",nil]; alert.tag = 3; [alert show]; } -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (alertView.tag == 2) { if (buttonIndex != alertView.cancelButtonIndex) { self.periodDic = @{@"subject":@"2",@"price":@"免费",@"periodType":@"1"}; if ([alertView.message containsString:@"科三"]) { self.periodDic = @{@"subject":@"3",@"price":@"免费",@"periodType":@"1"}; } [[NSUserDefaults standardUserDefaults] setObject:self.periodDic forKey:@"periodInfo"]; self.periodType = 1; [self makeNoPlanScanView]; } } if (alertView.tag == 3) { if (buttonIndex == alertView.cancelButtonIndex) { return; }else{ BindVC *bindVC = [[BindVC alloc] init]; [bindVC bindSuccessWithBlock:^{ [self coachLogin]; }]; [self.navigationController pushViewController:bindVC animated:YES]; } } if (alertView.tag == 4) { if (buttonIndex == alertView.cancelButtonIndex) { return; }else{ //终端注册 [self doDeviceReg]; } } } //设置实操参数 -(void)setPeriodDic:(NSDictionary *)periodDic { _periodDic = periodDic; [[NSUserDefaults standardUserDefaults] setObject:_periodDic forKey:@"periodInfo"]; } #pragma mark - get -(BMKLocationManager *)locationManager{ if (!_locationManager) { //初始化实例 _locationManager = [[BMKLocationManager alloc] init]; //设置delegate _locationManager.delegate = self; _locationManager.allowsBackgroundLocationUpdates = YES; //设置返回位置的坐标系类型 默认为国标 _locationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;//百度经纬度坐标 } return _locationManager; } #pragma mark tableview -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (tableView == _blueTableView) { return peripheralArray.count; } if (self.periodType == 3) { return stuListArray.count; }else{ return uploadGPSArray.count; } } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (tableView == _blueTableView) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"peripheralCell"]; if (peripheralArray.count > 0) { CBPeripheral *peripheeal = peripheralArray[indexPath.row]; cell.textLabel.text = peripheeal.name; } return cell; } if (self.periodType == 3) { //模拟 PeriodStuCell *cell = [tableView dequeueReusableCellWithIdentifier:@"moniStuCell"]; if (cell == nil) { cell = [[PeriodStuCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"moniStuCell"]; } cell.dataDic = stuListArray[indexPath.row]; return cell; }else{ //实操 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"coachgpsCell"]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"coachgpsCell"]; cell.backgroundColor = [UIColor clearColor]; cell.selectionStyle = UITableViewCellSelectionStyleNone; } [cell.textLabel setText:uploadGPSArray[indexPath.row] Font:Font16 TextColor:newSubTitleColor]; return cell; } } -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (tableView == _blueTableView) { CBPeripheral *peripheral = peripheralArray[indexPath.row]; self.peripheral = peripheral; [self.cbcManager connectPeripheral:self.peripheral options:nil]; } } -(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{ return [UIView new]; } -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 0.1; } #pragma mark 数据请求 - (void)doTeach { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]]; // [arr addPro:@"imei" Value:[Tools getIDFV]]; // [arr addPro:@"imei" Value:@"80D85448-CD43-497C-98F9-6482F0443686"]; [arr addPro:@"sim" Value:defUser.userDict[@"mobile"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; [arr addPro:@"jxbh" Value:defUser.userDict[@"jxbh"]]; NSString* method = @"doTeach"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { ShowMsg(@"数据出错,请重试!"); return ; } if ([root[@"code"] isEqualToString:@"1"]) { // [self showRegistTextField]; ShowMsg(root[@"body"]); return; } if ([root[@"body"] isEqualToString:@"该设备不存在!"]) { // [self showRegistTextField]; return; } if ([root[@"body"] isEqualToString:@"允许带教"]) { //判断是否签到过 // if (!isSignInState) { // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"签到中,请稍后" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; // [alert show]; // return; // } //如果是模拟 不用判断很多 只要签到过没有计时其他模式计时 就可以打开 if (self.periodType == 3) { [self requestCoachLocation]; return; } //根据self.periodType判断是否可以继续带教 if (periodBtn.selected && self.periodType != 3) { //带教中 ShowMsg(@"正在带教中,不能进行此操作"); return; } //对实操计时 前面的判断全成功之后 得到允许带教的指令 进入蓝牙选择 判断完蓝牙 再去生成二维码 if ([[NSString stringWithFormat:@"%@",defUser.userDict[@"openObd"]] isEqualToString:@"1"]) { [self searchBlueTooth]; }else { [self enterMakeScanView]; } } }]; } - (void)enterMakeScanView { //断开蓝牙连接 关掉蓝牙 隐藏蓝牙外设列表页面 [self closeBlueTooth]; if (self.periodType == 0) { //未选择带教模式 提示使用默认 NSString *messageString = @"您未选择带教模式,当前默认为科二实操,免费带教,是否继续?"; self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"]; if ([self.periodDic isKindOfClass:[NSDictionary class]]) { if ([[self.periodDic objectForKey:@"subject"] isEqualToString:@"3"]) { messageString = @"您未选择带教模式,当前默认为科三实操,免费带教,是否继续?"; } } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:messageString delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"继续", nil]; alert.tag = 2; [alert show]; return; } if (self.periodType == 1) { // if ([defUser.userDict[@"devnum"] length] < 1) { // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"终端注册号获取失败,请尝试重新登录" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; // [alert show]; // return; // } [self makeNoPlanScanView]; } if (self.periodType == 2) { [self makePlanScanView]; } } - (void)doDeviceReg { if (RegistField.text.length < 1) { ShowMsg(@"请输入车牌号码"); [self showRegistTextField]; return; } NSString *carNum = RegistField.text; if (![carNum containsString:@"闽"]) { carNum = [NSString stringWithFormat:@"闽%@",RegistField.text]; } if (![carNum containsString:@"学"]) { carNum = [NSString stringWithFormat:@"%@学",RegistField.text]; } // if ([defUser.userDict[@"devnum"] length] < 1) { // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"终端注册号获取失败,请尝试重新登录" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; // [alert show]; // return; // } [LoadingView showHUD]; if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"sim" Value:defUser.userDict[@"mobile"]]; [arr addPro:@"licnum" Value:carNum]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; [arr addPro:@"jxbh" Value:defUser.userDict[@"jxbh"]]; NSString* method = @"doDeviceReg"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { RemoveHUD(); if (!root) { ShowMsg(@"注册失败!"); return ; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); return; } ShowMsg(@"注册成功!"); reLogin(); }]; } - (void)showRegistTextField { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"手机注册" message:@"手机未注册为终端设备,请输入当前手机带练车辆的车牌号码完成注册" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput; RegistField = [alert textFieldAtIndex:0]; RegistField.placeholder = @"请输入车牌号码"; alert.tag = 4; [alert show]; } //更新登录信息 -(void)coachLogin { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr = [NSMutableArray array]; [arr addPro:@"sfzhm" Value:defUser.sfzmhm]; [arr addPro:@"pwd" Value:defUser.userDict[@"pwd"]]; NSString* method = @"coachLogin"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { RemoveHUD(); if (!root || [root[@"code"] isEqualToString:@"1"]) { return; } //更新信息 defUser.isLogin = YES; defUser.userDict = root[@"body"]; //NSLog(@"----><>%@",defUser.userDict); }]; } /**判断是否正在带教。在view建立和点击带教的时候用*/ - (void)getCoachSignStatus { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; NSString* method = @"getCoachSignStatus"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { return; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); return; } self.coachSignStatus = [root[@"body"] integerValue]; periodBtn.selected = YES; isTerminal = NO; overBtn.hidden = YES; switch (self.coachSignStatus) { case RQCoachSignStatusNone: { periodBtn.selected = NO; isTerminal = NO; overBtn.hidden = YES; break; } case RQCoachSignStatusPhoneActual: { //如果没有上传位置 说明是断线重连 否则是正在带教的情况 if (!uploadGpsTimer) { self.periodType = 4; [self getCoachSignStuRecords]; } break; } case RQCoachSignStatussSimulation: { self.periodType = 3; if (stuListArray.count < 1) {//如果学员小于1 有可能是重新进入的软件 重新加载学员列表控件 [self initPeriodBar]; [self getCoachSignStuRecordsMnWithIsOver:NO]; } break; } case RQCoachSignStatusTerminalActual: { //终端实操 isTerminal = YES; self.periodType = 2; overBtn.hidden = YES; break; } case RQCoachSignStatusCentralizedTraining: { break; } case RQCoachSignStatusSubscribe: { self.periodType = 2; [self initPeriodBar]; overBtn.hidden = NO; break; } default: break; } }]; } //获取实操计时学员 - (void)getCoachSignStuRecords { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"coachId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; NSString* method = @"getCoachSignStuRecords"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { return; } if ([root[@"code"] isEqualToString:@"1"]) { return; } stuSignInDic = root[@"body"]; if (isOverScan) { if (stuSignInDic.count < 1 && self.coachSignStatus != RQCoachSignStatusSubscribe) { //结束计时 无学员 //获取到学员为空 就停止刷新 关闭二维码 改变按钮状态 [Tools playAudioWithString:@"扫描成功,带教结束"]; [self removeScanView]; [self resetPeriodView]; //关闭教练后台上传位置 [self finishUploadCoachGPS]; // 默认改为模拟带教 self.periodType = 3; periodBtn.selected = NO; overBtn.hidden = YES; myDelegate.isPeriodIng = NO; } }else{ if (stuSignInDic.count > 0) { //开始计时 有学员 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; if (self.periodType == 4) {//断线重连学员 self.periodType = 1; [Tools playAudioWithString:@"当前有带教学员,恢复位置上传"]; //获取本地的科目和价格 self.periodDic = [userDefaults objectForKey:@"periodInfo"]; if ([self.periodDic[@"periodType"] isEqualToString:@"2"]) { self.periodType = 2; } }else{//正常开始计时 [Tools playAudioWithString:@"扫描成功,开始带教"]; [self removeScanView];//获取到学员 就停止刷新 关闭二维码 } [stuListArray addObject:stuSignInDic]; [self initPeriodBar]; }else{ if (self.periodType == 4) { //刚进入app时候 getCoachSignStatus返回有实操计时 其实找不到 [self finishUploadCoachGPS]; // 默认改为模拟带教 self.periodType = 3; } } } }]; } //获取模拟学员签到列表 - (void)getCoachSignStuRecordsMnWithIsOver:(BOOL)isOver { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; NSString* method = @"getCoachSignStuRecordsMn"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { return; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); return; } stuListArray = root[@"body"]; [periodTableView reloadData]; [periodTableView.mj_header endRefreshing]; if (isOver) { if (stuListArray.count < 1) { //没有模拟学员 可以结束 [Tools playAudioWithString:@"成功结束模拟带教"]; [self resetPeriodView]; // 默认改为模拟带教 self.periodType = 3; periodBtn.selected = NO; overBtn.hidden = YES; // myDelegate.isPeriodIng = NO; }else{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"正在带教%d名学员模拟练习,不能进行此操作",(int)stuListArray.count] delegate:nil cancelButtonTitle:@"确认" otherButtonTitles:nil, nil]; [alert show]; } }else { [self initPeriodBar]; } }]; } /**获取教练当天签到详情*/ - (void)getCoachSignForTrain { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; NSString* method = @"getCoachSignForTrain"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { return; } if ([root[@"code"] isEqualToString:@"1"]) { if ([root[@"body"] isKindOfClass:[NSString class]]) { ShowMsg(root[@"body"]); } return; } NSDictionary *dic = root[@"body"]; if (![dic isKindOfClass:[NSDictionary class]]) { return; } //0 未签到 1 已签到 2隔日签退 //dic[@"status"] switch ([dic[@"status"] integerValue]) { case 0: [self uploadAppSignInfoWithType:@"1"]; break; case 1: isSignInState = YES; break; case 2: if (isTerminal) { isSignInState = YES; //终端签到中 不要签退 return; } [self uploadAppSignInfoWithType:@"0"]; break; default: break; } //判断日期是否有问题 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd"]; NSString *dateString = [formatter stringFromDate:[NSDate date]]; if (![dateString isEqualToString:dic[@"currentTime"]]) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"您的手机日期可能存在偏差,请核对" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; [alert show]; } }]; } //教练签到/签退 - (void)uploadAppSignInfoWithType:(NSString *)singType { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } BOOL requestResult = [self.locationManager requestLocationWithReGeocode:NO withNetworkState:NO completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) { if (error) { ShowMsg([NSString stringWithFormat:@"定位失败:%@",error.description]); }else{ [self reallyUploadAppSignInfoWithType:singType location:location.location.coordinate]; } }]; if (requestResult == NO) { // ShowMsg(@"发起定位请求失败"); } } - (void)reallyUploadAppSignInfoWithType:(NSString *)singType location:(CLLocationCoordinate2D)location { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *timeString = [dateFormatter stringFromDate:[NSDate date]]; NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"sim" Value:defUser.userDict[@"mobile"]]; [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"gps" Value:[NSString stringWithFormat:@"%f,%f,%@,3",location.longitude,location.latitude,timeString]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; NSString *method = @"saveCoachSignIn"; if (![singType isEqualToString:@"1"]) { //签退 method = @"saveCoachSignOut"; } [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { if ([singType isEqualToString:@"1"]) { ShowMsg(@"签到失败,请重试"); }else{ ShowMsg(@"签退失败,请重试"); } return; } if (![root[@"code"] isEqualToString:@"0"]) { ShowMsg(root[@"body"]); return; } if ([singType isEqualToString:@"1"]) { //签到成功 isSignInState = YES; }else{ //隔日签退成功 就签到 [self uploadAppSignInfoWithType:@"1"]; } }]; } #pragma mark 上传教练位置相关 /** * @brief 当定位发生错误时,会调用代理的此方法。 * @param manager 定位 BMKLocationManager 类。 * @param error 返回的错误,参考 CLError 。 */ - (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error{ ShowMsg([NSString stringWithFormat:@"获取位置错误:%@",error.description]); } /** * @brief 连续定位回调函数。 * @param manager 定位 BMKLocationManager 类。 * @param location 定位结果,参考BMKLocation。 * @param error 错误信息。 */ - (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didUpdateLocation:(BMKLocation * _Nullable)location orError:(NSError * _Nullable)error{ myLocation = location.location.coordinate; } - (void)beginUploadCoachGPS { [self.locationManager startUpdatingLocation]; uploadCount = 0; //这里让定时器开始前(第0s [self saveCoachGpsInfo]; if (!uploadGpsTimer) { uploadGpsTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(saveCoachGpsInfo) userInfo:nil repeats:YES]; } } - (void)finishUploadCoachGPS { //先关闭定时器 if (uploadGpsTimer) { [uploadGpsTimer invalidate]; uploadGpsTimer = nil; } [self.locationManager stopUpdatingLocation]; } - (void)saveCoachGpsInfo { //这个点要采集的时候的时间 所以用这个 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; NSString *sfmString = dateString; if (sfmString.length > 10) { sfmString = [[sfmString componentsSeparatedByString:@" "] lastObject]; } if (![Util connectedToNetWork]) { [uploadGPSArray addObject:[NSString stringWithFormat:@"%@ 网络无连接,上传位置失败!",sfmString]]; [periodTableView reloadData]; uploadCount = 0; return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"lon" Value:[NSString stringWithFormat:@"%f",myLocation.longitude]]; [arr addPro:@"lat" Value:[NSString stringWithFormat:@"%f",myLocation.latitude]]; [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]]; [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]]; [arr addPro:@"crtime" Value:dateString]; NSString* method = @"saveCoachGpsInfo"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root) { [uploadGPSArray addObject:[NSString stringWithFormat:@"%@ 上传位置失败!",sfmString]]; [periodTableView reloadData]; uploadCount = 0; return; } if ([root[@"code"] isEqualToString:@"1"]) { NSString *str = root[@"body"]; [uploadGPSArray addObject:str]; [periodTableView reloadData]; uploadCount = 0; if ([str containsString:@"签退"]) { [Tools playAudioWithString:root[@"body"]]; ShowMsg(root[@"body"]); myDelegate.isPeriodIng = NO; [self finishUploadCoachGPS];//关闭教练后台上传位置 // 默认改为模拟带教 self.periodType = 3; periodBtn.selected = NO; overBtn.hidden = YES; [self resetPeriodView]; } return; } if (uploadCount%6 == 0) { //上传位置成功;2;0;2;0 总时长、有效时长、无效时长、待审核时长 NSArray *results = [root[@"body"] componentsSeparatedByString:@";"]; [uploadGPSArray addObject:[NSString stringWithFormat:@"%@ %@!",sfmString,results[0]]]; if (!myDelegate.isBackgroundTask) { [periodTableView reloadData]; } if (results.count < 5) { return; } allTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[1]]; valueTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[2]]; invalidTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[3]]; waitTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[4]]; } uploadCount ++; }]; } #pragma mark 生成二维码 模拟 -(void)requestCoachLocation { [MBProgressHUD showMessag:@"正在获取位置..." toView:self.view]; BOOL requestResult = [self.locationManager requestLocationWithReGeocode:NO withNetworkState:NO completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) { [MBProgressHUD hideHUDForView:self.view animated:NO]; if (error) { ShowMsg([NSString stringWithFormat:@"定位失败:%@",error.description]); }else{ [self makeImitateScanViewWithCoachLocation:location.location.coordinate]; } }]; if (requestResult == NO) { // ShowMsg(@"发起定位请求失败"); } } -(void)makeImitateScanViewWithCoachLocation:(CLLocationCoordinate2D)coachLocation { if (scanView) { return; } CGFloat x,y,w,h; x = 20; y = 100; w = kSize.width - 40; h = kSize.width + 20; scanView = [[UIView alloc] setxywh]; scanView.backgroundColor = [UIColor whiteColor]; [scanView borderColor:lineColor width:1 cornorRadios:5]; [self.view addSubview:scanView]; x = 0; y = 0; h = 30; UILabel *label = [[UILabel alloc] setxywh]; [label setText:@"学员可扫二维码开始模拟计时" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [scanView addSubview:label]; x = (w - 250)/2.0; y += h + 10; w = h = 250; scanImgView = [[UIImageView alloc] setxywh]; [scanView addSubview:scanImgView]; x = 0; y += h + 10; w = kSize.width - 40; h =30; label = [[UILabel alloc] setxywh]; [label setText:@"二维码有效时间:10:00" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [scanView addSubview:label]; timerLabel = label; UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]]; cancelImg.frame = CGRectMake(w - 25, 5, 20, 20); [scanView addSubview:cancelImg]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(w - 50, 0, 50, 50); btn.backgroundColor = [UIColor clearColor]; [btn addTarget:self action:@selector(removeScanView) forControlEvents:UIControlEventTouchUpInside]; [scanView addSubview:btn]; NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [formatter stringFromDate:effectiveDate]; NSString *scanString = [NSString stringWithFormat:@"#JSDTMO#;imitSignIn;%@;%@;%f;%f;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],coachLocation.longitude,coachLocation.latitude,dateString];//标识符 type 教练outID 教练名字 教练经度 教练纬度 有效时间 //NSLog(@"加密前---><>%@",scanString); scanString = [DES3Util encrypt:scanString]; scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString]; //NSLog(@"加密后--><>%@",scanString); UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f]; qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)]; scanImgView.image = qrcode; //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来 timeI = 600; if (timer) { //如果存在 置为空 [timer invalidate]; timer = nil; } timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInImitate) userInfo:nil repeats:YES]; } //二维码的验证 -(void)timeRunInImitate { timeI --; if (timeI%5 == 0) { [self getCoachSignStuRecordsMnWithIsOver:NO]; } timerLabel.text = [NSString stringWithFormat:@"二维码有效时间:%d:%d",timeI/60,timeI%60]; if (timeI == 0) { NSString *textString = @"二维码已过期,请刷新(点击刷新)"; NSString *titleString = @"刷新(点击刷新)"; CGFloat w = [textString sizeForFont:Font16].width; CGFloat x = (kSize.width - w)/2.0; CGFloat y = timerLabel.y; CGFloat h = timerLabel.height; timerLabel.frame = setDIYFrame; [timerLabel setText:textString Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; w = [titleString sizeForFont:Font16].width; x += [textString sizeForFont:Font16].width - w; UIButton *btn = [[UIButton alloc] setxywh]; btn.backgroundColor = [UIColor clearColor]; [btn target:self Tag:7]; [scanView addSubview:btn]; [btn addViewWithRect:CGRectMake(x, y + h -5, w, 1) Color:[UIColor orangeColor]]; //关闭定时器 [timer invalidate]; timer = nil; timeI = 600; } } #pragma mark 生成二维码 非计划 -(void)makeNoPlanScanView { if (scanView) { return; } if (isAfterDelay == YES) { isAfterDelay = NO; if (timer) { [timer invalidate]; timer = nil; } } isOverScan = NO; CGFloat x,y,w,h; x = 20; y = 100; w = kSize.width - 40; h = kSize.width + 20; scanView = [[UIView alloc] setxywh]; scanView.backgroundColor = [UIColor whiteColor]; [scanView borderColor:lineColor width:1 cornorRadios:5]; [self.view addSubview:scanView]; x = 0; y = 0; h = 30; UILabel *label = [[UILabel alloc] setxywh]; [label setText:@"学员可扫二维码开始计时" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [scanView addSubview:label]; x = (w - 250)/2.0; y += h + 10; w = h = 250; scanImgView = [[UIImageView alloc] setxywh]; [scanView addSubview:scanImgView]; x = 0; y += h + 10; w = kSize.width - 40; h =30; label = [[UILabel alloc] setxywh]; [label setText:@"二维码有效时间:10:00" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [scanView addSubview:label]; timerLabel = label; UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]]; cancelImg.frame = CGRectMake(w - 25, 5, 20, 20); [scanView addSubview:cancelImg]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(w - 50, 0, 50, 50); btn.backgroundColor = [UIColor clearColor]; [btn addTarget:self action:@selector(removeScanViewAndIsCanTime) forControlEvents:UIControlEventTouchUpInside]; [scanView addSubview:btn]; NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [formatter stringFromDate:effectiveDate]; NSString *scanString = [NSString stringWithFormat:@"#JSDTMO#;signIn;%@;%@;%@;%@;%@;%@;%@;NOMACADRESS;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],[_periodDic[@"price"] containsString:@"免费"]?@"0":_periodDic[@"price"],_periodDic[@"subject"],defUser.userDict[@"mobile"],defUser.userDict[@"devnum"],peripheralName,dateString];//参数分别是 type 教练outID 教练姓名 价格 科目 电话号码 终端设备号 蓝牙名称 有效时间 //NSLog(@"加密前---><>%@",scanString); scanString = [DES3Util encrypt:scanString]; scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString]; //NSLog(@"加密后--><>%@",scanString); UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f]; qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)]; scanImgView.image = qrcode; //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来 timeI = 600; if (timer) { //如果存在 置为空 [timer invalidate]; timer = nil; } timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES]; } #pragma mark 生成二维码 计划 -(void)makePlanScanView { if (scanView) { return; } isOverScan = NO; CGFloat x,y,w,h; x = 20; if (kSize.width > 350) { x = 40; } y = 100; w = kSize.width - 2*x; h = kSize.width + 20; scanView = [[UIView alloc] setxywh]; scanView.backgroundColor = [UIColor whiteColor]; [scanView borderColor:lineColor width:1 cornorRadios:5]; [self.view addSubview:scanView]; NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateStr = [formatter stringFromDate:effectiveDate]; NSString *scanString = [NSString stringWithFormat:@"#JSDTMO#;planSignIn;%@;%@;%@;%@;%@;%@;%@;NOMACADRESS;%@;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],_periodDic[@"userId"],_periodDic[@"rid"],defUser.userDict[@"mobile"],defUser.userDict[@"devnum"],peripheralName,dateStr,defUser.userDict[@"id"]];//参数分别是 type 教练outID 教练姓名 学生ID 预约ID 电话号码 终端设备号 蓝牙名称 有效时间 教练ID //NSLog(@"加密前---><>%@",scanString); scanString = [DES3Util encrypt:scanString]; scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString]; //NSLog(@"加密后--><>%@",scanString); UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f]; qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)]; x = (w - 250)/2.0; y = 20; w = h = 250; scanImgView = [[UIImageView alloc] setxywh]; scanImgView.image = qrcode; [scanView addSubview:scanImgView]; if (kSize.width > 350) { x = 40; } w = kSize.width - 2*x; x = 0; y += h + 10; h =30; UILabel *label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"二维码有效时间:10:00"] Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [scanView addSubview:label]; timerLabel = label; UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]]; cancelImg.frame = CGRectMake(w - 25, 5, 20, 20); [scanView addSubview:cancelImg]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(w - 50, 0, 50, 50); btn.backgroundColor = [UIColor clearColor]; [btn addTarget:self action:@selector(removeScanViewAndIsCanTime) forControlEvents:UIControlEventTouchUpInside]; [scanView addSubview:btn]; //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来 timeI = 600; if (timer) { //如果存在 置为空 [timer invalidate]; timer = nil; } timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES]; } #pragma mark 结束二维码 定时器 销毁 //结束二维码 - (void)makeOverScanView { if (scanView) { return; } if (isAfterDelay == YES) { isAfterDelay = NO; if (timer) { [timer invalidate]; timer = nil; } } isOverScan = YES; CGFloat x,y,w,h; x = 20; if (kSize.width > 350) { x = 40; } y = 100; w = kSize.width - 2*x; h = kSize.width + 20; scanView = [[UIView alloc] setxywh]; scanView.backgroundColor = [UIColor whiteColor]; [scanView borderColor:lineColor width:1 cornorRadios:5]; [self.view addSubview:scanView]; NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [formatter stringFromDate:effectiveDate]; NSString *scanString = [NSString stringWithFormat:@"#JSDTMO#;signOut;%@;%@;%@",defUser.userDict[@"outId"],[stuSignInDic objectForKey:@"TSO_ID"],dateString];//参数分别是 type 教练outID 学生outID 有效时间 if ([self.periodDic[@"periodType"] isEqualToString:@"2"]) {//计划的 self.periodType = 2; scanString = [NSString stringWithFormat:@"#JSDTMO#;planSignOut;%@;%@;%@;%@",defUser.userDict[@"id"],self.periodDic[@"userId"],dateString,self.periodDic[@"RO_ID"]];//参数分别是 type 教练Id 学生userID 有效时间 订单ID } //NSLog(@"加密前---><>%@",scanString); scanString = [DES3Util encrypt:scanString]; scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString]; //NSLog(@"加密后--><>%@",scanString); UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f]; qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)]; x = (w - 250)/2.0; y = 20; w = h = 250; scanImgView = [[UIImageView alloc] setxywh]; scanImgView.image = qrcode; [scanView addSubview:scanImgView]; x = 20; if (kSize.width > 350) { x = 40; } w = kSize.width - 2*x; x = 20; y += h + 10; h =30; UILabel *label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"二维码有效时间:10:00"] Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [scanView addSubview:label]; timerLabel = label; UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]]; cancelImg.frame = CGRectMake(w - 25, 5, 20, 20); [scanView addSubview:cancelImg]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(w - 50, 0, 50, 50); btn.backgroundColor = [UIColor clearColor]; [btn addTarget:self action:@selector(removeScanViewAndIsCanTime) forControlEvents:UIControlEventTouchUpInside]; [scanView addSubview:btn]; //倒计时 每隔5秒调服务器 timeI = 600; if (timer) { //如果存在 置为空 [timer invalidate]; timer = nil; } timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES]; } //二维码的验证 -(void)timeRunInShiCao { timeI --; if (timeI%5 == 0) { [self getCoachSignStuRecords]; } timerLabel.text = [NSString stringWithFormat:@"二维码有效时间:%d:%d",timeI/60,timeI%60]; if (timeI == 0) { NSString *textString = @"二维码已过期,请刷新(点击刷新)"; NSString *titleString = @"刷新(点击刷新)"; CGFloat w = [textString sizeForFont:Font16].width; CGFloat x = (kSize.width - w)/2.0; CGFloat y = timerLabel.y; CGFloat h = timerLabel.height; timerLabel.frame = setDIYFrame; [timerLabel setText:textString Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; w = [titleString sizeForFont:Font16].width; x += [textString sizeForFont:Font16].width - w; UIButton *btn = [[UIButton alloc] setxywh]; btn.backgroundColor = [UIColor clearColor]; [btn target:self Tag:7]; [scanView addSubview:btn]; [btn addViewWithRect:CGRectMake(x, y + h -5, w, 1) Color:[UIColor orangeColor]]; //关闭定时器 [timer invalidate]; timer = nil; timeI = 600; } } -(void)removeScanViewAndIsCanTime { //不要立即关闭定时器 做30秒的延迟 if (scanView) { [scanView removeFromSuperview]; scanView = nil; } isAfterDelay = YES; [self performSelector:@selector(closeTimer) withObject:nil afterDelay:30]; } -(void)closeTimer { if (isAfterDelay == YES) { if (timer) { [timer invalidate]; timer = nil; } isAfterDelay = NO; } } -(void)removeScanView { if (timer) { [timer invalidate]; timer = nil; } [scanView removeFromSuperview]; scanView = nil; } - (CIImage *)createQRForString:(NSString *)qrString { NSData *stringData = [qrString dataUsingEncoding:NSUTF8StringEncoding]; // 创建filter CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; // 设置内容和纠错级别 [qrFilter setValue:stringData forKey:@"inputMessage"]; [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"]; // 返回CIImage return qrFilter.outputImage; } - (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size { CGRect extent = CGRectIntegral(image.extent); CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent)); // 创建bitmap; size_t width = CGRectGetWidth(extent) * scale; size_t height = CGRectGetHeight(extent) * scale; CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); CIContext *context = [CIContext contextWithOptions:nil]; CGImageRef bitmapImage = [context createCGImage:image fromRect:extent]; CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone); CGContextScaleCTM(bitmapRef, scale, scale); CGContextDrawImage(bitmapRef, extent, bitmapImage); // 保存bitmap到图片 CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef); UIImage * img = [UIImage imageWithCGImage:scaledImage]; CGImageRelease(scaledImage); CGContextRelease(bitmapRef); CGImageRelease(bitmapImage); CGColorSpaceRelease(cs); return img; } -(UIImage *)addIconToQRCodeImage:(UIImage *)image withIcon:(UIImage *)icon withIconSize:(CGSize)iconSize { UIGraphicsBeginImageContext(image.size); //通过两张图片进行位置和大小的绘制,实现两张图片的合并;其实此原理做法也可以用于多张图片的合并 CGFloat widthOfImage = image.size.width; CGFloat heightOfImage = image.size.height; CGFloat widthOfIcon = iconSize.width; CGFloat heightOfIcon = iconSize.height; [image drawInRect:CGRectMake(0, 0, widthOfImage, heightOfImage)]; [icon drawInRect:CGRectMake((widthOfImage-widthOfIcon)/2, (heightOfImage-heightOfIcon)/2, widthOfIcon, heightOfIcon)]; UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; } #pragma mark scroll & 滑动按钮 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ if (_mainScroll == scrollView) { lastOffset = scrollView.contentOffset; NSInteger pInd = (int)(lastOffset.x / kSize.width); if (pInd == 1) { [self updateData]; } if (pInd == self.pageIndex) { return;//滑动不足切换页面 } self.pageIndex = pInd; } } //分段按钮,和scroll联动 -(void)segSelected:(UIButton*)sender { if (sender.tag == 1) { [self updateData]; } if (sender.tag == self.pageIndex) { return; } self.pageIndex = sender.tag; } -(void)setPageIndex:(NSInteger)pageIndex{ [_segBtnArray[_pageIndex] setSelected:NO]; _pageIndex = pageIndex; [_segBtnArray[_pageIndex] setSelected:YES]; //为了实现循环滚动 [_mainScroll setContentOffset:CGPointMake(kSize.width*pageIndex, _mainScroll.contentOffset.y) animated:NO]; CGSize size = btnBar.frame.size; [UIView animateWithDuration:.2 animations:^{ btnBar.frame = CGRectMake(kSize.width/_segBtnArray.count * _pageIndex + 20, btnBar.frame.origin.y, size.width, size.height); }]; } #pragma mark 蓝牙相关 - (void)searchBlueTooth { isNeed = NO; peripheralArray = [NSMutableArray array]; [self.view addSubview:self.blueTableView]; [_blueTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"peripheralCell"]; //初始化蓝牙 并搜索 [self getCBCmanager]; } - (void)closeBlueTooth { [peripheralArray removeAllObjects]; [_blueTableView reloadData]; [_blueTableView removeFromSuperview]; //断开连接 if (self.peripheral) { [self.cbcManager cancelPeripheralConnection:self.peripheral]; } self.peripheral.delegate = nil; self.peripheral = nil; self.writeCharacteristic = nil; self.readCharacteristic = nil; self.cbcManager = nil; } -(UITableView *)blueTableView { if (!_blueTableView) { _blueTableView = [[UITableView alloc] initWithFrame:CGRectMake(20, 80, kSize.width - 40, kSize.height - 180) style:UITableViewStylePlain]; [_blueTableView borderCornorRadios:5]; _blueTableView.delegate = self; _blueTableView.dataSource = self; UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSize.width - 40, 40)]; UILabel *header = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, kSize.width - 40, 40)]; [header setText:@"请选择带教车辆OBD" Font:Font17 TextColor:subTitleColor Alignment:NSTextAlignmentCenter]; [headerView addSubview:header]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(kSize.width - 40 - 50, 0, 50, 40)]; [btn setTitle:@"取消" textColor:kTitleColor font:Font17 fotState:UIControlStateNormal]; [btn target:self Tag:9]; [headerView addSubview:btn]; [_blueTableView setTableHeaderView:headerView]; } return _blueTableView; } //建立一个Central Manager实例进行蓝牙管理 -(CBCentralManager *)getCBCmanager { if (!_cbcManager) { _cbcManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; } return _cbcManager; } //只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态 - (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"); break; case 4: { //蓝牙未开启 NSLog(@"CBCentralManagerStatePoweredOff"); ShowMsg(@"请打开手机蓝牙"); [Tools playAudioWithString:@"请打开手机蓝牙"]; } break; case 5: { //蓝牙已开启 NSLog(@"CBCentralManagerStatePoweredOn"); // 搜索外设 [self.cbcManager scanForPeripheralsWithServices:nil // 通过某些服务筛选外设 options:nil]; // dict,条件 // 搜索成功之后,会调用找到外设的代理方法 } break; default: break; } } // 发现外设后调用的方法 - (void)centralManager:(CBCentralManager *)central // 中心管理者 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设 advertisementData:(NSDictionary *)advertisementData // 外设携带的数据 RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度 { //F1C38B70-C866-4E3E-8F1B-AE382E1DB151 NSLog(@"%@<<-->>%@",peripheral,advertisementData); if (![peripheralArray containsObject:peripheral]) { [peripheralArray addObject:peripheral]; [_blueTableView reloadData]; } } // 中心管理者连接外设成功 - (void)centralManager:(CBCentralManager *)central // 中心管理者 didConnectPeripheral:(CBPeripheral *)peripheral // 外设 { //将教练选中OBD的名字发给学员端 peripheralName = peripheral.name; // 连接成功之后,可以进行服务和特征的发现 // 设置外设的代理 self.peripheral.delegate = self; // 外设发现服务,传nil代表不过滤 [self.peripheral discoverServices:nil]; if (!isJudgeCarUUID) { [Tools playAudioWithString:@"车宰蓝牙连接成功,允许带教!"]; } } // 外设连接失败 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name); //ShowMsg(@"蓝牙连接失败!请重试"); if (self.cbcManager && self.peripheral) { [self.cbcManager connectPeripheral:self.peripheral options:nil]; } } // 丢失连接 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name); // if (self.cbcManager && self.peripheral) { // [self.cbcManager connectPeripheral:self.peripheral options:nil]; // } } //查找服务的所有特征 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { if (error) { NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]); return; } //服务并不是我们的目标,也没有实际意义。我们需要用的是服务下的特征,查询(每一个服务下的若干)特征 for (CBService *service in peripheral.services) { [peripheral discoverCharacteristics:nil forService:service]; } } // 发现外设服务里的特征的时候调用的代理方法(这个是比较重要的方法,你在这里可以通过事先知道UUID找到你需要的特征,订阅特征,或者这里写入数据给特征也可以) - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { for (CBCharacteristic *cha in service.characteristics) { if ([cha.UUID isEqual:[CBUUID UUIDWithString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]]) { NSLog(@"读取特征-->>>%@",cha); self.readCharacteristic = cha; // [peripheral readValueForCharacteristic:cha]; [peripheral setNotifyValue:YES forCharacteristic:cha]; } if ([cha.UUID isEqual:[CBUUID UUIDWithString:@"6E400002-B5A3-F393-E0A9-E50E24DCCA9E"]]) { NSLog(@"写入特征-->>>%@",cha); self.writeCharacteristic = cha; } } } //- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { // // if (error) { // NSLog(@"Error changing notification state: %@", error.localizedDescription); // //[peripheral setNotifyValue:YES forCharacteristic:self.readCharacteristic]; // } // // if (characteristic.isNotifying) { // [peripheral readValueForCharacteristic:characteristic]; // // } else { // Notification has stopped // // so disconnect from the peripheral // NSLog(@"Notification stopped on %@. Disconnecting", characteristic); // // } // //} // 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if ([characteristic isEqual:self.readCharacteristic] ) { NSString *hexString = [self convertDataToHexStr:characteristic.value]; // if (![hexString containsString:@"be05011234"] && ![hexString isEqualToString:@"914e"]) { // NSLog(@"%s, ----><>%@--->%@----><>%@", __FUNCTION__,characteristic.value,characteristic.UUID,hexString); // } //数据完整性检测 if ([hexString containsString:@"be"]) { //数据首包 lastData = [[hexString componentsSeparatedByString:@"be"] lastObject]; int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]]; if (lastData.length < dataLength*2 + 2) { isNeed = YES; return; } }else { if (isNeed) {//上个包数据不够 hexString = [lastData stringByAppendingString:hexString]; lastData = hexString; int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]]; if (lastData.length < dataLength*2 + 2) { return; }else { isNeed = NO; hexString = [@"dsbe" stringByAppendingString:hexString]; } } } NSLog(@"检测完数据的完整性----><>%@",hexString); // 心跳包验证 if ([hexString containsString:@"be0501"]) {//心跳包命令 执行验证然后回复 //得到数据 hexString = [[hexString componentsSeparatedByString:@"be0501"] lastObject]; if (hexString.length > 8) { hexString = [hexString substringToIndex:8]; } //计算数据 hexString = [self getResultWithHexString:hexString]; if (hexString.length < 14) { NSString *OString = @"0000"; hexString = [OString stringByAppendingString:hexString]; } //验证数据 hexString = [NSString stringWithFormat:@"be0381%@",[hexString substringFromIndex:hexString.length - 4]]; [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:hexString]]; //判断是否判断车架号 if (isJudgeCarUUID) { if (carUUID.length < 1) { [self performSelector:@selector(writeOrder) withObject:nil afterDelay:1]; } }else { //继续走计时流程 [self enterMakeScanView]; } return; } if ([hexString containsString:@"be"]) { hexString = [[hexString componentsSeparatedByString:@"be"] lastObject]; NSLog(@"车架号-----><>%@",hexString); //获取有效字节长度 - 标示长度的字节 int stringLength = [self getHexNumWithString:[hexString substringToIndex:2]] - 1; //解析后需要的数据 要将16进制asc转化成我们能看的字符串 hexString = [self convertHexStrToString:[hexString substringWithRange:NSMakeRange(2, stringLength*2)]]; //教练端只获取车架号 so NSString *uuid = [NSString stringWithFormat:@"%@",hexString]; carUUID = uuid; //服务器保存的车架号 //defUser.userDict[@"franum"]; 服务器返回的车架号 NSString *caruuid = @"1G1JC5444R725236"; if ([carUUID containsString:caruuid]) { //车架号一致 继续走计时流程 carUUID = @""; [Tools playAudioWithString:@"车宰蓝牙连接成功,允许带教!"]; [self enterMakeScanView]; }else { //教练选择车辆车架号与服务器纪录数据不符 不能带教 carUUID = @""; ShowMsg(@"车宰蓝牙与账号不匹配,请重新选择车宰蓝牙"); [Tools playAudioWithString:@"车宰蓝牙与账号不匹配,请重新选择车宰蓝牙"]; [_cbcManager cancelPeripheralConnection:self.peripheral]; } return; } } } - (void)writeOrder { [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:@"BE0183"]]; } //写数据 -(void)writeCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic value:(NSData *)value { [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse]; //只有 characteristic.properties 有write的权限才可以写 // if(characteristic.properties & CBCharacteristicPropertyWrite){ // /* // 最好一个type参数可以为CBCharacteristicWriteWithoutResponse或type:CBCharacteristicWriteWithResponse,区别是是否会有反馈 // */ // [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse]; // }else{ // NSLog(@"该特征不可写!"); // } } // 需要注意的是特征的属性是否支持写数据 - (void)yf_peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)data forCharacteristic:(nonnull CBCharacteristic *)characteristic { NSLog(@"写入特征值-->%@",data); /* 打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值 常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式 */ // 此时由于枚举属性是NS_OPTIONS,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含& } #pragma mark 16进制与NSData之间的转化 及验证算法计算 //data转换为16进制 - (NSString *)convertDataToHexStr:(NSData *)data { if (!data || [data length] == 0) { return @""; } NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]]; [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) { unsigned char *dataBytes = (unsigned char*)bytes; for (NSInteger i = 0; i < byteRange.length; i++) { NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff]; if ([hexStr length] == 2) { [string appendString:hexStr]; } else { [string appendFormat:@"0%@", hexStr]; } } }]; return string; } //16进制转换为data - (NSData *)convertHexStrToData:(NSString *)str { if (!str || [str length] == 0) { return nil; } NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8]; NSRange range; if ([str length] % 2 == 0) { range = NSMakeRange(0, 2); } else { range = NSMakeRange(0, 1); } for (NSInteger i = range.location; i < [str length]; i += 2) { unsigned int anInt; NSString *hexCharStr = [str substringWithRange:range]; NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr]; [scanner scanHexInt:&anInt]; NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1]; [hexData appendData:entity]; range.location += range.length; range.length = 2; } return hexData; } - (NSString *)getResultWithHexString:(NSString *)hexString { if (hexString.length < 8) { NSLog(@"验证算法输入数据错误"); return @"erroe"; } int x = [self getHexNumWithString:[hexString substringToIndex:4]]; int y = [self getHexNumWithString:[hexString substringFromIndex:4]]; int z = 0x1323; hexString = [NSString stringWithFormat:@"%x",(x*z+y)^z]; // NSLog(@"%d,%d,%d,%x,%x,%x<---->%@",x,y,z,x,y,z,hexString); return hexString; } /** 将原本是16进制数字的字符串转换成计算机可以识别的int型10进制数据 */ - (int)getHexNumWithString:(NSString *)string { int number = 0; for (int i = 0; i < string.length; i ++) { NSString *letterOrNumber = [string substringWithRange:NSMakeRange(string.length - i - 1, 1)]; int a = 0; if ([letterOrNumber isEqualToString:@"a"] || [letterOrNumber isEqualToString:@"A"]) { a = 10; }else if ([letterOrNumber isEqualToString:@"b"] || [letterOrNumber isEqualToString:@"B"]){ a = 11; }else if ([letterOrNumber isEqualToString:@"c"] || [letterOrNumber isEqualToString:@"C"]){ a = 12; }else if ([letterOrNumber isEqualToString:@"d"] || [letterOrNumber isEqualToString:@"D"]){ a = 13; }else if ([letterOrNumber isEqualToString:@"e"] || [letterOrNumber isEqualToString:@"E"]){ a = 14; }else if ([letterOrNumber isEqualToString:@"f"] || [letterOrNumber isEqualToString:@"F"]){ a = 15; }else { a = [letterOrNumber intValue]; } a = a * pow(16, i); number += a; } return number; } //将十六进制的字符串转换成NSString则可使用如下方式 - (NSString *)convertHexStrToString:(NSString *)str { if (!str || [str length] == 0) { return nil; } NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8]; NSRange range; if ([str length] % 2 == 0) { range = NSMakeRange(0, 2); } else { range = NSMakeRange(0, 1); } for (NSInteger i = range.location; i < [str length]; i += 2) { unsigned int anInt; NSString *hexCharStr = [str substringWithRange:range]; NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr]; [scanner scanHexInt:&anInt]; NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1]; [hexData appendData:entity]; range.location += range.length; range.length = 2; } NSString *string = [[NSString alloc]initWithData:hexData encoding:NSUTF8StringEncoding]; return string; } //将NSString转换成十六进制的字符串则可使用如下方式 + (NSString *)convertStringToHexStr:(NSString *)str { if (!str || [str length] == 0) { return @""; } NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]]; [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) { unsigned char *dataBytes = (unsigned char*)bytes; for (NSInteger i = 0; i < byteRange.length; i++) { NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff]; if ([hexStr length] == 2) { [string appendString:hexStr]; } else { [string appendFormat:@"0%@", hexStr]; } } }]; return string; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end