12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453 |
- //
- // MNQtTrainVC.m
- // jiaPei
- //
- // Created by EchoShacolee on 2018/4/3.
- // Copyright © 2018年 JCZ. All rights reserved.
- //
- /*
- 首次连接流程:app搜索到外设 连接发送指令kGetMNdevVersion获取终端版本。判断是否需要升级。
- 升级完成/不需要升级 app发送请求kGetDevNumAndStuCardOrder获取终端序列号,
- ---看UI吧。那就是整个流程
- 然后 过程人脸验证会根据 登录返回的 mnqFacePorcess 判断是否开启,
- */
- #import "MNQtTrainVC.h"
- #import "ScanVC.h"
- #import <CoreBluetooth/CoreBluetooth.h>
- #import <BaiduMapAPI_Utils/BMKUtilsComponent.h>//bd计算相关
- #import "DES3Util.h"
- #import "MNQDev.h"
- #import <AFHTTPSessionManager.h>
- #import "PrecautionsView.h"
- #import "StepImageView.h"
- #define BLE_SEND_MAX_LEN 20
- #define BLE_SEND_PER_LEN 0x0384 //900(0x0384)==图片
- static NSString * const mnTableName = @"mnPeriod";
- static NSString * const kServiceUUID = @"6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
- static NSString * const kCharacteristicUUID_write = @"6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
- static NSString * const kCharacteristicUUID_reade = @"6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
- static NSString * const kGetDevNumAndStuCardOrder = @"be000383eded";
- static NSString * const kTakePhotoOrder = @"be000384eded";
- static NSString * const kGetPhotoData = @"be000497";
- static NSString * const kGetMNdevVersion = @"be00038aeded";
- @interface MNQtTrainVC ()<CBCentralManagerDelegate,CBPeripheralDelegate,CLLocationManagerDelegate,UITableViewDelegate,UITableViewDataSource,UIAlertViewDelegate>
- {
- NSDateFormatter *dateFormatter;
- NSMutableDictionary *minuteTrainDic;//分钟学时用参数 签到和断线重连时候初始化 分钟学时发送之前更新字典
- NSMutableDictionary *gatherTrainDic;//汇总学时用参数 签到和断线重连时候初始化 分钟学时发送之前更新字典 并存本地 短线重连用来恢复计时
- NSTimer *timer;//学时计时器(它的存在可以且已经有用于判断是否在计时中)
- NSInteger seconds;//学时计数
- MNQDev *mnqDev;//模拟器
-
- //过程验证
- BOOL onProcessVerification;//是否正在过程验证
- NSInteger processVerificationTime;//过程验证时间 == 0 未开启, >0 开启需要验证
- NSInteger processVerificationMaxCount;//允许失败次数 自己yy了一下==0不限制,服务器应该不会返回0吧 目前设置的是3次 超过三次就app发起签退
- NSInteger processVerificationFailureCount;//失败次数
- NSInteger photoSeconds;//拍照时间
-
- //学时相关
- NSString *subject; //当前训练科目
- NSString *classId; //课堂ID
- NSString *classCode; //课程编码
- NSString *trainNum; //学时编号
- NSString *trainOrderNum;//学时编号用序列 每天置0
- NSArray *minuteTrainArray;//分钟学时数组 用于汇总学时时候 获取本地库未上传的分钟学时
- NSMutableArray<NSString *> *dataSourceArray; //表的数据源 组成部分:颜色数字+提示字 1为红色失败 2为绿色成功
-
- //地图定位
- CLLocationCoordinate2D myCoordinate;//定位我的位置
- CLLocationManager *locationManager;//系统gps
-
-
- //蓝牙相关
- NSTimer *signInTimer;//发起拍照命令等待计时器
- NSString *peripheralName;//蓝牙名称
- BOOL isConnectBlueTooth;//是否与蓝牙连接状态
- NSInteger disconnectSeconds;//蓝牙断开的时长
-
- //蓝牙每一包
- NSString *blueToothOrder;//最新的蓝牙命令 用于蓝牙未回应重新作操作
- BOOL dataIsLack;//如果为yes代表数据不完整 需要下次接收到的数据拼接
- NSInteger lackVertifyTime;//蓝牙数据分次返回等待时间,超过5s重新发送命令
- NSString *lastData;//接收蓝牙数据时 一个数据包分次返回时 之前的数据
- //组合拳限制命令重复请求 不过只有照片的时候用到了。计时器1拍照启动 计时器2开始计时启动(以后不再有重要蓝牙命令)
- NSString *blueToothOrder_old;//记录旧的蓝牙命令,为reOrderCount服务
- NSInteger reOrderCount;//蓝牙重新请求的次数 如果大于三次 不继续请求 接收到回应就重置 防治无限请求蓝牙
-
- //图片相关
- NSString *imageData;//图片数据
- NSInteger imgLongth;//图片的总长度 或者每个包的长度
-
- //升级包data
- NSString *nowVersion;
- NSString *packgeHexStr;//模拟设备升级包
-
-
- //UI
- UIScrollView *mainScrView;
- NSMutableArray *detailLabArr; //学时信息表格lab
- UILabel *timeLabel; //计时lable
- NSString *logs; //训练日志
- NSArray *stepTitlesArr; //步骤内容数组
-
- //保留(未使用)
- UIView *trainView; //计时状态学时展示部分相关view
- UITableView *mainTableView; //trainview addsubview maintableview
- MBProgressHUD *openBlueToothMbp;
-
- }
- //蓝牙
- @property (nonatomic, strong) CBCentralManager *cbcManager;
- /** 已连接的外设*/
- @property (nonatomic, strong) CBPeripheral *peripheral;
- /** 要写入的特征值*/
- @property (nonatomic, strong) CBCharacteristic *writeCharacteristic;
- /** 要读的特征值*/
- @property (nonatomic, strong) CBCharacteristic *readCharacteristic;
- //当前步骤
- @property(nonatomic,assign)StepImageView *currentStep;
- @property(nonatomic,strong)NSArray *stepsArr;
- @property(nonatomic,strong)NSArray *arrowArr;
- @property (nonatomic, strong) UIImageView *photoImg;
- //UI
- @property (strong, nonatomic) UILabel *statusLab;
- @property (strong, nonatomic) UIView *trainMessageView;
- @property (strong, nonatomic) StepImageView *step1;//设备连接
- @property (strong, nonatomic) StepImageView *step2;//模拟设备升级
- @property (strong, nonatomic) StepImageView *step3;//身份/设备信息验证
- @property (strong, nonatomic) StepImageView *step4;//人脸比对
- @property (strong, nonatomic) StepImageView *step5;//训练计时中
- @property (strong, nonatomic) StepImageView *step6;//签退
- @end
- @implementation MNQtTrainVC
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- self.title = @"模拟计时";
- self.view.backgroundColor = backGroundColor;
- dateFormatter = [NSDateFormatter rq_defaultDateFormatter];
- isConnectBlueTooth = NO;
- dataSourceArray = [NSMutableArray array];
- logs = @"";
- seconds = 0;
- onProcessVerification = NO;
-
- processVerificationTime = [[NSString stringWithFormat:@"%@",defUser.userDict[@"mnqFacePorcess"]] integerValue];
- processVerificationMaxCount = [[NSString stringWithFormat:@"%@",defUser.userDict[@"mnqFaceCount"]] integerValue];
-
- //测试用
- // processVerificationTime = 2;
- // processVerificationMaxCount = 2;
-
- //初始化gatherTrainDic(这一步可以拿到状态接口返回并存储的claaid等课时相关信息)
- [self getGatherTrainDic];
- //UI
- [self myInit];
- [self customTrainMessageView];//创建学时记录“表”
- [self reloadDetailLab];//教学信息更新(这个其实可以考虑放在goonTrain和beginTime)
- //开启定位(设置允许后台定位)
- [self setGPSLocationService];
- //根据mn状态,下一步
- [self nextWithCurrentStatu:[myDelegate.mnTrainType integerValue]];
-
- }
- -(void)viewDidAppear:(BOOL)animated{
- [super viewDidAppear:animated];
-
- }
- -(void)viewDidDisappear:(BOOL)animated{
- [super viewDidDisappear:animated];
- if (signInTimer.isValid) {
- [signInTimer invalidate];
- signInTimer = nil;
- }
- if (timer == nil) {
- [locationManager stopUpdatingLocation];
- [self closeBlueTooth];
- }
-
- }
- - (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- #pragma mark - 设置步骤
- //1-6
- - (void)setCurrentStep:(StepImageView *)currentStep
- {
-
- if (_currentStep == currentStep) {
- return;
- }
- _currentStep = currentStep;
-
- NSInteger index = [_stepsArr indexOfObject:currentStep];
-
- //箭头
- if (currentStep != _step6) {
- UIButton *currentArrow = _arrowArr[index];
- for (UIButton *arrow in _arrowArr) {
- if (arrow == currentArrow) {
- arrow.selected = YES;
- }else{
- arrow.selected = NO;
- }
- }
- }
-
- //step
- //训练中蓝牙断开
- if (_currentStep == _step1 && timer) {
- _step1.status = ClickStatusMid;
- _step2.status = ClickStatusHaveDone;
- _step3.status = ClickStatusHaveDone;
- _step4.status = ClickStatusHaveDone;
- _step5.status = ClickStatuseNormal;
- _step6.status = ClickStatusHighlighted;
- return;
- }
-
- for (StepImageView *step in _stepsArr) {
- if (step == _currentStep) {
- step.status = ClickStatusMid;
- if (step == _step5) {
- _step6.status = ClickStatusHighlighted;
- }
- break;
- }else{
- step.status = ClickStatusHaveDone;
- }
- }
- }
- #pragma mark -添加日志记录
- -(void)addLogsWithConten:(NSString *)content status:(NSInteger)status{
-
- NSString *statusStr = @"";
- switch (status) {
- case 0:
- statusStr = @"失败";
- break;
- case 1:
- statusStr = @"中...";
- break;
- case 2:
- statusStr = @"成功";
- break;
- default:
-
- break;
- }
-
- [dateFormatter setDateFormat:@"HH:mm:ss "];
- NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
- // NSString *logStr = [NSString stringWithFormat:@"%@: %@%@\n",dateString,content,statusStr];
- // logs = [logs stringByAppendingString:logStr];
- //这里和安卓的不一样 iOS日志统计的状态栏显示的东西
- if (status == 4396) {
- logs = [logs stringByAppendingString:[NSString stringWithFormat:@"%@: %@\n",dateString,content]];
- }
- return;
- }
- #pragma mark -UI
- -(void)myInit{
-
- [self customNavigationBar];
-
- UIScrollView *sv = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, kSize.width, kSize.height-kNavOffSet-kSafeAreaBottomHeight)];
- mainScrView = sv;
- sv.backgroundColor = backGroundColor;
- [self.view addSubview:sv];
-
- CGFloat x,y,w,h;
- x = y = 0;
- w = kSize.width;
- h = 56;
- UIView *view = [[UIView alloc]setxywh];
- view.backgroundColor = [UIColor whiteColor];
- [sv addSubview:view];
-
- x = 5;
- h = 36;
- y = 10;
- w = 40;
- UILabel *lab = [[UILabel alloc]setxywh];
- [lab setText:@"状态:" Font:Font17 TextColor:kTitleColor];
- [view addSubview:lab];
-
- x += w;
- w = kSize.width - x - 90;
- lab = [[UILabel alloc]setxywh];
- _statusLab = lab;
- [lab setText:@"" Font:Font17 TextColor:subTitleColor];
- [view addSubview:lab];
-
- x = kSize.width - 75;
- w = 70;
- 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:16 fotState:UIControlStateNormal];
- [checkMinRecordBtn addTarget:self action:@selector(checkLogs:) forControlEvents:UIControlEventTouchUpInside];
- checkMinRecordBtn.backgroundColor = defGreen;
- [view addSubview:checkMinRecordBtn];
-
- x = 5;
- y = CGRectGetMaxY(view.frame) + 10;
- w = kSize.width - 10;
- h = w * 70/300;
- view = [[UIView alloc]setxywh];
- _trainMessageView = view;
- view.backgroundColor = [UIColor whiteColor];
- [sv addSubview:view];
- [self customTrainMessageView];
-
- //
- x = 5;
- y = CGRectGetMaxY(view.frame) + 10;
- w = kSize.width-10;
- h = kSize.width+50;
- view = [[UIView alloc]setxywh];
- view.backgroundColor = [UIColor whiteColor];
- [sv addSubview:view];
- [self customStepsWithView:(UIView *)view];
-
- sv.contentSize = CGSizeMake(0, y+h);
- }
- -(void)customTrainMessageView
- {
- CGFloat w = (_trainMessageView.width)/4;
- CGFloat h = _trainMessageView.height*0.4;
- CGFloat lineW = 1;
- NSArray *titles = @[@"所需学时",@"已完成学时",@"剩余学时",@"当天学时"];
- detailLabArr = [NSMutableArray new];
- for (int i=0; i<2; i++) {
- for (int j=0; j<4; j++) {
-
- UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(j%4*w, h/4+i*h, w, h)];
- lab.adjustsFontSizeToFitWidth = YES;
- lab.textAlignment = NSTextAlignmentCenter;
- [self.trainMessageView addSubview:lab];
- if (i==0) {
- lab.text = titles[j];
- lab.textColor = subTitleColor;
- }else{
- lab.textColor = kTitleColor;
- if (j==3) {
- timeLabel = lab;
- }else{
- [detailLabArr addObject:lab];
- }
- }
-
- //line
- //垂直
- if (j != 0) {
- UIView *lineVer = [[UIView alloc]initWithFrame:CGRectMake(w*j, h/2, lineW, h*1.5)];
- lineVer.backgroundColor = KlineColor;
- [self.trainMessageView addSubview:lineVer];
- }
-
- }
- }
- }
- - (IBAction)checkLogs:(id)sender {
- [PrecautionsView showPrecautionsViewWithContent:logs];
- }
- -(void)checkPrecautions
- {
- [PrecautionsView showPrecautionsViewWithContent:@"注意:\n\n1.训练过程中,请保持蓝牙连接,蓝牙断开计时会停止。\n\n2.学员中途短暂离开无须签退;当学员再次回到模拟设备附近计时会自动恢复。若没有收到计时恢复语音提示,请前往“模拟计时”确认计时是否恢复。\n\n3.允许app切换到后台运行,允许手机黑屏,不允许关闭app。(需要设置\"始终允许访问位置\",如果选择仅在\"使用应用期间\"访问位置,则不能在后台计时。查看方式:系统设置-优易学车-位置)\n\n4.部分手机或因内存不足,在app后台运行的时候被手机系统关闭,计时停止。(如果遇到这种情况,请学员关闭其它部分app,保持“优易学车”在前台运行)\n\n5.部分地区根据规定需要进行过程验证的,请在收到过程验证通知后(app停止计时),前往模拟计时点击人脸验证,通过后将恢复计时 \n\n6.图标说明:\n浅灰色--未执行,不可操作;\n深灰色--已执行,不可操作;\n正蓝色--执行中,不可操作;\n正绿色--执行失败或未执行,可操作;\n(注:仅绿色表示可以被选中执行该步骤,其它颜色不能被选中)\n\n祝您体验愉快"];
- }
- -(void)customStepsWithView:(UIView *)view{
-
- NSArray *imgs = @[@"2_mn",@"1_mn",@"3_mn",@"4_mn",@"5_mn",@"6_mn"];
- NSArray *titles = @[@"设备连接",@"终端升级",@"身份认证",@"人脸验证",@"训练过程",@"学员签退"];
- stepTitlesArr = titles;
- NSArray *arrowImgs = @[@"mn_right",@"mn_down",@"mn_left",@"mn_down",@"mn_right"];
-
- CGFloat wid = kSize.width/3;
- CGFloat bd = kSize.width/3/3;
-
- NSMutableArray *tmpArr = [NSMutableArray new];
- NSMutableArray *jiantouArr = [NSMutableArray new];
- for (int i=0; i<6; i++) {
- CGRect frame = CGRectMake(bd+(wid+bd)*(i%2), 0+(wid+0)*(i/2), wid, wid);
- if (i==2 || i==3) {
- frame.origin.x = bd+(wid+bd)*((i+1)%2);
- }
- //步骤
- StepImageView *step = [[StepImageView alloc]initWithFrame:frame image:imgs[i] title:titles[i]];
- [view addSubview:step];
- [tmpArr addObject:step];
-
- //箭头
- if (i==5) {
- continue;
- }
- UIButton *jiantou = [UIButton buttonWithType:UIButtonTypeCustom];
- jiantou.userInteractionEnabled = NO;
- jiantou.frame = CGRectMake(0, 0, 20, 20);
- if (i==1 || i==3) {
- jiantou.center = CGPointMake(step.center.x, CGRectGetMaxY(step.frame)+wid/8);
- }else{
- jiantou.center = CGPointMake(kSize.width/2, step.y+step.height/2);
- }
- UIImage *normalImg = [[UIImage imageNamed:arrowImgs[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
- [jiantou setImage:normalImg forState:UIControlStateNormal];
- UIImage *sleImg = [[UIImage imageNamed:[NSString stringWithFormat:@"%@_H",arrowImgs[i]]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
- [jiantou setImage:sleImg forState:UIControlStateSelected];
-
- [view addSubview:jiantou];
- [jiantouArr addObject:jiantou];
- }
-
- _arrowArr = [NSArray arrayWithArray:jiantouArr];
- _stepsArr = [NSArray arrayWithArray:tmpArr];
- _step1 = _stepsArr[0];
- _step2 = _stepsArr[1];
- _step3 = _stepsArr[2];
- _step4 = _stepsArr[3];
- _step5 = _stepsArr[4];
- _step6 = _stepsArr[5];
-
- __weak typeof(self)weakSelf = self;
- _step1.clickBlock = ^{
- NSLog(@"clickStep1");
- weakSelf.step1.status = ClickStatusHighlighted;
- if([myDelegate.mnTrainType isEqualToString:@"2"]){
- [weakSelf getBlueToothAndDevOrder];
- }else if ([myDelegate.mnTrainType isEqualToString:@"0"]) {//正在计时
- if (weakSelf.cbcManager && weakSelf.peripheral) {
- [weakSelf.cbcManager connectPeripheral:weakSelf.peripheral options:nil];
- }
- }
- };
-
- _step2.clickBlock = ^{
- NSLog(@"clickStep2");
- [weakSelf UpdateMNDev];
- };
-
- _step3.clickBlock = ^{
- NSLog(@"clickStep3");
- blueToothOrder = kGetDevNumAndStuCardOrder;
- [weakSelf sendBlueToothOrder];
- };
-
- _step4.clickBlock = ^{
- NSLog(@"clickStep4");
- [weakSelf takePhotoByBlueTooth];
- };
-
- _step5.clickBlock = ^{
- NSLog(@"clickStep5");
- };
-
- _step6.clickBlock = ^{
- NSLog(@"clickStep6");
- [weakSelf wantSignOut];
- };
- }
- -(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;
-
- //注意事项
- backBbi = [[UIBarButtonItem alloc] initWithTitle:@"注意事项" style:UIBarButtonItemStylePlain target:self action:@selector(checkPrecautions)];
- [backBbi setTintColor:defGreen];
- [self.navigationItem setRightBarButtonItem:backBbi];
- self.navigationController.navigationBar.translucent = NO;
- }
- -(void)goBackByNavigation{
- if (self.navigationController.presentingViewController) {
- [self.navigationController dismissViewControllerAnimated:YES completion:nil];
- }else{
- [self.navigationController popViewControllerAnimated:YES];
- }
- }
- #pragma mark - UI更新
- -(void)reloadDetailLab{
- //更新UI展示内容
- if (gatherTrainDic[@"subject"]) {
- subject = gatherTrainDic[@"subject"];
- self.navigationItem.title = [NSString stringWithFormat:@"科目%@模拟计时",[subject isEqualToString:@"2"]?@"二":@"三"];
- }
- seconds = [gatherTrainDic[@"allTime"] integerValue];
- timeLabel.text = @"00:00:00";
- if (seconds != 0) {
- [self upDateTime];
- }
-
- int i=0;
- for (UILabel * detailLab in detailLabArr) {
- switch (i) {
- case 0:
- detailLab.text = [self getTimeByMinString:gatherTrainDic[@"allNeed"]];
- break;
- case 1:
- detailLab.text = [self getTimeByMinString:gatherTrainDic[@"allCompelet"]];
- break;
- case 2:
- {
- NSInteger allComplete = [gatherTrainDic[@"allCompelet"] integerValue];
- NSInteger allNeed = [gatherTrainDic[@"allNeed"] integerValue];
- if (allNeed - allComplete > 0) {
- detailLab.text = [self getTimeByMinString:[NSString stringWithFormat:@"%ld",allNeed - allComplete]];
- }else{
- detailLab.text = @"0分";
- }
- }
- break;
-
- default:
- break;
- }
- i++;
- }
- }
- -(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];
- }
- //更新UI上的时间
- -(void)upDateTime{
-
- int hour = (int)seconds / 3600;
- int min = (int)seconds % 3600 / 60;
- int second = (int)seconds % 3600 % 60;
- NSString *min_s;
- NSString *second_s;
- if (min<10) {
- min_s=[NSString stringWithFormat:@"0%d",min];
- }else{
- min_s=[NSString stringWithFormat:@"%d",min];
- }
- if (second<10) {
- second_s=[NSString stringWithFormat:@"0%d",second];
- }else{
- second_s=[NSString stringWithFormat:@"%d",second];
- }
- timeLabel.text = [NSString stringWithFormat:@"0%d:%@:%@",hour,min_s,second_s];
- }
- /**
- 本方法会播放语音/本地通知提示,更新状态栏,新增日志记录
- @param string 提示/日志/状态内容
- @param audioStr 如果为nil则处于后台不添加本地通知
- */
- - (void)addBlueToothLabelWithContent:(NSString *)string mp3:(NSString *)audioStr{
- [self addLogsWithConten:string status:4396];
- _statusLab.text = string;
- if(audioStr){
- if (myDelegate.isBackgroundTask) {
- [self addLocalNotificationWithAudio:audioStr];
- }else {
- string = [string stringByReplacingOccurrencesOfString:@"重" withString:@"虫"];
- [Tools playAudioWithString:string];
- }
- }
- }
- #pragma mark - start
- - (void)nextWithCurrentStatu:(NSInteger )statu{
-
- self.currentStep = _step1;
-
- /*
- Type 定义 0 成功获取学员信息
- 1 学员还未在模拟器签到(这种状态是不允许进入当前VC的)
- 2.已在模拟设备登录 未进行人脸比对
- 3 无法获取到当前训练科目 (先选科目以后,不存在该状态。科目会在签到(人脸验证)的时候提交)
- 4 隔日签到记录
- 5 分钟学时科目异常
- */
-
- //已登录但未进行人脸比对签到
- if (statu == 2) {
- NSString *kemu = gatherTrainDic[@"subject"];
- if (kemu && kemu.length != 0) {
- //获取蓝牙名/序列号
- [self getBlueToothAndDevOrder];
- }else{
- [self slelectTrainSubject];
- return;
- }
-
- return;
- }
- //成功获取学员信息
- if (statu == 0) {
- classId = gatherTrainDic[@"classId"];
- classCode = gatherTrainDic[@"classCode"];
- //训练中,恢复计时
- [self goonTrain];
- return;
- }
-
- //隔日训练
- if (statu == 4) {
- _step6.status = ClickStatusMid;
- //查看是否存在本地学时
- minuteTrainArray = [DB_Helper quearyTrainWithClassId:gatherTrainDic[@"classId"] type:mnTableName];
- if (minuteTrainArray.count > 0) {
- [self uploadAppTrainPlWithSignOut:YES];
- }else{
- [gatherTrainDic setValue:@"2" forKey:@"isOver"];
- classId = gatherTrainDic[@"classId"];
- classCode = gatherTrainDic[@"classCode"];
- minuteTrainArray = [DB_Helper quearyTrainWithClassId:gatherTrainDic[@"classId"] type:mnTableName];
- if (minuteTrainArray.count > 0) {
- [self uploadAppTrainPlWithSignOut:YES];
- }else{
- [self signOut];
- }
- }
- return;
- }
-
-
- //以下两种状态(1,3)此处无需判断
- //学员还未在模拟器签到(这种状态是不允许进入当前VC的,可以无视)
- // if(statu == 1){
- //
- // UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:@"提醒" message:@"当前暂未检测到PC端已登录信息;如需计时,请扫描PC端登录二维码完成登录" preferredStyle:UIAlertControllerStyleAlert];
- //
- // [alertFind addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
- // [self goBackByNavigation];
- // }]];
- // [alertFind addAction:[UIAlertAction actionWithTitle:@"扫码登录" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- //
- // [self openScan];
- // }]];
- // [alertFind addAction:[UIAlertAction actionWithTitle:@"PC端已登录" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- //
- // [self getCurrentState];打开的时候考虑一下获取状态后的操作
- // }]];
- //
- // [self presentViewController:alertFind animated:true completion:nil];
- //
- // return;
- // }
-
- if (statu == 5) {
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:@"分钟学时科目异常" preferredStyle:UIAlertControllerStyleAlert];
- [alertFind addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
- [self goBackByNavigation];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- return;
- }
-
- if (statu == 3) {
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:@"无法获取到当前训练科目" preferredStyle:UIAlertControllerStyleAlert];
- [alertFind addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
- [self goBackByNavigation];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- return;
- }
- }
- #pragma mark 蓝牙相关
- - (void)searchBlueTooth {
-
- dataIsLack = NO;
- lastData = @"";
- blueToothOrder = @"";
- reOrderCount = 0;
-
- if ([myDelegate.mnTrainType isEqualToString: @"0"]) {//说明是断线重连
- minuteTrainDic = [NSMutableDictionary dictionary];
- [minuteTrainDic setValue:gatherTrainDic[@"classId"] forKey:@"classId"];
- [minuteTrainDic setValue:gatherTrainDic[@"classCode"] forKey:@"classCode"];
- [minuteTrainDic setValue:gatherTrainDic[@"trainNum"] forKey:@"trainNum"];
-
- trainNum = gatherTrainDic[@"trainNum"];
- photoSeconds = [gatherTrainDic[@"photoTime"] integerValue];
- timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];//处理UI交互阻塞计时
- myDelegate.mnPeriodVC = self;
- // [self addBlueToothLabelWithContent:@"断线重连成功,已恢复训练" mp3:nil];
- // [Tools playAudioWithString:@"断线虫连成功,已恢复训练"];
- disconnectSeconds = 4;//替换上面的提醒zzz
- }
-
- 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");
- {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"请在“设置”中打开蓝牙访问权限" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
- [alert show];
- }
- break;
- case 4:
- {
- //蓝牙未开启
- [self addBlueToothLabelWithContent:@"蓝牙未开启" mp3:nil];
- //NSLog(@"CBCentralManagerStatePoweredOff");
- if (peripheralName.length > 0) {
- // showMsgByAlert(self, @"请打开手机蓝牙");
- openBlueToothMbp = [MBProgressHUD showMessage:@"请打开手机蓝牙" toView:self.view];//这个加载每一次都是新建的 不用担心和其它公用
- [Tools playAudioWithString:@"请打开手机蓝牙"];
- }
- self.currentStep = _step1;
-
- isConnectBlueTooth = NO;
- }
- break;
- case 5:
- {
- //蓝牙已开启
- if (openBlueToothMbp) {
- [openBlueToothMbp hideAnimated:YES];
- }
-
- [self addBlueToothLabelWithContent:@"蓝牙已开启" mp3:nil];
- //NSLog(@"CBCentralManagerStatePoweredOn");
- if (peripheralName.length < 1) {
- return;
- }
-
- // 搜索外设
- if (self.peripheral) {
- return;
- }
-
- // 搜索成功之后,会调用找到外设的代理方法
- [self addBlueToothLabelWithContent:@"正在连接模拟设备..." 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 containsString: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);
-
- isConnectBlueTooth = YES;
-
- // 连接成功之后,可以进行服务和特征的发现
- // 设置外设的代理
- self.peripheral.delegate = self;
- // 外设发现服务,传nil代表不过滤
- [self.peripheral discoverServices:@[ [CBUUID UUIDWithString:kServiceUUID] ]];
-
- if (!timer) {//非计时
- [self addBlueToothLabelWithContent:@"模拟设备连接成功" mp3:nil];//如果学员在150s内没有开始计时启动timer 那么训练日志里面就会多出一条这个记录
- }else{//计时
- //计时离线超过3s语音提示/恢复按钮UI步骤。timer存在且大于3 计时中
- if (disconnectSeconds > 3){
- //判断是否需要执行过程验证,恢复到不同的操作
- if (onProcessVerification) {
- [self addBlueToothLabelWithContent:@"模拟设备连接成功" mp3:nil];
- _currentStep = _step4;//不触发setCurrentStep 步骤的方法
- _step4.status = ClickStatusHighlighted;//这里不考虑学员自己在照片传输到一半的过程中,离开蓝牙范围。统一激活人脸签到按钮,点击可以重新发拍照指令。
- _step1.status = ClickStatusHaveDone;
- _step5.status = ClickStatusHaveDone;
- }else{
- self.currentStep = _step5;
- //这里恢复计时的时候判断一下是否需要过程验证
- if (photoSeconds%(processVerificationTime*60) != 0) {
- [self addBlueToothLabelWithContent:@"设备连接成功,恢复计时" mp3:@"mn_blueToothConnect.mp3"];
- }
- }
- }
- }
-
- disconnectSeconds = 0;
- }
- // 外设连接失败
- - (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
- {
- NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);
-
- isConnectBlueTooth = NO;
-
- if (self.cbcManager && self.peripheral) {
- [self.cbcManager connectPeripheral:self.peripheral options:nil];
- }
-
- //因为硬件那边的某些问题 现在设置连接间隔不符合苹果的要求 会固定每155s(测试)断开一次。所以断开提示设置为3s之后才提示
- dispatch_time_t zz = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
- dispatch_after(zz, dispatch_get_main_queue(), ^{
- if (timer && !isConnectBlueTooth) {
- self.currentStep = _step1;
- _step1.status = ClickStatusHighlighted;
- if (timer) {
- [self addBlueToothLabelWithContent:@"设备连接断开,计时停止" mp3:@"mn_blueToothDisconnect.mp3"];
- }else{
- [self addBlueToothLabelWithContent:@"设备连接断开" mp3:nil];
- }
- }
- });
-
- }
- //查找服务的所有特征
- - (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:kServiceUUID]]) {
- //搜索特性
- [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;
- }
-
- for (CBCharacteristic *cha in service.characteristics) {
-
- if ([cha.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID_reade]]) {
- // NSLog(@"读取特征-->>>%@",cha);
- self.readCharacteristic = cha;
- [peripheral setNotifyValue:YES forCharacteristic: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:kCharacteristicUUID_write]]) {
- // NSLog(@"写入特征-->>>%@",cha);//0x04对应的是CBCharacteristicPropertyWriteWithoutResponse || 0x0A对应的是CBCharacteristicPropertyNotify
- self.writeCharacteristic = cha;
-
- bool isReal = [myDelegate.mnTrainType integerValue] == 2;//走到这一步只会有 0 成功获取学员信息(学员是计时状态 != app在跑定时器) / 2.已在模拟设备登录,未进行人脸比对
- if (isReal && (_currentStep == _step1 || _currentStep == _step2)) {//未开始
- //获取版本号
- self.currentStep = _step2;
-
- blueToothOrder = kGetMNdevVersion;
- [self sendBlueToothOrder];
-
- }
-
- /*非计时状态,中间断开,重发蓝牙指令?
- 1.现在每一步都可以点击按钮重新操作,即学员主动发送蓝牙指令;
- 2.终端重新连接后会继续以前的动作。app会响应收到的数据执行相关操作
- 鉴于以上两点,app就不主动重新发送蓝牙连接了*/
- //if(blueToothOrder.length > 0){
- // [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:kCharacteristicUUID_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]; 这里不要再去读啊,否则会收到每一次发送数据的最后一包(20)
- } 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--->%ld<>%@",seconds,hexString);
- lackVertifyTime = 0;
-
- //数据完整性检测
- if ([hexString containsString:@"be"] && dataIsLack == NO) {
- //数据首包
- lastData = hexString;
- if (lastData.length < 6) {
- return;
- }
- int dataLength = [Tools getHexNumWithString:[lastData substringWithRange:NSMakeRange(2, 4)]];
- if (lastData.length < dataLength*2 + 6) {
- dataIsLack = YES;
- return;
- }
- }else {
- if (dataIsLack) {//上个包数据不够
- hexString = [lastData stringByAppendingString:hexString];
- lastData = hexString;
-
- int dataLength = [Tools getHexNumWithString:[lastData substringWithRange:NSMakeRange(2, 4)]];
- if (lastData.length < dataLength*2 + 6) {
- return;
- }else {
- dataIsLack = NO;
- }
- }else{
- return;
- }
- }
-
- if ([hexString containsString:@"be"]) {//防止其它莫名奇妙的指令
- NSString *order = [hexString substringWithRange:NSMakeRange(6, 2)];
-
- //获取到模拟设备版本,进行版本判断
- if([order isEqualToString:@"0a"]){
- [self checkDevVersionWithHexString:hexString];
- return;
- }
-
- //升级
- if ([order isEqualToString:@"0b"]) {
- [self sendMsgWithSubPackageWithHexString:hexString];//发送指定升级包
- return;
- }
-
- //升级成功
- if ([order isEqualToString:@"0c"]) {
- ShowMsg(@"模拟设备升级完成");
- [self addBlueToothLabelWithContent:@"模拟设备升级完成" mp3:nil];
- [Tools playAudioWithString:@"模拟设备升级完成"];
- return;
- }
-
- //获取到终端信息
- if ([order isEqualToString:@"03"]) {
- [self signFirstCheckWithHexString:hexString];//验证序列号/物理卡id
- return;
- }
-
- //拍照成功开始返回的照片包(第一包开始)
- if ([order isEqualToString:@"17"]) {
- [self getDataForPictureWithString:hexString];
- return;
- }
-
- }
-
- }
- }
- -(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error{
- if (error) {
- NSLog(@"写入数据失败-->%@:%@",blueToothOrder,error);
- }else{
- NSLog(@"写入数据成功-->: %@",blueToothOrder);
- }
- }
- //根据数据内容生成图片
- - (void)getDataForPictureWithString:(NSString *)hexString {
-
- //取相片
- NSString *len = [hexString substringWithRange:NSMakeRange(2, 4)];
- NSInteger packageLength = [Tools getHexNumWithString:len];
- if ([blueToothOrder containsString:kGetPhotoData]) {
- NSString *newData = [[hexString substringFromIndex:10] stringByReplacingOccurrencesOfString:@"eded" withString:@""];
- imageData = [imageData stringByAppendingString:newData];//每次发起拍照命令前 将图片数据清空
-
- NSString *currentHexOrder = [hexString substringWithRange:NSMakeRange(8, 2)];
- int pOrderNum = [Tools getHexNumWithString:currentHexOrder];
-
- if ([currentHexOrder isEqualToString:@"00"]) {//循环发送命令
- //照片数据全取出 显示照片
- NSData *image = [Tools convertHexStrToData:imageData];
- //获取到照片 上传服务器
- if (image) {
- blueToothOrder = @"upLoadWAIT";
- //如果是签到拍照生成classId等相关
- if (onProcessVerification == NO) {
- [self getClassIdAndSoOn];
- }
- [self upLoadPhotoWithImage:[UIImage imageWithData:image]];
-
- }
-
- }else{
-
- NSString *orderStr = [NSString stringWithFormat:@"%.2x",pOrderNum + 1];////命令+1 然后转为16进制
- blueToothOrder = [NSString stringWithFormat:@"%@%@eded",kGetPhotoData,orderStr];
- [self sendBlueToothOrder];
- }
- return;
- }
-
- //如果是拍照指令 并且 返回了第一包的数据
- if ([blueToothOrder isEqualToString:kTakePhotoOrder] && [[hexString substringWithRange:NSMakeRange(6, 2)] isEqualToString:@"17"]) {
-
- [self addBlueToothLabelWithContent:@"拍照已完成,正在采集照片信息..." mp3:@"mn_takePhotoColloctPic.mp3"];
-
- //拍照成功 发指令获取数据
- if (packageLength*2 == hexString.length-6 && [hexString containsString:@"eded"]) {//判断完整性
- imageData = [[hexString substringFromIndex:10] stringByReplacingOccurrencesOfString:@"eded" withString:@""];//每次发起拍照命令前 将图片数据清空
- blueToothOrder = [NSString stringWithFormat:@"%@02eded",kGetPhotoData];//获取指定图像包
- }else{
- blueToothOrder = [NSString stringWithFormat:@"%@01eded",kGetPhotoData];//获取指定图像包
- }
-
- [self sendBlueToothOrder];
- }
- }
- #pragma mark 一些方法
- -(void)checkDevVersionWithHexString:(NSString *)hexString{
-
- NSMutableString *mStr = [NSMutableString stringWithString:hexString];
- NSString *str = [[mStr substringFromIndex:6] stringByReplacingOccurrencesOfString:@"eded" withString:@""];
-
- NSArray *arr = [[Tools convertHexStrToString:str] componentsSeparatedByString:@";"];
- NSInteger zz = [[NSString stringWithFormat:@"%@",arr[1]] integerValue];
- nowVersion = [NSString stringWithFormat:@"%ld",zz];
- //版本更新检查
- [self UpdateMNDev];//这返回了三个参数,DM91-MN,0003,L000003 我们只用到中间的序列号
- }
- - (void)signFirstCheckWithHexString:(NSString *)hexString{
-
- NSMutableString *mStr = [NSMutableString stringWithString:hexString];
- NSString *str = [[mStr substringFromIndex:6] stringByReplacingOccurrencesOfString:@"eded" withString:@""];
-
- NSArray *arr = [[Tools convertHexStrToString:str] componentsSeparatedByString:@";"];
-
- //如果是返回序列号,判断是否符合服务器返回的序列号,符合则命令拍照
- if ([arr[1] isEqualToString: mnqDev.mnqSn]) {
- if ([arr[0] containsString:mnqDev.cardId]) {
-
- [self addBlueToothLabelWithContent:@"身份信息认证成功" mp3:nil];
- self.currentStep = _step4;
- //发起拍照命令
- [self takePhotoByBlueTooth];
-
- }else{
- _currentStep.status = ClickStatusHighlighted;
- showMsgByAlertWithSureBlock(self, @"请刷本人身份证", ^{
- _currentStep.status = ClickStatusMid;
- blueToothOrder = kGetDevNumAndStuCardOrder;
- [self sendBlueToothOrder];
- });
- [Tools playAudioWithString:@"请刷本人身份证"];
- [self addBlueToothLabelWithContent:@"身份信息认证失败" mp3:nil];
- }
-
- }else{
- _currentStep.status = ClickStatusHighlighted;
- showMsgByAlert(self, @"模拟设备序列号不匹配");
- [Tools playAudioWithString:@"模拟设备序列号不匹配"];
- [self addBlueToothLabelWithContent:@"身份信息认证失败" mp3:nil];
- }
- }
- - (void)showAlertTakePhotoFailWithStr:(NSString *)failureStr {
-
- _currentStep.status = ClickStatusHighlighted;
-
- blueToothOrder = @"";
-
- UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:[NSString stringWithFormat:@"人脸比对失败(%@),是否重新采集照片",failureStr] preferredStyle:UIAlertControllerStyleAlert];
- [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
-
- //关闭定时器
- if (signInTimer) {
- [signInTimer invalidate];
- signInTimer = nil;
- }
-
- }]];
- [alert addAction:[UIAlertAction actionWithTitle:@"重新拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
- _currentStep.status = ClickStatusMid;
- [self performSelector:@selector(takePhotoByBlueTooth) withObject:nil afterDelay:1];
- }]];
- [self presentViewController:alert animated:NO completion:nil];
- }
- - (void)wantSignOut{
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:@"您确定要结束当前模拟计时训练吗?" preferredStyle:UIAlertControllerStyleAlert];
-
- [alertFind addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
- _step6.status = ClickStatusHighlighted;
- }]];
- [alertFind addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- self.currentStep = _step6;
- //先关闭定时器
- if (timer.isValid) {
- [timer invalidate];
- timer = nil;
- myDelegate.mnPeriodVC = nil;
- }
-
- //关闭蓝牙连接
- [self closeBlueTooth];
-
- [gatherTrainDic setValue:@"2" forKey:@"isOver"];
- [self saveGatherTrainDic];
-
- minuteTrainArray = [DB_Helper quearyTrainWithClassId:gatherTrainDic[@"classId"] type:mnTableName];
- if (minuteTrainArray.count > 0) {
-
- [self uploadAppTrainPlWithSignOut:YES];
- }else{
- [self signOut];
- }
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- }
- - (void)removeImage {
-
- if (_photoImg) {
- [_photoImg removeFromSuperview];
- }
- }
- #pragma mark - 蓝牙写入数据
- - (void)sendBlueToothOrder{
-
- //不同蓝牙指令重置失败次数
- if (blueToothOrder != blueToothOrder_old) {
- blueToothOrder_old = blueToothOrder;
- reOrderCount = 0;
- }
-
- lackVertifyTime = 0;
- dataIsLack = NO;
- lastData = nil;
- if (blueToothOrder && blueToothOrder.length != 0) {
- [self.peripheral writeValue:[Tools convertHexStrToData:blueToothOrder] forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse];
- }
-
- }
- #pragma mark - 拍照命令
- //发送拍照命令
- - (void)takePhotoByBlueTooth
- {
- imageData = @"";
- lastData = @"";
- imgLongth = 0;
- reOrderCount = 0;
- //发送拍照指令
- [Tools playAudioWithString:@"拍照准备"];
- dispatch_time_t zz = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
- dispatch_after(zz, dispatch_get_main_queue(), ^{
- blueToothOrder = kTakePhotoOrder;
- [self sendBlueToothOrder];//每次发送蓝牙指令lackVertifyTime = 0;
- });
-
-
- if (!signInTimer) {
- signInTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(signInTimerRun) userInfo:nil repeats:YES];
- }
- }
- //此定时器仅存在于拍照的整个过程
- - (void)signInTimerRun {
-
- if (isConnectBlueTooth) {
- //每一包分批次等待时间
- lackVertifyTime++;
- if (dataIsLack && lackVertifyTime == 5) {
- reOrderCount ++;
- if (reOrderCount < 3) {
- [self sendBlueToothOrder];//重发拍照/获取图片相关指令
- }else {
- //apap蓝牙指令交流失败
- showMsgByAlert(self, @"拍照失败!");
- [Tools playAudioWithString:@"拍照失败!"];
- _currentStep.status = ClickStatusHighlighted;
- }
- }
- }
- }
- - (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;
- }
- }
- #pragma mark - 模拟设备升级
- - (void)startUpdateMNQDevWithFilePath:(NSURL *)filePath{
-
- MBProgressHUD *hud = [MBProgressHUD HUDForView:self.view];
- hud.label.text = @"模拟设备升级中";
- hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
-
- NSData *data = [NSData dataWithContentsOfURL:filePath];
- packgeHexStr = [Tools convertDataToHexStr:data];
- [self sendMsgWithSubPackageWithHexString:@"be00040b01eded"];//这里模仿外设请求第一包
- }
- -(void)sendMsgWithSubPackageWithHexString:(NSString *)hexStr{
- NSString *orderStr = [hexStr substringWithRange:NSMakeRange(8, 2)];
- NSInteger order = [Tools getHexNumWithString:orderStr];
- NSString *perHexString = nil;
- MBProgressHUD *hud = [MBProgressHUD HUDForView:self.view];
-
- if (packgeHexStr.length == 0) {
- //升级完成
- perHexString = [NSString stringWithFormat:@"be00048b00eded"];
- hud.progress = 1.0;
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUDForView:self.view];
- });
-
- }else if (packgeHexStr.length > order*1792) {
-
- perHexString = [NSString stringWithFormat:@"be%.4x8b%@%@eded",BLE_SEND_PER_LEN,orderStr,[packgeHexStr substringWithRange:NSMakeRange(order*1792-1792, 1792)]];
- hud.progress = 1.0*order/(packgeHexStr.length/1792);
-
- }else{
-
- NSString *newStr = [packgeHexStr substringWithRange:NSMakeRange(order*1792-1792, packgeHexStr.length%1792)];
- perHexString = [NSString stringWithFormat:@"be%.4lx8b%@%@eded",packgeHexStr.length%1792/2+4,orderStr,newStr];
-
- packgeHexStr = @"";
-
- }
- NSLog(@"升级包==> : %ld == %@ ",perHexString.length,perHexString);
- [self sendMsgWithSubPackage:[Tools convertHexStrToData:perHexString]];
- }
- //分包发送蓝牙数据
- -(void)sendMsgWithSubPackage:(NSData*)msgData
- {
- for (int i = 0; i < [msgData length]; i += BLE_SEND_MAX_LEN) {
- // 预加 最大包长度,如果依然小于总数据长度,可以取最大包数据大小
- if ((i + BLE_SEND_MAX_LEN) < [msgData length]) {
- NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, BLE_SEND_MAX_LEN];
- NSData *subData = [msgData subdataWithRange:NSRangeFromString(rangeStr)];
- NSLog(@"升级小小包subData:%@",subData);
- [self.peripheral writeValue:subData forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithoutResponse];// 这里之所以用这个属性是为了提升发送速度。用带回应的也能写入成功 只是因为回调结果导致过程太慢
- //根据接收模块的处理能力做相应延时
- usleep(20 * 1000);
- }
- else {
- NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, (int)([msgData length] - i)];
- NSData *subData = [msgData subdataWithRange:NSRangeFromString(rangeStr)];
- NSLog(@"升级小小包subData:%@",subData);
- [self.peripheral writeValue:subData forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
- usleep(20 * 1000);
- }
- }
- }
- #pragma mark - 添加本地通知
- -(void)addLocalNotificationWithAudio:(NSString *)audioName{
- //定义本地通知对象
- UILocalNotification *notification = [[UILocalNotification alloc]init];
- //设置调用时间
- notification.fireDate = [NSDate date];
- //设置通知属性
- NSString *bodyString = @"优易学车提醒您";
- if ([audioName isEqualToString:@"mn_takePhotoColloctPic.mp3"]) {
- bodyString = @"拍照已完成,正在采集照片数据";//其实这个mp3 感觉也是没太必要的。这个时候都没计时 学员应该多关注一些手机,app在前台才对
- }else if ([audioName isEqualToString:@"mn_blueToothConnect.mp3"]) {
- bodyString = @"模拟设备连接成功";
- }else if ([audioName isEqualToString:@"mn_blueToothDisconnect.mp3"]) {
- bodyString = @"模拟设备已断开,计时暂停,正在尝试重新连接";
- }else if ([audioName isEqualToString:@"mn_blueToothQuit.mp3"]) {
- bodyString = @"模拟计时已签退,本次计时结束";
- }else if ([audioName isEqualToString:@"mn_processVerification.mp3"]){
- bodyString = @"计时停止,请进行拍照验证";
- }
-
- notification.alertBody = bodyString; //通知主体
- notification.applicationIconBadgeNumber = 1;//应用程序图标右上角显示的消息数
- notification.alertAction = @"打开应用"; //待机界面的滑动动作提示
- notification.soundName = audioName;//收到通知时播放的声音,默认消息声音
-
- NSDictionary *userDict = [NSDictionary dictionaryWithObjectsAndKeys:@"nothing",@"MNQTrainVC", nil];
- notification.userInfo = userDict;
- //调用通知
- [[UIApplication sharedApplication] scheduleLocalNotification:notification];
- }
- #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;
- //}
- - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(nonnull NSArray<CLLocation *> *)locations {
- CLLocation *loctaion = [locations firstObject];
- CLLocationCoordinate2D coordinate = loctaion.coordinate;
- myCoordinate = BMKCoordTrans(coordinate, BMK_COORDTYPE_GPS, BMK_COORDTYPE_BD09LL);//转换GPS坐标至百度坐标(加密后的坐标)
- }
- //#pragma mark 打开相机扫描二维码
- //-(void)openScan{
- // ScanVC *scan = [[ScanVC alloc] init];
- // scan.type = @"";
- // [scan scanBlock:^(NSString *dataString) {
- // if ([dataString isEqualToString:@"success"]) {
- // myDelegate.mnTrainType = @"2";
- // [self getBlueToothAndDevOrder];
- // }
- // }];
- // [self navPushHideTabbarToVC:scan];
- //}
- #pragma mark - 本地数据读取
- - (void)saveGatherTrainDic
- {
- NSString *filePath = [Tools getPathWithFileName:@"MNQTrainDic.plist"];
- [gatherTrainDic writeToFile:filePath atomically:YES];
- }
- - (void)getGatherTrainDic
- {
- NSString *filePath = [Tools getPathWithFileName:@"MNQTrainDic.plist"];
- if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
-
- gatherTrainDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
- }
- }
- #pragma mark tableview
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- return dataSourceArray.count;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
- cell.selectionStyle = UITableViewCellSelectionStyleNone;
- }
-
- [cell.textLabel setText:[dataSourceArray[dataSourceArray.count - indexPath.row - 1] substringFromIndex:1] Font:Font17 TextColor:[[dataSourceArray[dataSourceArray.count - indexPath.row - 1] substringToIndex:1] isEqualToString:@"1"]?[UIColor redColor]:[UIColor blackColor]];
- [cell.textLabel setNumberOfLines:0];
-
- return cell;
- }
- #pragma mark -选择科目
- - (void)slelectTrainSubject{
- BOOL isOpenTwo = [defUser.userDict[@"mnqTwoOpen"] isEqualToString:@"1"];
- BOOL isOpenThree = [defUser.userDict[@"mnqThreeOpen"] isEqualToString:@"1"];
- //同时开启
- if (isOpenTwo && isOpenThree) {
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:@"请选择训练科目" preferredStyle:UIAlertControllerStyleAlert];
-
- [alertFind addAction:[UIAlertAction actionWithTitle:@"科二" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
- subject = @"2";
- self.navigationItem.title = [NSString stringWithFormat:@"科目%@模拟计时",[subject isEqualToString:@"2"]?@"二":@"三"];
- [self getBlueToothAndDevOrder];
- }]];
- [alertFind addAction:[UIAlertAction actionWithTitle:@"科三" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- subject = @"3";
- self.navigationItem.title = [NSString stringWithFormat:@"科目%@模拟计时",[subject isEqualToString:@"2"]?@"二":@"三"];
- [self getBlueToothAndDevOrder];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
-
- }else if (isOpenTwo || isOpenThree){
- //其中一个开启
- subject = isOpenTwo ? @"2" : @"3";
- self.navigationItem.title = [NSString stringWithFormat:@"科目%@模拟计时",[subject isEqualToString:@"2"]?@"二":@"三"];
- [self getBlueToothAndDevOrder];
- }else{
- //都未开启
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:@"暂未开启模拟计时" preferredStyle:UIAlertControllerStyleAlert];
- [alertFind addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
-
- [self goBackByNavigation];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- }
- }
- #pragma mark - 继续计时
- - (void)goonTrain{
-
- //蓝牙
- peripheralName = gatherTrainDic[@"blueName"];
- if (peripheralName.length > 0) {
- //如果之前有蓝牙 现在也要重新开启起来
- [self searchBlueTooth];
- }else{
- [self getBlueToothAndDevOrder];
- return;
- }
- }
- #pragma mark 开始计时
- - (void)beginTimer {
-
- //更新表统计
- [self reloadDetailLab];
-
- //过程验证计时
- photoSeconds = 0;
-
- self.currentStep = _step5;
-
- //过程中不需要再发送重要指令。该定时器主要处理拍照命令
- if (signInTimer) {
- [signInTimer invalidate];
- signInTimer = nil;
- }
-
- myDelegate.mnTrainType = @"0";
- [self addBlueToothLabelWithContent:@"签到成功,开始计时" mp3:nil];
- [Tools playAudioWithString:[NSString stringWithFormat:@"开始训练,训练过程中允许手机黑屏,请不要关闭应用,否则会影响学时上传,祝您体验愉快"]];
-
- //将之前的学时全部清空
- [DB_Helper deleteAllTrainWithType:mnTableName];
-
- [gatherTrainDic setValue:subject forKey:@"subject"];//训练科目
- [gatherTrainDic setValue:peripheralName forKey:@"blueName"];//蓝牙名
- [gatherTrainDic setValue:classId forKey:@"classId"];//课堂id
- [gatherTrainDic setValue:classCode forKey:@"classCode"];//课程编码
- [gatherTrainDic setValue:trainNum forKey:@"trainNum"];//学时编号
- [gatherTrainDic setValue:@"0" forKey:@"photoSeconds"];//秒 服务器训练状态返回接口(登录完之后调用)/以及人脸比对接口会返回更新该值
- [gatherTrainDic setValue:@"0" forKey:@"isOver"];//是否结束
- [self saveGatherTrainDic];//保存至本地 可以用于断线重连
-
- //classId , classCode , trainNum
- minuteTrainDic = [NSMutableDictionary dictionary];
- [minuteTrainDic setValue:classId forKey:@"classId"];
- [minuteTrainDic setValue:classCode forKey:@"classCode"];
- [minuteTrainDic setValue:trainNum forKey:@"trainNum"];
-
- disconnectSeconds = 0;
- timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];//处理UI交互阻塞计时
- trainView.hidden = NO;
- myDelegate.mnPeriodVC = self;
- }
- - (void)timerRun
- {
- NSLog(@"timerRuning");
- //计时过程中蓝牙断开连接
- if (!isConnectBlueTooth && peripheralName.length > 0) {
- disconnectSeconds ++;
-
- //如果超过10分钟 停止每5s自动连接
- if (disconnectSeconds >= 10*60) {
- return;
- }
-
- if (disconnectSeconds%5 == 0) {
- if (_cbcManager && self.peripheral) {
- //[Tools playAudioWithString:@"设备连接中,请稍等"];这个在中途断开的时候 还是不要提示了
- [_cbcManager connectPeripheral:self.peripheral options:nil];
- }
- }
-
- return;
- }
-
- //每processVerificationTime进行过程验证 photoSeconds!= 0 第一次进来的时候规避掉过程验证
- if (photoSeconds !=0 && processVerificationTime != 0 && onProcessVerification == NO) {//processVerificationTime不等于0表示需要验证
- if (photoSeconds%(processVerificationTime*60) == 0) {
- onProcessVerification = YES;
- processVerificationFailureCount = 0;
- /*是否停止计时器
- 为了防止学员在收到提醒以后并且长时间(>3s)离开了蓝牙连接范围,为了走前面的每5s自动连接蓝牙重连操作,所以还是不停止计时器了
- */
- _currentStep = _step4;//不触发setCurrentStep 步骤的方法
- _step5.status = ClickStatusHaveDone;
- #if 0
- //手机通知学员
- [self addBlueToothLabelWithContent:@"计时停止,请进行拍照验证" mp3:@"mn_processVerification.mp3"];
- //让学员发起过程验证拍照指令
- _step4.status = ClickStatusHighlighted;
- UIAlertView *servicesDisabledAlert = [[UIAlertView alloc] initWithTitle:@"过程验证" message:@"模拟计时已停止,请前往 个人-模拟计时 进行人脸验证" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
- [servicesDisabledAlert show];
- #else
- //手机不通知学员,添加日志记录
- NSString *string = @"计时停止,请进行拍照验证";
- [self addLogsWithConten:string status:4396];
- _statusLab.text = string;
- //这种直接发起拍照命令的方式,符合过程验证“抓拍”的意义。但是鉴于只有app向学员传达了训练状态这一点,还是让学员主动操作手机进行过程验证吧。如果需要改的话 就用下面这种方式
- /*5s是为了等待前面的语音提示完成,避免与拍照语音提示冲突;
- 这里是否要考虑如果是过程验证拍照,想要在手机黑屏的情况下让学员完成验证过程,怎么做比较好呢?该怎么和学员交流呢
- */
- _step4.status = ClickStatusMid;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self takePhotoByBlueTooth];
- });
-
- #endif
-
- }
- }
-
- //过程验证,停止计时
- if (onProcessVerification) {
- return;
- }
- //计时器正常运作(蓝牙一定是连接的,且不处于过程验证状态)
- seconds++;
- photoSeconds++;
- NSLog(@"%ld---->最新蓝牙指令:%@ ---->拍照时间:%ld",seconds,blueToothOrder,photoSeconds);
- //每一分钟记录上传一次学时
- if (seconds%60 == 0) {
- //生成新的trainNum 先取之前的(签到时候的或者上一分钟的) 后四位序列码+1。顺便存入userDefault
- NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- int OrderNum = [[[[userDefaults valueForKey:@"mnTrainOrderNum"] componentsSeparatedByString:@","] lastObject] intValue] + 1;
- NSString *trainString = @"";
- if (OrderNum < 10) {
- trainString = [NSString stringWithFormat:@"000%d",OrderNum];
- }else if (OrderNum < 100){
- trainString = [NSString stringWithFormat:@"00%d",OrderNum];
- }else if (OrderNum < 1000){
- trainString = [NSString stringWithFormat:@"0%d",OrderNum];
- }else{
- trainString = [NSString stringWithFormat:@"%d",OrderNum];
- }
- trainNum = [NSString stringWithFormat:@"%@%@",[trainNum substringToIndex:trainNum.length - 4],trainString];
- //将trainOrderNum写入NSUserDefaults
- trainOrderNum = [NSString stringWithFormat:@"%@,%d",[[[userDefaults valueForKey:@"mnTrainOrderNum"] componentsSeparatedByString:@","] firstObject],OrderNum];
- [userDefaults setValue:trainOrderNum forKey:@"mnTrainOrderNum"];
- //这个点就当前时间
- [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
- NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
- [minuteTrainDic setValue:dateString forKey:@"gps"];//这里不想新增表字段了 并且正常情况应该是gps里面包含了dateString。这里为了存取方便就。。
- [minuteTrainDic setValue:trainNum forKey:@"trainNum"];
- NSDictionary *dict = [NSDictionary dictionaryWithDictionary:minuteTrainDic];
- [DB_Helper saveTrainWithDic:dict type:mnTableName];
- //更新gatherTrainDic数据 并存入本地
- [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoSeconds] forKey:@"photoTime"];
- [gatherTrainDic setValue:trainNum forKey:@"trainNum"];
- [self saveGatherTrainDic];
- minuteTrainArray = [DB_Helper quearyTrainWithClassId:gatherTrainDic[@"classId"] type:mnTableName];
- [self uploadAppTrainPlWithSignOut:NO];
- }
-
-
- //更新UI上的时间
- [self upDateTime];
- }
- - (void)getClassIdAndSoOn
- {
- //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];
- //13位整数+.+小数。其中第十位刚好是秒
- classId = [[NSString stringWithFormat:@"%lf",timeInterval] substringToIndex:10];
-
-
- //课程编码 classCode
- NSString *carTypeString = @"21";
- if ([defUser.userDict[@"carType"] isEqualToString:@"A1"]) {
- carTypeString = @"01";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"A2"]) {
- carTypeString = @"02";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"A3"]) {
- carTypeString = @"03";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"B1"]) {
- carTypeString = @"11";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"B2"]) {
- carTypeString = @"12";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"C1"]) {
- carTypeString = @"21";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"C2"]) {
- carTypeString = @"22";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"C3"]) {
- carTypeString = @"23";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"C4"]) {
- carTypeString = @"24";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"C5"]) {
- carTypeString = @"25";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"D"]) {
- carTypeString = @"31";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"E"]) {
- carTypeString = @"32";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"F"]) {
- carTypeString = @"33";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"M"]) {
- carTypeString = @"41";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"N"]) {
- carTypeString = @"42";
- }
- if ([defUser.userDict[@"carType"] isEqualToString:@"P"]) {
- carTypeString = @"43";
- }
-
- classCode = [NSString stringWithFormat:@"3%@%@120000",carTypeString,subject];
-
-
- //学时编号 trainNum
- NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
- formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
- [formatter setDateFormat:@"yyMMdd"];
- NSString *dateString = [formatter stringFromDate:[NSDate date]];
-
- NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- trainOrderNum = [userDefaults valueForKey:@"mnTrainOrderNum"]; //170209,20
- //![trainOrderNum isKindOfClass:[NSString class]]
- //判断是否是同一天
- if (trainOrderNum == nil || ![[[trainOrderNum componentsSeparatedByString:@","] firstObject] isEqualToString:dateString]) {
- [userDefaults setValue:[NSString stringWithFormat:@"%@,0",dateString] forKey:@"mnTrainOrderNum"];
- }
-
- trainOrderNum = [userDefaults valueForKey:@"mnTrainOrderNum"];
- NSString *trainString = @"";
- int trainInt = [[[trainOrderNum componentsSeparatedByString:@","] lastObject] intValue];
- if (trainInt < 10) {
- trainString = [NSString stringWithFormat:@"000%d",trainInt];
- }else if (trainInt < 100){
- trainString = [NSString stringWithFormat:@"00%d",trainInt];
- }else if (trainInt < 1000){
- trainString = [NSString stringWithFormat:@"0%d",trainInt];
- }else{
- trainString = [NSString stringWithFormat:@"%d",trainInt];
- }
-
-
- trainNum = [NSString stringWithFormat:@"%@%@%@",mnqDev.devnum,dateString,trainString];
- }
- #pragma mark 网络请求
- //获取蓝牙名/序列号
- - (void)getBlueToothAndDevOrder{
-
- NSMutableArray *arr=[NSMutableArray array];
- [arr addPro:@"stuId" Value:defUser.userDict[@"outId"]];
- [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]];
- NSString* method = @"getStuCardIdOrBluetooth";
- [MBProgressHUD showMessage:@"正在获取模拟设备信息" toView:self.view];
- [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
- [MBProgressHUD hideHUDForView:self.view];
- if (!root) {
- ShowMsg(@"请求失败");
- _currentStep.status = ClickStatusHighlighted;
- return;
- }
-
- if (![root[@"code"] isEqualToString:@"0"]) {
- showMsgByAlert(self, root[@"msg"]);
- _currentStep.status = ClickStatusHighlighted;
- return;
- }
-
- //获取到蓝牙名(序列号)搜索蓝牙连接
- NSDictionary *dic = root[@"body"];
- if (![dic isKindOfClass:[NSDictionary class]]) {
- ShowMsg(@"数据异常");
- _currentStep.status = ClickStatusHighlighted;
- return;
- }
- mnqDev = [[MNQDev alloc]init];
- mnqDev.devnum = dic[@"devnum"];
- mnqDev.cardId = dic[@"cardId"];
- mnqDev.carnum = dic[@"carnum"];
- mnqDev.inscode = dic[@"inscode"];
- mnqDev.mnqSn = dic[@"mnqSn"];
- mnqDev.imei = dic[@"imei"];
-
- peripheralName = mnqDev.carnum;
- [self searchBlueTooth];
-
- }];
- }
- //判断模拟设备版本号,是否需要升级
- -(void)UpdateMNDev{
- NSMutableArray *arr=[NSMutableArray array];
- [arr addPro:@"versionCode" Value:nowVersion];
- [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]];
- [arr addPro:@"imei" Value:mnqDev.imei];
- [arr addPro:@"devnum" Value:mnqDev.devnum];
- [arr addPro:@"inscode" Value:@""];
-
- NSString* method = @"upgradesVersion";
- [MBProgressHUD showMessage:@"正在检查模拟设备版本信息" toView:self.view];
- [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
- [MBProgressHUD hideHUDForView:self.view];
- if (!root) {
- _currentStep.status = ClickStatusHighlighted;
- [self addBlueToothLabelWithContent:@"模拟设备更新检查失败" mp3:nil];
- ShowMsg(@"请求失败");
- return;
- }
- if ([root[@"code"] isEqualToString:@"-1"]) {//这里和jiapeimanager里面的-1处理冲突了。就不管它吧,不是很重要。
- _currentStep.status = ClickStatusHighlighted;
- [self addBlueToothLabelWithContent:@"模拟设备更新检查失败" mp3:nil];
- ShowMsg(root[@"msg"]);
- return;
- }
- if ([root[@"code"] isEqualToString:@"1"]) {
- //不需要更新
- self.currentStep = _step3;
- blueToothOrder = kGetDevNumAndStuCardOrder;
- [self sendBlueToothOrder];
- return;
- }
-
- //检测到新版本
- NSString *urlStr = root[@"body"];
- if ([root[@"code"] isEqualToString:@"0"]) {
- if (urlStr && urlStr.length != 0) {
- [self addBlueToothLabelWithContent:@"模拟设备升级中" mp3:nil];
- [self downLoadNewDataWithurl:urlStr];
- }
- }
-
- }];
-
- }
- -(void)downLoadNewDataWithurl:(NSString *)urlStr{
-
- //创建传话管理者
- AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
-
- NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
- //下载文件
- /*
- 第一个参数:请求对象
- 第二个参数:progress 进度回调
- 第三个参数:destination 回调(目标位置)
- 有返回值
- targetPath:临时文件路径
- response:响应头信息
- 第四个参数:completionHandler 下载完成后的回调
- filePath:最终的文件路径
- */
- NSURLSessionDownloadTask *download = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
- //下载进度
- dispatch_async(dispatch_get_main_queue(), ^{
- MBProgressHUD *hud = [MBProgressHUD HUDForView:self.view];
- hud.label.text = [NSString stringWithFormat:@"正在下载模拟设备更新包(%.2f%%)",100.0 * (downloadProgress.completedUnitCount / downloadProgress.totalUnitCount)];
- });
- NSLog(@"%.2f",1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
- }
- destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
- //保存的文件路径
- NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
- return [NSURL fileURLWithPath:fullPath];
-
- }
- completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
- if (error) {
- _currentStep.status = ClickStatusHighlighted;
- NSLog(@"下载更新包出错:%@",error);
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD hideHUDForView:self.view];
- showMsgByAlert(self, @"下载更新包出错");
- });
- return;
- }
- NSLog(@"升级包filePath: %@",filePath);
- if (filePath) {
- [self startUpdateMNQDevWithFilePath:filePath];
- }
-
- }];
-
- //执行Task
- dispatch_async(dispatch_get_main_queue(), ^{
- [MBProgressHUD showMessage:@"正在下载模拟设备更新包" toView:self.view];
- });
- [download resume];
-
- }
- //人脸比对签到face2face/过程验证faceComparison onProcessVerification == yes 过程验证
- - (void)upLoadPhotoWithImage:(UIImage *)image{
-
- //蓝牙照片不作处理(调整图片像素)
- UIImage *cutImg;
- if (peripheralName.length > 0) {
- cutImg = image;
- }else {
- //剪切 然后压缩图片
- NSData *data = UIImageJPEGRepresentation([image scaledAndCutToSize:CGSizeMake(240, 320)],0.5);
- cutImg = [UIImage imageWithData:data];
- }
-
- if (!myDelegate.isBackgroundTask) {
- if (!_photoImg) {
- _photoImg = [[UIImageView alloc] initWithFrame:CGRectMake(10, kSize.height - kNavOffSet - 200 - kSafeAreaBottomHeight, 200, 150)];
- _photoImg.userInteractionEnabled = YES;
- UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)];
- [label setText:@"点击移除照片" Font:Font17 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
- [_photoImg addSubview:label];
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(removeImage)];
- [_photoImg addGestureRecognizer:tap];
- }
- [self.view addSubview:_photoImg];
- _photoImg.image = cutImg;
- [self performSelector:@selector(removeImage) withObject:nil afterDelay:10];
- }
- NSMutableArray *arr=[NSMutableArray array];
- [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]];
- [arr addPro:@"photo" Value:[UIImageJPEGRepresentation(cutImg,1.0) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]];//不带水印照片
- [arr addPro:@"lng" Value:[NSString stringWithFormat:@"%f",myCoordinate.longitude]];
- [arr addPro:@"lat" Value:[NSString stringWithFormat:@"%f",myCoordinate.latitude]];
- [arr addPro:@"stuId" Value:defUser.userDict[@"outId"]];
- [arr addPro:@"subject" Value:subject];
- [arr addPro:@"subjcode" Value:classCode];
- [arr addPro:@"classId" Value:classId];
- NSString *method = onProcessVerification ? @"faceComparison" : @"face2face";
- [MBProgressHUD showMessage:@"正在进行人脸比对" toView:self.view];
- [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
- [MBProgressHUD hideHUDForView:self.view animated:YES];
- blueToothOrder = @"";
-
- if (!root) {
- _currentStep.status = ClickStatusHighlighted;
- if (![Util connectedToNetWork]) {
- blueToothOrder = @"";
- showMsgByAlert(self, @"请检查手机网络连接是否正常");
- return;
- }
- [Tools playAudioWithString:@"人脸比对请求失败"];
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:@"人脸比对请求失败" preferredStyle:UIAlertControllerStyleAlert];
-
- [alertFind addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
- _currentStep.status = ClickStatusHighlighted;
- }]];
- [alertFind addAction:[UIAlertAction actionWithTitle:@"再试一次" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- _currentStep.status = ClickStatusMid;
- [self upLoadPhotoWithImage:image];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- return;
- }
-
- if ([root[@"code"] isEqualToString:@"90"]) {
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:root[@"msg"] preferredStyle:UIAlertControllerStyleAlert];
-
- [alertFind addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
-
- [LoginViewController loginFromVC:self];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- return;
- }
- if ([root[@"code"] isEqualToString:@"1"]) {
- [Tools playAudioWithString:root[@"msg"]];
- [self addBlueToothLabelWithContent:[NSString stringWithFormat:@"人脸验证失败"] mp3:nil];
- if (onProcessVerification) {
- //判断次数==0表示不限制失败次数,这个次数限制似乎就只有防止恶意调用接口的作用,减轻服务器压力?
- if (processVerificationMaxCount != 0) {
- processVerificationFailureCount++;
- //达到最大次数
- if (processVerificationFailureCount == processVerificationMaxCount) {
- [self processVerificationSignOut];
- return;
- }
- }
- }
- [self showAlertTakePhotoFailWithStr:root[@"msg"]];
- return;
- }
- //过程验证不存在这种情况。就不管吧。但是为了防止服务器给一个惊喜 还是判断一下
- //code = 2;已经签到成功了(可能因为上一次请求网络延迟,服务器已经签到成功,手机没有get到这个信息)
- if (onProcessVerification && [root[@"code"] isEqualToString:@"2"]) {
- [self getCurrentState];
- return;
- }
- //code = 0;正常成功状态。
- if ([root[@"code"] isEqualToString:@"0"]) {
- if (onProcessVerification) {
- //过程人脸比对成功 恢复计时;
- photoSeconds = 0;//通过验证
- onProcessVerification = NO;
- self.currentStep = _step5;
-
- //过程中不需要再发送重要指令。该定时器主要处理拍照命令
- if (signInTimer) {
- [signInTimer invalidate];
- signInTimer = nil;
- }
-
- [self addBlueToothLabelWithContent:@"过程验证成功,恢复计时" mp3:nil];
- [Tools playAudioWithString:[NSString stringWithFormat:@"过程验证成功,恢复计时"]];
- }else{
- //code = 0;正常成功状态。
- //更新数据
- [gatherTrainDic setValue:root[@"body"][@"CreditRation"] forKey:@"allNeed"];//总需学时
- [gatherTrainDic setValue:root[@"body"][@"DurationSum"] forKey:@"allCompelet"];//已完成学时
- CGFloat seconds = [[NSString stringWithFormat:@"%@",root[@"body"][@"Duration"]] floatValue]*60;
- [gatherTrainDic setValue:[NSString stringWithFormat:@"%f",seconds] forKey:@"allTime"];//当天学时
- [self saveGatherTrainDic];
-
- //人脸比对成功服务器签到 开始计时
- [self beginTimer];
- }
- }
-
- }];
- }
- - (void)processVerificationSignOut{
- self.currentStep = _step6;
- //先关闭定时器
- if (timer.isValid) {
- [timer invalidate];
- timer = nil;
- myDelegate.mnPeriodVC = nil;
- }
-
- //关闭蓝牙连接
- [self closeBlueTooth];
-
- [gatherTrainDic setValue:@"2" forKey:@"isOver"];
- [self saveGatherTrainDic];
-
- minuteTrainArray = [DB_Helper quearyTrainWithClassId:gatherTrainDic[@"classId"] type:mnTableName];
- if (minuteTrainArray.count > 0) {
-
- [self uploadAppTrainPlWithSignOut:YES];
- }else{
- [self signOut];
- }
- }
- //上传分钟学时(批量) 这里要判断一下是否是最后签退过来的要做上传提示
- - (void)uploadAppTrainPlWithSignOut:(BOOL)isSignOut
- {
- if (![Util connectedToNetWork]) {
- if (isSignOut) {
- _step6.status = ClickStatusHighlighted;
- showMsgUnconnect();
- }
- [dateFormatter setDateFormat:@"HH:mm"];
- NSString *timeString = [dateFormatter stringFromDate:[NSDate date]];
- [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 学时上传失败!",timeString]];
- [mainTableView reloadData];
- return;
- }
-
- NSMutableArray *mArr = [NSMutableArray new];;
- for (NSDictionary *dic in minuteTrainArray) {
-
- NSMutableDictionary * csDic = [NSMutableDictionary new];
- [csDic setValue:defUser.userDict[@"outId"] forKey:@"stuId"];
- [csDic setValue:dic[@"trainNum"] forKey:@"trainNo"];
- [csDic setValue:dic[@"classCode"] forKey:@"subjcode"];
- [csDic setValue:dic[@"classId"] forKey:@"classId"];
- [csDic setValue:dic[@"gps"] forKey:@"recordTime"];
- [csDic setValue:defUser.userDict[@"city"] forKey:@"dqbh"];
-
- [mArr addObject:csDic];
- }
- NSError *error = nil;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:mArr
- options:NSJSONWritingPrettyPrinted
- error:&error];
- NSString *jsonString = nil;
- if ([jsonData length] != 0 && error == nil){
- // 使用这个方法的返回,我们就可以得到想要的JSON串
- jsonString = [[NSString alloc] initWithData:jsonData
- encoding:NSUTF8StringEncoding];
- }else{
- NSLog(@"数据解析异常:%@",error);
- }
-
-
- NSMutableArray *arr=[NSMutableArray array];
- [arr addPro:@"trains" Value:jsonString];
-
- NSString* method = @"uploadTrainMinPl";
- if (isSignOut) {
- [MBProgressHUD showMessage:@"正在补传学时" toView:self.view];
- [self addBlueToothLabelWithContent:@"正在补传学时" mp3:nil];
- }
-
- NSString *timeString = [dateFormatter stringFromDate:[NSDate date]];
- [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"];
-
- if (!root) {
-
- if (isSignOut) {
- _currentStep.status = ClickStatusHighlighted;
- [Tools playAudioWithString:@"学时补传失败"];
- [self addBlueToothLabelWithContent:@"学时补传失败" mp3:nil];
- }
- [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 学时上传失败!",timeString]];
- return ;
- }
-
- if ([root[@"code"] isEqualToString:@"1"]) {
-
- if (isSignOut) {
- _currentStep.status = ClickStatusHighlighted;
- [Tools playAudioWithString:root[@"msg"]];
- showMsgByAlert(self, root[@"msg"]);
- [self addBlueToothLabelWithContent:[NSString stringWithFormat:@"学时补传失败:%@",root[@"msg"]] mp3:nil];
- }
- [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 学时上传失败!",timeString]];
- return;
- }
-
- if ([root[@"code"] isEqualToString:@"2"]) {//超过规定时间 服务器通知签退
- [self haveSignOutByUser:NO];
- return;
- }
-
- [dataSourceArray addObject:[NSString stringWithFormat:@"0%@ 学时上传成功!",timeString]];
-
- [DB_Helper deleteTrainWithClassId:gatherTrainDic[@"classId"] type:mnTableName];
-
- if (isSignOut) {
- [self addBlueToothLabelWithContent:@"学时补传成功" mp3:nil];
- [self signOut];
- }else{
- [mainTableView reloadData];
- }
-
- }];
- }
- - (void)signOut{
-
- if (![Util connectedToNetWork]) {
- _step6.status = ClickStatusHighlighted;
- showMsgUnconnect();
- return;
- }
-
- NSMutableArray *arr=[NSMutableArray array];
- [arr addPro:@"stuId" Value:defUser.userDict[@"outId"]];
- [arr addPro:@"dqbh" Value:defUser.userDict[@"city"]];
- [arr addPro:@"subjcode" Value:classCode];
- [arr addPro:@"classId" Value:classId];//签退如果没有这个东西 这段学时会无效
- [arr addPro:@"lng" Value:[NSString stringWithFormat:@"%f",myCoordinate.longitude]];
- [arr addPro:@"lat" Value:[NSString stringWithFormat:@"%f",myCoordinate.latitude]];
-
- NSString* method = @"uploadMnqSignOut";
- [MBProgressHUD showLoadToView:self.view];
- [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
-
- [MBProgressHUD hideHUDForView:self.view animated:YES];
- if (!root) {
- _step6.status = ClickStatusHighlighted;
- ShowMsg(@"请求失败");
- [Tools playAudioWithString:@"请求失败"];
- return ;
- }
-
- if ([root[@"code"] isEqualToString:@"90"]) {//缺少outid
- UIAlertController *alertFind = [UIAlertController alertControllerWithTitle:nil message:root[@"msg"] preferredStyle:UIAlertControllerStyleAlert];
-
- [alertFind addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
-
- [LoginViewController loginFromVC:self];
- }]];
- [self presentViewController:alertFind animated:true completion:nil];
- return;
- }
-
- if ([root[@"code"] isEqualToString:@"1"]) {
- _step6.status = ClickStatusHighlighted;
- ShowMsg(root[@"msg"]);
- [Tools playAudioWithString:root[@"msg"]];
- return;
- }
-
- [self haveSignOutByUser:YES];
-
- }];
- }
-
- //获取当前训练状态;
- -(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"]) {
-
- /*模拟训练状态判断
- 0 成功获取学员信息
- 1 学员还未在模拟器签到
- 2.已登录,未签到(未进行人脸验证)
- 3 无法获取到当前训练科目(人脸比对验证通过,但是没有上传任何学时)
- 4 隔日签到记录
- 5 分钟学时科目异常
- */
- NSString *status = [NSString stringWithFormat:@"%@",root[@"body"][@"mn"][@"TYPE"]];
-
- //获取到状态
- if ([status integerValue] == 0) {
-
- [self beginTimer];
- }else{
- //既然人脸比对结果提示已经在训练中了 就不该有其它状态,如果还是发生了,就作比对结果返回异常处理
- [self showAlertTakePhotoFailWithStr:@"异常情况"];
- }
-
- }else{
- ShowMsg(root[@"msg"]);
- }
-
- }];
-
- }
- #pragma mark - 签退成功后的操作
- - (void)haveSignOutByUser:(BOOL)isByUser{
-
- if (isByUser == NO) {//如果不是用户操作的签退
- self.currentStep = _step6;
- //先关闭定时器
- if (timer.isValid) {
- [timer invalidate];
- timer = nil;
- myDelegate.mnPeriodVC = nil;
- }
-
- //关闭蓝牙连接
- [self closeBlueTooth];
-
- [gatherTrainDic setValue:@"2" forKey:@"isOver"];
- [self saveGatherTrainDic];
- }
-
- //语音提示
- NSString *alertMessage = @"模拟计时已签退,本次计时结束";
- if (processVerificationFailureCount == processVerificationMaxCount && processVerificationFailureCount != 0) {
- alertMessage = [NSString stringWithFormat:@"本次计时,过程验证失败次数%ld次,计时结束",processVerificationFailureCount];
- [self addBlueToothLabelWithContent:alertMessage mp3:@"mn_blueToothQuit.mp3"];
-
- }else{
- [self addBlueToothLabelWithContent:@"模拟计时已签退,本次计时结束" mp3:@"mn_blueToothQuit.mp3"];
- }
-
- [DB_Helper deleteAllTrainWithType:mnTableName];
- //将本地状态置为结束
- [gatherTrainDic setValue:@"1" forKey:@"isOver"];
- [gatherTrainDic removeObjectForKey:@"classId"];
- [gatherTrainDic removeObjectForKey:@"subject"];
- [self saveGatherTrainDic];
-
- //关闭学时状态显示
- [dataSourceArray removeAllObjects];
- [mainTableView reloadData];
- trainView.hidden = YES;
-
- //timeLabel.text = @"00:00:00" ;
-
- //先关闭定时器
- if (timer.isValid) {
- [timer invalidate];
- timer = nil;
- }
- myDelegate.mnPeriodVC = nil;
- myDelegate.mnTrainType = @"1";
-
-
- //清空detailLab(top)
- //for (UILabel *detailLab in detailLabArr) {
- //detailLab.text = @"";
- //}
-
-
- UIAlertView *servicesDisabledAlert = [[UIAlertView alloc] initWithTitle:@"提醒" message:[NSString stringWithFormat:@"%@.\n(ps:手机蓝牙可以关掉啦)",alertMessage] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
- servicesDisabledAlert.delegate = self;
- [servicesDisabledAlert show];
-
- }
- //仅针对“手机蓝牙可以关掉啦” ->只有它设置了代理为self才会触发下面的方法 ->退出当前页面
- -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
- [self goBackByNavigation];//如果不是当前vc,测试也ok
- }
-
- #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;
- }
- @end
|