ViewController.m 98 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706
  1. //
  2. // ViewController.m
  3. // JSJPCoach
  4. //
  5. // Created by apple on 2017/3/10.
  6. // Copyright © 2017年 Danson. All rights reserved.
  7. //
  8. #import "ViewController.h"
  9. #import "PersonalVC.h"
  10. #import "PeriodVC.h"
  11. #import "ExploreVC.h"
  12. #import "ModelVC.h"
  13. #import "PeriodStuCell.h"
  14. #import "DES3Util.h"
  15. #import "LoginVC.h"
  16. #import "BindVC.h"
  17. #import "STButton.h"
  18. #import "MBProgressHUD+Add.h"
  19. #import "MJRefresh.h"
  20. #import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件
  21. #import <BMKLocationkit/BMKLocationComponent.h>//引入定位功能所有的头文件
  22. //蓝牙
  23. #import <CoreBluetooth/CoreBluetooth.h>
  24. typedef NS_ENUM(NSInteger, RQCoachSignStatus) {
  25. /// 未带教
  26. RQCoachSignStatusNone = 0,
  27. /// 手机实操
  28. RQCoachSignStatusPhoneActual = 1,
  29. /// 模拟
  30. RQCoachSignStatussSimulation = 2,
  31. /// 实操终端
  32. RQCoachSignStatusTerminalActual = 3,
  33. /// 集中训练
  34. RQCoachSignStatusCentralizedTraining = 4,
  35. /// 预约
  36. RQCoachSignStatusSubscribe = 5,
  37. };
  38. @interface ViewController ()<UIScrollViewDelegate,UITableViewDelegate,UITableViewDataSource,BMKLocationManagerDelegate,UIAlertViewDelegate,CBCentralManagerDelegate,CBPeripheralDelegate>
  39. {
  40. UITextField *BindNumberField;
  41. UITextField *RegistField;
  42. UIView *btnBar; //分段选择器下方的滚动条。
  43. UIButton *periodBtn;
  44. UIButton *modelBtn;
  45. UIButton *overBtn;
  46. UIView *periodView;
  47. UITableView *periodTableView;
  48. UIScrollView *noticeScroll;
  49. UILabel *allTimeLabel, *valueTimeLabel, *invalidTimeLabel, *waitTimeLabel;
  50. CGFloat periodViewH;
  51. CGPoint lastOffset; //保存scroll主页面。最后一次滚动的offset
  52. NSMutableArray *stuListArray;
  53. NSMutableArray *uploadGPSArray;
  54. //注意事项
  55. UIView *noticeView;
  56. UIButton *isForeverBtn;
  57. //计时
  58. NSTimer *timer;
  59. UILabel *timerLabel;
  60. UIImageView *scanImgView;
  61. UIView *scanView;//二维码页面
  62. NSDictionary *stuSignInDic;
  63. BOOL isAfterDelay;
  64. BOOL isOverScan;
  65. int timeI;
  66. BOOL isSignInState;
  67. BOOL isTerminal;//是否在终端实操计时
  68. //上传位置定时器
  69. NSTimer *uploadGpsTimer;
  70. CLLocationCoordinate2D myLocation;//实操用
  71. CLLocationCoordinate2D coachLocation;//模拟用
  72. NSInteger uploadCount;
  73. //蓝牙
  74. NSMutableArray<CBPeripheral *> *peripheralArray;
  75. NSString *peripheralName;
  76. BOOL isNeed;//如果为yes代表数据不完整 需要下次接收到的数据拼接
  77. NSString *lastData;//前边包的数据
  78. NSString *carUUID;
  79. BOOL isJudgeCarUUID;//如果不判断 教练直接签到计时 如果判断 就获取车架号
  80. }
  81. @property (assign, readwrite, nonatomic) RQCoachSignStatus coachSignStatus;
  82. @property(nonatomic,strong)BMKLocationManager *locationManager;
  83. @property(nonatomic,strong)UIScrollView *mainScroll;
  84. /**分段选择器的按钮
  85. */
  86. @property(nonatomic,strong)NSMutableArray *segBtnArray;
  87. /**用于使scroll和按钮联动
  88. */
  89. @property(nonatomic,assign)NSInteger pageIndex;
  90. //蓝牙
  91. @property (nonatomic, strong) CBCentralManager *cbcManager;
  92. /** 已连接的外设*/
  93. @property (nonatomic, strong) CBPeripheral *peripheral;
  94. /** 要写入的特征值*/
  95. @property (nonatomic, strong) CBCharacteristic *writeCharacteristic;
  96. /** 要读的特征值*/
  97. @property (nonatomic, strong) CBCharacteristic *readCharacteristic;
  98. @property (nonatomic, strong) UITableView *blueTableView;
  99. @end
  100. @implementation ViewController
  101. - (void)viewDidLoad {
  102. [super viewDidLoad];
  103. UIImageView *backImageView = [[UIImageView alloc] initWithFrame:kFrame];
  104. backImageView.image = [UIImage imageNamed:@"bgImage"];
  105. [self.view addSubview:backImageView];
  106. UIImageView *statusImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kSize.width, kStatusHeight + kSegmentHeight)];
  107. statusImageView.backgroundColor = RGB_COLOR(7, 11, 24);
  108. [backImageView addSubview:statusImageView];
  109. periodViewH = [defUser.userDict[@"cityId"] isEqualToString:@"3503"]? 0 : (kSize.height-kSafeAreaBottomHeight)/6.0;
  110. _pageIndex = 1;
  111. self.periodType = 3;//2018/9/18 默认为模拟带教
  112. isSignInState = NO;
  113. isTerminal = NO;
  114. stuListArray = [NSMutableArray array];
  115. uploadGPSArray = [NSMutableArray array];
  116. isJudgeCarUUID = YES;
  117. if ([[NSString stringWithFormat:@"%@",defUser.userDict[@"isJudge"]] isEqualToString:@"0"]) {
  118. isJudgeCarUUID = NO;
  119. }
  120. peripheralName = @"NONAME";
  121. //选择框
  122. NSArray *segTitleArray = @[@"我",@"预约",@"发现"];
  123. CGFloat segW = kSize.width/(segTitleArray.count);
  124. _segBtnArray = [NSMutableArray arrayWithCapacity:3];
  125. for (int i = 0; i<3; i ++)
  126. {
  127. UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(segW*i,kStatusHeight,segW,kSegmentHeight)];
  128. if (i == 1) {
  129. [button setImage:[UIImage imageNamed:@"carIcon"] forState:UIControlStateNormal];
  130. [button setImage:[[UIImage imageNamed:@"carIcon"] tint:defGreen] forState:UIControlStateSelected];
  131. [button setImageEdgeInsets:UIEdgeInsetsMake(2, (segW - 40)/2.0, 2, (segW - 40)/2.0)];
  132. button.selected = YES;
  133. }else{
  134. [button setTitle:[segTitleArray objectAtIndex:i] forState:UIControlStateNormal];
  135. [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  136. [button setTitleColor:defGreen forState:UIControlStateSelected];
  137. [button.titleLabel setFont:[UIFont scaleSize:Font18]];
  138. }
  139. [button addTarget:self action:@selector(segSelected:) forControlEvents:UIControlEventTouchUpInside];
  140. [button setTag:i];
  141. [self.view addSubview:button];
  142. [_segBtnArray addObject:button];
  143. }
  144. btnBar = [[UIView alloc] initWithFrame:CGRectMake(segW + 20, kStatusHeight + kSegmentHeight - 3, segW - 40, 3)];
  145. [btnBar setBackgroundColor:defGreen];
  146. [self.view addSubview:btnBar];
  147. //mainScroll
  148. CGFloat mainScrH = kSize.height - kNavOffSet - periodViewH - kSafeAreaBottomHeight;
  149. _mainScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, kNavOffSet, kSize.width, mainScrH)];
  150. _mainScroll.delegate = self;
  151. [_mainScroll setShowsHorizontalScrollIndicator:NO];
  152. [self.view addSubview:_mainScroll];
  153. PersonalVC *personalVC = [[PersonalVC alloc] initWithScrFrame:CGRectMake(0, 0, kSize.width, mainScrH)];
  154. [self addChildViewController:personalVC];
  155. [_mainScroll addSubview:personalVC.view];
  156. PeriodVC *periodVC = [[PeriodVC alloc] init];
  157. periodVC.view.frame = CGRectMake(kSize.width, 0, kSize.width, mainScrH);
  158. [self addChildViewController:periodVC];
  159. [_mainScroll addSubview:periodVC.view];
  160. periodView = periodVC.view;
  161. [self resetPeriodView];
  162. ExploreVC * exploreVC = [[ExploreVC alloc] initWithScrFrame:CGRectMake(kSize.width*2, 0, kSize.width, mainScrH)];
  163. [self addChildViewController:exploreVC];
  164. [_mainScroll addSubview:exploreVC.view];
  165. NSLog(@"%@",_mainScroll.subviews);
  166. [_mainScroll setContentSize:CGSizeMake(kSize.width * 3, 0)];
  167. [_mainScroll setContentOffset:CGPointMake(kSize.width, _mainScroll.contentOffset.y) animated:NO];
  168. [_mainScroll setPagingEnabled:YES];
  169. [_mainScroll setDecelerationRate:.2]; //用于使scroll快速完成减速
  170. //底部按钮 3、4、5 tag
  171. CGFloat x, y, w, h;
  172. y = kSize.height - periodViewH - kSafeAreaBottomHeight;
  173. h = periodViewH - 20;
  174. if (h > 80) {
  175. h = 80;
  176. y += (periodViewH - 100)/2.0;
  177. }
  178. w = h;
  179. x = kSize.width/2.0 - w/2.0;
  180. periodBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  181. periodBtn.frame = setDIYFrame;
  182. [periodBtn setRound];
  183. periodBtn.backgroundColor = defGreen;
  184. [periodBtn setTitle:@"带教" textColor:[UIColor whiteColor] font:Font18 fotState:UIControlStateNormal];
  185. [periodBtn setTitle:@"带教中" textColor:[UIColor whiteColor] font:Font18 fotState:UIControlStateSelected];
  186. [periodBtn target:self Tag:3];
  187. [self.view addSubview:periodBtn];
  188. periodBtn.hidden = [defUser.userDict[@"cityId"] isEqualToString:@"3503"];
  189. x = 20;
  190. w = w/1.46;
  191. y += (h - w)/2 + 5;
  192. h = w;
  193. modelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  194. modelBtn.frame = setDIYFrame;
  195. [modelBtn setRound];
  196. modelBtn.backgroundColor = RGB_COLOR(145, 160, 175);
  197. [modelBtn setTitle:@"模式" textColor:[UIColor blackColor] font:Font16 fotState:UIControlStateNormal];
  198. [modelBtn target:self Tag:4];
  199. //@lee-mark:暂时移除模式
  200. [self.view addSubview:modelBtn];
  201. modelBtn.hidden = [defUser.userDict[@"cityId"] isEqualToString:@"3503"];
  202. x = kSize.width - w - 20;
  203. overBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  204. overBtn.frame = setDIYFrame;
  205. [overBtn setRound];
  206. overBtn.backgroundColor = RGB_COLOR(145, 160, 175);
  207. [overBtn setTitle:@"结束" textColor:newTitleColor font:Font16 fotState:UIControlStateNormal];
  208. [overBtn target:self Tag:5];
  209. [self.view addSubview:overBtn];
  210. [RACObserve(defUser, isLogin) subscribeNext:^(id _Nullable x) {
  211. [self updateData];
  212. }];
  213. [RACObserve(self, periodType) subscribeNext:^(id _Nullable x) {
  214. if (self.periodType != 0) {//选择过模式了0.0
  215. for (UIView *view in periodView.subviews) {
  216. if ([view isKindOfClass:[UILabel class]]) {
  217. UILabel *label = (UILabel *)view;
  218. if ([label.text containsString:@"带教类型"]) {
  219. if (self.periodType == 3) {
  220. label.text = @"带教类型:模拟";
  221. }else{
  222. switch (self.coachSignStatus) {
  223. case RQCoachSignStatusTerminalActual:
  224. label.text = [NSString stringWithFormat:@"带教类型:实操终端"];
  225. break;
  226. default: {
  227. self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"];
  228. NSString *subject = [self.periodDic[@"subject"] isEqualToString:@"2"] ? @"科二实操" : @"科三实操";
  229. label.text = [NSString stringWithFormat:@"带教类型:%@",subject];
  230. break;
  231. }
  232. }
  233. }
  234. }
  235. if ([label.text containsString:@"价格"]) {
  236. if (self.periodType == 3) {
  237. label.text = @"价格:免费";
  238. }else{
  239. switch (self.coachSignStatus) {
  240. case RQCoachSignStatusTerminalActual:
  241. label.text = @"";
  242. break;
  243. default: {
  244. NSString *priceString = self.periodDic[@"price"];
  245. if ([priceString containsString:@"免费"]) {
  246. priceString = @"价格:免费";
  247. }else{
  248. priceString = [NSString stringWithFormat:@"价格:%@元/时",priceString];
  249. }
  250. label.text = priceString;
  251. }
  252. break;
  253. }
  254. }
  255. }
  256. }
  257. }
  258. }
  259. }];
  260. }
  261. - (void)viewWillAppear:(BOOL)animated {
  262. [super viewWillAppear:animated];
  263. self.navigationController.navigationBarHidden = YES;
  264. [self updateData];
  265. }
  266. - (void)updateData {
  267. //如果登陆过之后 要更新信息
  268. if (defUser.isLogin && defUser.userDict[@"outId"] && defUser.userDict[@"cityId"]) {
  269. // [self getCoachSignForTrain];//判断是否签到按钮
  270. [self getCoachSignStatus];//获取是否有带教学员
  271. }else {
  272. periodBtn.selected = NO;
  273. isTerminal = NO;
  274. overBtn.hidden = YES;
  275. }
  276. }
  277. -(void)viewWillDisappear:(BOOL)animated
  278. {
  279. [super viewWillDisappear:animated];
  280. self.navigationController.navigationBarHidden = NO;
  281. }
  282. /**
  283. 调用时间:确定带教成功 有学员列表 或者恢复带教 有学员列表 模拟有点特殊 没有学员列表也可以是带教中 只要生成了二维码就调这个接口
  284. 要做的事情:更改底部按钮状态 初始化计时页面 开启位置上传
  285. */
  286. - (void)initPeriodBar
  287. {
  288. periodBtn.selected = YES;
  289. overBtn.hidden = NO;
  290. //初始化计时面板
  291. if (periodView) {
  292. for (UIView *view in periodView.subviews) {
  293. [view removeFromSuperview];
  294. }
  295. }
  296. CGFloat x,y,w,h;
  297. w = kSize.width;
  298. if (self.periodType == 3) {//模拟
  299. x = y = 20;
  300. w -= 2*x;
  301. h = 30;
  302. UILabel *label = [[UILabel alloc] setxywh];
  303. [label setText:@"带教类型:模拟" Font:Font16 TextColor:newTitleColor];
  304. [periodView addSubview:label];
  305. y += h + 10;
  306. label = [[UILabel alloc] setxywh];
  307. [label setText:@"带教学员:" Font:Font16 TextColor:newTitleColor];
  308. [periodView addSubview:label];
  309. x = 0;
  310. y += h;
  311. h = _mainScroll.height - y;
  312. w = kSize.width;
  313. periodTableView = [[UITableView alloc] initWithFrame:setDIYFrame style:UITableViewStylePlain];
  314. periodTableView.backgroundColor = [UIColor clearColor];
  315. periodTableView.delegate = self;
  316. periodTableView.dataSource = self;
  317. periodTableView.rowHeight = 80;
  318. [periodView addSubview:periodTableView];
  319. periodTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
  320. [self getCoachSignStatus];
  321. [self getCoachSignStuRecordsMnWithIsOver:YES];
  322. }];
  323. }else{
  324. x = 10;
  325. y = 20;
  326. w -= 2*x;
  327. h = 30;
  328. // UILabel *label = [[UILabel alloc] setxywh];
  329. // [label setText:@"带教信息" Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentCenter];
  330. // [periodView addSubview:label];
  331. self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"];
  332. NSString *subject = @"科二实操";
  333. if ([self.periodDic isKindOfClass:[NSDictionary class]]) {
  334. subject = [self.periodDic[@"subject"] isEqualToString:@"2"] ? @"科二实操" : @"科三实操";
  335. }
  336. UILabel *label = [[UILabel alloc] setxywh];
  337. [label setText:[NSString stringWithFormat:@"带教类型:%@",subject] Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentLeft];
  338. [periodView addSubview:label];
  339. NSString *priceString = self.periodDic[@"price"];
  340. if ([priceString containsString:@"免费"]) {
  341. priceString = @"价格:免费";
  342. }else{
  343. priceString = [NSString stringWithFormat:@"价格:%@元/时",priceString];
  344. }
  345. label = [[UILabel alloc] setxywh];
  346. [label setText:priceString Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentRight];
  347. [periodView addSubview:label];
  348. y += h;
  349. label = [[UILabel alloc] setxywh];
  350. [label setText:@"带教学员:" Font:Font16 TextColor:newTitleColor];
  351. [periodView addSubview:label];
  352. x = 0;
  353. y += h;
  354. w = kSize.width;
  355. h = 80;
  356. UIView *view = [[UIView alloc] setxywh];
  357. [periodView addSubview:view];
  358. PeriodStuCell *cell = [[PeriodStuCell alloc] initWithFrame:CGRectMake(0, 0, w, h)];
  359. cell.nameLabel.text = stuSignInDic[@"TSO_NAME"];
  360. if ([stuSignInDic[@"TSO_PHONE"] length] > 0) {
  361. NSMutableAttributedString *abs = [[NSMutableAttributedString alloc]initWithString:stuSignInDic[@"TSO_PHONE"]];
  362. [abs beginEditing];
  363. //字体大小
  364. [abs addAttribute:NSFontAttributeName
  365. value:[UIFont scaleSize:Font17]
  366. range:NSMakeRange(0, [stuSignInDic[@"TSO_PHONE"] length])];
  367. //字体颜色
  368. [abs addAttribute:NSForegroundColorAttributeName
  369. value:canClickColor
  370. range:NSMakeRange(0, [stuSignInDic[@"TSO_PHONE"] length])];
  371. //下划线
  372. [abs addAttribute:NSUnderlineStyleAttributeName
  373. value:@(NSUnderlineStyleSingle)
  374. range:NSMakeRange(0, [stuSignInDic[@"TSO_PHONE"] length])];
  375. cell.telLabel.attributedText = abs;
  376. }else{
  377. cell.telLabel.text = stuSignInDic[@"TSO_PHONE"];
  378. }
  379. cell.imgPath = stuSignInDic[@"TSO_PHOTO_PATH"];
  380. [view addSubview:cell];
  381. y += h;
  382. h = 25;
  383. w = kSize.width/4.0;
  384. NSArray *titles = @[@"总时长",@"有效时长",@"无效时长",@"待审核"];
  385. NSArray *colors = @[newTitleColor,[UIColor greenColor],[UIColor redColor],defGreen];
  386. NSMutableArray *labels = [NSMutableArray arrayWithCapacity:4];
  387. for (int i = 0; i < 4; i ++) {
  388. label = [[UILabel alloc] initWithFrame:CGRectMake(i*w, y, w, h)];
  389. label.backgroundColor = [UIColor colorWithWhite:.7 alpha:.2];
  390. [label setText:titles[i] Font:Font16 TextColor:newTitleColor Alignment:NSTextAlignmentCenter];
  391. [periodView addSubview:label];
  392. label = [[UILabel alloc] initWithFrame:CGRectMake(i*w, y + h, w, h)];
  393. [label setText:@"0分钟" Font:Font16 TextColor:colors[i] Alignment:NSTextAlignmentCenter];
  394. [periodView addSubview:label];
  395. [labels addObject:label];
  396. if (i != 0) {
  397. [label addViewWithRect:CGRectMake(i*w, y, 1, 2*h) Color:newBackGroundColor];
  398. }
  399. }
  400. allTimeLabel = labels[0];
  401. valueTimeLabel = labels[1];
  402. invalidTimeLabel = labels[2];
  403. waitTimeLabel = labels[3];
  404. // [allTimeLabel addViewWithRect:CGRectMake(20, y, kSize.width - 40, 1) Color:newBackGroundColor];
  405. [allTimeLabel addViewWithRect:CGRectMake(20, y + 2*h - 1, kSize.width - 40, 1) Color:newBackGroundColor];
  406. y += 2*h;
  407. w = kSize.width;
  408. h = _mainScroll.height - y + 1;
  409. periodTableView = [[UITableView alloc] initWithFrame:setDIYFrame style:UITableViewStylePlain];
  410. periodTableView.backgroundColor = [UIColor clearColor];
  411. periodTableView.delegate = self;
  412. periodTableView.dataSource = self;
  413. periodTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  414. [periodView addSubview:periodTableView];
  415. //开启后台上传位置
  416. // [self beginUploadCoachGPS];
  417. myDelegate.isPeriodIng = YES;
  418. }
  419. }
  420. /** 将periodView置回未计时状态
  421. */
  422. - (void)resetPeriodView
  423. {
  424. if (periodView) {
  425. for (UIView *view in periodView.subviews) {
  426. [view removeFromSuperview];
  427. }
  428. }
  429. //在这里将上传位置信息全清空
  430. [uploadGPSArray removeAllObjects];
  431. self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"];
  432. NSString *subject = @"科二实操";
  433. if ([self.periodDic isKindOfClass:[NSDictionary class]]) {
  434. subject = [self.periodDic[@"subject"] isEqualToString:@"2"] ? @"科二实操" : @"科三实操";
  435. }
  436. UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 30, kSize.width - 40, 30)];
  437. [label setText:[NSString stringWithFormat:@"带教类型:%@",subject] Font:Font18 TextColor:newTitleColor];
  438. [periodView addSubview:label];
  439. label = [[UILabel alloc] initWithFrame:CGRectMake(20, 60, kSize.width - 40, 30)];
  440. [label setText:@"价格:免费" Font:Font18 TextColor:newTitleColor];
  441. [periodView addSubview:label];
  442. NSString *title = @"查看注意事项";
  443. CGFloat w = [title sizeForFont:Font17].width + 10;
  444. UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(kSize.width - w - 20, 60, w, 30)];
  445. [button setTitle:@"查看注意事项" textColor:defGreen font:Font17 fotState:UIControlStateNormal];
  446. [button setTitle:@"隐藏注意事项" textColor:defGreen font:Font17 fotState:UIControlStateSelected];
  447. [button target:self Tag:8];
  448. [periodView addSubview:button];
  449. [button addViewWithRect:CGRectMake(kSize.width - w - 20, 85, w, 1) Color:defGreen];
  450. CGFloat y = 120;
  451. CGFloat h = kSize.width/3.0 - 10;
  452. UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, y, kSize.width - 40, h)];
  453. imageView.image = [UIImage imageNamed:@"periodStep.png"];
  454. [imageView borderCornorRadios:5];
  455. [periodView addSubview:imageView];
  456. NSString *string = @"教练您好:\n 本系统采用分钟学时的方法计算学时,所以请您在带教的过程中注意以下几点: \n\n1、确保您的手机能正常联网,3G以上网络能给您带来更好的效果 \n\n2、带教过程中,规定不允许离开训练场和打电话,系统会实时采集您的位置,用于学员分钟学时有效性判断,请确保网络正常连接,系统允许临时接电话,默认15分钟内,具体按管理部门规定,如果超过规定时间,学员的分钟学时全部无效 \n\n3、如果您选择计时收费,请确认您已经选择好了培训科目和培训价格,否则系统无法进行计费训练 \n\n4、培训结束后,学员可以对您的带教进行评价或投诉,一旦发生投诉,系统将会上传至省监管平台,将会影响您的信誉 \n\n5、为确保学员分钟学时有效,请确保您跟学员的位置在规定范围内,否则学员分钟学时无效 \n\n6、如果是收费训练,在训练结束后,可以在我的订单中选择收款,生成二维码,学员扫码支付成功后,学员学时有效,请提醒您的学员及时支付,否则,学时将不会计入有效学时";
  457. CGFloat noticeH = [string heightForWid:kSize.width - 40 Font:Font17] + 10;
  458. y += h + 10;
  459. noticeScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, y, kSize.width, _mainScroll.height - y)];
  460. [periodView addSubview:noticeScroll];
  461. noticeScroll.contentSize = CGSizeMake(kSize.width, noticeH + 30);
  462. UILabel *noticeLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, kSize.width - 40, noticeH)];
  463. [noticeLabel setText:string Font:Font17 TextColor:backGroundColor];
  464. noticeLabel.numberOfLines = 0;
  465. [noticeScroll addSubview:noticeLabel];
  466. noticeScroll.hidden = YES;
  467. }
  468. - (void)initNoticeView
  469. {
  470. noticeView = [[UIView alloc] initWithFrame:kFrame];
  471. noticeView.backgroundColor = [UIColor colorWithWhite:.01 alpha:.4];
  472. [[UIApplication sharedApplication].keyWindow addSubview:noticeView];
  473. NSString *noticeString = @"教练您好:\n\n 本系统采用分钟学时的方法计算学时,所以请您在带教的过程中注意以下几点: \n\n1、确保您的手机能正常联网,3G以上网络能给您带来更好的效果 \n\n2、带教过程中,规定不允许离开训练场和打电话,系统会实时采集您的位置,用于学员分钟学时有效性判断,请确保网络正常连接,系统允许临时接电话,默认15分钟内,具体按管理部门规定,如果超过规定时间,学员的分钟学时全部无效 \n\n3、如果您选择计时收费,请确认您已经选择好了培训科目和培训价格,否则系统无法进行计费训练 \n\n4、培训结束后,学员可以对您的带教进行评价或投诉,一旦发生投诉,系统将会上传至省监管平台,将会影响您的信誉 \n\n5、为确保学员分钟学时有效,请确保您跟学员的位置在规定范围内,否则学员分钟学时无效 \n\n6、如果是收费训练,在训练结束后,可以在我的订单中选择收款,生成二维码,学员扫码支付成功后,学员学时有效,请提醒您的学员及时支付,否则,学时将不会计入有效学时";
  474. CGFloat noticeH = [noticeString heightForWid:kSize.width - 80 Font:Font17] + 10;
  475. UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(20, kNavOffSet, kSize.width - 40, kSize.height - kNavOffSet - 100)];
  476. scrollView.contentSize = CGSizeMake(kSize.width - 40, noticeH + 50);
  477. scrollView.backgroundColor = newBackGroundColor;
  478. [noticeView addSubview:scrollView];
  479. [scrollView addViewWithRect:CGRectMake(20, scrollView.y + scrollView.height, scrollView.width, 1)];
  480. UILabel *noticeLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, kSize.width - 80, noticeH)];
  481. noticeLabel.numberOfLines = 0;
  482. [noticeLabel setText:noticeString Font:Font17 TextColor:newTitleColor];
  483. [scrollView addSubview:noticeLabel];
  484. UIView *btnView = [[UIView alloc] initWithFrame:CGRectMake(20, scrollView.y + scrollView.height + 1, scrollView.width, 40)];
  485. btnView.backgroundColor = newBackGroundColor;
  486. [noticeView addSubview:btnView];
  487. NSArray *titles = @[@"不再显示",@"不同意",@"同意"];
  488. CGFloat w = scrollView.width/4.0;
  489. for (int i = 0; i < 3; i ++) {
  490. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  491. if (i == 0) {
  492. btn.frame = CGRectMake(0, 0, 2*w, 40);
  493. }else{
  494. btn.frame = CGRectMake(w + i*w, 0, w, 40);
  495. }
  496. [btn setTitle:titles[i] textColor:newTitleColor font:Font18 fotState:UIControlStateNormal];
  497. [btn target:self Tag:20 + i];
  498. [btnView addSubview:btn];
  499. if (i == 0) {
  500. isForeverBtn = btn;
  501. }
  502. }
  503. [isForeverBtn addViewWithRect:CGRectMake(2*w - 1, 0, 1, 40) Color:newSubTitleColor];
  504. [isForeverBtn addViewWithRect:CGRectMake(3*w - 1, 0, 1, 40) Color:newSubTitleColor];
  505. }
  506. - (void)btnClick:(UIButton *)sender
  507. {
  508. if (!defUser.isLogin) {
  509. [LoginVC loginFromVC:self];
  510. return ;
  511. }
  512. //3 带教 4 模式。 5结束
  513. if (sender.tag == 3) {
  514. if (isTerminal) {
  515. //正在终端带教中
  516. ShowMsg(@"正在终端带教学员,无法进行此操作");
  517. [Tools playAudioWithString:@"正在终端带教学员,请在终端投屏中查看带教信息"];
  518. return;
  519. }
  520. if (![sender isKindOfClass:[STButton class]]) {
  521. //注意事项
  522. if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"isShowNotice"] isKindOfClass:[NSString class]]) {
  523. if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"isShowNotice"] isEqualToString:@"doNotShowNotice"]) {
  524. [self initNoticeView];
  525. return;
  526. }
  527. }else{
  528. [self initNoticeView];
  529. return;
  530. }
  531. }
  532. //判断是否绑定(取消绑定IMIE)
  533. // if ([defUser.userDict[@"city"] isEqualToString:@"3503"]) {
  534. //
  535. // }else {
  536. // if ([defUser.userDict[@"imei"] length] > 0) {
  537. // if (![defUser.userDict[@"imei"] isEqualToString:[Tools getIDFV]]) {
  538. // ShowMsg(@"账号与绑定手机不匹配,请用本人手机带教学员");
  539. // [Tools playAudioWithString:@"账号与绑定手机不匹配,请用本人手机带教学员"];
  540. // return;
  541. // }
  542. // }else{
  543. // [self goToBindVC];
  544. // return;
  545. // }
  546. // }
  547. //判断是否注册车辆
  548. [self doTeach];
  549. return;
  550. }
  551. if (sender.tag == 4) {
  552. //判断是否可以选择模式 带教中 不能选择模式
  553. if (periodBtn.selected) {
  554. ShowMsg(@"正在带教中,不能进行此操作");
  555. return;
  556. }
  557. ModelVC *vc = [[ModelVC alloc] init];
  558. vc.superVC = self;
  559. vc.modalPresentationStyle = UIModalPresentationFullScreen;
  560. [self presentViewController:vc animated:YES completion:^{
  561. [Tools playAudioWithString:@"请选择带教模式"];
  562. }];
  563. return;
  564. }
  565. if (sender.tag == 5) {
  566. if (self.periodType == 3) {
  567. [self getCoachSignStuRecordsMnWithIsOver:YES];
  568. }else if (self.periodType == 2) {
  569. ModelVC *vc = [[ModelVC alloc] init];
  570. vc.modelPageType = RQModelPageTypeSubscribe;
  571. vc.superVC = self;
  572. [vc initWithCoachOrderBlock:^(NSDictionary *dic) {
  573. self.periodDic = dic;
  574. [self makeOverScanView];
  575. }];
  576. vc.modalPresentationStyle = UIModalPresentationFullScreen;
  577. [self presentViewController:vc animated:YES completion:^{
  578. [Tools playAudioWithString:@"请选择预约学员"];
  579. }];
  580. }else{
  581. // 取消判断IMEI
  582. // if ([defUser.userDict[@"imei"] length] > 0) {
  583. // if (![defUser.userDict[@"imei"] isEqualToString:[Tools getIDFV]]) {
  584. // ShowMsg(@"账号与绑定手机不匹配,请用本人手机带教学员");
  585. // [Tools playAudioWithString:@"账号与绑定手机不匹配,请用本人手机带教学员"];
  586. // return;
  587. // }
  588. // }
  589. [self makeOverScanView];
  590. }
  591. return;
  592. }
  593. //更新二维码
  594. if (sender.tag == 7) {
  595. NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600];
  596. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  597. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  598. NSString *dateString = [formatter stringFromDate:effectiveDate];
  599. NSString *scanString = @"";
  600. if (self.periodType == 1) {
  601. //实时
  602. 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 教练姓名 价格 科目 电话号码 终端设备号 蓝牙名称 有效时间
  603. }
  604. if (self.periodType == 2) {
  605. //预约
  606. 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
  607. }
  608. if (self.periodType == 3) {
  609. //模拟
  610. scanString = [NSString stringWithFormat:@"#JSDTMO#;imitSignIn;%@;%@;%f;%f;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],coachLocation.longitude,coachLocation.latitude,dateString];//标识符 type 教练outID 教练名字 教练经度 教练纬度 有效时间
  611. }
  612. if (isOverScan) {
  613. scanString = [NSString stringWithFormat:@"#JSDTMO#;signOut;%@;%@;%@",defUser.userDict[@"outId"],[stuSignInDic objectForKey:@"TSO_ID"],dateString];//参数分别是 type 教练outID 学生outID 有效时间
  614. }
  615. //NSLog(@"加密前---><>%@",scanString);
  616. scanString = [DES3Util encrypt:scanString];
  617. scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString];
  618. //NSLog(@"加密后--><>%@",scanString);
  619. UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f];
  620. qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)];
  621. scanImgView.image = qrcode;
  622. //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来
  623. timeI = 600;
  624. if (self.periodType == 3) {
  625. if (timer) {
  626. //如果存在 置为空
  627. [timer invalidate];
  628. timer = nil;
  629. }
  630. timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInImitate) userInfo:nil repeats:YES];
  631. }else{
  632. if (timer) {
  633. //如果存在 置为空
  634. [timer invalidate];
  635. timer = nil;
  636. }
  637. timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES];
  638. }
  639. return;
  640. }
  641. if (sender.tag == 8) {//显示 隐藏
  642. sender.selected = !sender.selected;
  643. if (sender.selected) {
  644. }
  645. noticeScroll.hidden = sender.selected ? NO : YES;
  646. //ShowMsg([NSString stringWithFormat:@"%@",sender.selected ? @"显示流程图":@"隐藏流程图"]);
  647. }
  648. if (sender.tag == 9) {//取消蓝牙连接 取消计时
  649. [self closeBlueTooth];
  650. return;
  651. }
  652. if (sender.tag == 20) {//是否还要显示
  653. sender.selected = !sender.selected;
  654. if (sender.selected) {
  655. sender.backgroundColor = defGreen;
  656. }else{
  657. sender.backgroundColor = [UIColor clearColor];
  658. }
  659. }
  660. if (sender.tag == 21) {
  661. [noticeView removeFromSuperview];
  662. }
  663. if (sender.tag == 22) {
  664. if (isForeverBtn.selected) {
  665. //不再显示 本地存个字段
  666. [[NSUserDefaults standardUserDefaults] setValue:@"doNotShowNotice" forKey:@"isShowNotice"];
  667. }
  668. [noticeView removeFromSuperview];
  669. //重新回到tag==3的触发事件中
  670. STButton *st = [[STButton alloc] init];
  671. st.tag = 3;
  672. [self btnClick:st];
  673. }
  674. }
  675. - (void)goToBindVC
  676. {
  677. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"您的账号还未绑定手机,绑定后当前手机只能用于当前帐号带教学员" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"去绑定",nil];
  678. alert.tag = 3;
  679. [alert show];
  680. }
  681. -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
  682. {
  683. if (alertView.tag == 2) {
  684. if (buttonIndex != alertView.cancelButtonIndex) {
  685. self.periodDic = @{@"subject":@"2",@"price":@"免费",@"periodType":@"1"};
  686. if ([alertView.message containsString:@"科三"]) {
  687. self.periodDic = @{@"subject":@"3",@"price":@"免费",@"periodType":@"1"};
  688. }
  689. [[NSUserDefaults standardUserDefaults] setObject:self.periodDic forKey:@"periodInfo"];
  690. self.periodType = 1;
  691. [self makeNoPlanScanView];
  692. }
  693. }
  694. if (alertView.tag == 3) {
  695. if (buttonIndex == alertView.cancelButtonIndex) {
  696. return;
  697. }else{
  698. BindVC *bindVC = [[BindVC alloc] init];
  699. [bindVC bindSuccessWithBlock:^{
  700. [self coachLogin];
  701. }];
  702. [self.navigationController pushViewController:bindVC animated:YES];
  703. }
  704. }
  705. if (alertView.tag == 4) {
  706. if (buttonIndex == alertView.cancelButtonIndex) {
  707. return;
  708. }else{
  709. //终端注册
  710. [self doDeviceReg];
  711. }
  712. }
  713. }
  714. //设置实操参数
  715. -(void)setPeriodDic:(NSDictionary *)periodDic {
  716. _periodDic = periodDic;
  717. [[NSUserDefaults standardUserDefaults] setObject:_periodDic forKey:@"periodInfo"];
  718. }
  719. #pragma mark - get
  720. -(BMKLocationManager *)locationManager{
  721. if (!_locationManager) {
  722. //初始化实例
  723. _locationManager = [[BMKLocationManager alloc] init];
  724. //设置delegate
  725. _locationManager.delegate = self;
  726. _locationManager.allowsBackgroundLocationUpdates = YES;
  727. //设置返回位置的坐标系类型 默认为国标
  728. _locationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;//百度经纬度坐标
  729. }
  730. return _locationManager;
  731. }
  732. #pragma mark tableview
  733. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  734. {
  735. if (tableView == _blueTableView) {
  736. return peripheralArray.count;
  737. }
  738. if (self.periodType == 3) {
  739. return stuListArray.count;
  740. }else{
  741. return uploadGPSArray.count;
  742. }
  743. }
  744. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  745. {
  746. if (tableView == _blueTableView) {
  747. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"peripheralCell"];
  748. if (peripheralArray.count > 0) {
  749. CBPeripheral *peripheeal = peripheralArray[indexPath.row];
  750. cell.textLabel.text = peripheeal.name;
  751. }
  752. return cell;
  753. }
  754. if (self.periodType == 3) {
  755. //模拟
  756. PeriodStuCell *cell = [tableView dequeueReusableCellWithIdentifier:@"moniStuCell"];
  757. if (cell == nil) {
  758. cell = [[PeriodStuCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"moniStuCell"];
  759. }
  760. cell.dataDic = stuListArray[indexPath.row];
  761. return cell;
  762. }else{
  763. //实操
  764. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"coachgpsCell"];
  765. if (cell == nil) {
  766. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"coachgpsCell"];
  767. cell.backgroundColor = [UIColor clearColor];
  768. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  769. }
  770. [cell.textLabel setText:uploadGPSArray[indexPath.row] Font:Font16 TextColor:newSubTitleColor];
  771. return cell;
  772. }
  773. }
  774. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  775. if (tableView == _blueTableView) {
  776. CBPeripheral *peripheral = peripheralArray[indexPath.row];
  777. self.peripheral = peripheral;
  778. [self.cbcManager connectPeripheral:self.peripheral options:nil];
  779. }
  780. }
  781. -(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
  782. return [UIView new];
  783. }
  784. -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
  785. {
  786. return 0.1;
  787. }
  788. #pragma mark 数据请求
  789. - (void)doTeach
  790. {
  791. if (![Util connectedToNetWork]) {
  792. showMsgUnconnect();
  793. return;
  794. }
  795. NSMutableArray *arr=[NSMutableArray array];
  796. [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]];
  797. // [arr addPro:@"imei" Value:[Tools getIDFV]];
  798. // [arr addPro:@"imei" Value:@"80D85448-CD43-497C-98F9-6482F0443686"];
  799. [arr addPro:@"sim" Value:defUser.userDict[@"mobile"]];
  800. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  801. [arr addPro:@"jxbh" Value:defUser.userDict[@"jxbh"]];
  802. NSString* method = @"doTeach";
  803. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  804. if (!root) {
  805. ShowMsg(@"数据出错,请重试!");
  806. return ;
  807. }
  808. if ([root[@"code"] isEqualToString:@"1"]) {
  809. // [self showRegistTextField];
  810. ShowMsg(root[@"body"]);
  811. return;
  812. }
  813. if ([root[@"body"] isEqualToString:@"该设备不存在!"]) {
  814. // [self showRegistTextField];
  815. return;
  816. }
  817. if ([root[@"body"] isEqualToString:@"允许带教"]) {
  818. //判断是否签到过
  819. // if (!isSignInState) {
  820. // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"签到中,请稍后" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  821. // [alert show];
  822. // return;
  823. // }
  824. //如果是模拟 不用判断很多 只要签到过没有计时其他模式计时 就可以打开
  825. if (self.periodType == 3) {
  826. [self requestCoachLocation];
  827. return;
  828. }
  829. //根据self.periodType判断是否可以继续带教
  830. if (periodBtn.selected && self.periodType != 3) {
  831. //带教中
  832. ShowMsg(@"正在带教中,不能进行此操作");
  833. return;
  834. }
  835. //对实操计时 前面的判断全成功之后 得到允许带教的指令 进入蓝牙选择 判断完蓝牙 再去生成二维码
  836. if ([[NSString stringWithFormat:@"%@",defUser.userDict[@"openObd"]] isEqualToString:@"1"]) {
  837. [self searchBlueTooth];
  838. }else {
  839. [self enterMakeScanView];
  840. }
  841. }
  842. }];
  843. }
  844. - (void)enterMakeScanView {
  845. //断开蓝牙连接 关掉蓝牙 隐藏蓝牙外设列表页面
  846. [self closeBlueTooth];
  847. if (self.periodType == 0) {
  848. //未选择带教模式 提示使用默认
  849. NSString *messageString = @"您未选择带教模式,当前默认为科二实操,免费带教,是否继续?";
  850. self.periodDic = [[NSUserDefaults standardUserDefaults] objectForKey:@"periodInfo"];
  851. if ([self.periodDic isKindOfClass:[NSDictionary class]]) {
  852. if ([[self.periodDic objectForKey:@"subject"] isEqualToString:@"3"]) {
  853. messageString = @"您未选择带教模式,当前默认为科三实操,免费带教,是否继续?";
  854. }
  855. }
  856. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:messageString delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"继续", nil];
  857. alert.tag = 2;
  858. [alert show];
  859. return;
  860. }
  861. if (self.periodType == 1) {
  862. // if ([defUser.userDict[@"devnum"] length] < 1) {
  863. // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"终端注册号获取失败,请尝试重新登录" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  864. // [alert show];
  865. // return;
  866. // }
  867. [self makeNoPlanScanView];
  868. }
  869. if (self.periodType == 2) {
  870. [self makePlanScanView];
  871. }
  872. }
  873. - (void)doDeviceReg
  874. {
  875. if (RegistField.text.length < 1) {
  876. ShowMsg(@"请输入车牌号码");
  877. [self showRegistTextField];
  878. return;
  879. }
  880. NSString *carNum = RegistField.text;
  881. if (![carNum containsString:@"闽"]) {
  882. carNum = [NSString stringWithFormat:@"闽%@",RegistField.text];
  883. }
  884. if (![carNum containsString:@"学"]) {
  885. carNum = [NSString stringWithFormat:@"%@学",RegistField.text];
  886. }
  887. // if ([defUser.userDict[@"devnum"] length] < 1) {
  888. // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"终端注册号获取失败,请尝试重新登录" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  889. // [alert show];
  890. // return;
  891. // }
  892. [LoadingView showHUD];
  893. if (![Util connectedToNetWork]) {
  894. showMsgUnconnect();
  895. return;
  896. }
  897. NSMutableArray *arr=[NSMutableArray array];
  898. [arr addPro:@"sim" Value:defUser.userDict[@"mobile"]];
  899. [arr addPro:@"licnum" Value:carNum];
  900. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  901. [arr addPro:@"jxbh" Value:defUser.userDict[@"jxbh"]];
  902. NSString* method = @"doDeviceReg";
  903. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  904. RemoveHUD();
  905. if (!root) {
  906. ShowMsg(@"注册失败!");
  907. return ;
  908. }
  909. if ([root[@"code"] isEqualToString:@"1"]) {
  910. ShowMsg(root[@"body"]);
  911. return;
  912. }
  913. ShowMsg(@"注册成功!");
  914. reLogin();
  915. }];
  916. }
  917. - (void)showRegistTextField
  918. {
  919. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"手机注册" message:@"手机未注册为终端设备,请输入当前手机带练车辆的车牌号码完成注册" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
  920. alert.alertViewStyle = UIAlertViewStylePlainTextInput;
  921. RegistField = [alert textFieldAtIndex:0];
  922. RegistField.placeholder = @"请输入车牌号码";
  923. alert.tag = 4;
  924. [alert show];
  925. }
  926. //更新登录信息
  927. -(void)coachLogin
  928. {
  929. if (![Util connectedToNetWork]) {
  930. showMsgUnconnect();
  931. return;
  932. }
  933. NSMutableArray *arr = [NSMutableArray array];
  934. [arr addPro:@"sfzhm" Value:defUser.sfzmhm];
  935. [arr addPro:@"pwd" Value:defUser.userDict[@"pwd"]];
  936. NSString* method = @"coachLogin";
  937. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  938. RemoveHUD();
  939. if (!root || [root[@"code"] isEqualToString:@"1"]) {
  940. return;
  941. }
  942. //更新信息
  943. defUser.isLogin = YES;
  944. defUser.userDict = root[@"body"];
  945. //NSLog(@"----><>%@",defUser.userDict);
  946. }];
  947. }
  948. /**判断是否正在带教。在view建立和点击带教的时候用*/
  949. - (void)getCoachSignStatus
  950. {
  951. if (![Util connectedToNetWork]) {
  952. showMsgUnconnect();
  953. return;
  954. }
  955. NSMutableArray *arr=[NSMutableArray array];
  956. [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]];
  957. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  958. NSString* method = @"getCoachSignStatus";
  959. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  960. if (!root) {
  961. return;
  962. }
  963. if ([root[@"code"] isEqualToString:@"1"]) {
  964. ShowMsg(root[@"body"]);
  965. return;
  966. }
  967. self.coachSignStatus = [root[@"body"] integerValue];
  968. periodBtn.selected = YES;
  969. isTerminal = NO;
  970. overBtn.hidden = YES;
  971. switch (self.coachSignStatus) {
  972. case RQCoachSignStatusNone: {
  973. periodBtn.selected = NO;
  974. isTerminal = NO;
  975. overBtn.hidden = YES;
  976. break;
  977. }
  978. case RQCoachSignStatusPhoneActual: {
  979. //如果没有上传位置 说明是断线重连 否则是正在带教的情况
  980. if (!uploadGpsTimer) {
  981. self.periodType = 4;
  982. [self getCoachSignStuRecords];
  983. }
  984. break;
  985. }
  986. case RQCoachSignStatussSimulation: {
  987. self.periodType = 3;
  988. if (stuListArray.count < 1) {//如果学员小于1 有可能是重新进入的软件 重新加载学员列表控件
  989. [self initPeriodBar];
  990. [self getCoachSignStuRecordsMnWithIsOver:NO];
  991. }
  992. break;
  993. }
  994. case RQCoachSignStatusTerminalActual: {
  995. //终端实操
  996. isTerminal = YES;
  997. self.periodType = 2;
  998. overBtn.hidden = YES;
  999. break;
  1000. }
  1001. case RQCoachSignStatusCentralizedTraining: {
  1002. break;
  1003. }
  1004. case RQCoachSignStatusSubscribe: {
  1005. self.periodType = 2;
  1006. [self initPeriodBar];
  1007. overBtn.hidden = NO;
  1008. break;
  1009. }
  1010. default:
  1011. break;
  1012. }
  1013. }];
  1014. }
  1015. //获取实操计时学员
  1016. - (void)getCoachSignStuRecords
  1017. {
  1018. if (![Util connectedToNetWork]) {
  1019. showMsgUnconnect();
  1020. return;
  1021. }
  1022. NSMutableArray *arr=[NSMutableArray array];
  1023. [arr addPro:@"coachId" Value:defUser.userDict[@"outId"]];
  1024. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  1025. NSString* method = @"getCoachSignStuRecords";
  1026. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  1027. if (!root) {
  1028. return;
  1029. }
  1030. if ([root[@"code"] isEqualToString:@"1"]) {
  1031. return;
  1032. }
  1033. stuSignInDic = root[@"body"];
  1034. if (isOverScan) {
  1035. if (stuSignInDic.count < 1 && self.coachSignStatus != RQCoachSignStatusSubscribe) { //结束计时 无学员
  1036. //获取到学员为空 就停止刷新 关闭二维码 改变按钮状态
  1037. [Tools playAudioWithString:@"扫描成功,带教结束"];
  1038. [self removeScanView];
  1039. [self resetPeriodView];
  1040. //关闭教练后台上传位置
  1041. [self finishUploadCoachGPS];
  1042. // 默认改为模拟带教
  1043. self.periodType = 3;
  1044. periodBtn.selected = NO;
  1045. overBtn.hidden = YES;
  1046. myDelegate.isPeriodIng = NO;
  1047. }
  1048. }else{
  1049. if (stuSignInDic.count > 0) { //开始计时 有学员
  1050. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  1051. if (self.periodType == 4) {//断线重连学员
  1052. self.periodType = 1;
  1053. [Tools playAudioWithString:@"当前有带教学员,恢复位置上传"];
  1054. //获取本地的科目和价格
  1055. self.periodDic = [userDefaults objectForKey:@"periodInfo"];
  1056. if ([self.periodDic[@"periodType"] isEqualToString:@"2"]) {
  1057. self.periodType = 2;
  1058. }
  1059. }else{//正常开始计时
  1060. [Tools playAudioWithString:@"扫描成功,开始带教"];
  1061. [self removeScanView];//获取到学员 就停止刷新 关闭二维码
  1062. }
  1063. [stuListArray addObject:stuSignInDic];
  1064. [self initPeriodBar];
  1065. }else{
  1066. if (self.periodType == 4) {
  1067. //刚进入app时候 getCoachSignStatus返回有实操计时 其实找不到
  1068. [self finishUploadCoachGPS];
  1069. // 默认改为模拟带教
  1070. self.periodType = 3;
  1071. }
  1072. }
  1073. }
  1074. }];
  1075. }
  1076. //获取模拟学员签到列表
  1077. - (void)getCoachSignStuRecordsMnWithIsOver:(BOOL)isOver
  1078. {
  1079. if (![Util connectedToNetWork]) {
  1080. showMsgUnconnect();
  1081. return;
  1082. }
  1083. NSMutableArray *arr=[NSMutableArray array];
  1084. [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]];
  1085. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  1086. NSString* method = @"getCoachSignStuRecordsMn";
  1087. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  1088. if (!root) {
  1089. return;
  1090. }
  1091. if ([root[@"code"] isEqualToString:@"1"]) {
  1092. ShowMsg(root[@"body"]);
  1093. return;
  1094. }
  1095. stuListArray = root[@"body"];
  1096. [periodTableView reloadData];
  1097. [periodTableView.mj_header endRefreshing];
  1098. if (isOver) {
  1099. if (stuListArray.count < 1) {
  1100. //没有模拟学员 可以结束
  1101. [Tools playAudioWithString:@"成功结束模拟带教"];
  1102. [self resetPeriodView];
  1103. // 默认改为模拟带教
  1104. self.periodType = 3;
  1105. periodBtn.selected = NO;
  1106. overBtn.hidden = YES;
  1107. // myDelegate.isPeriodIng = NO;
  1108. }else{
  1109. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"正在带教%d名学员模拟练习,不能进行此操作",(int)stuListArray.count] delegate:nil cancelButtonTitle:@"确认" otherButtonTitles:nil, nil];
  1110. [alert show];
  1111. }
  1112. }else {
  1113. [self initPeriodBar];
  1114. }
  1115. }];
  1116. }
  1117. /**获取教练当天签到详情*/
  1118. - (void)getCoachSignForTrain
  1119. {
  1120. if (![Util connectedToNetWork]) {
  1121. showMsgUnconnect();
  1122. return;
  1123. }
  1124. NSMutableArray *arr=[NSMutableArray array];
  1125. [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]];
  1126. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  1127. NSString* method = @"getCoachSignForTrain";
  1128. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  1129. if (!root) {
  1130. return;
  1131. }
  1132. if ([root[@"code"] isEqualToString:@"1"]) {
  1133. if ([root[@"body"] isKindOfClass:[NSString class]]) {
  1134. ShowMsg(root[@"body"]);
  1135. }
  1136. return;
  1137. }
  1138. NSDictionary *dic = root[@"body"];
  1139. if (![dic isKindOfClass:[NSDictionary class]]) {
  1140. return;
  1141. }
  1142. //0 未签到 1 已签到 2隔日签退
  1143. //dic[@"status"]
  1144. switch ([dic[@"status"] integerValue]) {
  1145. case 0:
  1146. [self uploadAppSignInfoWithType:@"1"];
  1147. break;
  1148. case 1:
  1149. isSignInState = YES;
  1150. break;
  1151. case 2:
  1152. if (isTerminal) {
  1153. isSignInState = YES;
  1154. //终端签到中 不要签退
  1155. return;
  1156. }
  1157. [self uploadAppSignInfoWithType:@"0"];
  1158. break;
  1159. default:
  1160. break;
  1161. }
  1162. //判断日期是否有问题
  1163. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  1164. [formatter setDateFormat:@"yyyy-MM-dd"];
  1165. NSString *dateString = [formatter stringFromDate:[NSDate date]];
  1166. if (![dateString isEqualToString:dic[@"currentTime"]]) {
  1167. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"温馨提示" message:@"您的手机日期可能存在偏差,请核对" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
  1168. [alert show];
  1169. }
  1170. }];
  1171. }
  1172. //教练签到/签退
  1173. - (void)uploadAppSignInfoWithType:(NSString *)singType
  1174. {
  1175. if (![Util connectedToNetWork]) {
  1176. showMsgUnconnect();
  1177. return;
  1178. }
  1179. BOOL requestResult = [self.locationManager requestLocationWithReGeocode:NO withNetworkState:NO completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) {
  1180. if (error)
  1181. {
  1182. ShowMsg([NSString stringWithFormat:@"定位失败:%@",error.description]);
  1183. }else{
  1184. [self reallyUploadAppSignInfoWithType:singType location:location.location.coordinate];
  1185. }
  1186. }];
  1187. if (requestResult == NO) {
  1188. //
  1189. ShowMsg(@"发起定位请求失败");
  1190. }
  1191. }
  1192. - (void)reallyUploadAppSignInfoWithType:(NSString *)singType location:(CLLocationCoordinate2D)location
  1193. {
  1194. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  1195. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  1196. NSString *timeString = [dateFormatter stringFromDate:[NSDate date]];
  1197. NSMutableArray *arr=[NSMutableArray array];
  1198. [arr addPro:@"sim" Value:defUser.userDict[@"mobile"]];
  1199. [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]];
  1200. [arr addPro:@"gps" Value:[NSString stringWithFormat:@"%f,%f,%@,3",location.longitude,location.latitude,timeString]];
  1201. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  1202. NSString *method = @"saveCoachSignIn";
  1203. if (![singType isEqualToString:@"1"]) {
  1204. //签退
  1205. method = @"saveCoachSignOut";
  1206. }
  1207. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  1208. if (!root) {
  1209. if ([singType isEqualToString:@"1"]) {
  1210. ShowMsg(@"签到失败,请重试");
  1211. }else{
  1212. ShowMsg(@"签退失败,请重试");
  1213. }
  1214. return;
  1215. }
  1216. if (![root[@"code"] isEqualToString:@"0"]) {
  1217. ShowMsg(root[@"body"]);
  1218. return;
  1219. }
  1220. if ([singType isEqualToString:@"1"]) {
  1221. //签到成功
  1222. isSignInState = YES;
  1223. }else{
  1224. //隔日签退成功 就签到
  1225. [self uploadAppSignInfoWithType:@"1"];
  1226. }
  1227. }];
  1228. }
  1229. #pragma mark 上传教练位置相关
  1230. /**
  1231. * @brief 当定位发生错误时,会调用代理的此方法。
  1232. * @param manager 定位 BMKLocationManager 类。
  1233. * @param error 返回的错误,参考 CLError 。
  1234. */
  1235. - (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error{
  1236. ShowMsg([NSString stringWithFormat:@"获取位置错误:%@",error.description]);
  1237. }
  1238. /**
  1239. * @brief 连续定位回调函数。
  1240. * @param manager 定位 BMKLocationManager 类。
  1241. * @param location 定位结果,参考BMKLocation。
  1242. * @param error 错误信息。
  1243. */
  1244. - (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didUpdateLocation:(BMKLocation * _Nullable)location orError:(NSError * _Nullable)error{
  1245. myLocation = location.location.coordinate;
  1246. }
  1247. - (void)beginUploadCoachGPS
  1248. {
  1249. [self.locationManager startUpdatingLocation];
  1250. uploadCount = 0;
  1251. //这里让定时器开始前(第0s
  1252. [self saveCoachGpsInfo];
  1253. if (!uploadGpsTimer) {
  1254. uploadGpsTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(saveCoachGpsInfo) userInfo:nil repeats:YES];
  1255. }
  1256. }
  1257. - (void)finishUploadCoachGPS {
  1258. //先关闭定时器
  1259. if (uploadGpsTimer) {
  1260. [uploadGpsTimer invalidate];
  1261. uploadGpsTimer = nil;
  1262. }
  1263. [self.locationManager stopUpdatingLocation];
  1264. }
  1265. - (void)saveCoachGpsInfo
  1266. {
  1267. //这个点要采集的时候的时间 所以用这个
  1268. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  1269. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  1270. NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
  1271. NSString *sfmString = dateString;
  1272. if (sfmString.length > 10) {
  1273. sfmString = [[sfmString componentsSeparatedByString:@" "] lastObject];
  1274. }
  1275. if (![Util connectedToNetWork]) {
  1276. [uploadGPSArray addObject:[NSString stringWithFormat:@"%@ 网络无连接,上传位置失败!",sfmString]];
  1277. [periodTableView reloadData];
  1278. uploadCount = 0;
  1279. return;
  1280. }
  1281. NSMutableArray *arr=[NSMutableArray array];
  1282. [arr addPro:@"lon" Value:[NSString stringWithFormat:@"%f",myLocation.longitude]];
  1283. [arr addPro:@"lat" Value:[NSString stringWithFormat:@"%f",myLocation.latitude]];
  1284. [arr addPro:@"coachOutId" Value:defUser.userDict[@"outId"]];
  1285. [arr addPro:@"dqbh" Value:defUser.userDict[@"cityId"]];
  1286. [arr addPro:@"crtime" Value:dateString];
  1287. NSString* method = @"saveCoachGpsInfo";
  1288. [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) {
  1289. if (!root) {
  1290. [uploadGPSArray addObject:[NSString stringWithFormat:@"%@ 上传位置失败!",sfmString]];
  1291. [periodTableView reloadData];
  1292. uploadCount = 0;
  1293. return;
  1294. }
  1295. if ([root[@"code"] isEqualToString:@"1"]) {
  1296. NSString *str = root[@"body"];
  1297. [uploadGPSArray addObject:str];
  1298. [periodTableView reloadData];
  1299. uploadCount = 0;
  1300. if ([str containsString:@"签退"]) {
  1301. [Tools playAudioWithString:root[@"body"]];
  1302. ShowMsg(root[@"body"]);
  1303. myDelegate.isPeriodIng = NO;
  1304. [self finishUploadCoachGPS];//关闭教练后台上传位置
  1305. // 默认改为模拟带教
  1306. self.periodType = 3;
  1307. periodBtn.selected = NO;
  1308. overBtn.hidden = YES;
  1309. [self resetPeriodView];
  1310. }
  1311. return;
  1312. }
  1313. if (uploadCount%6 == 0) {
  1314. //上传位置成功;2;0;2;0 总时长、有效时长、无效时长、待审核时长
  1315. NSArray *results = [root[@"body"] componentsSeparatedByString:@";"];
  1316. [uploadGPSArray addObject:[NSString stringWithFormat:@"%@ %@!",sfmString,results[0]]];
  1317. if (!myDelegate.isBackgroundTask) {
  1318. [periodTableView reloadData];
  1319. }
  1320. if (results.count < 5) {
  1321. return;
  1322. }
  1323. allTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[1]];
  1324. valueTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[2]];
  1325. invalidTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[3]];
  1326. waitTimeLabel.text = [NSString stringWithFormat:@"%@分钟",results[4]];
  1327. }
  1328. uploadCount ++;
  1329. }];
  1330. }
  1331. #pragma mark 生成二维码 模拟
  1332. -(void)requestCoachLocation
  1333. {
  1334. [MBProgressHUD showMessag:@"正在获取位置..." toView:self.view];
  1335. BOOL requestResult = [self.locationManager requestLocationWithReGeocode:NO withNetworkState:NO completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) {
  1336. [MBProgressHUD hideHUDForView:self.view animated:NO];
  1337. if (error)
  1338. {
  1339. ShowMsg([NSString stringWithFormat:@"定位失败:%@",error.description]);
  1340. }else{
  1341. [self makeImitateScanViewWithCoachLocation:location.location.coordinate];
  1342. }
  1343. }];
  1344. if (requestResult == NO) {
  1345. //
  1346. ShowMsg(@"发起定位请求失败");
  1347. }
  1348. }
  1349. -(void)makeImitateScanViewWithCoachLocation:(CLLocationCoordinate2D)coachLocation
  1350. {
  1351. if (scanView) {
  1352. return;
  1353. }
  1354. CGFloat x,y,w,h;
  1355. x = 20;
  1356. y = 100;
  1357. w = kSize.width - 40;
  1358. h = kSize.width + 20;
  1359. scanView = [[UIView alloc] setxywh];
  1360. scanView.backgroundColor = [UIColor whiteColor];
  1361. [scanView borderColor:lineColor width:1 cornorRadios:5];
  1362. [self.view addSubview:scanView];
  1363. x = 0;
  1364. y = 0;
  1365. h = 30;
  1366. UILabel *label = [[UILabel alloc] setxywh];
  1367. [label setText:@"学员可扫二维码开始模拟计时" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1368. [scanView addSubview:label];
  1369. x = (w - 250)/2.0;
  1370. y += h + 10;
  1371. w = h = 250;
  1372. scanImgView = [[UIImageView alloc] setxywh];
  1373. [scanView addSubview:scanImgView];
  1374. x = 0;
  1375. y += h + 10;
  1376. w = kSize.width - 40;
  1377. h =30;
  1378. label = [[UILabel alloc] setxywh];
  1379. [label setText:@"二维码有效时间:10:00" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1380. [scanView addSubview:label];
  1381. timerLabel = label;
  1382. UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]];
  1383. cancelImg.frame = CGRectMake(w - 25, 5, 20, 20);
  1384. [scanView addSubview:cancelImg];
  1385. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  1386. btn.frame = CGRectMake(w - 50, 0, 50, 50);
  1387. btn.backgroundColor = [UIColor clearColor];
  1388. [btn addTarget:self action:@selector(removeScanView) forControlEvents:UIControlEventTouchUpInside];
  1389. [scanView addSubview:btn];
  1390. NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600];
  1391. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  1392. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  1393. NSString *dateString = [formatter stringFromDate:effectiveDate];
  1394. NSString *scanString = [NSString stringWithFormat:@"#JSDTMO#;imitSignIn;%@;%@;%f;%f;%@",defUser.userDict[@"outId"],defUser.userDict[@"name"],coachLocation.longitude,coachLocation.latitude,dateString];//标识符 type 教练outID 教练名字 教练经度 教练纬度 有效时间
  1395. //NSLog(@"加密前---><>%@",scanString);
  1396. scanString = [DES3Util encrypt:scanString];
  1397. scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString];
  1398. //NSLog(@"加密后--><>%@",scanString);
  1399. UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f];
  1400. qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)];
  1401. scanImgView.image = qrcode;
  1402. //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来
  1403. timeI = 600;
  1404. if (timer) {
  1405. //如果存在 置为空
  1406. [timer invalidate];
  1407. timer = nil;
  1408. }
  1409. timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInImitate) userInfo:nil repeats:YES];
  1410. }
  1411. //二维码的验证
  1412. -(void)timeRunInImitate
  1413. {
  1414. timeI --;
  1415. if (timeI%5 == 0) {
  1416. [self getCoachSignStuRecordsMnWithIsOver:NO];
  1417. }
  1418. timerLabel.text = [NSString stringWithFormat:@"二维码有效时间:%d:%d",timeI/60,timeI%60];
  1419. if (timeI == 0) {
  1420. NSString *textString = @"二维码已过期,请刷新(点击刷新)";
  1421. NSString *titleString = @"刷新(点击刷新)";
  1422. CGFloat w = [textString sizeForFont:Font16].width;
  1423. CGFloat x = (kSize.width - w)/2.0;
  1424. CGFloat y = timerLabel.y;
  1425. CGFloat h = timerLabel.height;
  1426. timerLabel.frame = setDIYFrame;
  1427. [timerLabel setText:textString Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1428. w = [titleString sizeForFont:Font16].width;
  1429. x += [textString sizeForFont:Font16].width - w;
  1430. UIButton *btn = [[UIButton alloc] setxywh];
  1431. btn.backgroundColor = [UIColor clearColor];
  1432. [btn target:self Tag:7];
  1433. [scanView addSubview:btn];
  1434. [btn addViewWithRect:CGRectMake(x, y + h -5, w, 1) Color:[UIColor orangeColor]];
  1435. //关闭定时器
  1436. [timer invalidate];
  1437. timer = nil;
  1438. timeI = 600;
  1439. }
  1440. }
  1441. #pragma mark 生成二维码 非计划
  1442. -(void)makeNoPlanScanView
  1443. {
  1444. if (scanView) {
  1445. return;
  1446. }
  1447. if (isAfterDelay == YES) {
  1448. isAfterDelay = NO;
  1449. if (timer) {
  1450. [timer invalidate];
  1451. timer = nil;
  1452. }
  1453. }
  1454. isOverScan = NO;
  1455. CGFloat x,y,w,h;
  1456. x = 20;
  1457. y = 100;
  1458. w = kSize.width - 40;
  1459. h = kSize.width + 20;
  1460. scanView = [[UIView alloc] setxywh];
  1461. scanView.backgroundColor = [UIColor whiteColor];
  1462. [scanView borderColor:lineColor width:1 cornorRadios:5];
  1463. [self.view addSubview:scanView];
  1464. x = 0;
  1465. y = 0;
  1466. h = 30;
  1467. UILabel *label = [[UILabel alloc] setxywh];
  1468. [label setText:@"学员可扫二维码开始计时" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1469. [scanView addSubview:label];
  1470. x = (w - 250)/2.0;
  1471. y += h + 10;
  1472. w = h = 250;
  1473. scanImgView = [[UIImageView alloc] setxywh];
  1474. [scanView addSubview:scanImgView];
  1475. x = 0;
  1476. y += h + 10;
  1477. w = kSize.width - 40;
  1478. h =30;
  1479. label = [[UILabel alloc] setxywh];
  1480. [label setText:@"二维码有效时间:10:00" Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1481. [scanView addSubview:label];
  1482. timerLabel = label;
  1483. UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]];
  1484. cancelImg.frame = CGRectMake(w - 25, 5, 20, 20);
  1485. [scanView addSubview:cancelImg];
  1486. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  1487. btn.frame = CGRectMake(w - 50, 0, 50, 50);
  1488. btn.backgroundColor = [UIColor clearColor];
  1489. [btn addTarget:self action:@selector(removeScanViewAndIsCanTime) forControlEvents:UIControlEventTouchUpInside];
  1490. [scanView addSubview:btn];
  1491. NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600];
  1492. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  1493. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  1494. NSString *dateString = [formatter stringFromDate:effectiveDate];
  1495. 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 教练姓名 价格 科目 电话号码 终端设备号 蓝牙名称 有效时间
  1496. //NSLog(@"加密前---><>%@",scanString);
  1497. scanString = [DES3Util encrypt:scanString];
  1498. scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString];
  1499. //NSLog(@"加密后--><>%@",scanString);
  1500. UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f];
  1501. qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)];
  1502. scanImgView.image = qrcode;
  1503. //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来
  1504. timeI = 600;
  1505. if (timer) {
  1506. //如果存在 置为空
  1507. [timer invalidate];
  1508. timer = nil;
  1509. }
  1510. timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES];
  1511. }
  1512. #pragma mark 生成二维码 计划
  1513. -(void)makePlanScanView
  1514. {
  1515. if (scanView) {
  1516. return;
  1517. }
  1518. isOverScan = NO;
  1519. CGFloat x,y,w,h;
  1520. x = 20;
  1521. if (kSize.width > 350) {
  1522. x = 40;
  1523. }
  1524. y = 100;
  1525. w = kSize.width - 2*x;
  1526. h = kSize.width + 20;
  1527. scanView = [[UIView alloc] setxywh];
  1528. scanView.backgroundColor = [UIColor whiteColor];
  1529. [scanView borderColor:lineColor width:1 cornorRadios:5];
  1530. [self.view addSubview:scanView];
  1531. NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600];
  1532. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  1533. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  1534. NSString *dateStr = [formatter stringFromDate:effectiveDate];
  1535. 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
  1536. //NSLog(@"加密前---><>%@",scanString);
  1537. scanString = [DES3Util encrypt:scanString];
  1538. scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString];
  1539. //NSLog(@"加密后--><>%@",scanString);
  1540. UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f];
  1541. qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)];
  1542. x = (w - 250)/2.0;
  1543. y = 20;
  1544. w = h = 250;
  1545. scanImgView = [[UIImageView alloc] setxywh];
  1546. scanImgView.image = qrcode;
  1547. [scanView addSubview:scanImgView];
  1548. if (kSize.width > 350) {
  1549. x = 40;
  1550. }
  1551. w = kSize.width - 2*x;
  1552. x = 0;
  1553. y += h + 10;
  1554. h =30;
  1555. UILabel *label = [[UILabel alloc] setxywh];
  1556. [label setText:[NSString stringWithFormat:@"二维码有效时间:10:00"] Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1557. [scanView addSubview:label];
  1558. timerLabel = label;
  1559. UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]];
  1560. cancelImg.frame = CGRectMake(w - 25, 5, 20, 20);
  1561. [scanView addSubview:cancelImg];
  1562. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  1563. btn.frame = CGRectMake(w - 50, 0, 50, 50);
  1564. btn.backgroundColor = [UIColor clearColor];
  1565. [btn addTarget:self action:@selector(removeScanViewAndIsCanTime) forControlEvents:UIControlEventTouchUpInside];
  1566. [scanView addSubview:btn];
  1567. //倒计时 每隔5秒调服务器 然后看是否有学员签到 如果有 展示出来
  1568. timeI = 600;
  1569. if (timer) {
  1570. //如果存在 置为空
  1571. [timer invalidate];
  1572. timer = nil;
  1573. }
  1574. timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES];
  1575. }
  1576. #pragma mark 结束二维码 定时器 销毁
  1577. //结束二维码
  1578. - (void)makeOverScanView
  1579. {
  1580. if (scanView) {
  1581. return;
  1582. }
  1583. if (isAfterDelay == YES) {
  1584. isAfterDelay = NO;
  1585. if (timer) {
  1586. [timer invalidate];
  1587. timer = nil;
  1588. }
  1589. }
  1590. isOverScan = YES;
  1591. CGFloat x,y,w,h;
  1592. x = 20;
  1593. if (kSize.width > 350) {
  1594. x = 40;
  1595. }
  1596. y = 100;
  1597. w = kSize.width - 2*x;
  1598. h = kSize.width + 20;
  1599. scanView = [[UIView alloc] setxywh];
  1600. scanView.backgroundColor = [UIColor whiteColor];
  1601. [scanView borderColor:lineColor width:1 cornorRadios:5];
  1602. [self.view addSubview:scanView];
  1603. NSDate *effectiveDate = [NSDate dateWithTimeIntervalSinceNow:600];
  1604. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  1605. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  1606. NSString *dateString = [formatter stringFromDate:effectiveDate];
  1607. NSString *scanString = [NSString stringWithFormat:@"#JSDTMO#;signOut;%@;%@;%@",defUser.userDict[@"outId"],[stuSignInDic objectForKey:@"TSO_ID"],dateString];//参数分别是 type 教练outID 学生outID 有效时间
  1608. if ([self.periodDic[@"periodType"] isEqualToString:@"2"]) {//计划的
  1609. self.periodType = 2;
  1610. scanString = [NSString stringWithFormat:@"#JSDTMO#;planSignOut;%@;%@;%@;%@",defUser.userDict[@"id"],self.periodDic[@"userId"],dateString,self.periodDic[@"RO_ID"]];//参数分别是 type 教练Id 学生userID 有效时间 订单ID
  1611. }
  1612. //NSLog(@"加密前---><>%@",scanString);
  1613. scanString = [DES3Util encrypt:scanString];
  1614. scanString = [NSString stringWithFormat:@"#DECODE#%@",scanString];
  1615. //NSLog(@"加密后--><>%@",scanString);
  1616. UIImage *qrcode = [self createNonInterpolatedUIImageFormCIImage:[self createQRForString:scanString] withSize:250.0f];
  1617. qrcode = [self addIconToQRCodeImage:qrcode withIcon:[UIImage imageNamed:@"loginLogo"] withIconSize:CGSizeMake(40, 40)];
  1618. x = (w - 250)/2.0;
  1619. y = 20;
  1620. w = h = 250;
  1621. scanImgView = [[UIImageView alloc] setxywh];
  1622. scanImgView.image = qrcode;
  1623. [scanView addSubview:scanImgView];
  1624. x = 20;
  1625. if (kSize.width > 350) {
  1626. x = 40;
  1627. }
  1628. w = kSize.width - 2*x;
  1629. x = 20;
  1630. y += h + 10;
  1631. h =30;
  1632. UILabel *label = [[UILabel alloc] setxywh];
  1633. [label setText:[NSString stringWithFormat:@"二维码有效时间:10:00"] Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1634. [scanView addSubview:label];
  1635. timerLabel = label;
  1636. UIImageView *cancelImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cancel"]];
  1637. cancelImg.frame = CGRectMake(w - 25, 5, 20, 20);
  1638. [scanView addSubview:cancelImg];
  1639. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  1640. btn.frame = CGRectMake(w - 50, 0, 50, 50);
  1641. btn.backgroundColor = [UIColor clearColor];
  1642. [btn addTarget:self action:@selector(removeScanViewAndIsCanTime) forControlEvents:UIControlEventTouchUpInside];
  1643. [scanView addSubview:btn];
  1644. //倒计时 每隔5秒调服务器
  1645. timeI = 600;
  1646. if (timer) {
  1647. //如果存在 置为空
  1648. [timer invalidate];
  1649. timer = nil;
  1650. }
  1651. timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeRunInShiCao) userInfo:nil repeats:YES];
  1652. }
  1653. //二维码的验证
  1654. -(void)timeRunInShiCao
  1655. {
  1656. timeI --;
  1657. if (timeI%5 == 0) {
  1658. [self getCoachSignStuRecords];
  1659. }
  1660. timerLabel.text = [NSString stringWithFormat:@"二维码有效时间:%d:%d",timeI/60,timeI%60];
  1661. if (timeI == 0) {
  1662. NSString *textString = @"二维码已过期,请刷新(点击刷新)";
  1663. NSString *titleString = @"刷新(点击刷新)";
  1664. CGFloat w = [textString sizeForFont:Font16].width;
  1665. CGFloat x = (kSize.width - w)/2.0;
  1666. CGFloat y = timerLabel.y;
  1667. CGFloat h = timerLabel.height;
  1668. timerLabel.frame = setDIYFrame;
  1669. [timerLabel setText:textString Font:Font16 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter];
  1670. w = [titleString sizeForFont:Font16].width;
  1671. x += [textString sizeForFont:Font16].width - w;
  1672. UIButton *btn = [[UIButton alloc] setxywh];
  1673. btn.backgroundColor = [UIColor clearColor];
  1674. [btn target:self Tag:7];
  1675. [scanView addSubview:btn];
  1676. [btn addViewWithRect:CGRectMake(x, y + h -5, w, 1) Color:[UIColor orangeColor]];
  1677. //关闭定时器
  1678. [timer invalidate];
  1679. timer = nil;
  1680. timeI = 600;
  1681. }
  1682. }
  1683. -(void)removeScanViewAndIsCanTime
  1684. {
  1685. //不要立即关闭定时器 做30秒的延迟
  1686. if (scanView) {
  1687. [scanView removeFromSuperview];
  1688. scanView = nil;
  1689. }
  1690. isAfterDelay = YES;
  1691. [self performSelector:@selector(closeTimer) withObject:nil afterDelay:30];
  1692. }
  1693. -(void)closeTimer
  1694. {
  1695. if (isAfterDelay == YES) {
  1696. if (timer) {
  1697. [timer invalidate];
  1698. timer = nil;
  1699. }
  1700. isAfterDelay = NO;
  1701. }
  1702. }
  1703. -(void)removeScanView
  1704. {
  1705. if (timer) {
  1706. [timer invalidate];
  1707. timer = nil;
  1708. }
  1709. [scanView removeFromSuperview];
  1710. scanView = nil;
  1711. }
  1712. - (CIImage *)createQRForString:(NSString *)qrString {
  1713. NSData *stringData = [qrString dataUsingEncoding:NSUTF8StringEncoding];
  1714. // 创建filter
  1715. CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
  1716. // 设置内容和纠错级别
  1717. [qrFilter setValue:stringData forKey:@"inputMessage"];
  1718. [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"];
  1719. // 返回CIImage
  1720. return qrFilter.outputImage;
  1721. }
  1722. - (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size {
  1723. CGRect extent = CGRectIntegral(image.extent);
  1724. CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
  1725. // 创建bitmap;
  1726. size_t width = CGRectGetWidth(extent) * scale;
  1727. size_t height = CGRectGetHeight(extent) * scale;
  1728. CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
  1729. CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
  1730. CIContext *context = [CIContext contextWithOptions:nil];
  1731. CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
  1732. CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
  1733. CGContextScaleCTM(bitmapRef, scale, scale);
  1734. CGContextDrawImage(bitmapRef, extent, bitmapImage);
  1735. // 保存bitmap到图片
  1736. CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
  1737. UIImage * img = [UIImage imageWithCGImage:scaledImage];
  1738. CGImageRelease(scaledImage);
  1739. CGContextRelease(bitmapRef);
  1740. CGImageRelease(bitmapImage);
  1741. CGColorSpaceRelease(cs);
  1742. return img;
  1743. }
  1744. -(UIImage *)addIconToQRCodeImage:(UIImage *)image withIcon:(UIImage *)icon withIconSize:(CGSize)iconSize {
  1745. UIGraphicsBeginImageContext(image.size);
  1746. //通过两张图片进行位置和大小的绘制,实现两张图片的合并;其实此原理做法也可以用于多张图片的合并
  1747. CGFloat widthOfImage = image.size.width;
  1748. CGFloat heightOfImage = image.size.height;
  1749. CGFloat widthOfIcon = iconSize.width;
  1750. CGFloat heightOfIcon = iconSize.height;
  1751. [image drawInRect:CGRectMake(0, 0, widthOfImage, heightOfImage)];
  1752. [icon drawInRect:CGRectMake((widthOfImage-widthOfIcon)/2, (heightOfImage-heightOfIcon)/2,
  1753. widthOfIcon, heightOfIcon)];
  1754. UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
  1755. UIGraphicsEndImageContext();
  1756. return img;
  1757. }
  1758. #pragma mark scroll & 滑动按钮
  1759. -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
  1760. if (_mainScroll == scrollView) {
  1761. lastOffset = scrollView.contentOffset;
  1762. NSInteger pInd = (int)(lastOffset.x / kSize.width);
  1763. if (pInd == 1) {
  1764. [self updateData];
  1765. }
  1766. if (pInd == self.pageIndex) {
  1767. return;//滑动不足切换页面
  1768. }
  1769. self.pageIndex = pInd;
  1770. }
  1771. }
  1772. //分段按钮,和scroll联动
  1773. -(void)segSelected:(UIButton*)sender
  1774. {
  1775. if (sender.tag == 1) {
  1776. [self updateData];
  1777. }
  1778. if (sender.tag == self.pageIndex) {
  1779. return;
  1780. }
  1781. self.pageIndex = sender.tag;
  1782. }
  1783. -(void)setPageIndex:(NSInteger)pageIndex{
  1784. [_segBtnArray[_pageIndex] setSelected:NO];
  1785. _pageIndex = pageIndex;
  1786. [_segBtnArray[_pageIndex] setSelected:YES];
  1787. //为了实现循环滚动
  1788. [_mainScroll setContentOffset:CGPointMake(kSize.width*pageIndex, _mainScroll.contentOffset.y) animated:NO];
  1789. CGSize size = btnBar.frame.size;
  1790. [UIView animateWithDuration:.2 animations:^{
  1791. btnBar.frame = CGRectMake(kSize.width/_segBtnArray.count * _pageIndex + 20, btnBar.frame.origin.y, size.width, size.height);
  1792. }];
  1793. }
  1794. #pragma mark 蓝牙相关
  1795. - (void)searchBlueTooth {
  1796. isNeed = NO;
  1797. peripheralArray = [NSMutableArray array];
  1798. [self.view addSubview:self.blueTableView];
  1799. [_blueTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"peripheralCell"];
  1800. //初始化蓝牙 并搜索
  1801. [self getCBCmanager];
  1802. }
  1803. - (void)closeBlueTooth {
  1804. [peripheralArray removeAllObjects];
  1805. [_blueTableView reloadData];
  1806. [_blueTableView removeFromSuperview];
  1807. //断开连接
  1808. if (self.peripheral) {
  1809. [self.cbcManager cancelPeripheralConnection:self.peripheral];
  1810. }
  1811. self.peripheral.delegate = nil;
  1812. self.peripheral = nil;
  1813. self.writeCharacteristic = nil;
  1814. self.readCharacteristic = nil;
  1815. self.cbcManager = nil;
  1816. }
  1817. -(UITableView *)blueTableView {
  1818. if (!_blueTableView) {
  1819. _blueTableView = [[UITableView alloc] initWithFrame:CGRectMake(20, 80, kSize.width - 40, kSize.height - 180) style:UITableViewStylePlain];
  1820. [_blueTableView borderCornorRadios:5];
  1821. _blueTableView.delegate = self;
  1822. _blueTableView.dataSource = self;
  1823. UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSize.width - 40, 40)];
  1824. UILabel *header = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, kSize.width - 40, 40)];
  1825. [header setText:@"请选择带教车辆OBD" Font:Font17 TextColor:subTitleColor Alignment:NSTextAlignmentCenter];
  1826. [headerView addSubview:header];
  1827. UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(kSize.width - 40 - 50, 0, 50, 40)];
  1828. [btn setTitle:@"取消" textColor:kTitleColor font:Font17 fotState:UIControlStateNormal];
  1829. [btn target:self Tag:9];
  1830. [headerView addSubview:btn];
  1831. [_blueTableView setTableHeaderView:headerView];
  1832. }
  1833. return _blueTableView;
  1834. }
  1835. //建立一个Central Manager实例进行蓝牙管理
  1836. -(CBCentralManager *)getCBCmanager
  1837. {
  1838. if (!_cbcManager) {
  1839. _cbcManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
  1840. }
  1841. return _cbcManager;
  1842. }
  1843. //只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态
  1844. - (void)centralManagerDidUpdateState:(CBCentralManager *)central
  1845. {
  1846. switch (central.state) {
  1847. case 0:
  1848. //状态未知
  1849. NSLog(@"CBCentralManagerStateUnknown");
  1850. break;
  1851. case 1:
  1852. //连接断开 即将重置
  1853. NSLog(@"CBCentralManagerStateResetting");
  1854. break;
  1855. case 2:
  1856. //该平台不支持蓝牙
  1857. NSLog(@"CBCentralManagerStateUnsupported");
  1858. break;
  1859. case 3:
  1860. //未授权蓝牙使用 hovertree.com
  1861. NSLog(@"CBCentralManagerStateUnauthorized");
  1862. break;
  1863. case 4:
  1864. {
  1865. //蓝牙未开启
  1866. NSLog(@"CBCentralManagerStatePoweredOff");
  1867. ShowMsg(@"请打开手机蓝牙");
  1868. [Tools playAudioWithString:@"请打开手机蓝牙"];
  1869. }
  1870. break;
  1871. case 5:
  1872. {
  1873. //蓝牙已开启
  1874. NSLog(@"CBCentralManagerStatePoweredOn");
  1875. // 搜索外设
  1876. [self.cbcManager scanForPeripheralsWithServices:nil // 通过某些服务筛选外设
  1877. options:nil]; // dict,条件
  1878. // 搜索成功之后,会调用找到外设的代理方法
  1879. }
  1880. break;
  1881. default:
  1882. break;
  1883. }
  1884. }
  1885. // 发现外设后调用的方法
  1886. - (void)centralManager:(CBCentralManager *)central // 中心管理者
  1887. didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设
  1888. advertisementData:(NSDictionary *)advertisementData // 外设携带的数据
  1889. RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度
  1890. {
  1891. //F1C38B70-C866-4E3E-8F1B-AE382E1DB151
  1892. NSLog(@"%@<<-->>%@",peripheral,advertisementData);
  1893. if (![peripheralArray containsObject:peripheral]) {
  1894. [peripheralArray addObject:peripheral];
  1895. [_blueTableView reloadData];
  1896. }
  1897. }
  1898. // 中心管理者连接外设成功
  1899. - (void)centralManager:(CBCentralManager *)central // 中心管理者
  1900. didConnectPeripheral:(CBPeripheral *)peripheral // 外设
  1901. {
  1902. //将教练选中OBD的名字发给学员端
  1903. peripheralName = peripheral.name;
  1904. // 连接成功之后,可以进行服务和特征的发现
  1905. // 设置外设的代理
  1906. self.peripheral.delegate = self;
  1907. // 外设发现服务,传nil代表不过滤
  1908. [self.peripheral discoverServices:nil];
  1909. if (!isJudgeCarUUID) {
  1910. [Tools playAudioWithString:@"车宰蓝牙连接成功,允许带教!"];
  1911. }
  1912. }
  1913. // 外设连接失败
  1914. - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
  1915. {
  1916. NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name);
  1917. //ShowMsg(@"蓝牙连接失败!请重试");
  1918. if (self.cbcManager && self.peripheral) {
  1919. [self.cbcManager connectPeripheral:self.peripheral options:nil];
  1920. }
  1921. }
  1922. // 丢失连接
  1923. - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
  1924. {
  1925. NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);
  1926. // if (self.cbcManager && self.peripheral) {
  1927. // [self.cbcManager connectPeripheral:self.peripheral options:nil];
  1928. // }
  1929. }
  1930. //查找服务的所有特征
  1931. - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
  1932. if (error)
  1933. {
  1934. NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
  1935. return;
  1936. }
  1937. //服务并不是我们的目标,也没有实际意义。我们需要用的是服务下的特征,查询(每一个服务下的若干)特征
  1938. for (CBService *service in peripheral.services)
  1939. {
  1940. [peripheral discoverCharacteristics:nil forService:service];
  1941. }
  1942. }
  1943. // 发现外设服务里的特征的时候调用的代理方法(这个是比较重要的方法,你在这里可以通过事先知道UUID找到你需要的特征,订阅特征,或者这里写入数据给特征也可以)
  1944. - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
  1945. {
  1946. for (CBCharacteristic *cha in service.characteristics) {
  1947. if ([cha.UUID isEqual:[CBUUID UUIDWithString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]]) {
  1948. NSLog(@"读取特征-->>>%@",cha);
  1949. self.readCharacteristic = cha;
  1950. // [peripheral readValueForCharacteristic:cha];
  1951. [peripheral setNotifyValue:YES forCharacteristic:cha];
  1952. }
  1953. if ([cha.UUID isEqual:[CBUUID UUIDWithString:@"6E400002-B5A3-F393-E0A9-E50E24DCCA9E"]]) {
  1954. NSLog(@"写入特征-->>>%@",cha);
  1955. self.writeCharacteristic = cha;
  1956. }
  1957. }
  1958. }
  1959. //- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
  1960. //
  1961. // if (error) {
  1962. // NSLog(@"Error changing notification state: %@", error.localizedDescription);
  1963. // //[peripheral setNotifyValue:YES forCharacteristic:self.readCharacteristic];
  1964. // }
  1965. //
  1966. // if (characteristic.isNotifying) {
  1967. // [peripheral readValueForCharacteristic:characteristic];
  1968. //
  1969. // } else { // Notification has stopped
  1970. // // so disconnect from the peripheral
  1971. // NSLog(@"Notification stopped on %@. Disconnecting", characteristic);
  1972. //
  1973. // }
  1974. //
  1975. //}
  1976. // 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否
  1977. - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
  1978. {
  1979. if ([characteristic isEqual:self.readCharacteristic] ) {
  1980. NSString *hexString = [self convertDataToHexStr:characteristic.value];
  1981. // if (![hexString containsString:@"be05011234"] && ![hexString isEqualToString:@"914e"]) {
  1982. // NSLog(@"%s, ----><>%@--->%@----><>%@", __FUNCTION__,characteristic.value,characteristic.UUID,hexString);
  1983. // }
  1984. //数据完整性检测
  1985. if ([hexString containsString:@"be"]) {
  1986. //数据首包
  1987. lastData = [[hexString componentsSeparatedByString:@"be"] lastObject];
  1988. int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]];
  1989. if (lastData.length < dataLength*2 + 2) {
  1990. isNeed = YES;
  1991. return;
  1992. }
  1993. }else {
  1994. if (isNeed) {//上个包数据不够
  1995. hexString = [lastData stringByAppendingString:hexString];
  1996. lastData = hexString;
  1997. int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]];
  1998. if (lastData.length < dataLength*2 + 2) {
  1999. return;
  2000. }else {
  2001. isNeed = NO;
  2002. hexString = [@"dsbe" stringByAppendingString:hexString];
  2003. }
  2004. }
  2005. }
  2006. NSLog(@"检测完数据的完整性----><>%@",hexString);
  2007. // 心跳包验证
  2008. if ([hexString containsString:@"be0501"]) {//心跳包命令 执行验证然后回复
  2009. //得到数据
  2010. hexString = [[hexString componentsSeparatedByString:@"be0501"] lastObject];
  2011. if (hexString.length > 8) {
  2012. hexString = [hexString substringToIndex:8];
  2013. }
  2014. //计算数据
  2015. hexString = [self getResultWithHexString:hexString];
  2016. if (hexString.length < 14) {
  2017. NSString *OString = @"0000";
  2018. hexString = [OString stringByAppendingString:hexString];
  2019. }
  2020. //验证数据
  2021. hexString = [NSString stringWithFormat:@"be0381%@",[hexString substringFromIndex:hexString.length - 4]];
  2022. [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:hexString]];
  2023. //判断是否判断车架号
  2024. if (isJudgeCarUUID) {
  2025. if (carUUID.length < 1) {
  2026. [self performSelector:@selector(writeOrder) withObject:nil afterDelay:1];
  2027. }
  2028. }else {
  2029. //继续走计时流程
  2030. [self enterMakeScanView];
  2031. }
  2032. return;
  2033. }
  2034. if ([hexString containsString:@"be"]) {
  2035. hexString = [[hexString componentsSeparatedByString:@"be"] lastObject];
  2036. NSLog(@"车架号-----><>%@",hexString);
  2037. //获取有效字节长度 - 标示长度的字节
  2038. int stringLength = [self getHexNumWithString:[hexString substringToIndex:2]] - 1;
  2039. //解析后需要的数据 要将16进制asc转化成我们能看的字符串
  2040. hexString = [self convertHexStrToString:[hexString substringWithRange:NSMakeRange(2, stringLength*2)]];
  2041. //教练端只获取车架号 so
  2042. NSString *uuid = [NSString stringWithFormat:@"%@",hexString];
  2043. carUUID = uuid;
  2044. //服务器保存的车架号
  2045. //defUser.userDict[@"franum"]; 服务器返回的车架号
  2046. NSString *caruuid = @"1G1JC5444R725236";
  2047. if ([carUUID containsString:caruuid]) {
  2048. //车架号一致 继续走计时流程
  2049. carUUID = @"";
  2050. [Tools playAudioWithString:@"车宰蓝牙连接成功,允许带教!"];
  2051. [self enterMakeScanView];
  2052. }else {
  2053. //教练选择车辆车架号与服务器纪录数据不符 不能带教
  2054. carUUID = @"";
  2055. ShowMsg(@"车宰蓝牙与账号不匹配,请重新选择车宰蓝牙");
  2056. [Tools playAudioWithString:@"车宰蓝牙与账号不匹配,请重新选择车宰蓝牙"];
  2057. [_cbcManager cancelPeripheralConnection:self.peripheral];
  2058. }
  2059. return;
  2060. }
  2061. }
  2062. }
  2063. - (void)writeOrder {
  2064. [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:@"BE0183"]];
  2065. }
  2066. //写数据
  2067. -(void)writeCharacteristic:(CBPeripheral *)peripheral
  2068. characteristic:(CBCharacteristic *)characteristic
  2069. value:(NSData *)value
  2070. {
  2071. [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
  2072. //只有 characteristic.properties 有write的权限才可以写
  2073. // if(characteristic.properties & CBCharacteristicPropertyWrite){
  2074. // /*
  2075. // 最好一个type参数可以为CBCharacteristicWriteWithoutResponse或type:CBCharacteristicWriteWithResponse,区别是是否会有反馈
  2076. // */
  2077. // [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
  2078. // }else{
  2079. // NSLog(@"该特征不可写!");
  2080. // }
  2081. }
  2082. // 需要注意的是特征的属性是否支持写数据
  2083. - (void)yf_peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)data forCharacteristic:(nonnull CBCharacteristic *)characteristic
  2084. {
  2085. NSLog(@"写入特征值-->%@",data);
  2086. /*
  2087. 打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值
  2088. 常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式
  2089. */
  2090. // 此时由于枚举属性是NS_OPTIONS,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含&
  2091. }
  2092. #pragma mark 16进制与NSData之间的转化 及验证算法计算
  2093. //data转换为16进制
  2094. - (NSString *)convertDataToHexStr:(NSData *)data {
  2095. if (!data || [data length] == 0) {
  2096. return @"";
  2097. }
  2098. NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
  2099. [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
  2100. unsigned char *dataBytes = (unsigned char*)bytes;
  2101. for (NSInteger i = 0; i < byteRange.length; i++) {
  2102. NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
  2103. if ([hexStr length] == 2) {
  2104. [string appendString:hexStr];
  2105. } else {
  2106. [string appendFormat:@"0%@", hexStr];
  2107. }
  2108. }
  2109. }];
  2110. return string;
  2111. }
  2112. //16进制转换为data
  2113. - (NSData *)convertHexStrToData:(NSString *)str {
  2114. if (!str || [str length] == 0) {
  2115. return nil;
  2116. }
  2117. NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
  2118. NSRange range;
  2119. if ([str length] % 2 == 0) {
  2120. range = NSMakeRange(0, 2);
  2121. } else {
  2122. range = NSMakeRange(0, 1);
  2123. }
  2124. for (NSInteger i = range.location; i < [str length]; i += 2) {
  2125. unsigned int anInt;
  2126. NSString *hexCharStr = [str substringWithRange:range];
  2127. NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
  2128. [scanner scanHexInt:&anInt];
  2129. NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
  2130. [hexData appendData:entity];
  2131. range.location += range.length;
  2132. range.length = 2;
  2133. }
  2134. return hexData;
  2135. }
  2136. - (NSString *)getResultWithHexString:(NSString *)hexString {
  2137. if (hexString.length < 8) {
  2138. NSLog(@"验证算法输入数据错误");
  2139. return @"erroe";
  2140. }
  2141. int x = [self getHexNumWithString:[hexString substringToIndex:4]];
  2142. int y = [self getHexNumWithString:[hexString substringFromIndex:4]];
  2143. int z = 0x1323;
  2144. hexString = [NSString stringWithFormat:@"%x",(x*z+y)^z];
  2145. // NSLog(@"%d,%d,%d,%x,%x,%x<---->%@",x,y,z,x,y,z,hexString);
  2146. return hexString;
  2147. }
  2148. /**
  2149. 将原本是16进制数字的字符串转换成计算机可以识别的int型10进制数据
  2150. */
  2151. - (int)getHexNumWithString:(NSString *)string {
  2152. int number = 0;
  2153. for (int i = 0; i < string.length; i ++) {
  2154. NSString *letterOrNumber = [string substringWithRange:NSMakeRange(string.length - i - 1, 1)];
  2155. int a = 0;
  2156. if ([letterOrNumber isEqualToString:@"a"] || [letterOrNumber isEqualToString:@"A"]) {
  2157. a = 10;
  2158. }else if ([letterOrNumber isEqualToString:@"b"] || [letterOrNumber isEqualToString:@"B"]){
  2159. a = 11;
  2160. }else if ([letterOrNumber isEqualToString:@"c"] || [letterOrNumber isEqualToString:@"C"]){
  2161. a = 12;
  2162. }else if ([letterOrNumber isEqualToString:@"d"] || [letterOrNumber isEqualToString:@"D"]){
  2163. a = 13;
  2164. }else if ([letterOrNumber isEqualToString:@"e"] || [letterOrNumber isEqualToString:@"E"]){
  2165. a = 14;
  2166. }else if ([letterOrNumber isEqualToString:@"f"] || [letterOrNumber isEqualToString:@"F"]){
  2167. a = 15;
  2168. }else {
  2169. a = [letterOrNumber intValue];
  2170. }
  2171. a = a * pow(16, i);
  2172. number += a;
  2173. }
  2174. return number;
  2175. }
  2176. //将十六进制的字符串转换成NSString则可使用如下方式
  2177. - (NSString *)convertHexStrToString:(NSString *)str {
  2178. if (!str || [str length] == 0) {
  2179. return nil;
  2180. }
  2181. NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
  2182. NSRange range;
  2183. if ([str length] % 2 == 0) {
  2184. range = NSMakeRange(0, 2);
  2185. } else {
  2186. range = NSMakeRange(0, 1);
  2187. }
  2188. for (NSInteger i = range.location; i < [str length]; i += 2) {
  2189. unsigned int anInt;
  2190. NSString *hexCharStr = [str substringWithRange:range];
  2191. NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
  2192. [scanner scanHexInt:&anInt];
  2193. NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
  2194. [hexData appendData:entity];
  2195. range.location += range.length;
  2196. range.length = 2;
  2197. }
  2198. NSString *string = [[NSString alloc]initWithData:hexData encoding:NSUTF8StringEncoding];
  2199. return string;
  2200. }
  2201. //将NSString转换成十六进制的字符串则可使用如下方式
  2202. + (NSString *)convertStringToHexStr:(NSString *)str {
  2203. if (!str || [str length] == 0) {
  2204. return @"";
  2205. }
  2206. NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
  2207. NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
  2208. [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
  2209. unsigned char *dataBytes = (unsigned char*)bytes;
  2210. for (NSInteger i = 0; i < byteRange.length; i++) {
  2211. NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
  2212. if ([hexStr length] == 2) {
  2213. [string appendString:hexStr];
  2214. } else {
  2215. [string appendFormat:@"0%@", hexStr];
  2216. }
  2217. }
  2218. }];
  2219. return string;
  2220. }
  2221. - (void)didReceiveMemoryWarning {
  2222. [super didReceiveMemoryWarning];
  2223. // Dispose of any resources that can be recreated.
  2224. }
  2225. @end