Commit 8e01bae59a42a21f62dee69811dbb014b3ab476b

Authored by guoruipeng
1 parent 60a06855

添加文件及资源

Showing 144 changed files with 6168 additions and 0 deletions
CNLiveSportsModule/Assets/Crown@2x.png 0 → 100644

798 Bytes

CNLiveSportsModule/Assets/Crown@3x.png 0 → 100644

1.38 KB

CNLiveSportsModule/Assets/activity@2x.png 0 → 100644

574 Bytes

CNLiveSportsModule/Assets/activity@3x.png 0 → 100644

1.02 KB

CNLiveSportsModule/Assets/arrow_white_down@2x.png 0 → 100644

457 Bytes

CNLiveSportsModule/Assets/arrow_white_down@3x.png 0 → 100644

795 Bytes

CNLiveSportsModule/Assets/arrow_white_up@2x.png 0 → 100644

419 Bytes

CNLiveSportsModule/Assets/arrow_white_up@3x.png 0 → 100644

803 Bytes

CNLiveSportsModule/Assets/back-bg@2x.png 0 → 100644

2.44 KB

CNLiveSportsModule/Assets/back-bg@3x.png 0 → 100644

4.66 KB

CNLiveSportsModule/Assets/bmcg@2x.png 0 → 100644

11.4 KB

CNLiveSportsModule/Assets/bmcg@3x.png 0 → 100644

23.3 KB

CNLiveSportsModule/Assets/bnavi_icon_location_fixed@2x.png 0 → 100644

1.42 KB

CNLiveSportsModule/Assets/download album@2x.png 0 → 100644

2.09 KB

CNLiveSportsModule/Assets/download album@3x.png 0 → 100644

4.17 KB

CNLiveSportsModule/Assets/gps-bg@2x.png 0 → 100644

1.99 KB

CNLiveSportsModule/Assets/gps-bg@3x.png 0 → 100644

3.79 KB

CNLiveSportsModule/Assets/icon_nav_end@2x.png 0 → 100644

7.8 KB

CNLiveSportsModule/Assets/icon_nav_start@2x.png 0 → 100644

7.53 KB

CNLiveSportsModule/Assets/jl-bg@2x.png 0 → 100644

6.4 KB

CNLiveSportsModule/Assets/jl-bg@3x.png 0 → 100644

12.7 KB

CNLiveSportsModule/Assets/logo@2x.png 0 → 100644

6.36 KB

CNLiveSportsModule/Assets/logo@3x.png 0 → 100644

18.7 KB

CNLiveSportsModule/Assets/lxxqy-cj-bg@2x.png 0 → 100644

4.14 KB

CNLiveSportsModule/Assets/lxxqy-cj-bg@3x.png 0 → 100644

8.5 KB

CNLiveSportsModule/Assets/map-fw@2x.png 0 → 100644

3.12 KB

CNLiveSportsModule/Assets/map-fw@3x.png 0 → 100644

6.3 KB

CNLiveSportsModule/Assets/map-signal-tx@2x.png 0 → 100644

1.89 KB

CNLiveSportsModule/Assets/map-signal-tx@3x.png 0 → 100644

3.49 KB

CNLiveSportsModule/Assets/map_dw.png 0 → 100644

5.19 KB

CNLiveSportsModule/Assets/map_location-finish@2x.png 0 → 100644

3.07 KB

CNLiveSportsModule/Assets/map_location-finish@3x.png 0 → 100644

5.89 KB

CNLiveSportsModule/Assets/map_location-start@2x.png 0 → 100644

3.7 KB

CNLiveSportsModule/Assets/map_location-start@3x.png 0 → 100644

7.25 KB

CNLiveSportsModule/Assets/map_location@2x.png 0 → 100644

2.04 KB

CNLiveSportsModule/Assets/map_location@3x.png 0 → 100644

3.71 KB

CNLiveSportsModule/Assets/more@2x.png 0 → 100644

290 Bytes

CNLiveSportsModule/Assets/more@3x.png 0 → 100644

553 Bytes

CNLiveSportsModule/Assets/my_china_sport@2x.png 0 → 100644

2.83 KB

CNLiveSportsModule/Assets/my_china_sport@3x.png 0 → 100644

6.34 KB

CNLiveSportsModule/Assets/pbjs-finish@2x.png 0 → 100644

130 Bytes

CNLiveSportsModule/Assets/pbjs-finish@3x.png 0 → 100644

207 Bytes

CNLiveSportsModule/Assets/pbjs-play@2x.png 0 → 100644

554 Bytes

CNLiveSportsModule/Assets/pbjs-play@3x.png 0 → 100644

867 Bytes

CNLiveSportsModule/Assets/pbjs-time out@2x.png 0 → 100644

152 Bytes

CNLiveSportsModule/Assets/pbjs-time out@3x.png 0 → 100644

439 Bytes

CNLiveSportsModule/Assets/press finish@2x.png 0 → 100644

968 Bytes

CNLiveSportsModule/Assets/press finish@3x.png 0 → 100644

1.79 KB

CNLiveSportsModule/Assets/return@2x.png 0 → 100644

409 Bytes

CNLiveSportsModule/Assets/return@3x.png 0 → 100644

751 Bytes

CNLiveSportsModule/Assets/runbiaoji@2x.png 0 → 100644

1.21 KB

CNLiveSportsModule/Assets/runbiaoji@3x.png 0 → 100644

3.51 KB

CNLiveSportsModule/Assets/share-background@2x.png 0 → 100644

289 KB

CNLiveSportsModule/Assets/share-background@3x.png 0 → 100644

626 KB

CNLiveSportsModule/Assets/signal-good@2x.png 0 → 100644

197 Bytes

CNLiveSportsModule/Assets/signal-good@3x.png 0 → 100644

632 Bytes

CNLiveSportsModule/Assets/signal-low@2x.png 0 → 100644

133 Bytes

CNLiveSportsModule/Assets/signal-low@3x.png 0 → 100644

384 Bytes

CNLiveSportsModule/Assets/signal-mid@2x.png 0 → 100644

215 Bytes

CNLiveSportsModule/Assets/signal-mid@3x.png 0 → 100644

721 Bytes

CNLiveSportsModule/Assets/signal-none@2x.png 0 → 100644

146 Bytes

CNLiveSportsModule/Assets/signal-none@3x.png 0 → 100644

499 Bytes

CNLiveSportsModule/Assets/sport-people@2x.png 0 → 100644

816 Bytes

CNLiveSportsModule/Assets/sport-people@3x.png 0 → 100644

1.53 KB

CNLiveSportsModule/Assets/sport-route@2x.png 0 → 100644

1.36 KB

CNLiveSportsModule/Assets/sport-route@3x.png 0 → 100644

2.6 KB

CNLiveSportsModule/Assets/sport-speed@2x.png 0 → 100644

1.9 KB

CNLiveSportsModule/Assets/sport-speed@3x.png 0 → 100644

3.74 KB

CNLiveSportsModule/Assets/sport-step record@2x.png 0 → 100644

1.31 KB

CNLiveSportsModule/Assets/sport-step record@3x.png 0 → 100644

2.82 KB

CNLiveSportsModule/Assets/sport-step@2x.png 0 → 100644

2.15 KB

CNLiveSportsModule/Assets/sport-step@3x.png 0 → 100644

4.38 KB

CNLiveSportsModule/Assets/sport-time cost@2x.png 0 → 100644

1.97 KB

CNLiveSportsModule/Assets/sport-time cost@3x.png 0 → 100644

3.91 KB

CNLiveSportsModule/Assets/sport_china_grade_head@2x.png 0 → 100644

119 KB

CNLiveSportsModule/Assets/sport_china_grade_head@3x.png 0 → 100644

175 KB

CNLiveSportsModule/Assets/sport_china_my_acction@2x.png 0 → 100644

2.73 KB

CNLiveSportsModule/Assets/sport_china_my_acction@3x.png 0 → 100644

6.3 KB

CNLiveSportsModule/Assets/sport_china_my_record@2x.png 0 → 100644

2.31 KB

CNLiveSportsModule/Assets/sport_china_my_record@3x.png 0 → 100644

6.51 KB

CNLiveSportsModule/Assets/sport_china_my_tyjf@2x.png 0 → 100644

2.14 KB

CNLiveSportsModule/Assets/sport_china_my_tyjf@3x.png 0 → 100644

5.9 KB

CNLiveSportsModule/Assets/sports_china_nodata@2x.png 0 → 100644

16.6 KB

CNLiveSportsModule/Assets/sports_china_nodata@3x.png 0 → 100644

31.9 KB

CNLiveSportsModule/Assets/sports_china_share@2x.png 0 → 100644

1.07 KB

CNLiveSportsModule/Assets/sports_china_share@3x.png 0 → 100644

2.04 KB

CNLiveSportsModule/Assets/sports_china_wdhd_location@2x.png 0 → 100644

913 Bytes

CNLiveSportsModule/Assets/sports_china_wdhd_location@3x.png 0 → 100644

1.56 KB

CNLiveSportsModule/Assets/sports_china_wdhd_time@2x.png 0 → 100644

864 Bytes

CNLiveSportsModule/Assets/sports_china_wdhd_time@3x.png 0 → 100644

1.44 KB

CNLiveSportsModule/Assets/sports_china_wdjl_head@2x.png 0 → 100644

177 KB

CNLiveSportsModule/Assets/sports_china_wdjl_head@3x.png 0 → 100644

256 KB

CNLiveSportsModule/Assets/sports_china_wdjl_speed@2x.png 0 → 100644

907 Bytes

CNLiveSportsModule/Assets/sports_china_wdjl_speed@3x.png 0 → 100644

1.75 KB

CNLiveSportsModule/Assets/sports_china_wdjl_step@2x.png 0 → 100644

1.19 KB

CNLiveSportsModule/Assets/sports_china_wdjl_step@3x.png 0 → 100644

2.33 KB

CNLiveSportsModule/Assets/sports_china_wdjl_time@2x.png 0 → 100644

1009 Bytes

CNLiveSportsModule/Assets/sports_china_wdjl_time@3x.png 0 → 100644

1.84 KB

CNLiveSportsModule/Assets/sports_china_yplx_bm@2x.png 0 → 100644

3.96 KB

CNLiveSportsModule/Assets/sports_china_yplx_bm@3x.png 0 → 100644

17.1 KB

CNLiveSportsModule/Assets/startRunning_map@2x.png 0 → 100644

7.53 KB

CNLiveSportsModule/Assets/startRunning_map@3x.png 0 → 100644

23.1 KB

CNLiveSportsModule/Assets/track_loading@2x.png 0 → 100644

1.19 KB

CNLiveSportsModule/Assets/track_loading@3x.png 0 → 100644

2.19 KB

CNLiveSportsModule/Assets/up@2x.png 0 → 100644

341 Bytes

CNLiveSportsModule/Assets/up@3x.png 0 → 100644

692 Bytes

CNLiveSportsModule/Assets/xqt-share@2x.png 0 → 100644

1.6 KB

CNLiveSportsModule/Assets/xqt-share@3x.png 0 → 100644

7.16 KB

CNLiveSportsModule/Assets/xqy-return@2x.png 0 → 100644

1.39 KB

CNLiveSportsModule/Assets/xqy-return@3x.png 0 → 100644

5.63 KB

CNLiveSportsModule/Classes/Controller/CNStartRunningViewController.h 0 → 100644
  1 +//
  2 +// CNStartRunningViewController.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/13.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNCommonViewController.h"
  10 +#import "CNLiveSportsDetailModel.h"
  11 +
  12 +@protocol CNStartRunningVCDelegate <NSObject>
  13 +
  14 +- (void)backToFrontVC;
  15 +
  16 +@end
  17 +@interface CNStartRunningViewController : CNCommonViewController
  18 +@property (nonatomic, weak) id<CNStartRunningVCDelegate> delegate;
  19 +@property (nonatomic, strong) CNLiveSportsDetailModel *sportsDetailModel;
  20 +@property (nonatomic, copy) NSString *eventID;
  21 +@property (nonatomic, copy) NSString *eventName;
  22 +@property (nonatomic, copy) NSString *pointsStr;
  23 +
  24 +@end
  25 +
... ...
CNLiveSportsModule/Classes/Controller/CNStartRunningViewController.m 0 → 100644
  1 +//
  2 +// CNStartRunningViewController.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/13.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNStartRunningViewController.h"
  10 +#import "CNRunEndCircleProgress.h"
  11 +#import <CoreMotion/CoreMotion.h>
  12 +#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件
  13 +#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件
  14 +#import <BMKLocationkit/BMKLocationComponent.h>//定位功能
  15 +#import "CNLinePointNode.h"
  16 +#import "CNHistoryTrackParam.h"
  17 +#import "CNHistoryViewModel.h"
  18 +#import "CNHistoryTrackPoint.h"
  19 +#import <BaiduTraceSDK/BaiduTraceSDK.h>//鹰眼服务
  20 +#import "CNTrackTableView.h"
  21 +#import "CNTrackServiceManager.h"
  22 +#import "CNTrackLoaclDataManager.h"
  23 +#import "CNRunExitModel.h"
  24 +#import "CNLiveUploadManager.h"
  25 +#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>
  26 +#import "CNTrackUploadFailModel.h"
  27 +#import "CNReUploadViewController.h"
  28 +
  29 +
  30 +
  31 +@interface CNStartRunningViewController ()
  32 +<
  33 +BMKMapViewDelegate,
  34 +BMKLocationManagerDelegate,
  35 +BTKFenceDelegate,
  36 +UITableViewDelegate,
  37 +UITableViewDataSource,
  38 +CNTrackServiceManagerDelegate
  39 +>
  40 +//倒计时
  41 +@property (nonatomic, strong) UIView *startCountdownView;//倒计时321
  42 +@property (nonatomic, strong) UILabel *startCountdownLab;//倒计时321
  43 +//倒计时结束后
  44 +
  45 +@property (nonatomic, strong) UIView *fristBgView;//倒计时321
  46 +@property (nonatomic, strong) QMUIButton *backFirstBtn;//backFirstBtn
  47 +@property (nonatomic, strong) UILabel *currentKMLab;//0.00公里
  48 +
  49 +@property (nonatomic, strong) UILabel *gpsLab;//"GPS"
  50 +@property (nonatomic, strong) UIImageView *currentGPSImgView;//"GPS"img
  51 +@property (nonatomic, strong) UILabel *currentGPSLab;//GPS
  52 +
  53 +@property (nonatomic, strong) UIButton *detailMapBtn;//mapBtn
  54 +@property (nonatomic, strong) UILabel *mapDesLab;//GPS
  55 +
  56 +
  57 +@property (nonatomic, strong) UIImageView *speedImgView;//speed
  58 +@property (nonatomic, strong) UILabel *currentSpeedLab;
  59 +@property (nonatomic, strong) UILabel *speedDesLab;
  60 +
  61 +@property (nonatomic, strong) UIImageView *timeImgView;//time
  62 +@property (nonatomic, strong) UILabel *currentTimeLab;
  63 +@property (nonatomic, strong) UILabel *timeDesLab;
  64 +
  65 +@property (nonatomic, strong) UIImageView *stepImgView;//step
  66 +@property (nonatomic, strong) UILabel *currentStepLab;
  67 +@property (nonatomic, strong) UILabel *stepDesLab;
  68 +
  69 +@property (nonatomic, strong) QMUIButton *stopRunningBtn;//mapBtn
  70 +@property (nonatomic, strong) QMUIButton *goonRunningBtn;//mapBtn
  71 +@property (nonatomic, strong) UIView *endRunningBgView;//mapBtn
  72 +@property (nonatomic, strong) QMUIButton *endRunningBtn;//mapBtn
  73 +@property (nonatomic, strong) UIImageView *endTipView;//mapBtn
  74 +@property (nonatomic, strong) UILabel *endTipLab;//mapBtn
  75 +@property (strong, nonatomic) CNRunEndCircleProgress *progressView;
  76 +@property (nonatomic, strong) UILongPressGestureRecognizer *longPress;//tap
  77 +@property (nonatomic, strong) NSTimer *endTimer;//点击了结束按钮事件响应timer
  78 +@property (nonatomic, strong) NSTimer *startRunningTimer;//跑步的累计时间
  79 +
  80 +#pragma mark -- 地图.h
  81 +@property (nonatomic, strong) BMKMapView *mapView;//地图
  82 +@property (nonatomic, strong) BMKPolyline *originalPolyLine; //当前界面的多边形(运动轨迹)
  83 +@property (nonatomic, strong) BMKPointAnnotation *startAnnotation; //当前界面的标注
  84 +@property (nonatomic, strong) BMKPointAnnotation *endAnnotation; //当前界面的标注
  85 +@property (nonatomic, strong) QMUIButton *backBtn;//backBtn
  86 +@property (nonatomic, strong) QMUIButton *GPSBtn;//backBtn
  87 +@property (nonatomic, strong) QMUIButton *tipGPSBtn;//resetBtn
  88 +@property (nonatomic, strong) QMUIButton *resetBtn;//resetBtn
  89 +@property (nonatomic, strong) UIImageView *mapBottomView;//mapBottom
  90 +@property (nonatomic, strong) UILabel *mapCurrentSpeedLab;//mapBottom
  91 +@property (nonatomic, strong) UILabel *mapSpeedLab;//mapBottom
  92 +@property (nonatomic, strong) UILabel *mapCurrentTimeLab;//mapBottom
  93 +@property (nonatomic, strong) UILabel *mapTimeLab;//mapBottom
  94 +@property (nonatomic, strong) UILabel *mapCurrentKMLab;//mapBottom
  95 +@property (nonatomic, strong) UILabel *mapKMLab;//mapBottom
  96 +
  97 +
  98 +#pragma mark -- 定位.h
  99 +@property (nonatomic, strong) BMKLocationManager *locationManager;//定位管理
  100 +@property (nonatomic, strong) BMKUserLocation *userLocation; //当前位置对象
  101 +
  102 +@property (nonatomic, assign) CNLocationGPSState gpsState; //gps信号状态
  103 +#pragma mark -- 定位画线.h
  104 +@property (nonatomic, strong) BMKPolyline *stopBeforePolyLine; //停止前的路线
  105 +@property (nonatomic, assign) NSInteger recordReInTime; //停止前的路线
  106 +
  107 +@property (nonatomic, strong) CLLocation *firstStopAfterLinePoint;//停止后的路线的第一个点
  108 +@property (nonatomic, strong) BMKPolyline *stopAfterPolyLine; //停止后的路线
  109 +@property (nonatomic, strong) BMKPolyline *frontStopAfterPolyLine; //停止后的前一半路线
  110 +//不退出控制器,暂停之前的线
  111 +@property (nonatomic, strong) BMKPolyline *noExitStopFrontPolyLine; //停止后的路线
  112 +
  113 +
  114 +@property (nonatomic, strong) NSMutableArray *locationPoints;//用于画线的集合
  115 +@property (nonatomic, strong) CLLocation *currentLocation;// 中间变量->location类型(地理位置)
  116 +
  117 +#pragma mark -- 本地地理围栏.h
  118 +
  119 +#pragma mark -- 结束view.h
  120 +@property (nonatomic, strong) CNTrackTableView *tableView;
  121 +@property (nonatomic, strong) UIButton *saveBtn;
  122 +@property (nonatomic, strong) UIView *preSaveView;
  123 +@property (nonatomic, strong) UIImageView *loadingSaveView;
  124 +
  125 +@property (nonatomic, strong) UILabel *successStateLab;//tableviewcell中的一个变量
  126 +
  127 +#pragma mark -- 判断进入页面的方式.h
  128 +@property (nonatomic, strong) CNRunExitModel *exitModel;
  129 +@end
  130 +
  131 +@implementation CNStartRunningViewController{
  132 + BOOL _isStopEnd;//是否停止了长按结束按钮
  133 + double _pressEndBtnCurrentTime;//计时器走了多长时间(最长2,到2 isStopEnd置为yes)
  134 + NSInteger _totalTime;//跑步累计时间,单位秒
  135 + NSInteger _startRunningDate;
  136 + BOOL _isEndRunning;
  137 + CGFloat angle;
  138 + NSInteger _endRunningDate;
  139 + UIImageView *_headImg;//用于长按了结束按钮后拖动的问题
  140 +
  141 + NSInteger _stopDate;//暂停的时间
  142 + NSInteger _reStartDate;//重新开始的时间
  143 + NSInteger _lastStepCount;//最新的步数或起止步数
  144 + NSNumber *localFenceId;
  145 +
  146 + CNTrackUploadFailModel *failModel;//上传失败的model,存数据库
  147 + NSString *_endStatus;
  148 + BOOL _isStopRun;//用于判断是否在此控制器中是否点击了暂停,通过此控制器返回或其他操作都不做处理
  149 + BOOL _isStopAnimation;
  150 +
  151 +}
  152 +
  153 +
  154 +-(void)dealloc{
  155 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  156 + if (_endTimer) {
  157 + [_endTimer invalidate];
  158 + _endTimer = nil;
  159 + }
  160 + if (_startRunningTimer) {
  161 + [_startRunningTimer invalidate];
  162 + _startRunningTimer = nil;
  163 + }
  164 + NSLog(@"CNStartRunningViewController 释放了");
  165 +}
  166 +
  167 +-(void)viewWillAppear:(BOOL)animated{
  168 + [super viewWillAppear:animated];
  169 + [self.navigationController setNavigationBarHidden:YES animated:animated];
  170 + [self.mapView viewWillAppear];
  171 + self.mapView.delegate = self;
  172 + _locationManager.delegate = self;
  173 + self.recordReInTime = [CNLiveTimeTools getNowTimestamp];
  174 +}
  175 +
  176 +-(void)viewWillDisappear:(BOOL)animated{
  177 + [super viewWillDisappear:animated];
  178 + [self.navigationController setNavigationBarHidden:NO animated:animated];
  179 + [self.mapView viewWillDisappear];
  180 + self.mapView.delegate = nil;
  181 + if (_isEndRunning) {
  182 + _locationManager.delegate = nil;
  183 + }
  184 +}
  185 +
  186 +- (void)viewDidAppear:(BOOL)animated{
  187 + [super viewDidAppear:animated];
  188 + //禁用返回手势
  189 + if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
  190 + self.navigationController.interactivePopGestureRecognizer.delegate = nil;
  191 + self.navigationController.interactivePopGestureRecognizer.enabled = NO;
  192 + }
  193 +}
  194 +
  195 +-(void)viewDidDisappear:(BOOL)animated{
  196 + [super viewDidDisappear:animated];
  197 + self.navigationController.interactivePopGestureRecognizer.enabled = YES;
  198 +}
  199 +
  200 +- (void)viewDidLoad {
  201 + [super viewDidLoad];
  202 + NSString *str = [self.sportsDetailModel mj_JSONString];
  203 + [[NSUserDefaults standardUserDefaults] setObject:str forKey:@"CN_OLD_TRACK"];
  204 +
  205 + [CNTrackServiceManager defaultManager].delegate = self;
  206 + self.view.backgroundColor = [UIColor blackColor];
  207 + _isStopRun = NO;
  208 + [self.view addSubview:self.mapView];
  209 + [self.locationManager startUpdatingLocation];
  210 + [self.locationManager startUpdatingHeading];
  211 + self.mapView.hidden = YES;
  212 + self.exitModel = [[CNTrackLoaclDataManager shareManager]getExitModel:CNUserShareModelUid];
  213 + //查询一次服务器围栏:实时状态查询,是为了使服务器围栏监控生效
  214 + [self queryRealtimeStatus];
  215 +
  216 + if (self.exitModel && self.exitModel.eventId.length > 0) {
  217 + [self initData];
  218 + [self addFirstView];
  219 + [self startRunningTime];
  220 + }else{
  221 + [self startCountdown:^{
  222 + [self initData];
  223 + self.view.backgroundColor = [UIColor blackColor];
  224 + [self addFirstView];
  225 + [self startRunningTime];
  226 + }];
  227 + }
  228 +}
  229 +#pragma mark -- CNTrackServiceManagerDelegate
  230 +-(void)currentPedometer:(CNRunExitModel *)model{
  231 + if (!model) {
  232 + return;
  233 + }
  234 + double km = ([model.step integerValue])*60.0/100/1000;
  235 + //不四舍五入
  236 + NSInteger tempStep = [model.step integerValue];
  237 + if (tempStep > 0) {
  238 + self.currentStepLab.text = [NSString stringWithFormat:@"%ld",[model.step integerValue]];//步数
  239 + }else{
  240 + self.currentStepLab.text = @"0";
  241 + }
  242 + self.exitModel.step = self.currentStepLab.text;
  243 + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:70]};
  244 + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:15]};
  245 + NSAttributedString *attributedString = [self attributedText:@[[NSString stringWithFormat:@"%.2f",floor((km)*100)/100],@" 公里"] attributeAttay:@[attributesNum,attributesKM]];
  246 + self.currentKMLab.attributedText = attributedString;
  247 + self.currentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km];
  248 + self.mapCurrentKMLab.text = [NSString stringWithFormat:@"%.2f",floor((km)*100)/100];
  249 + self.mapCurrentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km];
  250 +}
  251 +#pragma mark -- mapDelegate
  252 +-(void)mapViewDidFinishLoading:(BMKMapView *)mapView{
  253 + //地图加载完成后,添加运营的线,添加终点的本地围栏
  254 + [self addMapOriginalLine];
  255 + //请求自己的历史轨迹
  256 + CNRunExitModel *tempM = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid];
  257 + if (tempM && [tempM.isStop isEqualToString:@"yes"]) {
  258 + [self.locationPoints removeAllObjects];
  259 + [self queryTwoMineHistoryLine];
  260 + }else if (tempM){
  261 + [self queryOneMineHistoryLine];
  262 + }
  263 +
  264 + [self.mapView addSubview:self.backBtn];
  265 + [self.backBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  266 + make.left.equalTo(self.mapView).offset(10);
  267 + make.top.equalTo(self.mapView).offset(kVerticalStatusHeight + 10);
  268 + make.size.mas_equalTo(CGSizeMake(45, 45));
  269 + }];
  270 + [self.mapView addSubview:self.GPSBtn];
  271 + [self.GPSBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  272 + make.centerY.equalTo(self.backBtn);
  273 + make.right.equalTo(self.mapView.mas_right).offset(-10);
  274 + make.size.mas_equalTo(CGSizeMake(78, 29));
  275 + }];
  276 + [self.mapView addSubview:self.tipGPSBtn];
  277 + [self.tipGPSBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  278 + make.right.equalTo(self.GPSBtn.mas_right);
  279 + make.top.equalTo(self.GPSBtn.mas_bottom);
  280 + make.size.mas_equalTo(CGSizeMake(140, 36));
  281 + }];
  282 + [self addMapBottomView];
  283 +}
  284 +
  285 +//line delegate
  286 +- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
  287 + // if ([overlay isKindOfClass:[BMKCircle class]]) {
  288 + // BMKCircleView *circleView = [[BMKCircleView alloc] initWithOverlay:overlay];
  289 + // circleView.fillColor = [[UIColor alloc] initWithRed:0 green:0 blue:1 alpha:0.3];
  290 + // circleView.strokeColor = [[UIColor alloc] initWithRed:0 green:0 blue:1 alpha:0];
  291 + // return circleView;
  292 + // }else{
  293 + if ([overlay isKindOfClass:[BMKPolyline class]] && [overlay isEqual:self.originalPolyLine]) {
  294 + BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:(BMKPolyline *)overlay];
  295 + polylineView.lineWidth = 2;
  296 + polylineView.strokeColor = [RGBOF(0x5BC4A4) colorWithAlphaComponent:1];
  297 + return polylineView;
  298 + } else {
  299 + BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:(BMKPolyline *)overlay];
  300 + polylineView.lineWidth = 2;
  301 + polylineView.strokeColor = [[UIColor redColor] colorWithAlphaComponent:1];
  302 + return polylineView;
  303 + }
  304 +
  305 + return nil;
  306 +}
  307 +//annotation delegate
  308 +- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
  309 + if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {
  310 + NSString *AnnotationViewID = @"startStopAnnotation";
  311 + BMKAnnotationView *annotationView = nil;
  312 + if (annotationView == nil) {
  313 + annotationView = [[BMKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
  314 + }
  315 + UIImageView *bgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 68, 68)];
  316 + bgView.image = [UIImage imageNamed:@"map-fw"];
  317 + UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 30, 38)];
  318 + if (annotation == _startAnnotation) {
  319 + imageView.image = [UIImage imageNamed:@"map_location-start"];
  320 + } else if (annotation == _endAnnotation){
  321 + imageView.image = [UIImage imageNamed:@"map_location-finish"];
  322 + }
  323 + // else{
  324 + // annotationView.image = [UIImage imageNamed:@"icon_fence_center"];
  325 + // return annotationView;
  326 + // }
  327 + // if (annotation == _startAnnotation || annotation == _endAnnotation) {
  328 + UIView *underView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 15, 7)];
  329 + underView.backgroundColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:0.5];
  330 + underView.centerX = imageView.centerX+2;
  331 + underView.centerY = imageView.centerY+38/2-3;
  332 + underView.layer.cornerRadius = 6;
  333 + underView.layer.masksToBounds = YES;
  334 + bgView.centerX = underView.centerX;
  335 + bgView.centerY = underView.centerY - 8;
  336 + [annotationView addSubview:bgView];
  337 + [annotationView addSubview:underView];
  338 + [annotationView addSubview:imageView];
  339 + annotationView.frame = CGRectMake(0, -38/2+5, 30, 38);
  340 + annotationView.enabled3D = YES;
  341 + annotationView.hidePaopaoWhenSingleTapOnMap = YES;
  342 + annotationView.hidePaopaoWhenDoubleTapOnMap = YES;
  343 + annotationView.hidePaopaoWhenTwoFingersTapOnMap = YES;
  344 + annotationView.hidePaopaoWhenSelectOthers = YES;
  345 + return annotationView;
  346 + // }
  347 + }
  348 + return nil;
  349 +}
  350 +
  351 +#pragma mark -- 定位delegate
  352 +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error {
  353 + NSLog(@"定位失败");
  354 +}
  355 +
  356 +// 定位SDK中,方向变更的回调
  357 +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateHeading:(CLHeading * _Nullable)heading{
  358 + if (!heading) {
  359 + return;
  360 + }
  361 + self.userLocation.heading = heading;
  362 + [self.mapView updateLocationData:self.userLocation];
  363 +}
  364 +
  365 +// 定位SDK中,位置变更的回调
  366 +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
  367 + if (error) {
  368 + //不处理
  369 + }
  370 + if (!location) {
  371 + return;
  372 + }
  373 + CLLocationAccuracy gpsValue = location.location.horizontalAccuracy;
  374 + if (gpsValue > 0 && gpsValue <= 20) {//gps信号好
  375 + self.gpsState = CNLocationGPSStateGood;
  376 + }else if (gpsValue > 20 && gpsValue <= 60){//gps信号中
  377 + self.gpsState = CNLocationGPSStateMedium;
  378 + }else if (gpsValue > 60 && gpsValue < 200){//gps信号差
  379 + self.gpsState = CNLocationGPSStatePoor;
  380 + }else{//gps信号无
  381 + self.gpsState = CNLocationGPSStateNull;
  382 + }
  383 + self.userLocation.location = location.location;
  384 + [self.mapView updateLocationData:self.userLocation];//动态更新我的位置数据
  385 + if (gpsValue < 100 && !_isStopRun) {
  386 + if (!self.currentLocation) {
  387 + self.currentLocation = location.location;
  388 + }
  389 + if (self.locationPoints.count == 0) {
  390 + [self.locationPoints addObject:location.location];
  391 + }
  392 + CLLocationDistance distance = [location.location distanceFromLocation:self.currentLocation];
  393 + if (distance < 3){
  394 + return;
  395 + }
  396 + [self.locationPoints addObject:location.location];
  397 + //画线
  398 + // 直接画stopAfter后的线,如果有暂停,就查出来后画before线,如果没有暂停,就查出来后直接附加到stopAfter线上
  399 + if (self.locationPoints.count > 1) {
  400 + [self addStopAfterPolyLine];
  401 + self.currentLocation = location.location;
  402 + }
  403 + }
  404 +}
  405 +
  406 +//权限改变
  407 +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
  408 + if (status == kCLAuthorizationStatusDenied) {
  409 + dispatch_async(dispatch_get_main_queue(), ^{
  410 + QMUIAlertAction *action1 = [QMUIAlertAction actionWithTitle:@"确定" style:QMUIAlertActionStyleCancel handler:^(__kindof QMUIAlertController *aAlertController, QMUIAlertAction *action) {
  411 + }];
  412 + QMUIAlertController *alertController = [QMUIAlertController alertControllerWithTitle:@"" message:@"无法获取你的位置信息。\n 请到手机系统的[隐私]->[定位服务]中打开定位服务,并允许网家家使用定位服务" preferredStyle:QMUIAlertControllerStyleAlert];
  413 + [alertController addAction:action1];
  414 + [alertController showWithAnimated:YES];
  415 + });
  416 + }
  417 +}
  418 +
  419 +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager doRequestAlwaysAuthorization:(CLLocationManager * _Nonnull)locationManager{
  420 + [locationManager requestAlwaysAuthorization];
  421 +}
  422 +#pragma mark -- private 历史轨迹
  423 +- (void)getHistoryPoints{
  424 + //请求自己的历史轨迹
  425 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {
  426 + [self queryTwoMineHistoryLine];
  427 + }else{
  428 + [self queryOneMineHistoryLine];
  429 + }
  430 +}
  431 +
  432 +#pragma mark -- private 实时画轨迹
  433 +- (void)addStopAfterPolyLine{
  434 + if (self.firstStopAfterLinePoint) {
  435 + [self.locationPoints insertObject:self.firstStopAfterLinePoint atIndex:0];
  436 + }
  437 + CLLocationCoordinate2D coors[self.locationPoints.count];
  438 + NSInteger count = 0;
  439 + for (size_t i = 0; i < self.locationPoints.count; i++) {
  440 + CLLocation *location = [self.locationPoints objectAtIndex:i];
  441 + coors[i] = location.coordinate;
  442 + count++;
  443 + }
  444 + self.stopAfterPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count];
  445 + dispatch_async(dispatch_get_main_queue(), ^{
  446 + if (self.stopAfterPolyLine) {// 防止重复绘制
  447 + [self.mapView removeOverlay:self.stopAfterPolyLine];
  448 + }
  449 + [self.mapView addOverlay:self.stopAfterPolyLine];
  450 + });
  451 +}
  452 +
  453 +#pragma mark -- private map
  454 +- (void)queryTwoMineHistoryLine{
  455 + CNRunExitModel *tempM = self.exitModel;
  456 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  457 + [paramInfo setStartTime:[tempM.startTime integerValue]];
  458 + [paramInfo setEndTime:[tempM.stopTime integerValue]];
  459 + [paramInfo setEntityName:CNUserShareModelUid];
  460 + [paramInfo setIsProcessed:true];
  461 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  462 + processOption.radiusThreshold = 100;
  463 + processOption.denoise = true;
  464 + processOption.vacuate = true;
  465 + processOption.mapMatch = false;
  466 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  467 + paramInfo.processOption = processOption;
  468 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  469 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  470 + vm.completionHandler = ^(NSArray *points) {
  471 + if (points.count > 0) {
  472 + NSMutableArray *mu = [NSMutableArray arrayWithCapacity:0];
  473 + for (CNHistoryTrackPoint *point in points) {
  474 + CLLocation *location = [[CLLocation alloc] initWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude];
  475 + [mu addObject:location];
  476 + }
  477 + //画线
  478 + CLLocationCoordinate2D coors[mu.count];
  479 + NSInteger count = 0;
  480 + for (size_t i = 0; i < mu.count; i++) {
  481 + CLLocation *location = [mu objectAtIndex:i];
  482 + coors[i] = location.coordinate;
  483 + count++;
  484 + }
  485 + self.stopBeforePolyLine = [BMKPolyline polylineWithCoordinates:coors count:count];
  486 + dispatch_async(dispatch_get_main_queue(), ^{
  487 + if (self.stopBeforePolyLine) {// 防止重复绘制
  488 + [self.mapView removeOverlay:self.stopBeforePolyLine];
  489 + }
  490 + [self.mapView addOverlay:self.stopBeforePolyLine];
  491 + });
  492 + }
  493 + };
  494 + [vm queryHistoryWithParam:paramInfo];
  495 +
  496 + if (tempM.reStartTime.length == 0 || [tempM.reStartTime isEqualToString:@"<null>"]) {
  497 + tempM.reStartTime = [NSString stringWithFormat:@"%ld",[CNLiveTimeTools getNowTimestamp]];
  498 + [[CNTrackLoaclDataManager shareManager] updateExitModel:tempM];
  499 + return;
  500 + }
  501 + CNHistoryTrackParam * paramInfo2 =[[CNHistoryTrackParam alloc]init];
  502 + [paramInfo2 setStartTime:[tempM.reStartTime integerValue]];
  503 + if (_isEndRunning) {
  504 + [paramInfo2 setEndTime:_endRunningDate];
  505 + }else{
  506 + [paramInfo2 setEndTime:self.recordReInTime];
  507 + }
  508 + [paramInfo2 setEntityName:CNUserShareModelUid];
  509 + [paramInfo2 setIsProcessed:true];
  510 + BTKQueryTrackProcessOption *processOption2 = [[BTKQueryTrackProcessOption alloc] init];
  511 + processOption2.radiusThreshold = 100;
  512 + processOption2.denoise = true;
  513 + processOption2.vacuate = true;
  514 + processOption2.mapMatch = false;
  515 + processOption2.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  516 + paramInfo2.processOption = processOption;
  517 + paramInfo2.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  518 + CNHistoryViewModel *vm2 = [[CNHistoryViewModel alloc] init];
  519 + vm2.completionHandler = ^(NSArray *points) {
  520 + if (points.count > 0) {
  521 + NSMutableArray *mu = [NSMutableArray arrayWithCapacity:0];
  522 + for (CNHistoryTrackPoint *point in points) {
  523 + CLLocation *location = [[CLLocation alloc] initWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude];
  524 + [mu addObject:location];
  525 + }
  526 + self.firstStopAfterLinePoint = [mu lastObject];
  527 + //画线
  528 + CLLocationCoordinate2D coors[mu.count];
  529 + NSInteger count = 0;
  530 + for (size_t i = 0; i < mu.count; i++) {
  531 + CLLocation *location = [mu objectAtIndex:i];
  532 + coors[i] = location.coordinate;
  533 + count++;
  534 + }
  535 + self.frontStopAfterPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count];
  536 + dispatch_async(dispatch_get_main_queue(), ^{
  537 + if (self.frontStopAfterPolyLine) {// 防止重复绘制
  538 + [self.mapView removeOverlay:self.frontStopAfterPolyLine];
  539 + }
  540 + [self.mapView addOverlay:self.frontStopAfterPolyLine];
  541 + });
  542 + }
  543 + };
  544 + [vm2 queryHistoryWithParam:paramInfo2];
  545 +}
  546 +- (void)queryOneMineHistoryLine{
  547 + CNRunExitModel *tempM = self.exitModel;
  548 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  549 + [paramInfo setStartTime:[tempM.startTime integerValue]];
  550 + if (_isEndRunning) {
  551 + [paramInfo setEndTime:_endRunningDate];
  552 + }else{
  553 + [paramInfo setEndTime:self.recordReInTime];
  554 + }
  555 + [paramInfo setEntityName:CNUserShareModelUid];
  556 + [paramInfo setIsProcessed:true];
  557 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  558 + processOption.radiusThreshold = 100;
  559 + processOption.denoise = true;
  560 + processOption.vacuate = true;
  561 + processOption.mapMatch = false;
  562 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  563 + paramInfo.processOption = processOption;
  564 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  565 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  566 + vm.completionHandler = ^(NSArray *points) {
  567 + if (points.count > 0) {
  568 + NSMutableArray *mu = [NSMutableArray arrayWithCapacity:0];
  569 + for (CNHistoryTrackPoint *point in points) {
  570 + CLLocation *location = [[CLLocation alloc] initWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude];
  571 + [mu addObject:location];
  572 + }
  573 + self.firstStopAfterLinePoint = [mu lastObject];
  574 + //画线
  575 + CLLocationCoordinate2D coors[mu.count];
  576 + NSInteger count = 0;
  577 + for (size_t i = 0; i < mu.count; i++) {
  578 + CLLocation *location = [mu objectAtIndex:i];
  579 + coors[i] = location.coordinate;
  580 + count++;
  581 + }
  582 + self.frontStopAfterPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count];
  583 + dispatch_async(dispatch_get_main_queue(), ^{
  584 + if (self.frontStopAfterPolyLine) {// 防止重复绘制
  585 + [self.mapView removeOverlay:self.frontStopAfterPolyLine];
  586 + }
  587 + [self.mapView addOverlay:self.frontStopAfterPolyLine];
  588 + });
  589 + }
  590 + };
  591 + [vm queryHistoryWithParam:paramInfo];
  592 +}
  593 +
  594 +- (void)addMapOriginalLine{
  595 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  596 + [paramInfo setStartTime:[self.sportsDetailModel.startTime integerValue]];
  597 + [paramInfo setEndTime:[self.sportsDetailModel.endTime integerValue]];
  598 + [paramInfo setEntityName:self.sportsDetailModel.entityName];
  599 + [paramInfo setIsProcessed:true];
  600 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  601 + processOption.radiusThreshold = 100;
  602 + processOption.denoise = true;
  603 + processOption.vacuate = true;
  604 + processOption.mapMatch = false;
  605 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  606 + paramInfo.processOption = processOption;
  607 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  608 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  609 + vm.completionHandler = ^(NSArray *points) {
  610 + NSMutableArray *pointNodes = [NSMutableArray arrayWithCapacity:0];
  611 + for (CNHistoryTrackPoint *point in points) {
  612 + CNLinePointNode *pointNode = [[CNLinePointNode alloc] init];
  613 + pointNode.coordinate = point.coordinate;
  614 + [pointNodes addObject:pointNode];
  615 + }
  616 + CLLocationCoordinate2D paths[pointNodes.count];
  617 + for (NSUInteger i = 0; i < pointNodes.count; i ++) {
  618 + CNLinePointNode *node = pointNodes[i];
  619 + paths[i] = node.coordinate;
  620 + }
  621 + self.originalPolyLine = [BMKPolyline polylineWithCoordinates:paths count:pointNodes.count];
  622 + self->_startAnnotation = [[BMKPointAnnotation alloc] init];
  623 + self->_startAnnotation.coordinate = paths[0];
  624 + self->_startAnnotation.title = @"起点";
  625 + self->_endAnnotation = [[BMKPointAnnotation alloc] init];
  626 + self->_endAnnotation.coordinate = paths[pointNodes.count-1];
  627 + self->_endAnnotation.title = @"终点";
  628 +
  629 + //确认终点后,先查询客服端围栏,后面再判断要不要添加客户端围栏
  630 + [self queryLocalFence];
  631 + dispatch_async(dispatch_get_main_queue(), ^{
  632 + /**
  633 + 向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay:
  634 + 方法来生成标注对应的View
  635 +
  636 + @param overlay 要添加的overlay
  637 + */
  638 + [self.mapView addOverlay:self.originalPolyLine];
  639 + //将标注添加到当前地图View中
  640 + [self->_mapView addAnnotation:self->_startAnnotation];
  641 + //将标注添加到当前地图View中
  642 + [self->_mapView addAnnotation:self->_endAnnotation];
  643 + [self mapViewFitPolyLine:self.originalPolyLine];
  644 +
  645 + });
  646 + };
  647 + [vm queryHistoryWithParam:paramInfo];
  648 +}
  649 +
  650 +//根据polyline设置地图范围
  651 +- (void)mapViewFitPolyLine:(BMKPolyline *) polyLine {
  652 + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY;
  653 + if (polyLine.pointCount < 1) {
  654 + return;
  655 + }
  656 + BMKMapPoint pt = polyLine.points[0];
  657 + // 左上角顶点
  658 + leftTopX = pt.x;
  659 + leftTopY = pt.y;
  660 + // 右下角顶点
  661 + rightBottomX = pt.x;
  662 + rightBottomY = pt.y;
  663 + for (int i = 1; i < polyLine.pointCount; i++) {
  664 + BMKMapPoint pt = polyLine.points[i];
  665 + leftTopX = pt.x < leftTopX ? pt.x : leftTopX;
  666 + leftTopY = pt.y < leftTopY ? pt.y : leftTopY;
  667 + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX;
  668 + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY;
  669 + }
  670 + BMKMapRect rect;
  671 + rect.origin = BMKMapPointMake(leftTopX, leftTopY);
  672 + rect.size = BMKMapSizeMake(rightBottomX - leftTopX, rightBottomY - leftTopY);
  673 + UIEdgeInsets padding = UIEdgeInsetsMake(100, 50, 100, 50);
  674 + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
  675 +}
  676 +
  677 +- (void)addMapBottomView{
  678 + [self.mapView addSubview:self.mapBottomView];
  679 + [self.mapBottomView mas_makeConstraints:^(MASConstraintMaker *make) {
  680 + make.left.right.equalTo(self.mapView);
  681 + make.bottom.equalTo(self.mapView.mas_bottom).offset(-kVerticalBottomSafeHeight);
  682 + make.height.equalTo(@(130));
  683 + }];
  684 +
  685 + [self.mapView addSubview:self.resetBtn];
  686 + [self.resetBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  687 + make.left.equalTo(self.mapView).offset(10);
  688 + make.bottom.equalTo(self.mapBottomView.mas_top).offset(-20);
  689 + make.size.mas_equalTo(CGSizeMake(48, 48));
  690 + }];
  691 + [self.mapBottomView addSubview:self.mapCurrentTimeLab];
  692 + [self.mapCurrentTimeLab mas_makeConstraints:^(MASConstraintMaker *make) {
  693 + make.centerX.equalTo(self.mapBottomView);
  694 + make.top.equalTo(self.mapBottomView).offset(27);
  695 + }];
  696 + [self.mapBottomView addSubview:self.mapTimeLab];
  697 + [self.mapTimeLab mas_makeConstraints:^(MASConstraintMaker *make) {
  698 + make.centerX.equalTo(self.mapBottomView);
  699 + make.top.equalTo(self.mapCurrentTimeLab.mas_bottom).offset(21);
  700 + }];
  701 + [self.mapBottomView addSubview:self.mapCurrentSpeedLab];
  702 + [self.mapCurrentSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) {
  703 + make.centerY.equalTo(self.mapCurrentTimeLab);
  704 + make.left.equalTo(self.mapBottomView).offset(30);
  705 + make.width.equalTo(@(SCREEN_WIDTH/3-40));
  706 + }];
  707 + [self.mapBottomView addSubview:self.mapSpeedLab];
  708 + [self.mapSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) {
  709 + make.centerY.equalTo(self.mapTimeLab);
  710 + make.centerX.equalTo(self.mapCurrentSpeedLab);
  711 + }];
  712 + [self.mapBottomView addSubview:self.mapCurrentKMLab];
  713 + [self.mapCurrentKMLab mas_makeConstraints:^(MASConstraintMaker *make) {
  714 + make.centerY.equalTo(self.mapCurrentTimeLab);
  715 + make.right.equalTo(self.mapBottomView.mas_right).offset(-40);
  716 + }];
  717 + [self.mapBottomView addSubview:self.mapKMLab];
  718 + [self.mapKMLab mas_makeConstraints:^(MASConstraintMaker *make) {
  719 + make.centerY.equalTo(self.mapTimeLab);
  720 + make.centerX.equalTo(self.mapCurrentKMLab);
  721 + }];
  722 +}
  723 +
  724 +-(void)setGpsState:(CNLocationGPSState)gpsState{
  725 + _gpsState = gpsState;
  726 + switch (gpsState) {
  727 + case CNLocationGPSStateGood:{
  728 + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-good"];
  729 + self.currentGPSLab.hidden = YES;
  730 + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-good"] forState:UIControlStateNormal];
  731 + self.tipGPSBtn.hidden = YES;
  732 + }
  733 + break;
  734 + case CNLocationGPSStateMedium:{
  735 + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-mid"];
  736 + self.currentGPSLab.hidden = YES;
  737 + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-mid"] forState:UIControlStateNormal];
  738 + self.tipGPSBtn.hidden = YES;
  739 + }
  740 + break;
  741 + case CNLocationGPSStatePoor:{
  742 + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-low"];
  743 + self.currentGPSLab.hidden = NO;
  744 + self.currentGPSLab.text = @"信号糟糕,数据准确度低";
  745 + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-low"] forState:UIControlStateNormal];
  746 + self.tipGPSBtn.hidden = NO;
  747 + [self.tipGPSBtn setTitle:@"信号糟糕,数据准确度低" forState:UIControlStateNormal];
  748 + }
  749 + break;
  750 + case CNLocationGPSStateNull:{
  751 + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-none"];
  752 + self.currentGPSLab.hidden = NO;
  753 + self.currentGPSLab.text = @"无信号,无法进行数据记录";
  754 + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-none"] forState:UIControlStateNormal];
  755 + self.tipGPSBtn.hidden = NO;
  756 + [self.tipGPSBtn setTitle:@"无信号,无法进行数据记录" forState:UIControlStateNormal];
  757 + }
  758 + break;
  759 + default:
  760 + break;
  761 + }
  762 +}
  763 +
  764 +- (void)backBtnAction:(id)sender{
  765 + if (_isEndRunning) {
  766 + [[NSNotificationCenter defaultCenter] removeObserver:self name:TrackServiceOperationResultNotification object:nil];
  767 + if (_endTimer) {
  768 + [_endTimer invalidate];
  769 + _endTimer = nil;
  770 + }
  771 + if (_startRunningTimer) {
  772 + [_startRunningTimer invalidate];
  773 + _startRunningTimer = nil;
  774 + }
  775 + if ([self.delegate respondsToSelector:@selector(backToFrontVC)]) {
  776 + [self.delegate backToFrontVC];
  777 + }
  778 + [self.navigationController popViewControllerAnimated:YES];
  779 + }else{
  780 + self.mapView.hidden = YES;
  781 + self.fristBgView.hidden = NO;
  782 + }
  783 +}
  784 +
  785 +- (void)resetBtnAction:(id)sender{
  786 + [self.mapView setCenterCoordinate:self.userLocation.location.coordinate animated:YES];
  787 +}
  788 +#pragma mark -- private 本地地理围栏
  789 +//删除客户端地理围栏
  790 +- (void)deleteLocalFence{
  791 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  792 + // 构建请求对象
  793 + BTKDeleteLocalFenceRequest *request = [[BTKDeleteLocalFenceRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:nil tag:2];
  794 + // 删除客户端地理围栏
  795 + [[BTKFenceAction sharedInstance] deleteLocalFenceWith:request delegate:self];
  796 + });
  797 +}
  798 +//删除本地地理围栏的回调
  799 +-(void)onDeleteLocalFence:(NSData *)response{
  800 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  801 + if (nil == dict) {
  802 + NSLog(@"Local Fence Delete格式转换出错");
  803 + }
  804 + if (0 != [dict[@"status"] intValue]) {
  805 + NSLog(@"客户端地理围栏删除返回错误");
  806 + }
  807 + if (_isEndRunning) {
  808 + return;
  809 + }
  810 + // 查询一次
  811 + [self queryLocalFence];
  812 +}
  813 +- (void)queryLocalFence {
  814 + // 查询所有以当前登录Entity为监控对象的客户端地理围栏
  815 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  816 + BTKQueryLocalFenceRequest *request = [[BTKQueryLocalFenceRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:nil tag:1];
  817 + [[BTKFenceAction sharedInstance] queryLocalFenceWith:request delegate:self];
  818 + });
  819 +}
  820 +
  821 +/**
  822 + 查询客户端围栏实体的回调方法
  823 + @param response 符合条件的客户端地理围栏
  824 + */
  825 +-(void)onQueryLocalFence:(NSData *)response {
  826 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  827 + if (_isEndRunning) {
  828 + //如果结束跑步,地理围栏相关的都不执行了
  829 + return;
  830 + }
  831 + BOOL isError = false;
  832 + if (nil == dict) {
  833 + NSLog(@"Local Fence List查询格式转换出错");
  834 +
  835 + }
  836 + if (0 != [dict[@"status"] intValue]) {
  837 + NSLog(@"客户端本地地理围栏查询返回错误");
  838 + isError = YES;
  839 + }
  840 + if (isError) {
  841 + //上面出错就直接删除
  842 + [self deleteLocalFence];
  843 + return;
  844 + }
  845 + // 如果之前没有创建过客户端围栏的话,查出来的结果就是0个围栏。这时候弹窗提示用户,去新建一个客户端围栏
  846 + NSInteger size = [dict[@"size"] intValue];
  847 + if (size == 0) {
  848 + NSLog(@"还没有创建过客户端围栏");
  849 + //创建本地围栏
  850 + [self createLocalFence];
  851 + return;
  852 + }
  853 + //全部删除客户端地理围栏
  854 + if ([dict[@"fences"] isKindOfClass:[NSArray class]] && ((NSArray *)dict[@"fences"]).count > 0) {
  855 + //删除所有后再删除的回调里查询
  856 + [self deleteLocalFence];
  857 + }
  858 +}
  859 +
  860 +//添加本地地理围栏(圆形)
  861 +- (void)createLocalFence{
  862 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  863 + BTKLocalCircleFence *fence = [[BTKLocalCircleFence alloc] initWithCenter:self.endAnnotation.coordinate radius:20 coordType:BTK_COORDTYPE_GCJ02 denoiseAccuracy:20 fenceName:@"localFence" monitoredObject:CNUserShareModelUid];
  864 + BTKCreateLocalFenceRequest *request = [[BTKCreateLocalFenceRequest alloc] initWithLocalCircleFence:fence tag:1];
  865 + [[BTKFenceAction sharedInstance] createLocalFenceWith:request delegate:self];
  866 + });
  867 +}
  868 +
  869 +//创建本地围栏的回调
  870 +- (void)onCreateLocalFence:(NSData *)response{
  871 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  872 + if (nil == dict) {
  873 + NSLog(@"Local Fence Create 格式转换出错");
  874 + return;
  875 + }
  876 + if (0 != [dict[@"status"] intValue]) {
  877 + NSLog(@"Local Fence Create 返回错误");
  878 + //创建失败,重新创建
  879 + return;
  880 + }
  881 + if (!dict[@"fence_id"]) {
  882 + return;
  883 + }
  884 + localFenceId = [NSNumber numberWithFloat:[dict[@"fence_id"] floatValue]];
  885 + //创建成功后查询一次本地围栏的实时状态,目的是使本地地理围栏生效
  886 + if (localFenceId) {
  887 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  888 + BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] tag:1];
  889 + [[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self];
  890 +
  891 +// #pragma mark -- TODO 把客户端地理围栏画出来
  892 +// BMKPointAnnotation *centerAnnotation = [[BMKPointAnnotation alloc] init];
  893 +// centerAnnotation.coordinate = self.endAnnotation.coordinate;
  894 +// centerAnnotation.title = @"圆心";
  895 +// BMKCircle *radiusCircle = [[BMKCircle alloc] init];
  896 +// radiusCircle.coordinate = self.endAnnotation.coordinate;
  897 +//// double radius = [self.radiusTextField.text doubleValue];
  898 +//// if (fabs(radius) > DBL_EPSILON) {
  899 +//// radiusCircle.radius = radius;
  900 +//// } else {
  901 +// radiusCircle.radius = 10.0;
  902 +// [self.mapView addAnnotation:centerAnnotation];
  903 +// [self.mapView addOverlay:radiusCircle];
  904 +
  905 +// }
  906 + });
  907 + }
  908 +}
  909 +
  910 +/**
  911 + 查询监控对象和客户端地理围栏的位置关系的回调方法
  912 +
  913 + @param response 查询结果
  914 + */
  915 +-(void)onQueryLocalFenceStatus:(NSData *)response{
  916 + if (_isStopRun) {
  917 + return;
  918 + }
  919 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  920 + if (nil == dict) {
  921 + NSLog(@"Local Fence Query格式转换出错");
  922 + return;
  923 + }
  924 + if (0 != [dict[@"status"] intValue]) {
  925 + NSLog(@"客户端地理围栏删除返回错误");
  926 + }
  927 + //不做成功和失败的处理,目的是使监控本地地理围栏生效
  928 +}
  929 +
  930 +//查询本地围栏的警报历史记录,是否经过过终点
  931 +- (void)queryLocalHistoryAlarm{
  932 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  933 + BTKQueryLocalFenceHistoryAlarmRequest *request = [[BTKQueryLocalFenceHistoryAlarmRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] startTime:self->_startRunningDate endTime:self->_endRunningDate tag:1];
  934 + // 发起查询请求
  935 + [[BTKFenceAction sharedInstance] queryLocalFenceHistoryAlarmWith:request delegate:self];
  936 + });
  937 +}
  938 +
  939 +/**
  940 + 查询客户端地理围栏历史报警信息的回调方法
  941 +
  942 + @param response 查询结果
  943 + */
  944 +-(void)onQueryLocalFenceHistoryAlarm:(NSData *)response{
  945 + BOOL errorOrNoMessage = false;
  946 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  947 + if (nil == dict) {
  948 + errorOrNoMessage = YES;
  949 + }
  950 + if (dict && 0 != [dict[@"status"] intValue]) {
  951 + NSLog(@"Query Local Fence History Alarm 返回错误");
  952 + //历史报警查询失败
  953 + errorOrNoMessage = YES;
  954 + }
  955 + if (dict && 0 == [dict[@"size"] intValue]) {
  956 + //过去24小时内没有报警信息
  957 + errorOrNoMessage = YES;
  958 + }
  959 + if (errorOrNoMessage) {//表示没有查询到或有错误,就不继续处理了,按照下面说明处理
  960 + //使用当前位置查询距离终点的距离,如果距离在范围内,则认为经过了终点
  961 + [self judgeSuccessTrack];
  962 + return;
  963 + }
  964 + // 解析数据
  965 +// NSMutableArray *alarmInfoText = [NSMutableArray arrayWithCapacity:[dict[@"size"] intValue]];
  966 + BOOL isEnterLocal = false;
  967 + for (NSDictionary *alarm in dict[@"alarms"]) {
  968 +// NSString *fenceName = alarm[@"fence_name"];
  969 +// NSString *monitoredObject = alarm[@"monitored_person"];
  970 +// NSString *action = nil;
  971 + if ([alarm[@"action"] isEqualToString:@"enter"]) {
  972 +// action = @"进入";
  973 + isEnterLocal = YES;//表示进入过本地地理围栏
  974 + break;
  975 + } else if ([alarm[@"action"] isEqualToString:@"exit"]) {
  976 +// action = @"离开";
  977 + }
  978 + }
  979 + if (!isEnterLocal) {//如果没有进入本地地理围栏的结果,则使用距离判断
  980 + [self judgeSuccessTrack];
  981 + }else{
  982 + //经过了终点
  983 + [self queryCurrentRunningEndPoint:^(NSArray *points) {
  984 + __block int successCount = 0;
  985 + __block NSMutableArray *mutArr = [NSMutableArray arrayWithArray:points];
  986 + for (CNLiveSportsCoordinatesModel *pointNode in self.sportsDetailModel.latLongitude) {
  987 + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:[pointNode.latitude doubleValue] longitude:[pointNode.longitude doubleValue]];
  988 + [mutArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  989 + CNHistoryTrackPoint *minePoint = obj;
  990 + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude];
  991 + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation];
  992 + if (distance < 50) {//表示这个点已经完成
  993 + [mutArr removeObjectsInRange:NSMakeRange(0, idx+1)];
  994 + successCount ++;
  995 + *stop = YES;
  996 + }
  997 + }];
  998 + }
  999 + if (successCount*1.000/self.sportsDetailModel.latLongitude.count*1.000 > 0.70) {//大于60%则认为任务完成
  1000 + dispatch_async(dispatch_get_main_queue(), ^{
  1001 + self->_endStatus = @"路线完成";
  1002 +
  1003 + self.successStateLab.text = self->_endStatus;
  1004 + [self uploadData:YES img:nil];
  1005 + });
  1006 + }else{
  1007 + dispatch_async(dispatch_get_main_queue(), ^{
  1008 + self->_endStatus = @"路线未完成";
  1009 + self.successStateLab.text = self->_endStatus;
  1010 + [self uploadData:NO img:nil];
  1011 + });
  1012 + }
  1013 + }];
  1014 + }
  1015 +}
  1016 +
  1017 +#pragma mark -- private 服务端地理围栏 : 超出或进入围栏警报
  1018 +//服务端
  1019 +-(void)serviceGetPushMessageHandler:(NSNotification *)notification {
  1020 + if (_isEndRunning || _isStopRun) {//暂停或结束都不接收通知
  1021 + return;
  1022 + }
  1023 + NSDictionary *info = notification.userInfo;
  1024 + NSDictionary *dict = info[@"message"];
  1025 +// dispatch_async(dispatch_get_main_queue(), ^{
  1026 +// [QMUITips showInfo:str inView:AppKeyWindow hideAfterDelay:2];
  1027 +// });
  1028 +// NSDictionary *dict = @{
  1029 +// @"action":action,
  1030 +// @"fenceType":fenceType,
  1031 +// @"fenceID":fenceID
  1032 +// };
  1033 + NSString *action = dict[@"action"];//进入/离开
  1034 + NSString *fenceType = dict[@"fenceType"];//围栏类型
  1035 + NSString *fenceID = dict[@"fenceID"];//围栏id
  1036 +
  1037 + if ([fenceType isEqualToString:@"服务端围栏"] && [fenceID isEqualToString:[NSString stringWithFormat:@"%@",self.sportsDetailModel.fenceId]]) {
  1038 + if ([action isEqualToString:@"离开"]) {
  1039 + dispatch_async(dispatch_get_main_queue(), ^{
  1040 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"您已偏离路径轨迹\n请您及时回归路径" preferredStyle:UIAlertControllerStyleAlert];
  1041 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1042 + }];
  1043 + [actionAlert addAction:action];
  1044 + [self presentViewController:actionAlert animated:YES completion:nil];
  1045 + });
  1046 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1047 + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
  1048 + AVSpeechSynthesizer *voice= [[AVSpeechSynthesizer alloc]init];
  1049 + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc]initWithString:@"您已偏离路径轨迹,请您及时回归路径"];
  1050 + AVSpeechSynthesisVoice *language = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
  1051 + utterance.voice= language;
  1052 + [voice speakUtterance:utterance];
  1053 + });
  1054 + }else{//进入
  1055 + dispatch_async(dispatch_get_main_queue(), ^{
  1056 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"您已回归路径轨迹\n继续参与运动吧" preferredStyle:UIAlertControllerStyleAlert];
  1057 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1058 + }];
  1059 + [actionAlert addAction:action];
  1060 + [self presentViewController:actionAlert animated:YES completion:nil];
  1061 + });
  1062 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1063 + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
  1064 + AVSpeechSynthesizer *voice= [[AVSpeechSynthesizer alloc]init];
  1065 + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc]initWithString:@"您已回归路径轨迹,继续参与运动吧"];
  1066 + AVSpeechSynthesisVoice *language = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
  1067 + utterance.voice= language;
  1068 + [voice speakUtterance:utterance];
  1069 + });
  1070 + }
  1071 + }else if ([fenceType isEqualToString:@"客户端围栏"] && [fenceID isEqualToString:[NSString stringWithFormat:@"%@",localFenceId?localFenceId:@""]] && [action isEqualToString:@"进入"]){//客户端
  1072 + CNRunExitModel *model = [[CNTrackLoaclDataManager shareManager]getExitModel:CNUserShareModelUid];
  1073 + if ([model.step isEqualToString:@"<null>"] || [model.step intValue] <= 100) {
  1074 + return;
  1075 + }
  1076 + BOOL b = [[NSUserDefaults standardUserDefaults] boolForKey:@"isShowOnce"];
  1077 + if (b) {
  1078 + return;
  1079 + }
  1080 + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isShowOnce"];
  1081 + //已经到达目的地 弹窗
  1082 + dispatch_async(dispatch_get_main_queue(), ^{
  1083 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"您已经到达终点附近\n可以结束运动了" preferredStyle:UIAlertControllerStyleAlert];
  1084 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1085 + self.fristBgView.hidden = NO;
  1086 + self.mapView.hidden = YES;
  1087 + }];
  1088 + [actionAlert addAction:action];
  1089 + [self presentViewController:actionAlert animated:YES completion:nil];
  1090 + });
  1091 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1092 + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
  1093 + AVSpeechSynthesizer *voice= [[AVSpeechSynthesizer alloc]init];
  1094 + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc]initWithString:@"您已经到达终点附近,可以结束运动了"];
  1095 + AVSpeechSynthesisVoice *language = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
  1096 + utterance.voice= language;
  1097 + [voice speakUtterance:utterance];
  1098 + });
  1099 +
  1100 + }
  1101 +}
  1102 +
  1103 +#pragma mark -- privat 地理围栏:围栏实时状态查询
  1104 +- (void)queryRealtimeStatus{
  1105 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1106 + BTKQueryServerFenceStatusRequest *request = [[BTKQueryServerFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self.sportsDetailModel.fenceId] ServiceID:BDMapServiceID tag:1];
  1107 + // 发起查询请求
  1108 + [[BTKFenceAction sharedInstance] queryServerFenceStatusWith:request delegate:self];
  1109 + });
  1110 +}
  1111 +#pragma mark -- 围栏
  1112 +//实时查询一次监控对象在服务端地理围栏内外的回调方法
  1113 +-(void)onQueryServerFenceStatus:(NSData *)response{
  1114 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  1115 + if (nil == dict) {
  1116 + NSLog(@"Server Fence List查询格式转换出错");
  1117 + return;
  1118 + }
  1119 + if ([dict[@"message"] isEqualToString:@"成功"]) {
  1120 +// NSArray *arrr = dict[@"monitored_statuses"];
  1121 +// NSDictionary *dictt = arrr[0];
  1122 +// NSString *ssttt = dictt[@"monitored_status"];
  1123 +// [QMUITips showWithText:[NSString stringWithFormat:@"%@___单次查询围栏内外的回调方法",ssttt] inView:self.mapView hideAfterDelay:1.5];
  1124 + }else{
  1125 +// [QMUITips showWithText:@"错误内外的回调方法" inView:self.mapView hideAfterDelay:1.5];
  1126 + }
  1127 +
  1128 + //查询一次本地地理围栏的状态
  1129 + //创建成功后查询一次本地围栏的实时状态,目的是使本地地理围栏生效
  1130 + if (localFenceId) {
  1131 + //本地地理围栏存在,查询一次本地地理围栏的实时状态
  1132 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1133 + BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] tag:1];
  1134 + [[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self];
  1135 + });
  1136 + }
  1137 +// else{
  1138 +// //本地地理围栏不存在,先创建一个本地地理围栏,然后再查实时状态
  1139 +// [self queryLocalFence];
  1140 +// }
  1141 +}
  1142 +////查询监控对象的服务端围栏报警信息的回调方法
  1143 +//-(void)onQueryServerFenceHistoryAlarm:(NSData *)response{
  1144 +// NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  1145 +// if (nil == dict) {
  1146 +// NSLog(@"Server Fence List查询格式转换出错");
  1147 +// return;
  1148 +// }
  1149 +// if (dict[@"message"]) {
  1150 +// // [QMUITips showWithText:dict[@"message"] inView:self.mapView hideAfterDelay:5];
  1151 +// }else{
  1152 +// [QMUITips showWithText:@"错误报警信息的回调方法" inView:self.mapView hideAfterDelay:5];
  1153 +// }
  1154 +//}
  1155 +
  1156 +#pragma mark -- private
  1157 +- (void)initData{
  1158 + [CNTrackServiceManager defaultManager].isStartRecord = YES;
  1159 + //禁止左滑返回
  1160 +// #pragma mark -- TODO 是否有必须禁止左滑
  1161 +
  1162 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceGetPushMessageHandler:) name:TrackServiceGetPushMessageNotification object:nil];//服务端地理围栏的警报通知
  1163 +// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runningFromBgToBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
  1164 + //app进入后台
  1165 +// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runningToBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
  1166 +
  1167 + //gps信号状态初始化
  1168 + self.gpsState = CNLocationGPSStateNull;
  1169 + [CNTrackServiceManager defaultManager].isClickGoOn = NO;//处理暂停的逻辑
  1170 + //跑步已经用时
  1171 + if (self.exitModel.eventId.length > 0) {
  1172 + if (self.exitModel.step.length > 0 && ![self.exitModel.step isEqualToString:@"<null>"]) {
  1173 + _lastStepCount = [self.exitModel.step integerValue];
  1174 + }else{
  1175 + _lastStepCount = 0;
  1176 + }
  1177 + _startRunningDate = [self.exitModel.startTime integerValue];
  1178 + double km = _lastStepCount*60.0/100/1000;
  1179 + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:70]};
  1180 + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:15]};
  1181 + NSAttributedString *attributedString = [self attributedText:@[[NSString stringWithFormat:@"%.2f",floor((km)*100)/100],@" 公里"] attributeAttay:@[attributesNum,attributesKM]];
  1182 + self.currentKMLab.attributedText = attributedString;
  1183 + self.mapCurrentKMLab.text = [NSString stringWithFormat:@"%.2f",floor((km)*100)/100];
  1184 + self.currentStepLab.text = [NSString stringWithFormat:@"%ld",_lastStepCount];
  1185 +
  1186 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {//重新进入后,处理出去前得暂停逻辑
  1187 + //现在的时间减去开始的时间,获取间隔的秒给_totalTime赋值
  1188 + _stopDate = [self.exitModel.stopTime integerValue];
  1189 + NSTimeInterval intervalS = [[NSDate dateWithTimeIntervalSince1970:_startRunningDate] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:_stopDate]];
  1190 + _totalTime = labs((NSInteger)intervalS);
  1191 + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]){
  1192 + _reStartDate = [self.exitModel.reStartTime integerValue];
  1193 + NSTimeInterval reIntervalS = [[NSDate dateWithTimeIntervalSince1970:_reStartDate] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:[CNLiveTimeTools getNowTimestamp]]];
  1194 + _totalTime += labs((NSInteger)reIntervalS);
  1195 + }else{
  1196 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",(long)[CNLiveTimeTools getNowTimestamp]];
  1197 + _reStartDate = [self.exitModel.reStartTime integerValue];
  1198 + [[CNTrackLoaclDataManager shareManager]updateExitModel:self.exitModel];
  1199 + }
  1200 + self.mapCurrentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km];
  1201 +
  1202 + self.currentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km];
  1203 + //记录步数
  1204 + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES];
  1205 + }else{
  1206 + //现在的时间减去开始的时间,获取间隔的秒给_totalTime赋值
  1207 + NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:[CNLiveTimeTools getNowTimestamp]];
  1208 + NSDate *date2 = [NSDate dateWithTimeIntervalSince1970:[self.exitModel.startTime integerValue]];
  1209 + NSInteger intervalS = [startDate timeIntervalSinceDate:date2];
  1210 + _totalTime = labs((NSInteger)intervalS);
  1211 + self.mapCurrentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km];
  1212 +
  1213 + self.currentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km];
  1214 + //记录步数
  1215 + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES];
  1216 + }
  1217 + }else{
  1218 + _totalTime = 0;
  1219 + _lastStepCount = 0;
  1220 + //持久记录开始时间
  1221 + self.exitModel = [[CNRunExitModel alloc] init];
  1222 + self.exitModel.eventId = self.eventID;
  1223 + self.exitModel.userId = CNUserShareModelUid;
  1224 + _startRunningDate = [CNLiveTimeTools getNowTimestamp];
  1225 + self.exitModel.startTime = [NSString stringWithFormat:@"%ld",(long)_startRunningDate];
  1226 + [[CNTrackLoaclDataManager shareManager] insertExitModel:self.exitModel];
  1227 + NSDate *date = [NSDate dateWithTimeIntervalSince1970:_startRunningDate];
  1228 + //记录步数
  1229 + [[CNTrackServiceManager defaultManager] recordStep:date isUser:YES];
  1230 + }
  1231 +}
  1232 +
  1233 +- (void)runningFromBgToBecomeActive{
  1234 +// //清空地图上自己的轨迹,清空array
  1235 +// dispatch_async(dispatch_get_main_queue(), ^{
  1236 +// [self.mapView removeOverlay:self.stopBeforePolyLine];
  1237 +// [self.mapView removeOverlay:self.stopAfterPolyLine];
  1238 +// [self.mapView removeOverlay:self.frontStopAfterPolyLine];
  1239 +// [self.locationPoints removeAllObjects];
  1240 +// });
  1241 +// //查询历史轨迹
  1242 +// [self getHistoryPoints];
  1243 +//
  1244 +// if (_isEndRunning) {
  1245 +// [[CNTrackServiceManager defaultManager] stopGather];
  1246 +// }else{
  1247 +// //控制鹰眼服务
  1248 +// if (![CNTrackServiceManager defaultManager].isServiceStarted) {
  1249 +// // 开启服务之间先配置轨迹服务的基础信息
  1250 +// BTKServiceOption *basicInfoOption = [[BTKServiceOption alloc] initWithAK:AK mcode:MCODE serviceID:serviceID keepAlive:YES];
  1251 +// [[BTKAction sharedInstance] initInfo:basicInfoOption];
  1252 +// // 开启服务
  1253 +// BTKStartServiceOption *startServiceOption = [[BTKStartServiceOption alloc] initWithEntityName:CNUserShareModelUid];
  1254 +// [[CNTrackServiceManager defaultManager] startServiceWithOption:startServiceOption];
  1255 +// }else{
  1256 +// if (![CNTrackServiceManager defaultManager].isGatherStarted) {
  1257 +// [[CNTrackServiceManager defaultManager] startGather];
  1258 +// }
  1259 +// }
  1260 +// //实时查询一次两个围栏
  1261 +// [self queryRealtimeStatus];
  1262 +// //创建成功后查询一次本地围栏的实时状态,目的是使本地地理围栏生效
  1263 +// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1264 +// if (self->localFenceId) {
  1265 +// BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] tag:1];
  1266 +// [[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self];
  1267 +// }
  1268 +// });
  1269 +// }
  1270 +
  1271 +}
  1272 +
  1273 +//- (void)runningToBackground{
  1274 +// //app进入后台的时候记录一下数据
  1275 +//
  1276 +//}
  1277 +
  1278 +//判断是否完成了规划的路线
  1279 +- (void)judgeSuccessTrack{
  1280 + [self queryCurrentRunningEndPoint:^(NSArray *points) {
  1281 + __block int successCount = 0;
  1282 + __block NSMutableArray *mutArr = [NSMutableArray arrayWithArray:points];
  1283 + //逆序遍历自己的轨迹点和终点做比较,差值小于20说明经过了终点
  1284 + __block BOOL isPassEndADD = false;
  1285 + [mutArr enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  1286 + CNHistoryTrackPoint *minePoint = obj;
  1287 + CLLocation *minP = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude];
  1288 + CLLocation *endP = [[CLLocation alloc] initWithLatitude:self.endAnnotation.coordinate.latitude longitude:self.endAnnotation.coordinate.longitude];
  1289 + CLLocationDistance distance = [minP distanceFromLocation:endP];
  1290 + if (distance < 20) {//完成了
  1291 + isPassEndADD = YES;
  1292 + *stop = YES;
  1293 + }
  1294 + }];
  1295 + if (!isPassEndADD) {
  1296 + //没经过终点说明没完成,直接请求服务器接口
  1297 + [self uploadData:NO img:nil];
  1298 + }else{
  1299 + for (CNLiveSportsCoordinatesModel *pointNode in self.sportsDetailModel.latLongitude) {
  1300 + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:[pointNode.latitude doubleValue] longitude:[pointNode.longitude doubleValue]];
  1301 + [mutArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  1302 + CNHistoryTrackPoint *minePoint = obj;
  1303 + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude];
  1304 + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation];
  1305 + if (distance < 50) {//表示这个点已经完成
  1306 + [mutArr removeObjectsInRange:NSMakeRange(0, idx+1)];
  1307 + successCount ++;
  1308 + *stop = YES;
  1309 + }
  1310 + }];
  1311 + }
  1312 + if (successCount*1.000/self.sportsDetailModel.latLongitude.count*1.000 > 0.70) {//大于70%则认为任务完成
  1313 + dispatch_async(dispatch_get_main_queue(), ^{
  1314 + self->_endStatus = @"路线完成";
  1315 + self.successStateLab.text = self->_endStatus;
  1316 + [self uploadData:YES img:nil];
  1317 + });
  1318 +
  1319 + }else{
  1320 + dispatch_async(dispatch_get_main_queue(), ^{
  1321 + self->_endStatus = @"路线未完成";
  1322 + self.successStateLab.text = self->_endStatus;
  1323 + [self uploadData:NO img:nil];
  1324 + });
  1325 + }
  1326 + }
  1327 + }];
  1328 +}
  1329 +
  1330 +- (void)alertEndSelect:(BOOL)isSuccessTrack img:(NSString *)imgUrlStr{
  1331 + //弹窗,无网络,是否暂存,是否重试
  1332 + dispatch_async(dispatch_get_main_queue(), ^{
  1333 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"上传数据失败\n是否重试" preferredStyle:UIAlertControllerStyleAlert];
  1334 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"重试" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1335 + [self uploadData:isSuccessTrack img:imgUrlStr];
  1336 + }];
  1337 + [actionAlert addAction:action];
  1338 + UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"暂存" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1339 + if (self->_endTimer) {
  1340 + [self->_endTimer invalidate];
  1341 + self->_endTimer = nil;
  1342 + }
  1343 + if (self->_startRunningTimer) {
  1344 + [self->_startRunningTimer invalidate];
  1345 + self->_startRunningTimer = nil;
  1346 + }
  1347 + [CNTrackServiceManager defaultManager].isStartRecord = NO;
  1348 + //长按结束了,删除数据库中的逻辑辅助数据
  1349 + [[CNTrackLoaclDataManager shareManager] deleteExitModel:CNUserShareModelUid];
  1350 + //更新上一页的最底部的按钮状态:发通知
  1351 + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveSport_DetailUplaod object:nil];
  1352 + //跳转到失败列表
  1353 + CNReUploadViewController *vc = [[CNReUploadViewController alloc] init];
  1354 + vc.isNeedBack = YES;
  1355 + self->_isStopAnimation = YES;
  1356 + [self.navigationController pushViewController:vc animated:YES];
  1357 + }];
  1358 + [actionAlert addAction:action1];
  1359 + [self presentViewController:actionAlert animated:YES completion:nil];
  1360 + });
  1361 +}
  1362 +
  1363 +- (void)uploadData:(BOOL)isSuccessTrack img:(NSString *)imgUrlStr{
  1364 + if (![CNLiveNetworking isNetworking]) {
  1365 + [self alertEndSelect:isSuccessTrack img:imgUrlStr];
  1366 + return;
  1367 + }
  1368 + self.exitModel = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid];
  1369 + NSString *strUrl = CNSportsChinaSaveRecordUrl;
  1370 + BOOL _isTempStop = NO;
  1371 + if (self.exitModel.isStop.length>0 && ![self.exitModel.isStop isEqualToString:@"<null>"]) {
  1372 + _isTempStop = YES;
  1373 + }
  1374 + NSString *_tempPace = [self.currentSpeedLab.text isEqualToString:@"--"]?@"0":self.currentSpeedLab.text;
  1375 + NSString *_tempStep = [self.currentStepLab.text isEqualToString:@"--"]?@"0":self.currentStepLab.text;
  1376 +
  1377 + NSDictionary *dict = @{
  1378 + @"eventId":self.eventID,
  1379 + @"sid":CNUserShareModelUid,
  1380 + @"employTime":[NSString stringWithFormat:@"%ld",(long)_totalTime],
  1381 + @"mileage":self.mapCurrentKMLab.text,
  1382 + @"pace":_tempPace,
  1383 + @"step":_tempStep,
  1384 + //@"roadmap":imgUrlStr,
  1385 + @"startTime":[NSString stringWithFormat:@"%ld",(long)_startRunningDate],
  1386 + @"endTime":[NSString stringWithFormat:@"%ld",(long)_endRunningDate],
  1387 + @"isPause":_isTempStop?@"1":@"0",
  1388 + @"pauseTime":_isTempStop?self.exitModel.stopTime:@"",
  1389 + @"continueTime":_isTempStop?self.exitModel.reStartTime:@"",
  1390 + @"completeStatus":isSuccessTrack?@"1":@"0"
  1391 + };
  1392 +
  1393 + [CNLiveNetworking requestNetworkWithMethod:CNLiveRequestMethodPOST URLString:strUrl Param:dict CacheType:CNLiveNetworkCacheTypeNetworkOnly CompletionBlock:^(NSURLSessionTask *requestTask, id responseObject, NSError *error) {
  1394 + if (error) {
  1395 + //弹窗,是否暂存,是否重试
  1396 + [self alertEndSelect:isSuccessTrack img:imgUrlStr];
  1397 + }else{
  1398 + if ([responseObject isKindOfClass:[NSDictionary class]]) {
  1399 + NSString *resultCode = [NSString stringWithFormat:@"%@", responseObject[@"errorCode"]];
  1400 + if ([resultCode isEqualToString:@"0"]) {
  1401 + //长按结束了,删除数据库中的逻辑辅助数据
  1402 + [[CNTrackLoaclDataManager shareManager] deleteExitModel:CNUserShareModelUid];
  1403 + [[CNTrackLoaclDataManager shareManager] deleteFUploadModel:self->failModel];
  1404 + //更新上一页的最底部的按钮状态:发通知
  1405 + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveSport_DetailUplaod object:nil];
  1406 + [self afterLongPress];
  1407 + }else{
  1408 + //弹窗,是否暂存,是否重试
  1409 + [self alertEndSelect:isSuccessTrack img:imgUrlStr];
  1410 + }
  1411 + }else{
  1412 + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5];
  1413 + }
  1414 + }
  1415 + }];
  1416 +}
  1417 +
  1418 +#pragma mark -- private 长按结束后的UI处理
  1419 +- (void)afterLongPress{
  1420 + dispatch_async(dispatch_get_main_queue(), ^{
  1421 + self.backBtn.userInteractionEnabled = YES;
  1422 + [self.preSaveView removeAllSubviews];
  1423 + [self.preSaveView removeFromSuperview];
  1424 + self.saveBtn.hidden = NO;
  1425 + self->_isStopAnimation = YES;
  1426 + });
  1427 +}
  1428 +
  1429 +- (void)backFirstBtnAction{
  1430 + if (_endTimer) {
  1431 + [_endTimer invalidate];
  1432 + _endTimer = nil;
  1433 + }
  1434 + if (_startRunningTimer) {
  1435 + [_startRunningTimer invalidate];
  1436 + _startRunningTimer = nil;
  1437 + }
  1438 + if ([self.delegate respondsToSelector:@selector(backToFrontVC)]) {
  1439 + [self.delegate backToFrontVC];
  1440 + }
  1441 + [self.navigationController popViewControllerAnimated:YES];
  1442 +}
  1443 +
  1444 +- (NSString *)getPaceSpeed:(double)second distance:(double)distance{
  1445 + if (distance != 0) {
  1446 + //计算分
  1447 + int minute = (int) (second / distance / 60);
  1448 + //获取秒
  1449 + double miaoMin = ((double) (second / distance / 60)) - ((int) (second / distance / 60));
  1450 + int miao = (int) (miaoMin * 60);
  1451 + return [NSString stringWithFormat:@"%d′%d″",minute,miao];
  1452 + } else {
  1453 + return @"0";
  1454 + }
  1455 +}
  1456 +
  1457 +- (void)startRunningTime{
  1458 +
  1459 + self.startRunningTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(cumulativeTiming) userInfo:nil repeats:YES];
  1460 +}
  1461 +
  1462 +- (void)cumulativeTiming{
  1463 + _totalTime ++;
  1464 + self.currentTimeLab.text = [CNLiveTimeTools getMMSSFromSS:[NSString stringWithFormat:@"%ld",(long)_totalTime]];
  1465 + self.mapCurrentTimeLab.text = [CNLiveTimeTools getMMSSFromSS:[NSString stringWithFormat:@"%ld",(long)_totalTime]];
  1466 +}
  1467 +
  1468 +// 获取带有不同样式的文字内容
  1469 +//stringArray 字符串数组
  1470 +//attributeAttay 样式数组
  1471 +- (NSAttributedString *)attributedText:(NSArray*)stringArray attributeAttay:(NSArray *)attributeAttay{
  1472 + // 定义要显示的文字内容
  1473 + NSString * string = [stringArray componentsJoinedByString:@""];//拼接传入的字符串数组
  1474 + // 通过要显示的文字内容来创建一个带属性样式的字符串对象
  1475 + NSMutableAttributedString * result = [[NSMutableAttributedString alloc] initWithString:string];
  1476 + for(NSInteger i = 0; i < stringArray.count; i++){
  1477 + // 将某一范围内的字符串设置样式
  1478 + [result setAttributes:attributeAttay[i] range:[string rangeOfString:stringArray[i]]];
  1479 + }
  1480 + // 返回已经设置好了的带有样式的文字
  1481 + return [[NSAttributedString alloc] initWithAttributedString:result];
  1482 +}
  1483 +
  1484 +- (void)addFirstView{
  1485 + [self.view addSubview:self.fristBgView];
  1486 + [self.fristBgView mas_makeConstraints:^(MASConstraintMaker *make) {
  1487 + make.left.right.top.bottom.equalTo(self.view);
  1488 + }];
  1489 + [self.fristBgView addSubview:self.backFirstBtn];
  1490 + [self.backFirstBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  1491 + make.top.equalTo(self.fristBgView).offset(kVerticalStatusHeight+10);
  1492 + make.left.equalTo(self.fristBgView).offset(5);
  1493 + make.size.mas_equalTo(CGSizeMake(40, 40));
  1494 + }];
  1495 + UIImageView *imageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"top_back_white"]];
  1496 + [self.backFirstBtn addSubview:imageV];
  1497 + [imageV mas_makeConstraints:^(MASConstraintMaker *make) {
  1498 + make.centerY.equalTo(self.backFirstBtn);
  1499 + make.right.equalTo(self.backFirstBtn).offset(-5);
  1500 + make.size.mas_equalTo(CGSizeMake(12, 20));
  1501 + }];
  1502 + [self.fristBgView addSubview:self.currentKMLab];
  1503 + [self.currentKMLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1504 + make.centerX.equalTo(self.view);
  1505 + make.top.equalTo(self.view).offset(130);
  1506 + }];
  1507 +
  1508 + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:70]};
  1509 + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:15]};
  1510 + NSAttributedString *attributedString = [self attributedText:@[self.mapCurrentKMLab.text,@" 公里"]
  1511 + attributeAttay:@[attributesNum,attributesKM]];
  1512 + self.currentKMLab.attributedText = attributedString;
  1513 +
  1514 +
  1515 + [self.fristBgView addSubview:self.gpsLab];
  1516 + [self.gpsLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1517 + make.left.equalTo(self.view).offset(25);
  1518 + make.top.equalTo(self.currentKMLab.mas_bottom).offset(100);
  1519 + }];
  1520 + [self.fristBgView addSubview:self.currentGPSImgView];
  1521 + [self.currentGPSImgView mas_makeConstraints:^(MASConstraintMaker *make) {
  1522 + make.centerY.equalTo(self.gpsLab);
  1523 + make.left.equalTo(self.gpsLab.mas_right).offset(10);
  1524 + }];
  1525 + [self.fristBgView addSubview:self.currentGPSLab];
  1526 + [self.currentGPSLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1527 + make.centerY.equalTo(self.gpsLab);
  1528 + make.left.equalTo(self.currentGPSImgView.mas_right).offset(10);
  1529 + }];
  1530 + [self.fristBgView addSubview:self.detailMapBtn];
  1531 + [self.detailMapBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  1532 + make.centerY.equalTo(self.gpsLab);
  1533 + make.right.equalTo(self.view.mas_right).offset(-25);
  1534 + make.width.height.equalTo(@(52));
  1535 + }];
  1536 + self.detailMapBtn.layer.cornerRadius = 52/2;
  1537 + self.detailMapBtn.layer.masksToBounds = YES;
  1538 + [self.fristBgView addSubview:self.mapDesLab];
  1539 + [self.mapDesLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1540 + make.centerX.equalTo(self.detailMapBtn);
  1541 + make.top.equalTo(self.detailMapBtn.mas_bottom).offset(10);
  1542 + }];
  1543 + [self.fristBgView addSubview:self.speedImgView];
  1544 + [self.speedImgView mas_makeConstraints:^(MASConstraintMaker *make) {
  1545 + make.top.equalTo(self.mapDesLab.mas_bottom).offset(25);
  1546 + make.left.equalTo(self.view).offset(45);
  1547 + make.size.mas_equalTo(CGSizeMake(26, 23));
  1548 + }];
  1549 + [self.fristBgView addSubview:self.currentSpeedLab];
  1550 + [self.currentSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1551 + make.centerX.equalTo(self.speedImgView);
  1552 + make.top.equalTo(self.speedImgView.mas_bottom).offset(20);
  1553 + make.width.equalTo(@(SCREEN_WIDTH/3-40));
  1554 + }];
  1555 + [self.fristBgView addSubview:self.speedDesLab];
  1556 + [self.speedDesLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1557 + make.centerX.equalTo(self.speedImgView);
  1558 + make.top.equalTo(self.currentSpeedLab.mas_bottom).offset(20);
  1559 + }];
  1560 + [self.fristBgView addSubview:self.timeImgView];
  1561 + [self.timeImgView mas_makeConstraints:^(MASConstraintMaker *make) {
  1562 + make.centerX.equalTo(self.view);
  1563 + make.centerY.equalTo(self.speedImgView);
  1564 + make.size.mas_equalTo(CGSizeMake(23, 25));
  1565 + }];
  1566 + [self.fristBgView addSubview:self.currentTimeLab];
  1567 + [self.currentTimeLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1568 + make.centerX.equalTo(self.timeImgView);
  1569 + make.centerY.equalTo(self.currentSpeedLab);
  1570 + }];
  1571 + [self.fristBgView addSubview:self.timeDesLab];
  1572 + [self.timeDesLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1573 + make.centerX.equalTo(self.timeImgView);
  1574 + make.centerY.equalTo(self.speedDesLab);
  1575 + }];
  1576 + [self.fristBgView addSubview:self.stepImgView];
  1577 + [self.stepImgView mas_makeConstraints:^(MASConstraintMaker *make) {
  1578 + make.centerY.equalTo(self.speedImgView);
  1579 + make.right.equalTo(self.view.mas_right).offset(-45);
  1580 + make.size.mas_equalTo(CGSizeMake(26, 24));
  1581 + }];
  1582 + [self.fristBgView addSubview:self.currentStepLab];
  1583 + [self.currentStepLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1584 + make.centerX.equalTo(self.stepImgView);
  1585 + make.centerY.equalTo(self.currentSpeedLab);
  1586 + }];
  1587 + [self.fristBgView addSubview:self.stepDesLab];
  1588 + [self.stepDesLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1589 + make.centerX.equalTo(self.stepImgView);
  1590 + make.centerY.equalTo(self.speedDesLab);
  1591 + }];
  1592 + [self.fristBgView addSubview:self.stopRunningBtn];
  1593 + [self.stopRunningBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  1594 + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60);
  1595 + make.size.mas_equalTo(CGSizeMake(90, 90));
  1596 + make.centerX.equalTo(self.view).offset(-SCREEN_WIDTH/4+SCREEN_WIDTH/16);
  1597 + }];
  1598 + self.stopRunningBtn.layer.cornerRadius = 90/2;
  1599 + self.stopRunningBtn.layer.masksToBounds = YES;
  1600 +
  1601 + [self.fristBgView addSubview:self.goonRunningBtn];
  1602 + self.goonRunningBtn.hidden = YES;
  1603 + [self.goonRunningBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  1604 + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60);
  1605 + make.size.mas_equalTo(CGSizeMake(90, 90));
  1606 + make.centerX.equalTo(self.view).offset(-SCREEN_WIDTH/4+SCREEN_WIDTH/16);
  1607 + }];
  1608 + self.goonRunningBtn.layer.cornerRadius = 90/2;
  1609 + self.goonRunningBtn.layer.masksToBounds = YES;
  1610 + [self.fristBgView addSubview:self.endRunningBgView];
  1611 + [self.endRunningBgView mas_makeConstraints:^(MASConstraintMaker *make) {
  1612 + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60);
  1613 + make.size.mas_equalTo(CGSizeMake(90, 90));
  1614 + make.centerX.equalTo(self.view).offset(SCREEN_WIDTH/4-SCREEN_WIDTH/16);
  1615 + }];
  1616 + self.endRunningBgView.layer.cornerRadius = 90/2;
  1617 + self.endRunningBgView.layer.masksToBounds = YES;
  1618 + [self.fristBgView addSubview:self.endRunningBtn];
  1619 + [self.endRunningBtn addGestureRecognizer:self.longPress];
  1620 + [self.endRunningBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  1621 + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60);
  1622 + make.size.mas_equalTo(CGSizeMake(90, 90));
  1623 + make.centerX.equalTo(self.view).offset(SCREEN_WIDTH/4-SCREEN_WIDTH/16);
  1624 + }];
  1625 + self.endRunningBtn.layer.cornerRadius = 90/2;
  1626 + self.endRunningBtn.layer.masksToBounds = YES;
  1627 + [self.fristBgView addSubview:self.endTipView];
  1628 + self.endTipView.hidden = YES;
  1629 + [self.endTipView mas_makeConstraints:^(MASConstraintMaker *make) {
  1630 + make.bottom.equalTo(self.endRunningBtn.mas_top);
  1631 + make.centerX.equalTo(self.endRunningBtn);
  1632 + make.size.mas_equalTo(CGSizeMake(72, 33));
  1633 + }];
  1634 + [self.endTipView addSubview:self.endTipLab];
  1635 + [self.endTipLab mas_makeConstraints:^(MASConstraintMaker *make) {
  1636 + make.centerX.equalTo(self.endTipView);
  1637 + make.top.equalTo(self.endTipView).offset(6);
  1638 + }];
  1639 +}
  1640 +- (void)showMapView:(UIButton *)btn{
  1641 + self.fristBgView.hidden = YES;
  1642 + self.mapView.hidden = NO;
  1643 +}
  1644 +- (void)stopRunningBtnAction:(UIButton *)btn{
  1645 + if ([self.exitModel.stopCount integerValue] == 1) {
  1646 +// [QMUITips showInfo:@"当前无法暂停" inView:self.view hideAfterDelay:1.5];
  1647 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"当前无法暂停" preferredStyle:UIAlertControllerStyleAlert];
  1648 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1649 +
  1650 + }];
  1651 + [actionAlert addAction:action];
  1652 + [self presentViewController:actionAlert animated:YES completion:nil];
  1653 + return;
  1654 + }
  1655 +
  1656 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"固定赛事只可暂停一次\n是否确定使用" preferredStyle:UIAlertControllerStyleAlert];
  1657 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"否" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1658 + }];
  1659 + [actionAlert addAction:action];
  1660 + UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"是" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1661 + [QMUITips showLoadingInView:AppKeyWindow];
  1662 + [CNTrackServiceManager defaultManager].isStartRecord = NO;
  1663 + self->_stopDate = [CNLiveTimeTools getNowTimestamp];
  1664 + self.exitModel.eventId = self.eventID;
  1665 + self.exitModel.startTime = [NSString stringWithFormat:@"%ld",self->_startRunningDate];
  1666 + self.exitModel.stopTime = [NSString stringWithFormat:@"%ld",self->_stopDate];
  1667 + self.exitModel.step = self.currentStepLab.text;
  1668 + self.exitModel.isStop = @"yes";
  1669 + self.exitModel.stopCount = @"1";
  1670 + [[CNTrackLoaclDataManager shareManager]updateExitModel:self.exitModel];
  1671 + self.stopRunningBtn.hidden = YES;
  1672 + self.goonRunningBtn.hidden = NO;
  1673 + //暂停时间和步数
  1674 + self.startRunningTimer.fireDate = [NSDate distantFuture];
  1675 + [CNTrackServiceManager defaultManager].isStartRecord = NO;
  1676 + //控制鹰眼服务
  1677 + [[CNTrackServiceManager defaultManager] stopGather];
  1678 + self->_isStopRun = YES;
  1679 + NSArray *arr = self.locationPoints;
  1680 + [self.locationPoints removeAllObjects];
  1681 + CLLocationCoordinate2D coors[arr.count];
  1682 + NSInteger count = 0;
  1683 + for (size_t i = 0; i < arr.count; i++) {
  1684 + CLLocation *location = [arr objectAtIndex:i];
  1685 + coors[i] = location.coordinate;
  1686 + count++;
  1687 + }
  1688 + self.noExitStopFrontPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count];
  1689 + if (self.noExitStopFrontPolyLine) {// 防止重复绘制
  1690 + [self.mapView removeOverlay:self.noExitStopFrontPolyLine];
  1691 + }
  1692 + if (self.stopAfterPolyLine) {
  1693 + [self.mapView removeOverlay:self.stopAfterPolyLine];
  1694 + }
  1695 + [self.mapView addOverlay:self.noExitStopFrontPolyLine];
  1696 + [QMUITips hideAllTips];
  1697 + }];
  1698 + [actionAlert addAction:action1];
  1699 + [self presentViewController:actionAlert animated:YES completion:nil];
  1700 +}
  1701 +
  1702 +- (void)goonRunningBtnAction:(UIButton *)btn{
  1703 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceResultHandler:) name:TrackServiceOperationResultNotification object:nil];//两个服务的通知
  1704 + //控制鹰眼服务
  1705 + if (![CNTrackServiceManager defaultManager].isServiceStarted) {
  1706 + // 开启服务之间先配置轨迹服务的基础信息
  1707 + BTKServiceOption *basicInfoOption = [[BTKServiceOption alloc] initWithAK:BDMapAK mcode:BDMapMCODE serviceID:BDMapServiceID keepAlive:YES];
  1708 + [[BTKAction sharedInstance] initInfo:basicInfoOption];
  1709 + // 开启服务
  1710 + BTKStartServiceOption *startServiceOption = [[BTKStartServiceOption alloc] initWithEntityName:CNUserShareModelUid];
  1711 + [[CNTrackServiceManager defaultManager] startServiceWithOption:startServiceOption];
  1712 + }else{
  1713 + if (![CNTrackServiceManager defaultManager].isGatherStarted) {
  1714 + [[CNTrackServiceManager defaultManager] startGather];
  1715 + }else{
  1716 + [CNTrackServiceManager defaultManager].isStartRecord = YES;
  1717 + [self.startRunningTimer setFireDate:[NSDate date]];
  1718 +// [self startRunningTime];
  1719 + _isStopRun = NO;
  1720 + [CNTrackServiceManager defaultManager].isClickGoOn = YES;
  1721 +
  1722 + //实时查询一次两个围栏
  1723 + [self queryRealtimeStatus];
  1724 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {
  1725 + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) {
  1726 + _reStartDate = [self.exitModel.reStartTime integerValue];
  1727 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",_reStartDate];
  1728 + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel];
  1729 + }else{
  1730 + _reStartDate = [CNLiveTimeTools getNowTimestamp];
  1731 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",_reStartDate];
  1732 + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel];
  1733 + }
  1734 + }
  1735 + self.stopRunningBtn.hidden = NO;
  1736 + self.goonRunningBtn.hidden = YES;
  1737 + // self.startRunningTimer.fireDate = [NSDate distantPast];
  1738 + //记录步数
  1739 + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES];
  1740 + }
  1741 + }
  1742 +}
  1743 +
  1744 +- (void)serviceResultHandler:(NSNotification *)notification {
  1745 + dispatch_async(dispatch_get_main_queue(), ^{
  1746 + NSDictionary *info = notification.userInfo;
  1747 + ServiceOperationType type = (ServiceOperationType)[info[@"type"] unsignedIntValue];
  1748 + NSString *title = info[@"title"];
  1749 + NSString *message = info[@"message"];
  1750 + switch (type) {
  1751 + case TRACK_SERVICE_OPERATION_TYPE_START_SERVICE:
  1752 + {
  1753 + if ([title isEqualToString:@"轨迹服务开启失败"]) {
  1754 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"服务异常,请重试。" preferredStyle:UIAlertControllerStyleAlert];
  1755 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1756 + }];
  1757 + [actionAlert addAction:action];
  1758 + [self presentViewController:actionAlert animated:YES completion:nil];
  1759 + }else{
  1760 + //开始服务成功,开启采集服务
  1761 + if (![CNTrackServiceManager defaultManager].isGatherStarted) {
  1762 + [[CNTrackServiceManager defaultManager] startGather];
  1763 + }
  1764 + }
  1765 + }
  1766 + break;
  1767 + case TRACK_SERVICE_OPERATION_TYPE_STOP_SERVICE:
  1768 + {
  1769 + //服务停止失败
  1770 + if ([title isEqualToString:@"轨迹服务停止失败"]) {
  1771 + NSLog(@"轨迹服务停止失败");
  1772 + if ([CNTrackServiceManager defaultManager].isServiceStarted) {
  1773 + [[CNTrackServiceManager defaultManager] stopService];//停止服务
  1774 + }
  1775 + }else{
  1776 + NSLog(@"轨迹服务停止成功");
  1777 + //停止更新位置
  1778 + if (self->_isEndRunning) {
  1779 + @try {
  1780 + [self.locationManager stopUpdatingLocation];
  1781 + [self.locationManager stopUpdatingHeading];
  1782 + } @catch (NSException *exception) {
  1783 + NSLog(@"CNStartRunningViewController.m 崩溃了");
  1784 + }
  1785 + }
  1786 + }
  1787 + }
  1788 + break;
  1789 + case TRACK_SERVICE_OPERATION_TYPE_START_GATHER:
  1790 + {
  1791 + if ([title isEqualToString:@"开始采集失败"]) {
  1792 + if ([message isEqualToString:@"没有开启后台定位权限"] || [message isEqualToString:@"没有开启系统定位服务"]){
  1793 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:@"无法获取你的位置信息" message:@"请到手机系统的[隐私]->[定位服务]->[网家家]中打开定位服务,并勾选\"始终\"选项" preferredStyle:UIAlertControllerStyleAlert];
  1794 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1795 + }];
  1796 + [actionAlert addAction:action];
  1797 + [self presentViewController:actionAlert animated:YES completion:nil];
  1798 + }else if([message isEqualToString:@"已经在采集轨迹,请勿重复开始"]){
  1799 + [CNTrackServiceManager defaultManager].isStartRecord = YES;
  1800 + [self.startRunningTimer setFireDate:[NSDate date]];
  1801 +// [self startRunningTime];
  1802 + self->_isStopRun = NO;
  1803 + [CNTrackServiceManager defaultManager].isClickGoOn = YES;
  1804 +
  1805 + //实时查询一次两个围栏
  1806 + [self queryRealtimeStatus];
  1807 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {
  1808 + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) {
  1809 + self->_reStartDate = [self.exitModel.reStartTime integerValue];
  1810 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate];
  1811 + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel];
  1812 + }else{
  1813 + self->_reStartDate = [CNLiveTimeTools getNowTimestamp];
  1814 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate];
  1815 + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel];
  1816 + }
  1817 + }
  1818 + self.stopRunningBtn.hidden = NO;
  1819 + self.goonRunningBtn.hidden = YES;
  1820 + // self.startRunningTimer.fireDate = [NSDate distantPast];
  1821 + //记录步数
  1822 + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES];
  1823 + }else{
  1824 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"服务异常,请重试。" preferredStyle:UIAlertControllerStyleAlert];
  1825 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1826 + }];
  1827 + [actionAlert addAction:action];
  1828 + [self presentViewController:actionAlert animated:YES completion:nil];
  1829 + }
  1830 + }else{
  1831 + [CNTrackServiceManager defaultManager].isStartRecord = YES;
  1832 + [self.startRunningTimer setFireDate:[NSDate date]];
  1833 +// [self startRunningTime];
  1834 + self->_isStopRun = NO;
  1835 + [CNTrackServiceManager defaultManager].isClickGoOn = YES;
  1836 +
  1837 + //实时查询一次两个围栏
  1838 + [self queryRealtimeStatus];
  1839 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {
  1840 + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) {
  1841 + self->_reStartDate = [self.exitModel.reStartTime integerValue];
  1842 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate];
  1843 + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel];
  1844 + }else{
  1845 + self->_reStartDate = [CNLiveTimeTools getNowTimestamp];
  1846 + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate];
  1847 + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel];
  1848 + }
  1849 + }
  1850 + self.stopRunningBtn.hidden = NO;
  1851 + self.goonRunningBtn.hidden = YES;
  1852 + // self.startRunningTimer.fireDate = [NSDate distantPast];
  1853 + //记录步数
  1854 + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES];
  1855 + }
  1856 + }
  1857 + break;
  1858 + case TRACK_SERVICE_OPERATION_TYPE_STOP_GATHER:
  1859 + {
  1860 + //采集停止失败
  1861 + if ([title isEqualToString:@"停止采集失败"]) {
  1862 + NSLog(@"停止采集失败");
  1863 + if ([CNTrackServiceManager defaultManager].isGatherStarted) {
  1864 + [[CNTrackServiceManager defaultManager] stopGather];//重新停止采集
  1865 + }else{
  1866 + if ([CNTrackServiceManager defaultManager].isServiceStarted) {
  1867 + [[CNTrackServiceManager defaultManager] stopService];//停止服务
  1868 + }
  1869 + }
  1870 + }else{//采集停止成功后,停止服务
  1871 + NSLog(@"停止采集成功");
  1872 + if ([CNTrackServiceManager defaultManager].isServiceStarted) {
  1873 + [[CNTrackServiceManager defaultManager] stopService];//停止服务
  1874 + }
  1875 + }
  1876 + }
  1877 + break;
  1878 + default:{
  1879 + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"服务异常,请重试。" preferredStyle:UIAlertControllerStyleAlert];
  1880 + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1881 + }];
  1882 + [actionAlert addAction:action];
  1883 + [self presentViewController:actionAlert animated:YES completion:nil];
  1884 + }
  1885 + break;
  1886 + }
  1887 + });
  1888 +}
  1889 +
  1890 +
  1891 +- (void)endRunningBtnAction:(UIButton *)btn{
  1892 + self.endTipView.hidden = NO;
  1893 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1894 + self.endTipView.hidden = YES;
  1895 + });
  1896 +}
  1897 +
  1898 +- (void)longPressAction:(UILongPressGestureRecognizer *)longPress{
  1899 + if (longPress.state == UIGestureRecognizerStateBegan) {
  1900 + self.endRunningBgView.transform = CGAffineTransformScale(self.endRunningBtn.transform, 1.2,1.2);
  1901 + _isStopEnd = NO;
  1902 + [self addProgressViewByAutoLayout];
  1903 + //开始计时
  1904 + _pressEndBtnCurrentTime = 0;//计时器归零
  1905 + self.endTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(cycleProgressRecord) userInfo:nil repeats:YES];
  1906 + }else if (longPress.state == UIGestureRecognizerStateCancelled || longPress.state == UIGestureRecognizerStateEnded || longPress.state == UIGestureRecognizerStateFailed){
  1907 + _isStopEnd = YES;
  1908 + }
  1909 +}
  1910 +//添加cycle
  1911 +- (void)addProgressViewByAutoLayout {
  1912 + self.progressView = [[CNRunEndCircleProgress alloc] initWithFrame:CGRectZero pathBackColor:[UIColor grayColor] pathFillColor:[UIColor whiteColor] startAngle:0 strokeWidth:20];
  1913 + self.progressView.backgroundColor = [UIColor clearColor];
  1914 + [self.endRunningBtn addSubview:self.progressView];
  1915 +
  1916 + [self.progressView mas_makeConstraints:^(MASConstraintMaker *make) {
  1917 + make.centerX.centerY.equalTo(self.endRunningBtn);
  1918 + make.size.mas_equalTo(CGSizeMake(90, 90));
  1919 + }];
  1920 + self.progressView.startAngle = 270;
  1921 + self.progressView.reduceAngle = 0;
  1922 + self.progressView.strokeWidth = 2;
  1923 + self.progressView.duration = 2;
  1924 + self.progressView.showPoint = NO;
  1925 + self.progressView.showProgressText = NO;
  1926 + self.progressView.increaseFromLast = YES;
  1927 +}
  1928 +- (void)cycleProgressRecord{
  1929 + if (_isStopEnd || _pressEndBtnCurrentTime >= 1.5) {
  1930 + if (_pressEndBtnCurrentTime >= 1.5) {
  1931 + self.endTipView.hidden = YES;
  1932 + _isEndRunning = YES;
  1933 + //持久记录结束时间
  1934 + _endRunningDate = [CNLiveTimeTools getNowTimestamp];
  1935 + self.backBtn.userInteractionEnabled = NO;
  1936 + [self afterLongPressDealAction];//长按结束后的处理
  1937 + }else{
  1938 + self.endTipView.hidden = NO;
  1939 + }
  1940 + self.endRunningBgView.transform = CGAffineTransformIdentity;
  1941 + _pressEndBtnCurrentTime = 0;
  1942 + _isStopEnd = YES;
  1943 + [self.progressView removeAllSubviews];
  1944 + [self.progressView removeFromSuperview];
  1945 + if ([self.endTimer isValid]){//停止计时器
  1946 + [self.endTimer invalidate];
  1947 + self.endTimer = nil;
  1948 + return;
  1949 + }
  1950 + }
  1951 + _pressEndBtnCurrentTime += 0.15;
  1952 + self.progressView.progress = _pressEndBtnCurrentTime/1.5;
  1953 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1954 + self.endTipView.hidden = YES;
  1955 + });
  1956 +}
  1957 +
  1958 +#pragma mark -- private 长按结束后的事件处理
  1959 +- (void)afterLongPressDealAction{
  1960 + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isShowOnce"];
  1961 + //(删除本地地理围栏;待定)停止服务端地理围栏;停止服务;
  1962 + //停止轨迹服务;停止定位、画线;停止计步器,暂停时间
  1963 + //停止服务端采集服务,去回调中停止另一个服务
  1964 + [self deleteLocalFence];//删除地理围栏
  1965 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceResultHandler:) name:TrackServiceOperationResultNotification object:nil];//两个服务的通知
  1966 + [[CNTrackServiceManager defaultManager] stopGather];//停止鹰眼服务
  1967 +
  1968 + self.startRunningTimer.fireDate = [NSDate distantFuture];
  1969 + [CNTrackServiceManager defaultManager].isStartRecord = NO;
  1970 + //把自己从地图中移除
  1971 + self.mapView.showsUserLocation = NO;
  1972 + //下面是UI
  1973 + self.fristBgView.hidden = YES;//隐藏主页面
  1974 + self.mapView.hidden = NO;//展示主界面
  1975 + [self.GPSBtn removeFromSuperview];//移除map上的gps
  1976 + [self.tipGPSBtn removeFromSuperview];//移除map上的gps提示
  1977 + [self.mapBottomView removeFromSuperview];//移除地图底部的view
  1978 + [self.resetBtn removeFromSuperview];//移除重新定位按钮
  1979 +
  1980 + //先往失败列表存一下,上传成功后再删除
  1981 + failModel = [[CNTrackUploadFailModel alloc] init];
  1982 + failModel.userId = CNUserShareModelUid;
  1983 + failModel.eventId = self.eventID;
  1984 + failModel.eventName = self.sportsDetailModel.title;
  1985 + failModel.startTime = self.exitModel.startTime;
  1986 + failModel.endTime = [NSString stringWithFormat:@"%ld",(long)_endRunningDate];
  1987 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {
  1988 + failModel.isStop = @"yes";
  1989 + failModel.stopTime = self.exitModel.stopTime;
  1990 + failModel.reStartTime = self.exitModel.reStartTime;
  1991 + }
  1992 + failModel.totalKM = self.mapCurrentKMLab.text;
  1993 + failModel.totalTime = [NSString stringWithFormat:@"%ld",(long)_totalTime];
  1994 + failModel.speed = self.currentSpeedLab.text;
  1995 + failModel.totalStep = self.currentStepLab.text;
  1996 + NSDictionary *dict = @{@"lat":[NSNumber numberWithDouble:_endAnnotation.coordinate.latitude],@"long":[NSNumber numberWithDouble:_endAnnotation.coordinate.longitude]};
  1997 + failModel.endCoordsDictStr = [dict mj_JSONString];
  1998 +
  1999 + failModel.pointsArrStr = self.pointsStr;
  2000 + failModel.startLoaction = self.sportsDetailModel.startLocation;
  2001 + failModel.endLocation = self.sportsDetailModel.endLocation;
  2002 + [[CNTrackLoaclDataManager shareManager] insertFUploadModel:failModel];
  2003 +
  2004 + [self.mapView addSubview:self.preSaveView];
  2005 + [self.preSaveView mas_makeConstraints:^(MASConstraintMaker *make) {
  2006 + make.left.right.bottom.equalTo(self.mapView);
  2007 + make.height.equalTo(@(49+kVerticalBottomSafeHeight));
  2008 + }];
  2009 + [self.preSaveView addSubview:self.loadingSaveView];
  2010 + [self.loadingSaveView mas_makeConstraints:^(MASConstraintMaker *make) {
  2011 + make.width.height.equalTo(@(24));
  2012 + make.centerY.equalTo(self.preSaveView).offset(-kVerticalBottomSafeHeight/2);
  2013 + make.centerX.equalTo(self.preSaveView).offset(-28);
  2014 + }];
  2015 +
  2016 + UILabel *lab = [[UILabel alloc] init];
  2017 + lab.text = @"保存中";
  2018 + lab.textAlignment = NSTextAlignmentLeft;
  2019 + lab.textColor = kWhiteColor;
  2020 + lab.font = [UIFont systemFontOfSize:18];
  2021 + [self.preSaveView addSubview:lab];
  2022 + [lab mas_makeConstraints:^(MASConstraintMaker *make) {
  2023 + make.centerY.equalTo(self.preSaveView).offset(-kVerticalBottomSafeHeight/2);
  2024 + make.left.equalTo(self.loadingSaveView.mas_right).offset(2);
  2025 + }];
  2026 + [self startAnimation];//转圈
  2027 + [self.mapView addSubview:self.saveBtn];
  2028 + [self.saveBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  2029 + make.left.right.bottom.equalTo(self.mapView);
  2030 + make.height.equalTo(@(49+kVerticalBottomSafeHeight));
  2031 + }];
  2032 + self.saveBtn.titleEdgeInsets = UIEdgeInsetsMake(-kVerticalBottomSafeHeight, 0, 0, 0);
  2033 + self.saveBtn.hidden = YES;
  2034 + [self.mapView addSubview:self.tableView];
  2035 + UIView *headerView = [UIView new];
  2036 + headerView.backgroundColor = [UIColor clearColor];
  2037 + headerView.frame = CGRectMake(0, 0, SCREEN_WIDTH, 345);
  2038 + self.tableView.tableHeaderView = headerView;
  2039 + [headerView addSubview:self.backBtn];
  2040 + self.tableView.view = self.backBtn;
  2041 + [self.backBtn mas_updateConstraints:^(MASConstraintMaker *make) {
  2042 + make.left.top.equalTo(headerView).offset(10);
  2043 + make.size.mas_equalTo(CGSizeMake(45, 45));
  2044 + }];
  2045 + [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
  2046 + make.left.right.equalTo(self.mapView);
  2047 + make.bottom.equalTo(self.mapView.mas_bottom).offset(-49-kVerticalBottomSafeHeight);
  2048 + make.top.equalTo(self.mapView);
  2049 + }];
  2050 + if (localFenceId) {
  2051 + //判断是否经过了终点
  2052 + [self queryLocalHistoryAlarm];
  2053 + }else{
  2054 + [self judgeSuccessTrack];
  2055 + }
  2056 +
  2057 +}
  2058 +
  2059 +#pragma mark -- 自己的历史轨迹
  2060 +- (void)queryCurrentRunningEndPoint:(void(^)(NSArray *))handle{
  2061 + NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:0];
  2062 + if ([self.exitModel.isStop isEqualToString:@"yes"]) {
  2063 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  2064 + [paramInfo setStartTime:[self.exitModel.startTime integerValue]];
  2065 + [paramInfo setEndTime:[self.exitModel.stopTime integerValue]];
  2066 + [paramInfo setEntityName:CNUserShareModelUid];
  2067 + [paramInfo setIsProcessed:true];
  2068 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  2069 + processOption.radiusThreshold = 100;
  2070 + processOption.denoise = true;
  2071 + processOption.vacuate = true;
  2072 + processOption.mapMatch = false;
  2073 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  2074 + paramInfo.processOption = processOption;
  2075 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  2076 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  2077 + vm.completionHandler = ^(NSArray *points) {
  2078 + [tempArray addObjectsFromArray:points];
  2079 + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) {
  2080 + CNHistoryTrackParam * paramInfo2 =[[CNHistoryTrackParam alloc]init];
  2081 + [paramInfo2 setStartTime:[self.exitModel.reStartTime integerValue]];
  2082 + [paramInfo2 setEndTime:self->_endRunningDate];
  2083 + [paramInfo2 setEntityName:CNUserShareModelUid];
  2084 + [paramInfo2 setIsProcessed:true];
  2085 + BTKQueryTrackProcessOption *processOption2 = [[BTKQueryTrackProcessOption alloc] init];
  2086 + processOption2.radiusThreshold = 100;
  2087 + processOption2.denoise = true;
  2088 + processOption2.vacuate = true;
  2089 + processOption2.mapMatch = false;
  2090 + processOption2.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  2091 + paramInfo2.processOption = processOption;
  2092 + paramInfo2.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  2093 + CNHistoryViewModel *vm2 = [[CNHistoryViewModel alloc] init];
  2094 + vm2.completionHandler = ^(NSArray *points) {
  2095 + [tempArray addObjectsFromArray:points];
  2096 + handle(tempArray);
  2097 + };
  2098 + [vm2 queryHistoryWithParam:paramInfo2];
  2099 + }else{
  2100 + handle(tempArray);
  2101 + }
  2102 + };
  2103 + [vm queryHistoryWithParam:paramInfo];
  2104 + }else{
  2105 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  2106 + [paramInfo setStartTime:[self.exitModel.startTime integerValue]];
  2107 + [paramInfo setEndTime:_endRunningDate];
  2108 + [paramInfo setEntityName:CNUserShareModelUid];
  2109 + [paramInfo setIsProcessed:true];
  2110 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  2111 + processOption.radiusThreshold = 100;
  2112 + processOption.denoise = true;
  2113 + processOption.vacuate = true;
  2114 + processOption.mapMatch = false;
  2115 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  2116 + paramInfo.processOption = processOption;
  2117 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  2118 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  2119 + vm.completionHandler = ^(NSArray *points) {
  2120 + [tempArray addObjectsFromArray:points];
  2121 + handle(tempArray);
  2122 + };
  2123 + [vm queryHistoryWithParam:paramInfo];
  2124 + }
  2125 +
  2126 +}
  2127 +
  2128 +//保存中转圈
  2129 +- (void)startAnimation{
  2130 + CGAffineTransform endAngle = CGAffineTransformMakeRotation(angle * (M_PI / 180.0f));
  2131 + __weak typeof(self) weakSelf = self;
  2132 + [UIView animateWithDuration:0.01 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
  2133 + weakSelf.loadingSaveView.transform = endAngle;
  2134 + } completion:^(BOOL finished) {
  2135 + __strong typeof(weakSelf) strongSelf = weakSelf;
  2136 + self->angle += 2;
  2137 + if (!self->_isStopAnimation) {
  2138 + [strongSelf startAnimation];
  2139 + }
  2140 + }];
  2141 +}
  2142 +
  2143 +- (void)saveBtnAction:(id)sender{
  2144 + [[NSNotificationCenter defaultCenter] removeObserver:self name:TrackServiceOperationResultNotification object:nil];
  2145 +
  2146 + if (_endTimer) {
  2147 + [_endTimer invalidate];
  2148 + _endTimer = nil;
  2149 + }
  2150 + if (_startRunningTimer) {
  2151 + [_startRunningTimer invalidate];
  2152 + _startRunningTimer = nil;
  2153 + }
  2154 + [CNTrackServiceManager defaultManager].isStartRecord = NO;
  2155 + if ([self.delegate respondsToSelector:@selector(backToFrontVC)]) {
  2156 + [self.delegate backToFrontVC];
  2157 + }
  2158 + [self.navigationController popViewControllerAnimated:YES];
  2159 +}
  2160 +
  2161 +- (void)startCountdown:(void(^)(void))handle{
  2162 + [self.view addSubview:self.startCountdownView];
  2163 + [self.startCountdownView addSubview:self.startCountdownLab];
  2164 + self.startCountdownLab.center = self.startCountdownView.center;
  2165 + __block int startIndex = 3;
  2166 + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{
  2167 + self.startCountdownLab.text = [NSString stringWithFormat:@"%d",startIndex];
  2168 + self.startCountdownLab.transform = CGAffineTransformScale(self.startCountdownLab.transform, 2,2);
  2169 + } completion:^(BOOL finished) {
  2170 + self.startCountdownLab.hidden = YES;
  2171 + self.startCountdownLab.transform = CGAffineTransformIdentity;
  2172 + startIndex --;//2
  2173 + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{
  2174 + self.startCountdownLab.hidden = NO;
  2175 + self.startCountdownLab.text = [NSString stringWithFormat:@"%d",startIndex];
  2176 + self.startCountdownLab.transform =CGAffineTransformScale(self.startCountdownLab.transform, 2,2);
  2177 + } completion:^(BOOL finished) {
  2178 + self.startCountdownLab.hidden = YES;
  2179 + self.startCountdownLab.transform =CGAffineTransformIdentity;
  2180 + startIndex --;//1
  2181 + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{
  2182 + self.startCountdownLab.hidden = NO;
  2183 + self.startCountdownLab.text = [NSString stringWithFormat:@"%d",startIndex];
  2184 + self.startCountdownLab.transform =CGAffineTransformScale(self.startCountdownLab.transform, 2,2);
  2185 + } completion:^(BOOL finished) {
  2186 + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{
  2187 + [self.startCountdownView removeAllSubviews];
  2188 + [self.startCountdownView removeFromSuperview];
  2189 + } completion:^(BOOL finished) {
  2190 + if (handle) {
  2191 + handle();
  2192 + }
  2193 + }];
  2194 + }];
  2195 + }];
  2196 + }];
  2197 +}
  2198 +#pragma mark -- tableviewdelegate
  2199 +-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
  2200 + if (_isEndRunning) {
  2201 + CGRect rect = [_headImg convertRect:_headImg.bounds toView:AppKeyWindow];
  2202 + self.tableView.receiverHeight = rect.origin.y;
  2203 + }
  2204 +}
  2205 +
  2206 +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  2207 + return 3;
  2208 +}
  2209 +
  2210 +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  2211 +
  2212 + static NSString *cellid = @"cellid";
  2213 + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
  2214 + UIImageView *bgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"jl-bg"]];
  2215 + if (!cell) {
  2216 + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellid];
  2217 + cell.backgroundColor = [UIColor clearColor];
  2218 + [cell addSubview:bgView];
  2219 + }
  2220 + cell.selectionStyle = UITableViewCellSelectionStyleNone;
  2221 +
  2222 + switch (indexPath.row) {
  2223 + case 0:
  2224 + {
  2225 + [self first:bgView cell:cell];
  2226 + }
  2227 + break;
  2228 + case 1:
  2229 + {
  2230 + [self second:bgView cell:cell];
  2231 + }
  2232 + break;
  2233 + case 2:
  2234 + {
  2235 + [self third:bgView cell:cell];
  2236 + }
  2237 + break;
  2238 + default:
  2239 + break;
  2240 + }
  2241 + return cell;
  2242 +}
  2243 +
  2244 +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
  2245 + CGFloat height = 0;
  2246 + switch (indexPath.row) {
  2247 + case 0:
  2248 + height = 250;
  2249 + break;
  2250 + case 1:
  2251 + height = 130;
  2252 + break;
  2253 + case 2:
  2254 + height = 260;
  2255 + break;
  2256 + default:
  2257 + break;
  2258 + }
  2259 + return height;
  2260 +}
  2261 +
  2262 +- (void)first:(UIImageView *)bgView cell:(UITableViewCell *)cell{
  2263 + [bgView mas_makeConstraints:^(MASConstraintMaker *make) {
  2264 + make.left.right.bottom.equalTo(cell);
  2265 + make.top.equalTo(cell).offset(20);
  2266 + }];
  2267 + _headImg = [[UIImageView alloc] init];
  2268 + [_headImg sd_setImageWithURL:[NSURL URLWithString:CNUserShareModel.faceUrl] placeholderImage:[UIImage imageNamed:@"TOUXIANG"]];
  2269 + [cell addSubview:_headImg];
  2270 + [_headImg mas_makeConstraints:^(MASConstraintMaker *make) {
  2271 + make.top.equalTo(cell).offset(3);
  2272 + make.left.equalTo(bgView.mas_left).offset(25);
  2273 + make.width.height.equalTo(@(50));
  2274 + }];
  2275 + _headImg.layer.cornerRadius = 25;
  2276 + _headImg.layer.masksToBounds = YES;
  2277 + _headImg.layer.borderWidth = 2;
  2278 + _headImg.layer.borderColor = [UIColor whiteColor].CGColor;
  2279 +
  2280 + UILabel *headLab = [[UILabel alloc]init];
  2281 + headLab.text = CNUserShareModel.nickname;
  2282 + headLab.font = [UIFont systemFontOfSize:13];
  2283 + headLab.textAlignment = NSTextAlignmentLeft;
  2284 + headLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2285 + [cell addSubview:headLab];
  2286 + [headLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2287 + make.left.equalTo(self->_headImg.mas_right).offset(10);
  2288 + make.right.equalTo(bgView.mas_right).offset(-18);
  2289 + make.bottom.equalTo(self->_headImg.mas_bottom);
  2290 + }];
  2291 +
  2292 + UIView *lineView = [[UIView alloc] init];
  2293 + lineView.backgroundColor = KGrayLineColor;
  2294 + [bgView addSubview:lineView];
  2295 + [lineView mas_makeConstraints:^(MASConstraintMaker *make) {
  2296 + make.left.equalTo(self->_headImg.mas_left);
  2297 + make.right.equalTo(bgView.mas_right).offset(-25);
  2298 + make.centerY.equalTo(bgView).offset(7);
  2299 + make.height.equalTo(@(0.5));
  2300 + }];
  2301 +
  2302 + UILabel *timeLab = [[UILabel alloc] init];
  2303 + NSDate *date = [NSDate dateWithTimeIntervalSince1970:_endRunningDate];
  2304 +
  2305 + NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  2306 + [formatter setDateFormat:@"yyyy/MM/dd HH:mm"];
  2307 + NSString *dateString = [formatter stringFromDate: date];
  2308 + timeLab.text = dateString;
  2309 + timeLab.font = [UIFont systemFontOfSize:10];
  2310 + timeLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2311 + timeLab.textAlignment = NSTextAlignmentLeft;
  2312 + [bgView addSubview:timeLab];
  2313 + [timeLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2314 + make.left.equalTo(lineView);
  2315 + make.bottom.equalTo(lineView.mas_top).offset(-13);
  2316 + }];
  2317 +
  2318 + UILabel *addressLab = [[UILabel alloc] init];
  2319 + addressLab.text = self.sportsDetailModel.title;
  2320 + addressLab.font = [UIFont systemFontOfSize:15];
  2321 + addressLab.numberOfLines = 0;
  2322 + addressLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2323 + addressLab.textAlignment = NSTextAlignmentLeft;
  2324 + [addressLab sizeToFit];
  2325 + [bgView addSubview:addressLab];
  2326 + [addressLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2327 + make.left.equalTo(lineView);
  2328 + make.bottom.equalTo(timeLab.mas_top).offset(-10);
  2329 + make.width.equalTo(@(SCREEN_WIDTH/2));
  2330 + }];
  2331 +
  2332 + UIView *tempView = [UIView new];
  2333 + [bgView addSubview:tempView];
  2334 + [tempView mas_makeConstraints:^(MASConstraintMaker *make) {
  2335 + make.top.equalTo(addressLab.mas_top);
  2336 + make.bottom.equalTo(timeLab.mas_bottom);
  2337 + make.left.right.equalTo(bgView);
  2338 + }];
  2339 +
  2340 + UILabel *totalKMLab = [[UILabel alloc] init];
  2341 + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:45]};
  2342 + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:10]};
  2343 + NSAttributedString *attributedString = [self attributedText:@[self.mapCurrentKMLab.text,@" 公里"] attributeAttay:@[attributesNum,attributesKM]];
  2344 + totalKMLab.attributedText = attributedString;
  2345 + totalKMLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2346 + totalKMLab.textAlignment = NSTextAlignmentRight;
  2347 + [bgView addSubview:totalKMLab];
  2348 + [totalKMLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2349 + make.centerY.equalTo(tempView);
  2350 + make.right.equalTo(lineView.mas_right);
  2351 + }];
  2352 + UILabel *endSpeedLab = [[UILabel alloc] init];
  2353 + endSpeedLab.text = self.currentSpeedLab.text;
  2354 + endSpeedLab.font = [UIFont boldSystemFontOfSize:24];
  2355 + endSpeedLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2356 + endSpeedLab.textAlignment = NSTextAlignmentCenter;
  2357 + [bgView addSubview:endSpeedLab];
  2358 + [endSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2359 + make.centerX.equalTo(bgView).offset(-SCREEN_WIDTH/2/2);
  2360 + make.top.equalTo(lineView.mas_bottom).offset(12);
  2361 + }];
  2362 +
  2363 +
  2364 + UILabel *endSpeedNameLab = [[UILabel alloc] init];
  2365 + endSpeedNameLab.text = @"配速";
  2366 + endSpeedNameLab.font = [UIFont systemFontOfSize:15];
  2367 + endSpeedNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2368 + endSpeedNameLab.textAlignment = NSTextAlignmentCenter;
  2369 + [bgView addSubview:endSpeedNameLab];
  2370 + [endSpeedNameLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2371 + make.centerX.equalTo(endSpeedLab);
  2372 + make.top.equalTo(endSpeedLab.mas_bottom).offset(12);
  2373 + }];
  2374 +
  2375 + UILabel *endTotalTimeLab = [[UILabel alloc] init];
  2376 + endTotalTimeLab.text = self.currentTimeLab.text;
  2377 + endTotalTimeLab.font = [UIFont boldSystemFontOfSize:24];
  2378 + endTotalTimeLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2379 + endTotalTimeLab.textAlignment = NSTextAlignmentCenter;
  2380 + [bgView addSubview:endTotalTimeLab];
  2381 + [endTotalTimeLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2382 + make.centerY.equalTo(endSpeedLab);
  2383 + make.centerX.equalTo(bgView).offset(SCREEN_WIDTH/2/2);
  2384 + }];
  2385 +
  2386 + UILabel *endTimeNameLab = [[UILabel alloc] init];
  2387 + endTimeNameLab.text = @"用时";
  2388 + endTimeNameLab.font = [UIFont systemFontOfSize:15];
  2389 + endTimeNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2390 + endTimeNameLab.textAlignment = NSTextAlignmentCenter;
  2391 + [bgView addSubview:endTimeNameLab];
  2392 + [endTimeNameLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2393 + make.centerY.equalTo(endSpeedNameLab);
  2394 + make.centerX.equalTo(endTotalTimeLab);
  2395 + }];
  2396 +}
  2397 +- (void)second:(UIImageView *)bgView cell:(UITableViewCell *)cell{
  2398 + [bgView mas_makeConstraints:^(MASConstraintMaker *make) {
  2399 + make.top.bottom.left.right.equalTo(cell);
  2400 + }];
  2401 + UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-step record"]];
  2402 + [bgView addSubview:imgView];
  2403 + [imgView mas_makeConstraints:^(MASConstraintMaker *make) {
  2404 + make.left.equalTo(bgView).offset(25);
  2405 + make.top.equalTo(bgView).offset(15);
  2406 + make.size.mas_equalTo(CGSizeMake(16, 17));
  2407 + }];
  2408 + UILabel *stepNameLab = [[UILabel alloc] init];
  2409 + stepNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2410 + stepNameLab.font = [UIFont systemFontOfSize:12];
  2411 + stepNameLab.text = @"总步数";
  2412 + stepNameLab.textAlignment = NSTextAlignmentLeft;
  2413 + [bgView addSubview:stepNameLab];
  2414 + [stepNameLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2415 + make.left.equalTo(imgView.mas_right).offset(10);
  2416 + make.bottom.equalTo(imgView.mas_bottom);
  2417 + }];
  2418 +
  2419 + UILabel *totalStepLab = [[UILabel alloc] init];
  2420 + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:28],NSForegroundColorAttributeName:[UIColor colorWithRed:35/255.0 green:212/255.0 blue:30/255.0 alpha:1.0]};
  2421 + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:12],NSForegroundColorAttributeName:[UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]};
  2422 + NSAttributedString *attributedString = [self attributedText:@[self.currentStepLab.text,@" 步"] attributeAttay:@[attributesNum,attributesKM]];
  2423 + totalStepLab.attributedText = attributedString;
  2424 + totalStepLab.textAlignment = NSTextAlignmentCenter;
  2425 + [bgView addSubview:totalStepLab];
  2426 + [totalStepLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2427 + make.centerX.centerY.equalTo(bgView);
  2428 + }];
  2429 +}
  2430 +
  2431 +- (void)third:(UIImageView *)bgView cell:(UITableViewCell *)cell{
  2432 + [bgView mas_makeConstraints:^(MASConstraintMaker *make) {
  2433 + make.top.bottom.left.right.equalTo(cell);
  2434 + }];
  2435 + UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-route"]];
  2436 + [bgView addSubview:imgView];
  2437 + [imgView mas_makeConstraints:^(MASConstraintMaker *make) {
  2438 + make.left.equalTo(bgView).offset(25);
  2439 + make.top.equalTo(bgView).offset(25);
  2440 + make.size.mas_equalTo(CGSizeMake(18, 18));
  2441 + }];
  2442 + UILabel *stepNameLab = [[UILabel alloc] init];
  2443 + stepNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2444 + stepNameLab.font = [UIFont systemFontOfSize:12];
  2445 + stepNameLab.text = @"跑步路线";
  2446 + stepNameLab.textAlignment = NSTextAlignmentLeft;
  2447 + [bgView addSubview:stepNameLab];
  2448 + [stepNameLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2449 + make.left.equalTo(imgView.mas_right).offset(10);
  2450 + make.bottom.equalTo(imgView.mas_bottom);
  2451 + }];
  2452 +
  2453 + UIView *green = [[UIView alloc] init];
  2454 + green.backgroundColor = [UIColor greenColor];
  2455 + [bgView addSubview:green];
  2456 + [green mas_makeConstraints:^(MASConstraintMaker *make) {
  2457 + make.left.equalTo(imgView);
  2458 + make.top.equalTo(imgView.mas_bottom).offset(19);
  2459 + make.width.height.equalTo(@(6));
  2460 + }];
  2461 + green.layer.cornerRadius = 3;
  2462 + green.layer.masksToBounds = YES;
  2463 +
  2464 + UILabel *qiLab = [[UILabel alloc] init];
  2465 + qiLab.text = @"(起)";
  2466 + qiLab.textAlignment = NSTextAlignmentCenter;
  2467 + qiLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2468 + qiLab.font = [UIFont systemFontOfSize:12];
  2469 + [bgView addSubview:qiLab];
  2470 + [qiLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2471 + make.centerY.equalTo(green);
  2472 + make.left.equalTo(green.mas_right).offset(9);
  2473 + }];
  2474 + UILabel *qiADDLab = [[UILabel alloc] init];
  2475 + qiADDLab.text = self.sportsDetailModel.startLocation;
  2476 + qiADDLab.textAlignment = NSTextAlignmentLeft;
  2477 + qiADDLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2478 + qiADDLab.font = [UIFont systemFontOfSize:14];
  2479 + [bgView addSubview:qiADDLab];
  2480 + [qiADDLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2481 + make.centerY.equalTo(green);
  2482 + make.left.equalTo(qiLab.mas_right).offset(9);
  2483 + }];
  2484 + UIView *line1 = [[UIView alloc] init];
  2485 + line1.backgroundColor = [UIColor colorWithRed:196/255.0 green:196/255.0 blue:196/255.0 alpha:1.0];
  2486 + [bgView addSubview:line1];
  2487 + [line1 mas_makeConstraints:^(MASConstraintMaker *make) {
  2488 + make.centerX.equalTo(green);
  2489 + make.top.equalTo(green.mas_bottom).offset(3);
  2490 + make.height.equalTo(@(25));
  2491 + make.width.equalTo(@(1));
  2492 + }];
  2493 +
  2494 + UIView *red = [[UIView alloc] init];
  2495 + red.backgroundColor = [UIColor colorWithRed:250/255.0 green:82/255.0 blue:52/255.0 alpha:1.0];
  2496 + [bgView addSubview:red];
  2497 + [red mas_makeConstraints:^(MASConstraintMaker *make) {
  2498 + make.centerX.equalTo(green);
  2499 + make.top.equalTo(line1.mas_bottom).offset(3);
  2500 + make.width.height.equalTo(@(6));
  2501 + }];
  2502 + red.layer.cornerRadius = 3;
  2503 + red.layer.masksToBounds = YES;
  2504 + UILabel *zhiLab = [[UILabel alloc] init];
  2505 + zhiLab.text = @"(止)";
  2506 + zhiLab.textAlignment = NSTextAlignmentCenter;
  2507 + zhiLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2508 + zhiLab.font = [UIFont systemFontOfSize:12];
  2509 + [bgView addSubview:zhiLab];
  2510 + [zhiLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2511 + make.centerY.equalTo(red);
  2512 + make.centerX.equalTo(qiLab);
  2513 + }];
  2514 + UILabel *zhiADDLab = [[UILabel alloc] init];
  2515 + zhiADDLab.text = self.sportsDetailModel.endLocation;
  2516 + zhiADDLab.textAlignment = NSTextAlignmentLeft;
  2517 + zhiADDLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2518 + zhiADDLab.font = [UIFont systemFontOfSize:14];
  2519 + [bgView addSubview:zhiADDLab];
  2520 + [zhiADDLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2521 + make.centerY.equalTo(red);
  2522 + make.left.equalTo(qiADDLab);
  2523 + }];
  2524 + UIView *line2 = [[UIView alloc] init];
  2525 + line2.backgroundColor = [UIColor colorWithRed:196/255.0 green:196/255.0 blue:196/255.0 alpha:1.0];
  2526 + [bgView addSubview:line2];
  2527 + [line2 mas_makeConstraints:^(MASConstraintMaker *make) {
  2528 + make.centerX.equalTo(green);
  2529 + make.top.equalTo(red.mas_bottom).offset(3);
  2530 + make.height.equalTo(@(25));
  2531 + make.width.equalTo(@(1));
  2532 + }];
  2533 +
  2534 + UIView *gray1 = [[UIView alloc] init];
  2535 + gray1.backgroundColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2536 + [bgView addSubview:gray1];
  2537 + [gray1 mas_makeConstraints:^(MASConstraintMaker *make) {
  2538 + make.centerX.equalTo(green);
  2539 + make.top.equalTo(line2.mas_bottom).offset(3);
  2540 + make.width.height.equalTo(@(4));
  2541 + }];
  2542 + gray1.layer.cornerRadius = 2;
  2543 + gray1.layer.masksToBounds = YES;
  2544 + UILabel *timeLab = [[UILabel alloc] init];
  2545 + timeLab.text = self.currentTimeLab.text;
  2546 + timeLab.textAlignment = NSTextAlignmentLeft;
  2547 + timeLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2548 + timeLab.font = [UIFont boldSystemFontOfSize:18];
  2549 + [bgView addSubview:timeLab];
  2550 + [timeLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2551 + make.centerY.equalTo(gray1);
  2552 + make.left.equalTo(qiLab);
  2553 + }];
  2554 + UILabel *timeNameLab = [[UILabel alloc] init];
  2555 + timeNameLab.text = @"跑步记录时长";
  2556 + timeNameLab.textAlignment = NSTextAlignmentLeft;
  2557 + timeNameLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2558 + timeNameLab.font = [UIFont systemFontOfSize:11];
  2559 + [bgView addSubview:timeNameLab];
  2560 + [timeNameLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2561 + make.left.equalTo(qiLab);
  2562 + make.top.equalTo(timeLab.mas_bottom).offset(6);
  2563 + }];
  2564 + UIView *line3 = [[UIView alloc] init];
  2565 + line3.backgroundColor = [UIColor colorWithRed:196/255.0 green:196/255.0 blue:196/255.0 alpha:1.0];
  2566 + [bgView addSubview:line3];
  2567 + [line3 mas_makeConstraints:^(MASConstraintMaker *make) {
  2568 + make.centerX.equalTo(green);
  2569 + make.top.equalTo(gray1.mas_bottom).offset(3);
  2570 + make.height.equalTo(@(55));
  2571 + make.width.equalTo(@(1));
  2572 + }];
  2573 + UIView *gray2 = [[UIView alloc] init];
  2574 + gray2.backgroundColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2575 + [bgView addSubview:gray2];
  2576 + [gray2 mas_makeConstraints:^(MASConstraintMaker *make) {
  2577 + make.centerX.equalTo(green);
  2578 + make.top.equalTo(line3.mas_bottom).offset(3);
  2579 + make.width.height.equalTo(@(4));
  2580 + }];
  2581 + gray2.layer.cornerRadius = 2;
  2582 + gray2.layer.masksToBounds = YES;
  2583 + self.successStateLab = [[UILabel alloc] init];
  2584 + self.successStateLab.text = _endStatus.length>0?_endStatus:@"路线未完成";
  2585 + self.successStateLab.textAlignment = NSTextAlignmentLeft;
  2586 + self.successStateLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0];
  2587 + self.successStateLab.font = [UIFont systemFontOfSize:11];
  2588 + [bgView addSubview:self.successStateLab];
  2589 + [self.successStateLab mas_makeConstraints:^(MASConstraintMaker *make) {
  2590 + make.centerY.equalTo(gray2);
  2591 + make.left.equalTo(qiLab);
  2592 + }];
  2593 +}
  2594 +#pragma mark -- lazy
  2595 +-(UIView *)startCountdownView{
  2596 + if (!_startCountdownView) {
  2597 + _startCountdownView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
  2598 + _startCountdownView.backgroundColor = [UIColor colorWithRed:91/255.0 green:196/255.0 blue:164/255.0 alpha:1.0];
  2599 + }
  2600 + return _startCountdownView;
  2601 +}
  2602 +
  2603 +- (UILabel *)startCountdownLab{
  2604 + if (!_startCountdownLab) {
  2605 + _startCountdownLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 150)];
  2606 + _startCountdownLab.textColor = [UIColor whiteColor];
  2607 + _startCountdownLab.font = [UIFont boldSystemFontOfSize:110];
  2608 + _startCountdownLab.textAlignment = NSTextAlignmentCenter;
  2609 + }
  2610 + return _startCountdownLab;
  2611 +}
  2612 +
  2613 +-(QMUIButton *)backFirstBtn{
  2614 + if(!_backFirstBtn){
  2615 + _backFirstBtn = [[QMUIButton alloc] init];
  2616 +// [_backFirstBtn setBackgroundImage:[UIImage imageNamed:@"top_back_white"] forState:UIControlStateNormal];
  2617 +// [_backFirstBtn setImage:[UIImage imageNamed:@"top_back"] forState:UIControlStateNormal];
  2618 +// _backFirstBtn.imageEdgeInsets = UIEdgeInsetsMake(-5, -3, 0, 0);
  2619 + [_backFirstBtn addTarget:self action:@selector(backFirstBtnAction) forControlEvents:UIControlEventTouchUpInside];
  2620 + }
  2621 + return _backFirstBtn;
  2622 +}
  2623 +
  2624 +-(UILabel *)currentKMLab{
  2625 + if (!_currentKMLab) {
  2626 + _currentKMLab = [[UILabel alloc] init];
  2627 + _currentKMLab.font = [UIFont boldSystemFontOfSize:70];
  2628 + _currentKMLab.textColor = kWhiteColor;
  2629 + _currentKMLab.text = @"0.00";
  2630 + _currentKMLab.textAlignment = NSTextAlignmentCenter;
  2631 + }
  2632 + return _currentKMLab;
  2633 +}
  2634 +
  2635 +-(UILabel *)gpsLab{
  2636 + if (!_gpsLab) {
  2637 + _gpsLab = [[UILabel alloc] init];
  2638 + _gpsLab.font = [UIFont boldSystemFontOfSize:18];
  2639 + _gpsLab.text = @"GPS";
  2640 + _gpsLab.textColor = kWhiteColor;
  2641 + _gpsLab.textAlignment = NSTextAlignmentCenter;
  2642 + }
  2643 + return _gpsLab;
  2644 +}
  2645 +-(UIImageView *)currentGPSImgView{
  2646 + if (!_currentGPSImgView) {
  2647 + _currentGPSImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"signal-low"]];
  2648 + }
  2649 + return _currentGPSImgView;
  2650 +}
  2651 +-(UILabel *)currentGPSLab{
  2652 + if (!_currentGPSLab) {
  2653 + _currentGPSLab = [[UILabel alloc] init];
  2654 + _currentGPSLab.font = [UIFont systemFontOfSize:10];
  2655 + _currentGPSLab.text = @"信号槽糕,数据准确度低";
  2656 + _currentGPSLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2657 + _currentGPSLab.textAlignment = NSTextAlignmentLeft;
  2658 +
  2659 + }
  2660 + return _currentGPSLab;
  2661 +}
  2662 +-(UIButton *)detailMapBtn{
  2663 + if (!_detailMapBtn) {
  2664 + _detailMapBtn = [[UIButton alloc] init];
  2665 + [_detailMapBtn setImage:[UIImage imageNamed:@"startRunning_map"] forState:UIControlStateNormal];
  2666 + [_detailMapBtn addTarget:self action:@selector(showMapView:) forControlEvents:UIControlEventTouchUpInside];
  2667 + }
  2668 + return _detailMapBtn;
  2669 +}
  2670 +-(UILabel *)mapDesLab{
  2671 + if (!_mapDesLab) {
  2672 + _mapDesLab = [[UILabel alloc] init];
  2673 + _mapDesLab.font = [UIFont systemFontOfSize:10];
  2674 + _mapDesLab.text = @"点击查看轨迹";
  2675 + _mapDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2676 + _mapDesLab.textAlignment = NSTextAlignmentCenter;
  2677 + }
  2678 + return _mapDesLab;
  2679 +}
  2680 +-(UIImageView *)speedImgView{
  2681 + if (!_speedImgView) {
  2682 + _speedImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-speed"]];
  2683 + }
  2684 + return _speedImgView;
  2685 +}
  2686 +-(UILabel *)currentSpeedLab{
  2687 + if (!_currentSpeedLab) {
  2688 + _currentSpeedLab = [[UILabel alloc] init];
  2689 + _currentSpeedLab.font = [UIFont systemFontOfSize:24];
  2690 + _currentSpeedLab.textColor = kWhiteColor;
  2691 + _currentSpeedLab.text = @"--";
  2692 + _currentSpeedLab.textAlignment = NSTextAlignmentCenter;
  2693 + }
  2694 + return _currentSpeedLab;
  2695 +}
  2696 +-(UILabel *)speedDesLab{
  2697 + if (!_speedDesLab) {
  2698 + _speedDesLab = [[UILabel alloc] init];
  2699 + _speedDesLab.font = [UIFont systemFontOfSize:15];
  2700 + _speedDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2701 + _speedDesLab.text = @"配速";
  2702 + _speedDesLab.textAlignment = NSTextAlignmentCenter;
  2703 + }
  2704 + return _speedDesLab;
  2705 +}
  2706 +-(UIImageView *)timeImgView{
  2707 + if (!_timeImgView) {
  2708 + _timeImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-time cost"]];
  2709 + }
  2710 + return _timeImgView;
  2711 +}
  2712 +-(UILabel *)currentTimeLab{
  2713 + if (!_currentTimeLab) {
  2714 + _currentTimeLab = [[UILabel alloc] init];
  2715 + _currentTimeLab.font = [UIFont systemFontOfSize:24];
  2716 + _currentTimeLab.textColor = kWhiteColor;
  2717 + _currentTimeLab.text = @"00:00:00";
  2718 + _currentTimeLab.textAlignment = NSTextAlignmentCenter;
  2719 + }
  2720 + return _currentTimeLab;
  2721 +}
  2722 +-(UILabel *)timeDesLab{
  2723 + if (!_timeDesLab) {
  2724 + _timeDesLab = [[UILabel alloc] init];
  2725 + _timeDesLab.font = [UIFont systemFontOfSize:15];
  2726 + _timeDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2727 + _timeDesLab.text = @"用时";
  2728 + _timeDesLab.textAlignment = NSTextAlignmentCenter;
  2729 + }
  2730 + return _timeDesLab;
  2731 +}
  2732 +-(UIImageView *)stepImgView{
  2733 + if (!_stepImgView) {
  2734 + _stepImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-step"]];
  2735 + }
  2736 + return _stepImgView;
  2737 +}
  2738 +-(UILabel *)currentStepLab{
  2739 + if (!_currentStepLab) {
  2740 + _currentStepLab = [[UILabel alloc] init];
  2741 + _currentStepLab.font = [UIFont systemFontOfSize:24];
  2742 + _currentStepLab.textColor = kWhiteColor;
  2743 + _currentStepLab.text = @"--";
  2744 + _currentStepLab.textAlignment = NSTextAlignmentCenter;
  2745 + }
  2746 + return _currentStepLab;
  2747 +}
  2748 +-(UILabel *)stepDesLab{
  2749 + if (!_stepDesLab) {
  2750 + _stepDesLab = [[UILabel alloc] init];
  2751 + _stepDesLab.font = [UIFont systemFontOfSize:15];
  2752 + _stepDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0];
  2753 + _stepDesLab.text = @"步";
  2754 + _stepDesLab.textAlignment = NSTextAlignmentCenter;
  2755 + }
  2756 + return _stepDesLab;
  2757 +}
  2758 +-(QMUIButton *)stopRunningBtn{
  2759 + if (!_stopRunningBtn) {
  2760 + _stopRunningBtn = [[QMUIButton alloc] init];
  2761 + _stopRunningBtn.imagePosition = QMUIButtonImagePositionTop;
  2762 + _stopRunningBtn.spacingBetweenImageAndTitle = 8;
  2763 + [_stopRunningBtn setBackgroundImage:[UIImage imageWithColor:kWhiteColor] forState:UIControlStateNormal];
  2764 + [_stopRunningBtn setImage:[UIImage imageNamed:@"pbjs-time out"] forState:UIControlStateNormal];
  2765 + [_stopRunningBtn setTitle:@"暂停" forState:UIControlStateNormal];
  2766 + [_stopRunningBtn setTitleColor:kBlackColor forState:UIControlStateNormal];
  2767 + _stopRunningBtn.titleLabel.font = [UIFont systemFontOfSize:13];
  2768 + [_stopRunningBtn addTarget:self action:@selector(stopRunningBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  2769 + }
  2770 + return _stopRunningBtn;
  2771 +}
  2772 +
  2773 +-(QMUIButton *)goonRunningBtn{
  2774 + if (!_goonRunningBtn) {
  2775 + _goonRunningBtn = [[QMUIButton alloc] init];
  2776 + _goonRunningBtn.imagePosition = QMUIButtonImagePositionTop;
  2777 + _goonRunningBtn.spacingBetweenImageAndTitle = 8;
  2778 + [_goonRunningBtn setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:91/255.0 green:196/255.0 blue:164/255.0 alpha:1.0]] forState:UIControlStateNormal];
  2779 + [_goonRunningBtn setImage:[UIImage imageNamed:@"pbjs-play"] forState:UIControlStateNormal];
  2780 + [_goonRunningBtn setTitle:@"继续" forState:UIControlStateNormal];
  2781 + [_goonRunningBtn setTitleColor:kWhiteColor forState:UIControlStateNormal];
  2782 + _goonRunningBtn.titleLabel.font = [UIFont systemFontOfSize:13];
  2783 +
  2784 + [_goonRunningBtn addTarget:self action:@selector(goonRunningBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  2785 + }
  2786 + return _goonRunningBtn;
  2787 +}
  2788 +
  2789 +-(UIView *)endRunningBgView{
  2790 + if (!_endRunningBgView) {
  2791 + _endRunningBgView = [[UIView alloc] init];
  2792 + _endRunningBgView.backgroundColor = [UIColor colorWithRed:250/255.0 green:112/255.0 blue:112/255.0 alpha:1.0];
  2793 + }
  2794 + return _endRunningBgView;
  2795 +}
  2796 +
  2797 +-(QMUIButton *)endRunningBtn{
  2798 + if (!_endRunningBtn) {
  2799 + _endRunningBtn = [[QMUIButton alloc] init];
  2800 + _endRunningBtn.imagePosition = QMUIButtonImagePositionTop;
  2801 + _endRunningBtn.spacingBetweenImageAndTitle = 8;
  2802 + [_endRunningBtn setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:250/255.0 green:112/255.0 blue:112/255.0 alpha:1.0]] forState:UIControlStateNormal];
  2803 + [_endRunningBtn setImage:[UIImage imageNamed:@"pbjs-finish"] forState:UIControlStateNormal];
  2804 + [_endRunningBtn setTitle:@"结束" forState:UIControlStateNormal];
  2805 + _endRunningBtn.titleLabel.font = [UIFont systemFontOfSize:13];
  2806 + [_endRunningBtn setTitleColor:kWhiteColor forState:UIControlStateNormal];
  2807 + [_endRunningBtn addTarget:self action:@selector(endRunningBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  2808 + }
  2809 + return _endRunningBtn;
  2810 +}
  2811 +
  2812 +-(UILongPressGestureRecognizer *)longPress{
  2813 + if (!_longPress) {
  2814 + _longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)];
  2815 + }
  2816 + return _longPress;
  2817 +}
  2818 +
  2819 +- (UIImageView *)endTipView{
  2820 + if (!_endTipView) {
  2821 + _endTipView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"press finish"]];
  2822 + }
  2823 + return _endTipView;
  2824 +}
  2825 +
  2826 +-(UILabel *)endTipLab{
  2827 + if (!_endTipLab) {
  2828 + _endTipLab = [[UILabel alloc] init];
  2829 + _endTipLab.text = @"长按结束";
  2830 + _endTipLab.textAlignment = NSTextAlignmentCenter;
  2831 + _endTipLab.textColor = kBlackColor;
  2832 + _endTipLab.font = [UIFont systemFontOfSize:12];
  2833 + }
  2834 + return _endTipLab;
  2835 +}
  2836 +
  2837 +-(BMKMapView *)mapView{
  2838 + if (!_mapView) {
  2839 + _mapView = [[BMKMapView alloc] init];
  2840 + _mapView.frame =CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
  2841 + _mapView.delegate = self;
  2842 + _mapView.zoomLevel = 19;//缩放等级4-21
  2843 + _mapView.showMapScaleBar = NO;//显示比例尺
  2844 + _mapView.showsUserLocation = YES;//显示定位图层
  2845 + // //显示我的位置,我的位置图标和地图都不会旋转
  2846 + _mapView.userTrackingMode = BMKUserTrackingModeHeading;
  2847 + // //更换我的位置图标
  2848 + // // self.mapView是BMKMapView对象
  2849 + BMKLocationViewDisplayParam *param = [[BMKLocationViewDisplayParam alloc] init];
  2850 + // //定位图标名称,需要将该图片放到 mapapi.bundle/images 目录下
  2851 + // // param.locationViewImgName = @"icon_nav_bus";
  2852 + // //用户自定义定位图标,V4.2.1以后支持
  2853 + param.locationViewImage = [UIImage imageNamed:@"map_dw"];
  2854 + //根据配置参数更新定位图层样式
  2855 + //设置显示精度圈,默认YES
  2856 + param.isAccuracyCircleShow = NO;
  2857 + //精度圈 边框颜色
  2858 +// param.accuracyCircleStrokeColor = kWhiteColor;
  2859 +// //精度圈 填充颜色
  2860 +// param.accuracyCircleFillColor = kWhiteColor;
  2861 + [_mapView updateLocationViewWithParam:param];
  2862 + }
  2863 + return _mapView;
  2864 +}
  2865 +
  2866 +-(QMUIButton *)backBtn{
  2867 + if(!_backBtn){
  2868 + _backBtn = [[QMUIButton alloc] init];
  2869 + [_backBtn setBackgroundImage:[UIImage imageNamed:@"back-bg"] forState:UIControlStateNormal];
  2870 + [_backBtn setImage:[UIImage imageNamed:@"top_back"] forState:UIControlStateNormal];
  2871 + _backBtn.imageEdgeInsets = UIEdgeInsetsMake(-5, -3, 0, 0);
  2872 + [_backBtn addTarget:self action:@selector(backBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  2873 + }
  2874 + return _backBtn;
  2875 +}
  2876 +
  2877 +- (QMUIButton *)GPSBtn{
  2878 + if(!_GPSBtn){
  2879 + _GPSBtn = [[QMUIButton alloc] init];
  2880 + [_GPSBtn setBackgroundImage:[UIImage imageNamed:@"gps-bg"] forState:UIControlStateNormal];
  2881 + [_GPSBtn setTitle:@"GPS " forState:UIControlStateNormal];
  2882 + [_GPSBtn setTitleColor:kBlackColor forState:UIControlStateNormal];
  2883 + _GPSBtn.titleLabel.font = [UIFont systemFontOfSize:10];
  2884 + [_GPSBtn setImage:[UIImage imageNamed:@"signal-low"] forState:UIControlStateNormal];
  2885 + _GPSBtn.imagePosition = QMUIButtonImagePositionRight;
  2886 + _GPSBtn.imageEdgeInsets = UIEdgeInsetsMake(-3, 0, 0, 0);
  2887 + _GPSBtn.titleEdgeInsets = UIEdgeInsetsMake(-3, 0, 0, 0);
  2888 + }
  2889 + return _GPSBtn;
  2890 +}
  2891 +
  2892 +- (QMUIButton *)tipGPSBtn{
  2893 + if(!_tipGPSBtn){
  2894 + _tipGPSBtn = [[QMUIButton alloc] init];
  2895 + [_tipGPSBtn setBackgroundImage:[UIImage imageNamed:@"map-signal-tx"] forState:UIControlStateNormal];
  2896 + [_tipGPSBtn setTitle:@"信号糟糕,数据准确度低" forState:UIControlStateNormal];
  2897 + [_tipGPSBtn setTitleColor:kBlackColor forState:UIControlStateNormal];
  2898 + _tipGPSBtn.titleLabel.font = [UIFont systemFontOfSize:10];
  2899 + _tipGPSBtn.titleEdgeInsets = UIEdgeInsetsMake(-1, 0, 0, 0);
  2900 + }
  2901 + return _tipGPSBtn;
  2902 +}
  2903 +-(BMKLocationManager *)locationManager{
  2904 + if (!_locationManager) {
  2905 + //初始化实例
  2906 + _locationManager = [[BMKLocationManager alloc] init];
  2907 + //设置delegate
  2908 + _locationManager.delegate = self;
  2909 + //设置返回位置的坐标系类型
  2910 + _locationManager.coordinateType = BMKLocationCoordinateTypeGCJ02;
  2911 + //设置距离过滤参数:10米
  2912 + _locationManager.distanceFilter = 1.0f;
  2913 + //设置预期精度参数:10米
  2914 + _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  2915 + //设置应用位置类型:步行、骑行等
  2916 + _locationManager.activityType = CLActivityTypeFitness;
  2917 + //设置是否自动停止位置更新
  2918 + _locationManager.pausesLocationUpdatesAutomatically = NO;
  2919 + //设置是否允许后台定位
  2920 + _locationManager.allowsBackgroundLocationUpdates = YES;
  2921 + //设置位置获取超时时间
  2922 +// _locationManager.locationTimeout = 10;
  2923 + //设置获取地址信息超时时间
  2924 + // _locationManager.reGeocodeTimeout = 3;
  2925 + }
  2926 + return _locationManager;
  2927 +}
  2928 +
  2929 +- (BMKUserLocation *)userLocation{
  2930 + if (!_userLocation) {
  2931 + _userLocation = [[BMKUserLocation alloc] init];
  2932 + }
  2933 + return _userLocation;
  2934 +}
  2935 +
  2936 +-(QMUIButton *)resetBtn{
  2937 + if(!_resetBtn){
  2938 + _resetBtn = [[QMUIButton alloc] init];
  2939 + [_resetBtn setBackgroundImage:[UIImage imageNamed:@"back-bg"] forState:UIControlStateNormal];
  2940 + [_resetBtn setImage:[UIImage imageNamed:@"map_location"] forState:UIControlStateNormal];
  2941 + _resetBtn.imageEdgeInsets = UIEdgeInsetsMake(-4.5, -0.5, 0, 0);
  2942 + [_resetBtn addTarget:self action:@selector(resetBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  2943 + }
  2944 + return _resetBtn;
  2945 +}
  2946 +
  2947 +-(UIImageView *)mapBottomView{
  2948 + if (!_mapBottomView) {
  2949 + _mapBottomView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"jl-bg"]];
  2950 + }
  2951 + return _mapBottomView;
  2952 +}
  2953 +-(UILabel *)mapCurrentSpeedLab{
  2954 + if (!_mapCurrentSpeedLab) {
  2955 + _mapCurrentSpeedLab = [[UILabel alloc] init];
  2956 + _mapCurrentSpeedLab.text = @"--";
  2957 + _mapCurrentSpeedLab.font = [UIFont boldSystemFontOfSize:24];
  2958 + _mapCurrentSpeedLab.textColor = kBlackColor;
  2959 + _mapCurrentSpeedLab.textAlignment = NSTextAlignmentCenter;
  2960 + }
  2961 + return _mapCurrentSpeedLab;
  2962 +}
  2963 +-(UILabel *)mapSpeedLab{
  2964 + if (!_mapSpeedLab) {
  2965 + _mapSpeedLab = [[UILabel alloc] init];
  2966 + _mapSpeedLab.text = @"配速";
  2967 + _mapSpeedLab.font = [UIFont systemFontOfSize:15];
  2968 + _mapSpeedLab.textColor = kBlackColor;
  2969 + _mapSpeedLab.textAlignment = NSTextAlignmentCenter;
  2970 + }
  2971 + return _mapSpeedLab;
  2972 +}
  2973 +-(UILabel *)mapCurrentTimeLab{
  2974 + if (!_mapCurrentTimeLab) {
  2975 + _mapCurrentTimeLab = [[UILabel alloc] init];
  2976 + _mapCurrentTimeLab.text = @"00:00:00";
  2977 + _mapCurrentTimeLab.font = [UIFont boldSystemFontOfSize:24];
  2978 + _mapCurrentTimeLab.textColor = kBlackColor;
  2979 + _mapCurrentTimeLab.textAlignment = NSTextAlignmentCenter;
  2980 + }
  2981 + return _mapCurrentTimeLab;
  2982 +}
  2983 +-(UILabel *)mapTimeLab{
  2984 + if (!_mapTimeLab) {
  2985 + _mapTimeLab = [[UILabel alloc] init];
  2986 + _mapTimeLab.text = @"用时";
  2987 + _mapTimeLab.font = [UIFont systemFontOfSize:15];
  2988 + _mapTimeLab.textColor = kBlackColor;
  2989 + _mapTimeLab.textAlignment = NSTextAlignmentCenter;
  2990 + }
  2991 + return _mapTimeLab;
  2992 +}
  2993 +
  2994 +-(UIView *)fristBgView{
  2995 + if (!_fristBgView) {
  2996 + _fristBgView = [[UIView alloc] init];
  2997 + _fristBgView.backgroundColor = kBlackColor;
  2998 + }
  2999 + return _fristBgView;
  3000 +}
  3001 +-(UILabel *)mapCurrentKMLab{
  3002 + if (!_mapCurrentKMLab) {
  3003 + _mapCurrentKMLab = [[UILabel alloc] init];
  3004 + _mapCurrentKMLab.text = @"0.00";
  3005 + _mapCurrentKMLab.font = [UIFont boldSystemFontOfSize:24];
  3006 + _mapCurrentKMLab.textColor = kBlackColor;
  3007 + _mapCurrentKMLab.textAlignment = NSTextAlignmentCenter;
  3008 + }
  3009 + return _mapCurrentKMLab;
  3010 +}
  3011 +-(UILabel *)mapKMLab{
  3012 + if (!_mapKMLab) {
  3013 + _mapKMLab = [[UILabel alloc] init];
  3014 + _mapKMLab.text = @"距离(km)";
  3015 + _mapKMLab.font = [UIFont systemFontOfSize:15];
  3016 + _mapKMLab.textColor = kBlackColor;
  3017 + _mapKMLab.textAlignment = NSTextAlignmentCenter;
  3018 + }
  3019 + return _mapKMLab;
  3020 +}
  3021 +
  3022 +-(CNTrackTableView *)tableView{
  3023 + if (!_tableView) {
  3024 + _tableView = [[CNTrackTableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
  3025 + _tableView.dataSource = self;
  3026 + _tableView.delegate = self;
  3027 + _tableView.receiverHeight = 345;
  3028 +// [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
  3029 + _tableView.backgroundColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.2];
  3030 + _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  3031 +// _tableView.separatorColor = [UIColor clearColor];
  3032 + _tableView.showsVerticalScrollIndicator = NO;
  3033 +
  3034 + }
  3035 + return _tableView;
  3036 +}
  3037 +-(UIView *)preSaveView{
  3038 + if (!_preSaveView) {
  3039 + _preSaveView = [[UIView alloc] init];
  3040 + _preSaveView.backgroundColor = RGBOF(0x5BC4A4);
  3041 + }
  3042 + return _preSaveView;
  3043 +}
  3044 +-(UIImageView *)loadingSaveView{
  3045 + if (!_loadingSaveView) {
  3046 + _loadingSaveView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"track_loading"]];
  3047 + }
  3048 + return _loadingSaveView;
  3049 +}
  3050 +-(UIButton *)saveBtn{
  3051 + if (!_saveBtn) {
  3052 + _saveBtn = [[UIButton alloc] init];
  3053 + [_saveBtn setTitle:@"完成" forState:UIControlStateNormal];
  3054 + _saveBtn.backgroundColor = RGBOF(0x5BC4A4);
  3055 + _saveBtn.userInteractionEnabled = YES;
  3056 + _saveBtn.titleLabel.font = [UIFont systemFontOfSize:18];
  3057 + [_saveBtn addTarget:self action:@selector(saveBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  3058 + }
  3059 + return _saveBtn;
  3060 +}
  3061 +-(NSMutableArray *)locationPoints{
  3062 + if (!_locationPoints) {
  3063 + _locationPoints = [NSMutableArray arrayWithCapacity:0];
  3064 + }
  3065 + return _locationPoints;
  3066 +}
  3067 +@end
... ...
CNLiveSportsModule/Classes/DB/CNRunExitModel.h 0 → 100644
  1 +//
  2 +// CNRunExitModel.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/24.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +
  13 +@interface CNRunExitModel : NSObject
  14 +//用户id
  15 +@property (nonatomic, copy) NSString *userId;
  16 +
  17 +//赛事id
  18 +@property (nonatomic, copy) NSString *eventId;
  19 +
  20 +//开始时间
  21 +@property (nonatomic, copy) NSString *startTime;
  22 +
  23 +//当前步数 30s存一次
  24 +@property (nonatomic, copy) NSString *step;
  25 +//是否暂停
  26 +@property (nonatomic, copy) NSString *isStop;
  27 +
  28 +//暂停时间
  29 +@property (nonatomic, copy) NSString *stopTime;
  30 +//重新开始的时间
  31 +@property (nonatomic, copy) NSString *reStartTime;
  32 +//暂停次数
  33 +@property (nonatomic, copy) NSString *stopCount;
  34 +
  35 +
  36 +
  37 +
  38 +//////////////////////////////////////////////////
  39 +//记录哪一天
  40 +@property (nonatomic, copy) NSString *time;
  41 +
  42 +//开始的地点
  43 +@property (nonatomic, copy) NSString *startAdd;
  44 +
  45 +//结束地点
  46 +@property (nonatomic, copy) NSString *stopAdd;
  47 +
  48 +//卡路里
  49 +@property (nonatomic, copy) NSString *calorie;
  50 +
  51 +//服务器赛道数据
  52 +@property (nonatomic, copy) NSString *eventData;
  53 +
  54 +// 根据数据库查询结果初始化
  55 +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet;
  56 +@end
  57 +
  58 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/DB/CNRunExitModel.m 0 → 100644
  1 +//
  2 +// CNRunExitModel.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/24.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNRunExitModel.h"
  10 +
  11 +@implementation CNRunExitModel
  12 +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet
  13 +{
  14 + if (!resultSet) return nil;
  15 + _userId = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"userId"]];
  16 + _eventId = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventId"]];
  17 + _startTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startTime"]];
  18 + _step = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"step"]];
  19 + _time = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"time"]];
  20 + _isStop = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"isStop"]];
  21 + _stopTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"stopTime"]];
  22 + _reStartTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"reStartTime"]];
  23 + _stopCount = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"stopCount"]];
  24 + _startAdd = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startAdd"]];
  25 + _stopAdd = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"stopAdd"]];
  26 + _calorie = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"calorie"]];
  27 + _eventData = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventData"]];
  28 + return self;
  29 +}
  30 +@end
... ...
CNLiveSportsModule/Classes/DB/CNRunToolModel.h 0 → 100644
  1 +//
  2 +// CNRunToolModel.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/7/4.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +@class CNRunToolPointModel;
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +
  13 +@interface CNRunToolModel : NSObject
  14 +@property (nonatomic, copy) NSString *userId;
  15 +@property (nonatomic, copy) NSString *eventId;
  16 +@property (nonatomic, copy) NSString *startTime;
  17 +@property (nonatomic, copy) NSString *step;
  18 +@property (nonatomic, copy) NSString *endTime;
  19 +@property (nonatomic, copy) NSString *pointsStr;
  20 +@property (nonatomic, copy) NSString *pointsCount;
  21 +@property (nonatomic, copy) NSString *endRun;
  22 +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet;
  23 +@end
  24 +
  25 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/DB/CNRunToolModel.m 0 → 100644
  1 +//
  2 +// CNRunToolModel.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/7/4.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNRunToolModel.h"
  10 +
  11 +@implementation CNRunToolModel
  12 +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet
  13 +{
  14 + if (!resultSet) return nil;
  15 + _userId = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"userId"]];
  16 + _eventId = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventId"]];
  17 + _startTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startTime"]];
  18 + _step = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"step"]];
  19 + _endTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"endTime"]];
  20 + _pointsStr = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"pointsStr"]];
  21 + _pointsCount = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"pointsCount"]];
  22 + _endRun = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"endRun"]];
  23 +
  24 + return self;
  25 +}
  26 +@end
... ...
CNLiveSportsModule/Classes/DB/CNRunToolPointModel.h 0 → 100644
  1 +//
  2 +// CNRunToolPointModel.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/7/4.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +/**打点的model*/
  13 +@interface CNRunToolPointModel : NSObject
  14 +
  15 +
  16 +//经度
  17 +@property (nonatomic, copy) NSString *latitude;
  18 +//纬度
  19 +@property (nonatomic, copy) NSString *longitude;
  20 +
  21 +//地点名称
  22 +@property (nonatomic, copy) NSString *pointName;
  23 +@end
  24 +
  25 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/DB/CNRunToolPointModel.m 0 → 100644
  1 +//
  2 +// CNRunToolPointModel.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/7/4.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNRunToolPointModel.h"
  10 +
  11 +@implementation CNRunToolPointModel
  12 +
  13 +@end
... ...
CNLiveSportsModule/Classes/DB/CNTrackLoaclDataManager.h 0 → 100644
  1 +//
  2 +// CNTrackLoaclDataManager.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/21.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +@class CNRunExitModel;
  11 +@class CNTrackUploadFailModel;
  12 +@class CNRunToolModel;
  13 +
  14 +@interface CNTrackLoaclDataManager : NSObject
  15 +// 获取单例
  16 ++ (instancetype)shareManager;
  17 +
  18 +// 插入数据
  19 +- (void)insertExitModel:(CNRunExitModel *)model;
  20 +
  21 +// 根据user id获取数据
  22 +- (CNRunExitModel *)getExitModel:(NSString *)userId;
  23 +
  24 +// 更新数据
  25 +- (void)updateExitModel:(CNRunExitModel *)model;
  26 +
  27 +// 删除数据
  28 +- (void)deleteExitModel:(NSString *)userId;
  29 +
  30 +
  31 +
  32 +// 插入数据
  33 +- (void)insertFUploadModel:(CNTrackUploadFailModel *)model;
  34 +
  35 +// 根据user id获取数据list 并排序
  36 +- (NSArray *)getFUploadModel:(NSString *)userId;
  37 +
  38 +// 删除单条数据,由开始时间
  39 +- (void)deleteFUploadModel:(CNTrackUploadFailModel *)model;
  40 +
  41 +
  42 +- (void)insertRunToolModel:(CNRunToolModel *)model;
  43 +- (void)updateRunToolModel:(CNRunToolModel *)model;
  44 +- (CNRunToolModel *)getRunToolModel:(NSString *)userId;
  45 +- (void)deleteRunToolModel:(CNRunToolModel *)model;
  46 +//- (CNLiveAlbumAudioListModel *)getWaitingModel; // 获取第一条等待的数据
  47 +//- (CNLiveAlbumAudioListModel *)getLastDownloadingModel; // 获取最后一条正在下载的数据
  48 +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllCacheData; // 获取所有数据
  49 +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllDownloadingData; // 根据lastStateTime倒叙获取所有正在下载的数据
  50 +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllDownloadedData; // 获取所有下载完成的数据
  51 +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllUnDownloadedData; // 获取所有未下载完成的数据(包含正在下载、等待、暂停、错误)
  52 +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllWaitingData; // 获取所有等待下载的数据
  53 +//- (CNLiveAlbumAudioListModel *)getModelwithActivityId:(NSString *)activityId; //根据ativityId获取数据
  54 +//
  55 +//
  56 +//// 更新数据
  57 +//- (void)updateWithModel:(CNLiveAlbumAudioListModel *)model option:(CNDBUpdateOption)option;
  58 +//
  59 +//// 删除数据
  60 +//- (void)deleteModelWithUrl:(NSString *)activityId;
  61 +@end
  62 +
  63 +
... ...
CNLiveSportsModule/Classes/DB/CNTrackLoaclDataManager.m 0 → 100644
  1 +//
  2 +// CNTrackLoaclDataManager.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/21.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNTrackLoaclDataManager.h"
  10 +#import "CNRunExitModel.h"
  11 +#import "CNTrackUploadFailModel.h"
  12 +#import "CNRunToolModel.h"
  13 +
  14 +@interface CNTrackLoaclDataManager ()
  15 +@property (nonatomic, strong) FMDatabaseQueue *dbQueue;
  16 +@property (nonatomic, copy) NSString *uploadFailPath;
  17 +@property (nonatomic, copy) NSString *runExitPath;
  18 +@property (nonatomic, copy) NSString *runToolPath;
  19 +
  20 +@end
  21 +
  22 +@implementation CNTrackLoaclDataManager
  23 ++ (instancetype)shareManager
  24 +{
  25 + static CNTrackLoaclDataManager *manager = nil;
  26 +
  27 + static dispatch_once_t onceToken;
  28 + dispatch_once(&onceToken, ^{
  29 + manager = [[self alloc] init];
  30 + });
  31 +
  32 + return manager;
  33 +}
  34 +
  35 +- (instancetype)init
  36 +{
  37 + if (self = [super init]) {
  38 + _runExitPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"CNTrackRunExit.sqlite"];
  39 + _uploadFailPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"CNTrackUploadFail.sqlite"];
  40 + _runToolPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"CNTrackRunTool.sqlite"];
  41 + [self createUploadFailedDB];
  42 + [self createRunExitDB];
  43 + [self createRunToolDB];
  44 + }
  45 + return self;
  46 +}
  47 +
  48 +
  49 +//创建上传失败的数据库
  50 +- (void)createUploadFailedDB{
  51 + // 数据库文件路径
  52 + NSString *path = self.uploadFailPath;
  53 + // 创建队列对象,内部会自动创建一个数据库, 并且自动打开
  54 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];
  55 +
  56 + [_dbQueue inDatabase:^(FMDatabase *db) {
  57 + // 创表
  58 + BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_UploadFail (id integer PRIMARY KEY AUTOINCREMENT, userId text, eventId text,eventName text,startTime text,endTime text,isStop text,stopTime text,reStartTime text,totalKM text,totalTime text,speed text,totalStep text,endCoordsDictStr text,pointsArrStr text,startLoaction text,endLocation text)"];
  59 + // if (![db columnExists:@"channelName" inTableWithName:@"t_videoCaches"] ) { //新添字段,先判断数据里有没有,没有,添加
  60 + // NSString *channelName = [NSString stringWithFormat:@"ALTER TABLE %@ ADD %@ INTEGER",@"t_videoCaches",@"channelName"];
  61 + // BOOL isSuccess = [db executeUpdate:channelName];
  62 + // if (isSuccess) {
  63 + // NSLog(@"插入成功");
  64 + // }else {
  65 + // NSLog(@"插入失败");
  66 + // }
  67 + // }
  68 + if (result) {
  69 + NSLog(@"UploadFail数据表创建成功");
  70 + }else {
  71 + NSLog(@"UploadFail数据表创建失败");
  72 + }
  73 + }];
  74 +}
  75 +//创建APP退出或返回功能的数据库
  76 +- (void)createRunExitDB{
  77 + // 数据库文件路径
  78 + NSString *path = self.runExitPath;
  79 + // 创建队列对象,内部会自动创建一个数据库, 并且自动打开
  80 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];
  81 +
  82 + [_dbQueue inDatabase:^(FMDatabase *db) {
  83 + // 创表
  84 + BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_RunExit (id integer PRIMARY KEY AUTOINCREMENT, userId text, eventId text,startTime text,step text,time text,isStop text,stopTime text,reStartTime text,stopCount text,startAdd text,stopAdd text,calorie text,eventData text)"];
  85 +// if (![db columnExists:@"channelName" inTableWithName:@"t_videoCaches"] ) { //新添字段,先判断数据里有没有,没有,添加
  86 +// NSString *channelName = [NSString stringWithFormat:@"ALTER TABLE %@ ADD %@ INTEGER",@"t_videoCaches",@"channelName"];
  87 +// BOOL isSuccess = [db executeUpdate:channelName];
  88 +// if (isSuccess) {
  89 +// NSLog(@"插入成功");
  90 +// }else {
  91 +// NSLog(@"插入失败");
  92 +// }
  93 +// }
  94 + if (result) {
  95 + NSLog(@"runExit数据表创建成功");
  96 + }else {
  97 + NSLog(@"runExit数据表创建失败");
  98 + }
  99 + }];
  100 +}
  101 +
  102 +- (void)createRunToolDB{
  103 + // 数据库文件路径
  104 + NSString *path = self.runToolPath;
  105 + // 创建队列对象,内部会自动创建一个数据库, 并且自动打开
  106 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];
  107 +
  108 + [_dbQueue inDatabase:^(FMDatabase *db) {
  109 + // 创表
  110 + BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_RunTool (id integer PRIMARY KEY AUTOINCREMENT, userId text, eventId text,startTime text,step text,endTime text,pointsStr text,pointsCount text,endRun text)"];
  111 + if (result) {
  112 + NSLog(@"runTool数据表创建成功");
  113 + }else {
  114 + NSLog(@"runTool数据表创建失败");
  115 + }
  116 + }];
  117 +}
  118 +
  119 +#pragma mark - 插入一条数据
  120 +- (void)insertExitModel:(CNRunExitModel *)model
  121 +{
  122 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath];
  123 + [_dbQueue inDatabase:^(FMDatabase *db) {
  124 + BOOL result = [db executeUpdate:@"INSERT INTO t_RunExit (userId,eventId,startTime,step,time,isStop,stopTime,reStartTime,stopCount,startAdd,stopAdd,calorie,eventData) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)", model.userId.length>0?model.userId :@"",
  125 + model.eventId.length>0?model.eventId:@"",
  126 + model.startTime.length>0?model.startTime:@"",
  127 + model.step.length>0?model.step:@"",
  128 + model.time.length>0?model.time:@"",
  129 + model.isStop.length>0?model.isStop:@"",
  130 + model.stopTime.length>0?model.stopTime:@"",
  131 + model.reStartTime.length>0?model.reStartTime:@"",
  132 + model.stopCount.length>0?model.stopCount:@"",
  133 + model.startAdd.length>0?model.startAdd:@"",
  134 + model.stopAdd.length>0?model.stopAdd:@"",
  135 + model.calorie.length>0?model.calorie:@"",
  136 + model.eventData.length>0?model.eventData :@""];//,model.schedule ?model.schedule:@"",model.channelName ? model.channelName:@"",model.time ? model.time:@"",model.url, model.resumeData, [NSNumber numberWithInteger:model.totalFileSize], [NSNumber numberWithInteger:model.tmpFileSize], [NSNumber numberWithInteger:model.state], [NSNumber numberWithFloat:model.progress], [NSNumber numberWithDouble:0], [NSNumber numberWithInteger:0], [NSNumber numberWithInteger:0],model.fileSize];
  137 + if (result) {
  138 + NSLog(@"插入成功");
  139 + }else {
  140 + NSLog(@"插入失败");
  141 + }
  142 + }];
  143 +}
  144 +
  145 +// 根据赛事id获取数据
  146 +- (CNRunExitModel *)getExitModel:(NSString *)userId{
  147 + __block CNRunExitModel *model = nil;
  148 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath];
  149 + [_dbQueue inDatabase:^(FMDatabase *db) {
  150 + FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_RunExit WHERE userId = ?", userId];
  151 + while ([resultSet next]) {
  152 + model = [[CNRunExitModel alloc] initWithFMResultSet:resultSet];
  153 + }
  154 + }];
  155 + return model;
  156 +}
  157 +
  158 +// 更新数据
  159 +- (void)updateExitModel:(CNRunExitModel *)model{
  160 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath];
  161 + [_dbQueue inDatabase:^(FMDatabase *db) {
  162 + BOOL result = [db executeUpdate:@"UPDATE t_RunExit SET eventId = ?, startTime = ?, step = ?, time = ?, isStop = ?, stopTime = ?,reStartTime = ?,stopCount = ?, startAdd = ?, stopAdd = ? ,calorie = ? ,eventData = ? WHERE userId = ?", model.eventId, model.startTime,model.step,model.time,model.isStop,model.stopTime,model.reStartTime,model.stopCount,
  163 + model.startAdd,model.stopAdd,model.calorie,model.eventData,model.userId];
  164 + if (result) {
  165 + NSLog(@"更新成功");
  166 + }else {
  167 + NSLog(@"更新失败");
  168 + }
  169 + }];
  170 +}
  171 +
  172 +// 删除数据
  173 +- (void)deleteExitModel:(NSString *)userId{
  174 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath];
  175 + [_dbQueue inDatabase:^(FMDatabase *db) { // where 后面跟的是条件
  176 + BOOL result = [db executeUpdate:@"DELETE FROM t_RunExit WHERE userId = ?", userId];
  177 + if (result) {
  178 + NSLog(@"删除成功");
  179 + }else {
  180 + NSLog(@"删除失败");
  181 + }
  182 + }];
  183 +}
  184 +
  185 +// 插入数据
  186 +- (void)insertFUploadModel:(CNTrackUploadFailModel *)model{
  187 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.uploadFailPath];
  188 + [_dbQueue inDatabase:^(FMDatabase *db) {
  189 + BOOL result = [db executeUpdate:@"INSERT INTO t_UploadFail (userId,eventId,eventName,startTime,endTime,isStop,stopTime,reStartTime,totalKM,totalTime,speed,totalStep,endCoordsDictStr,pointsArrStr,startLoaction,endLocation) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)",
  190 + model.userId.length>0?model.userId :@"",
  191 + model.eventId.length>0?model.eventId:@"", model.eventName.length>0?model.eventName:@"",
  192 + model.startTime.length>0?model.startTime:@"",
  193 + model.endTime.length>0?model.endTime:@"",
  194 + model.isStop.length>0?model.isStop:@"",
  195 + model.stopTime.length>0?model.stopTime:@"",
  196 + model.reStartTime.length>0?model.reStartTime:@"",
  197 + model.totalKM.length>0?model.totalKM:@"",
  198 + model.totalTime.length>0?model.totalTime:@"",
  199 + model.speed.length>0?model.speed:@"",
  200 + model.totalStep.length>0?model.totalStep:@"",model.endCoordsDictStr.length>0?model.endCoordsDictStr:@"",model.pointsArrStr.length>0?model.pointsArrStr:@"",model.startLoaction.length>0?model.startLoaction:@"",model.endLocation.length>0?model.endLocation:@""];
  201 + if (result) {
  202 + NSLog(@"插入成功");
  203 + }else {
  204 + NSLog(@"插入失败");
  205 + }
  206 + }];
  207 +}
  208 +
  209 +// 根据user id获取数据list 并排序
  210 +- (NSArray *)getFUploadModel:(NSString *)userId{
  211 +// order by lastStateTime desc
  212 + __block NSArray<CNTrackUploadFailModel *> *array = nil;
  213 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.uploadFailPath];
  214 + [_dbQueue inDatabase:^(FMDatabase *db) {
  215 + FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_UploadFail WHERE userId = ?", userId];
  216 + NSMutableArray *tmpArr = [NSMutableArray array];
  217 + while ([resultSet next]) {
  218 + [tmpArr addObject:[[CNTrackUploadFailModel alloc] initWithFMResultSet:resultSet]];
  219 + }
  220 + array = tmpArr;
  221 + }];
  222 + return array;
  223 +}
  224 +
  225 +// 删除单条数据,由开始时间
  226 +- (void)deleteFUploadModel:(CNTrackUploadFailModel *)model{
  227 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.uploadFailPath];
  228 + [_dbQueue inDatabase:^(FMDatabase *db) { // where 后面跟的是条件
  229 + BOOL result = [db executeUpdate:@"DELETE FROM t_UploadFail WHERE startTime = ?", model.startTime];
  230 + if (result) {
  231 + NSLog(@"删除成功");
  232 + }else {
  233 + NSLog(@"删除失败");
  234 + }
  235 + }];
  236 +}
  237 +
  238 +- (void)insertRunToolModel:(CNRunToolModel *)model
  239 +{
  240 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath];
  241 + [_dbQueue inDatabase:^(FMDatabase *db) {
  242 + BOOL result = [db executeUpdate:@"INSERT INTO t_RunTool (userId,eventId,startTime,step,endTime,pointsStr,pointsCount,endRun) VALUES (?, ?, ?,?, ?, ?,?,?)", model.userId.length>0?model.userId :@"",
  243 + model.eventId.length>0?model.eventId:@"",
  244 + model.startTime.length>0?model.startTime:@"",
  245 + model.step.length>0?model.step:@"",
  246 + model.endTime.length>0?model.endTime:@"",
  247 + model.pointsStr.length>0?model.pointsStr:@"",model.pointsCount.length>0?model.pointsCount:@"",model.endRun.length>0?model.endRun:@""];
  248 + if (result) {
  249 + NSLog(@"插入成功");
  250 + }else {
  251 + NSLog(@"插入失败");
  252 + }
  253 + }];
  254 +}
  255 +
  256 +// 更新数据
  257 +- (void)updateRunToolModel:(CNRunToolModel *)model{
  258 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath];
  259 + [_dbQueue inDatabase:^(FMDatabase *db) {
  260 + BOOL result = [db executeUpdate:@"UPDATE t_RunTool SET eventId = ?, startTime = ?,step = ?, endTime = ?, pointsStr = ?, pointsCount = ?,endRun = ? WHERE userId = ?", model.eventId, model.startTime,model.step,model.endTime,model.pointsStr,model.pointsCount,model.endRun,model.userId];
  261 + if (result) {
  262 + NSLog(@"更新成功");
  263 + }else {
  264 + NSLog(@"更新失败");
  265 + }
  266 + }];
  267 +}
  268 +
  269 +// 根据赛事id获取数据
  270 +- (CNRunToolModel *)getRunToolModel:(NSString *)userId{
  271 + __block CNRunToolModel *model = nil;
  272 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath];
  273 + [_dbQueue inDatabase:^(FMDatabase *db) {
  274 + FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_RunTool WHERE userId = ?", userId];
  275 + while ([resultSet next]) {
  276 + model = [[CNRunToolModel alloc] initWithFMResultSet:resultSet];
  277 + }
  278 + }];
  279 + return model;
  280 +}
  281 +
  282 +// 删除单条数据
  283 +- (void)deleteRunToolModel:(CNRunToolModel *)model{
  284 + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath];
  285 + [_dbQueue inDatabase:^(FMDatabase *db) { // where 后面跟的是条件
  286 + BOOL result = [db executeUpdate:@"DELETE FROM t_RunTool WHERE userId = ?", model.userId];
  287 + if (result) {
  288 + NSLog(@"删除成功");
  289 + }else {
  290 + NSLog(@"删除失败");
  291 + }
  292 + }];
  293 +}
  294 +
  295 +
  296 +@end
  297 +
... ...
CNLiveSportsModule/Classes/DB/CNTrackUploadFailModel.h 0 → 100644
  1 +//
  2 +// CNTrackUploadFailModel.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/26.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +
  12 +@interface CNTrackUploadFailModel : NSObject
  13 +//用户id
  14 +@property (nonatomic, copy) NSString *userId;
  15 +
  16 +//赛事id
  17 +@property (nonatomic, copy) NSString *eventId;
  18 +
  19 +//赛事名称
  20 +@property (nonatomic, copy) NSString *eventName;
  21 +
  22 +//开始时间
  23 +@property (nonatomic, copy) NSString *startTime;
  24 +
  25 +//结束时间
  26 +@property (nonatomic, copy) NSString *endTime;
  27 +
  28 +//是否暂停
  29 +@property (nonatomic, copy) NSString *isStop;
  30 +
  31 +//暂停时间
  32 +@property (nonatomic, copy) NSString *stopTime;
  33 +
  34 +//重新开始的时间
  35 +@property (nonatomic, copy) NSString *reStartTime;
  36 +
  37 +//公里
  38 +@property (nonatomic, copy) NSString *totalKM;
  39 +
  40 +//用时
  41 +@property (nonatomic, copy) NSString *totalTime;
  42 +
  43 +//配速
  44 +@property (nonatomic, copy) NSString *speed;
  45 +
  46 +//步数
  47 +@property (nonatomic, copy) NSString *totalStep;
  48 +
  49 +//赛事的终点坐标是个字典
  50 +@property (nonatomic, copy) NSString *endCoordsDictStr;
  51 +
  52 +//运营打的点
  53 +@property (nonatomic, copy) NSString *pointsArrStr;
  54 +
  55 +//----
  56 +//开始的地点
  57 +@property (nonatomic, copy) NSString *startLoaction;
  58 +//结束的地点
  59 +@property (nonatomic, copy) NSString *endLocation;
  60 +
  61 +// 根据数据库查询结果初始化
  62 +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet;
  63 +@end
  64 +
... ...
CNLiveSportsModule/Classes/DB/CNTrackUploadFailModel.m 0 → 100644
  1 +//
  2 +// CNTrackUploadFailModel.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/26.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNTrackUploadFailModel.h"
  10 +
  11 +@implementation CNTrackUploadFailModel
  12 +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet
  13 +{
  14 + if (!resultSet) return nil;
  15 + _userId = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"userId"]];
  16 + _eventId = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventId"]];
  17 + _eventName = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"eventName"]];
  18 + _startTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startTime"]];
  19 + _endTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"endTime"]];
  20 + _isStop = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"isStop"]];
  21 + _stopTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"stopTime"]];
  22 + _reStartTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"reStartTime"]];
  23 + _totalKM = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"totalKM"]];
  24 + _totalTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"totalTime"]];
  25 + _speed = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"speed"]];
  26 + _totalStep = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"totalStep"]];
  27 + _endCoordsDictStr = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"endCoordsDictStr"]];
  28 + _pointsArrStr = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"pointsArrStr"]];
  29 + return self;
  30 +}
  31 +@end
... ...
CNLiveSportsModule/Classes/Manage/CNTraceConst.h 0 → 100644
  1 +//
  2 +// CNTraceConst.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +/** CNLocationGPSState 枚举识别GPS信号状态
  13 + *
  14 + */
  15 +typedef NS_ENUM(int, CNLocationGPSState) {
  16 + CNLocationGPSStateGood = 0, ///GPS好
  17 + CNLocationGPSStateMedium, ///GPS中
  18 + CNLocationGPSStatePoor, ///GPS差
  19 + CNLocationGPSStateNull ///GPS无
  20 +};
  21 +
  22 +@interface CNTraceConst : NSObject
  23 +//FOUNDATION_EXPORT NSString * const AK;
  24 +//FOUNDATION_EXPORT NSString * const MCODE;
  25 +//FOUNDATION_EXPORT NSUInteger const serviceID;
  26 +FOUNDATION_EXPORT NSString * const TrackServiceOperationResultNotification;
  27 +FOUNDATION_EXPORT NSString * const TrackServiceGetPushMessageNotification;
  28 +
  29 +@end
  30 +
  31 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/Manage/CNTraceConst.m 0 → 100644
  1 +//
  2 +// CNTraceConst.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNTraceConst.h"
  10 +
  11 +@implementation CNTraceConst
  12 +
  13 +//#ifdef Environment_ON
  14 +//////////////////////////////正式
  15 +//
  16 +//#ifdef IPA_APPSTORE
  17 +//// 正式企业
  18 +//// 填写你在API控制台申请的iOS类型的AK
  19 +//NSString * const AK = @"1249woAM397jz6uGFEfXY4MxRxfkGtIN";
  20 +//
  21 +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier
  22 +//NSString * const MCODE = @"com.cnlive.CNLiveNetAddInHouse";
  23 +//
  24 +//NSUInteger const serviceID = 214690;
  25 +//
  26 +//#else
  27 +//// 正式个人
  28 +//// 填写你在API控制台申请的iOS类型的AK
  29 +//NSString * const AK = @"KbQoyL7KebOF1CvHWHqKa61pf8nMhUL4";
  30 +//
  31 +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier
  32 +//NSString * const MCODE = @"com.cnlive.CNLiveNetAdd";
  33 +//
  34 +//NSUInteger const serviceID = 214690;
  35 +//
  36 +//#endif
  37 +//
  38 +//#else
  39 +////////////////////////////////////////测试
  40 +//
  41 +//#ifdef IPA_APPSTORE
  42 +//// 测试企业
  43 +//// 填写你在API控制台申请的iOS类型的AK
  44 +//NSString * const AK = @"Nb4bz9t32YnmTkqVKrNHtToPQAwWvjzK";
  45 +//
  46 +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier
  47 +//NSString * const MCODE = @"com.cnlive.CNLiveNetAddInHouse.debug";
  48 +//// 填写你在鹰眼轨迹管理台创建的鹰眼服务对应的ID
  49 +//NSUInteger const serviceID = 213511;
  50 +//
  51 +//#else
  52 +//// 测试个人
  53 +//// 填写你在API控制台申请的iOS类型的AK
  54 +//NSString * const AK = @"jjrZsIZYalD5IPOkjzCOOqkApKLtn8LW";
  55 +//
  56 +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier
  57 +//NSString * const MCODE = @"com.cnlive.CNLiveNetAdd.debug";
  58 +//// 填写你在鹰眼轨迹管理台创建的鹰眼服务对应的ID
  59 +//NSUInteger const serviceID = 213511;
  60 +//
  61 +//#endif
  62 +//
  63 +//#endif
  64 +
  65 +
  66 +
  67 +
  68 +
  69 +
  70 +
  71 +NSString * const TrackServiceOperationResultNotification = @"TrackServiceOperationResultNotification";
  72 +
  73 +NSString * const TrackServiceGetPushMessageNotification = @"TrackServiceGetPushMessageNotification";
  74 +
  75 +@end
... ...
CNLiveSportsModule/Classes/Manage/CNTrackServiceManager.h 0 → 100644
  1 +//
  2 +// CNTrackServiceManager.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/10.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +typedef NS_ENUM(NSUInteger, ServiceOperationType) {
  12 + TRACK_SERVICE_OPERATION_TYPE_START_SERVICE,
  13 + TRACK_SERVICE_OPERATION_TYPE_STOP_SERVICE,
  14 + TRACK_SERVICE_OPERATION_TYPE_START_GATHER,
  15 + TRACK_SERVICE_OPERATION_TYPE_STOP_GATHER,
  16 +};
  17 +@class CNRunExitModel;
  18 +
  19 +@protocol CNTrackServiceManagerDelegate <NSObject>
  20 +
  21 +- (void)currentPedometer:(CNRunExitModel *)model;
  22 +- (void)currentToolPedometer:(NSInteger)stepCount;
  23 +
  24 +@end
  25 +@interface CNTrackServiceManager : NSObject <BTKTraceDelegate>
  26 +
  27 +@property (nonatomic, weak) id <CNTrackServiceManagerDelegate>delegate;
  28 ++(CNTrackServiceManager *)defaultManager;
  29 +@property (nonatomic, assign) BOOL isStartRecord;
  30 +
  31 +@property (nonatomic, assign) BOOL noAcceptFenceNotify;
  32 +@property (nonatomic, assign) BOOL isClickGoOn;
  33 +
  34 +/**
  35 + 标志是否已经开启轨迹服务
  36 + */
  37 +@property (nonatomic, assign) BOOL isServiceStarted;
  38 +
  39 +/**
  40 + 标志是否已经开始采集
  41 + */
  42 +@property (nonatomic, assign) BOOL isGatherStarted;
  43 +
  44 +/**
  45 + 开启轨迹服务
  46 +
  47 + @param startServiceOption 开启服务的选项
  48 + */
  49 +-(void)startServiceWithOption:(BTKStartServiceOption *)startServiceOption;
  50 +
  51 +/**
  52 + 停止轨迹服务
  53 + */
  54 +-(void)stopService;
  55 +
  56 +/**
  57 + 开始采集
  58 + */
  59 +-(void)startGather;
  60 +
  61 +/**
  62 + 停止采集
  63 + */
  64 +-(void)stopGather;
  65 +
  66 +
  67 +
  68 +//////////////////
  69 +
  70 +- (void)recordStep:(NSDate *)date isUser:(BOOL)isU;
  71 +@end
... ...
CNLiveSportsModule/Classes/Manage/CNTrackServiceManager.m 0 → 100644
  1 +//
  2 +// CNTrackServiceManager.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/10.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNTrackServiceManager.h"
  10 +#import <UserNotifications/UserNotifications.h>
  11 +#import <CoreMotion/CoreMotion.h>
  12 +#import "CNRunExitModel.h"
  13 +#import "CNTrackLoaclDataManager.h"
  14 +#import "CNRunToolModel.h"
  15 +
  16 +#define GLOBAL_QUEUE dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  17 +
  18 +static NSString * const YYPushMessageNotificationIdentifier = @"YYPushMessageNotificationIdentifier";
  19 +
  20 +@implementation CNTrackServiceManager{
  21 + CMPedometer *_pedometer;//计步器
  22 + NSInteger _lastStepCount;//最新的步数或起止步数
  23 + BOOL _isUser;
  24 +}
  25 +
  26 ++(CNTrackServiceManager *)defaultManager {
  27 + static CNTrackServiceManager *manager = nil;
  28 + static dispatch_once_t onceToken;
  29 + dispatch_once(&onceToken, ^{
  30 + manager = [[CNTrackServiceManager alloc] init];
  31 + });
  32 + return manager;
  33 +}
  34 +
  35 +-(instancetype)init {
  36 + self = [super init];
  37 + if (self) {
  38 + _isServiceStarted = FALSE;
  39 + _isGatherStarted = FALSE;
  40 + }
  41 + return self;
  42 +}
  43 +
  44 +#pragma mark private function
  45 +-(void)startServiceWithOption:(BTKStartServiceOption *)startServiceOption {
  46 + dispatch_async(GLOBAL_QUEUE, ^{
  47 + [[BTKAction sharedInstance] startService:startServiceOption delegate:self];
  48 + [[BTKAction sharedInstance] changeGatherAndPackIntervals:2 packInterval:10 delegate:self];
  49 + [[BTKAction sharedInstance] setLocationAttributeWithActivityType:CLActivityTypeFitness desiredAccuracy:kCLLocationAccuracyBest distanceFilter:1];
  50 + });
  51 +}
  52 +
  53 +-(void)stopService {
  54 + dispatch_async(GLOBAL_QUEUE, ^{
  55 + [[BTKAction sharedInstance] stopService:self];
  56 + });
  57 +}
  58 +
  59 +-(void)startGather {
  60 + dispatch_async(GLOBAL_QUEUE, ^{
  61 + [[BTKAction sharedInstance] startGather:self];
  62 + });
  63 +}
  64 +
  65 +-(void)stopGather {
  66 + dispatch_async(GLOBAL_QUEUE, ^{
  67 + [[BTKAction sharedInstance] stopGather:self];
  68 + });
  69 +}
  70 +
  71 +#pragma mark - BTKTraceDelegate
  72 +-(void)onStartService:(BTKServiceErrorCode)error {
  73 + // 维护状态标志
  74 + if (error == BTK_START_SERVICE_SUCCESS || error == BTK_START_SERVICE_SUCCESS_BUT_OFFLINE) {
  75 + NSLog(@"轨迹服务开启成功");
  76 + self.isServiceStarted = TRUE;
  77 + } else {
  78 + NSLog(@"轨迹服务开启失败");
  79 + }
  80 + // 构造广播内容
  81 + NSString *title = nil;
  82 + NSString *message = nil;
  83 + switch (error) {
  84 + case BTK_START_SERVICE_SUCCESS:
  85 + title = @"轨迹服务开启成功";
  86 + message = @"成功登录到服务端";
  87 + break;
  88 + case BTK_START_SERVICE_SUCCESS_BUT_OFFLINE:
  89 + title = @"轨迹服务开启成功";
  90 + message = @"当前网络不畅,未登录到服务端。网络恢复后SDK会自动重试";
  91 + break;
  92 + case BTK_START_SERVICE_PARAM_ERROR:
  93 + title = @"轨迹服务开启失败";
  94 + message = @"参数错误,点击右上角设置按钮设置参数";
  95 + break;
  96 + case BTK_START_SERVICE_INTERNAL_ERROR:
  97 + title = @"轨迹服务开启失败";
  98 + message = @"SDK服务内部出现错误";
  99 + break;
  100 + case BTK_START_SERVICE_NETWORK_ERROR:
  101 + title = @"轨迹服务开启失败";
  102 + message = @"网络异常";
  103 + break;
  104 + case BTK_START_SERVICE_AUTH_ERROR:
  105 + title = @"轨迹服务开启失败";
  106 + message = @"鉴权失败,请检查AK和MCODE等配置信息";
  107 + break;
  108 + case BTK_START_SERVICE_IN_PROGRESS:
  109 + title = @"轨迹服务开启失败";
  110 + message = @"正在开启服务,请稍后再试";
  111 + break;
  112 + case BTK_SERVICE_ALREADY_STARTED_ERROR:
  113 + title = @"轨迹服务开启失败";
  114 + message = @"已经成功开启服务,请勿重复开启";
  115 + break;
  116 + default:
  117 + title = @"轨迹服务开启失败";
  118 + message = @"轨迹服务开启结果未知";
  119 + break;
  120 + }
  121 + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_START_SERVICE),
  122 + @"title":title,
  123 + @"message":message,
  124 + };
  125 + // 发送广播
  126 + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info];
  127 +}
  128 +
  129 +-(void)onStopService:(BTKServiceErrorCode)error {
  130 + // 维护状态标志
  131 + if (error == BTK_STOP_SERVICE_NO_ERROR) {
  132 + NSLog(@"轨迹服务停止成功");
  133 + self.isServiceStarted = FALSE;
  134 + } else {
  135 + NSLog(@"轨迹服务停止失败");
  136 + }
  137 + // 构造广播内容
  138 + NSString *title = nil;
  139 + NSString *message = nil;
  140 + switch (error) {
  141 + case BTK_STOP_SERVICE_NO_ERROR:
  142 + title = @"轨迹服务停止成功";
  143 + message = @"SDK已停止工作";
  144 + break;
  145 + case BTK_STOP_SERVICE_NOT_YET_STARTED_ERROR:
  146 + title = @"轨迹服务停止失败";
  147 + message = @"还没有开启服务,无法停止服务";
  148 + break;
  149 + case BTK_STOP_SERVICE_IN_PROGRESS:
  150 + title = @"轨迹服务停止失败";
  151 + message = @"正在停止服务,请稍后再试";
  152 + break;
  153 + default:
  154 + title = @"轨迹服务停止失败";
  155 + message = @"轨迹服务停止结果未知";
  156 + break;
  157 + }
  158 + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_STOP_SERVICE),
  159 + @"title":title,
  160 + @"message":message,
  161 + };
  162 + // 发送广播
  163 + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info];
  164 +}
  165 +
  166 +-(void)onStartGather:(BTKGatherErrorCode)error {
  167 + // 维护状态标志
  168 + if (error == BTK_START_GATHER_SUCCESS) {
  169 + NSLog(@"开始采集成功");
  170 + self.isGatherStarted = TRUE;
  171 + } else {
  172 + NSLog(@"开始采集失败");
  173 + }
  174 + // 构造广播内容
  175 + NSString *title = nil;
  176 + NSString *message = nil;
  177 + switch (error) {
  178 + case BTK_START_GATHER_SUCCESS:
  179 + title = @"开始采集成功";
  180 + message = @"开始采集成功";
  181 + break;
  182 + case BTK_GATHER_ALREADY_STARTED_ERROR:
  183 + title = @"开始采集失败";
  184 + message = @"已经在采集轨迹,请勿重复开始";
  185 + break;
  186 + case BTK_START_GATHER_BEFORE_START_SERVICE_ERROR:
  187 + title = @"开始采集失败";
  188 + message = @"开始采集必须在开始服务之后调用";
  189 + break;
  190 + case BTK_START_GATHER_LOCATION_SERVICE_OFF_ERROR:
  191 + title = @"开始采集失败";
  192 + message = @"没有开启系统定位服务";
  193 + break;
  194 + case BTK_START_GATHER_LOCATION_ALWAYS_USAGE_AUTH_ERROR:
  195 + title = @"开始采集失败";
  196 + message = @"没有开启后台定位权限";
  197 + break;
  198 + case BTK_START_GATHER_INTERNAL_ERROR:
  199 + title = @"开始采集失败";
  200 + message = @"SDK服务内部出现错误";
  201 + break;
  202 + default:
  203 + title = @"开始采集失败";
  204 + message = @"开始采集轨迹的结果未知";
  205 + break;
  206 + }
  207 + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_START_GATHER),
  208 + @"title":title,
  209 + @"message":message,
  210 + };
  211 + // 发送广播
  212 + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info];
  213 +}
  214 +
  215 +-(void)onStopGather:(BTKGatherErrorCode)error {
  216 + // 维护状态标志
  217 + if (error == BTK_STOP_GATHER_NO_ERROR) {
  218 + NSLog(@"停止采集成功");
  219 + self.isGatherStarted = FALSE;
  220 + } else {
  221 + NSLog(@"停止采集失败");
  222 + }
  223 + // 构造广播内容
  224 + NSString *title = nil;
  225 + NSString *message = nil;
  226 + switch (error) {
  227 + case BTK_STOP_GATHER_NO_ERROR:
  228 + title = @"停止采集成功";
  229 + message = @"SDK停止采集本设备的轨迹信息";
  230 + break;
  231 + case BTK_STOP_GATHER_NOT_YET_STARTED_ERROR:
  232 + title = @"停止采集失败";
  233 + message = @"还没有开始采集,无法停止";
  234 + break;
  235 + default:
  236 + title = @"停止采集失败";
  237 + message = @"停止采集轨迹的结果未知";
  238 + break;
  239 + }
  240 + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_STOP_GATHER),
  241 + @"title":title,
  242 + @"message":message,
  243 + };
  244 + // 发送广播
  245 + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info];
  246 +}
  247 +
  248 +-(void)onGetPushMessage:(BTKPushMessage *)message {
  249 + if (self.noAcceptFenceNotify) {
  250 + return;
  251 + }
  252 + NSLog(@">>>>>>>>>>>接收到BD通知<<<<<<<<<<<<<");
  253 + // 不是地理围栏的报警,不解析
  254 + if (message.type != 0x03 && message.type != 0x04) {
  255 + return;
  256 + }
  257 + BTKPushMessageFenceAlarmContent *content = (BTKPushMessageFenceAlarmContent *)message.content;
  258 + NSString *fenceID = [NSString stringWithFormat:@"%lu", (unsigned long)content.fenceID];
  259 + NSString *monitoredObject = [NSString stringWithFormat:@"「%@」", content.monitoredObject];
  260 + NSString *action = nil;
  261 + if (content.actionType == BTK_FENCE_MONITORED_OBJECT_ACTION_TYPE_ENTER) {
  262 + action = @"进入";
  263 + } else {
  264 + action = @"离开";
  265 + }
  266 + NSString *fenceType = nil;
  267 + if (message.type == 0x03) {
  268 + fenceType = @"服务端围栏";
  269 + } else {
  270 + fenceType = @"客户端围栏";
  271 + }
  272 + // 通过触发报警的轨迹点,解析出触发报警的时间
  273 + BTKFenceAlarmLocationPoint *currentPoint = content.currentPoint;
  274 + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  275 + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  276 + NSDate *alarmDate = [NSDate dateWithTimeIntervalSince1970:currentPoint.loctime];
  277 + NSString *alarmDateStr = [dateFormatter stringFromDate:alarmDate];
  278 +
  279 + NSString *pushMessage = [NSString stringWithFormat:@"终端 %@ 在 %@ %@ %@%@", monitoredObject, alarmDateStr, action, fenceType, fenceID];
  280 + NSDictionary *dict = @{
  281 + @"action":action,
  282 + @"fenceType":fenceType,
  283 + @"fenceID":fenceID
  284 + };
  285 + NSLog(@"推送消息: %@", pushMessage);
  286 + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceGetPushMessageNotification object:nil userInfo:@{@"message":dict}];
  287 +}
  288 +
  289 +-(void)setIsStartRecord:(BOOL)isStartRecord{
  290 + _isStartRecord = isStartRecord;
  291 + if (!isStartRecord) {
  292 + if (_pedometer) {
  293 + [_pedometer stopPedometerUpdates];
  294 + _pedometer = nil;
  295 + }
  296 + }
  297 +}
  298 +
  299 +- (void)recordStep:(NSDate *)date isUser:(BOOL)isU{
  300 + if (!self.isStartRecord) {
  301 + return;
  302 + }
  303 + _isUser = isU;
  304 + if (isU) {
  305 + CNRunExitModel *tempM = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid];
  306 + if (tempM.step.length > 0 && ![tempM.step isEqualToString:@"<null>"]) {
  307 + _lastStepCount = [tempM.step integerValue];
  308 + }else{
  309 + _lastStepCount = 0;
  310 + }
  311 + }else{
  312 + CNRunToolModel *model = [[CNTrackLoaclDataManager shareManager] getRunToolModel:CNUserShareModelUid];
  313 + if (model.step.length > 0 && ![model.step isEqualToString:@"<null>"]) {
  314 + _lastStepCount = [model.step integerValue];
  315 + }else{
  316 + _lastStepCount = 0;
  317 + }
  318 + }
  319 +
  320 +
  321 + //开始记录步数
  322 + if([CMPedometer isStepCountingAvailable]){
  323 + //开始计步
  324 + _pedometer = [CMPedometer new];
  325 + [_pedometer startPedometerUpdatesFromDate:date withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) {
  326 + [self performSelectorOnMainThread:@selector(updateStepTotal:) withObject:pedometerData waitUntilDone:YES];
  327 + }];
  328 + }
  329 +}
  330 +
  331 +//更新步数和公里数和配速
  332 +- (void)updateStepTotal:(CMPedometerData *)pedometerData{
  333 + if (_isUser) {
  334 + CNRunExitModel *tempM = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid];
  335 + tempM.step = [NSString stringWithFormat:@"%ld",([pedometerData.numberOfSteps integerValue] + _lastStepCount)];
  336 + [[CNTrackLoaclDataManager shareManager] updateExitModel:tempM];
  337 + if ([self.delegate respondsToSelector:@selector(currentPedometer:)]) {
  338 + [self.delegate currentPedometer:tempM];
  339 + }
  340 + }else{
  341 + CNRunToolModel *model = [[CNTrackLoaclDataManager shareManager] getRunToolModel:CNUserShareModelUid];
  342 + NSInteger step = [pedometerData.numberOfSteps integerValue] +_lastStepCount;
  343 + model.step = [NSString stringWithFormat:@"%ld",([pedometerData.numberOfSteps integerValue] + _lastStepCount)];
  344 + [[CNTrackLoaclDataManager shareManager] updateRunToolModel:model];
  345 + if ([self.delegate respondsToSelector:@selector(currentToolPedometer:)]) {
  346 + [self.delegate currentToolPedometer:step];
  347 + }
  348 + }
  349 +}
  350 +@end
... ...
CNLiveSportsModule/Classes/Tool/CNHistoryTrackParam.h 0 → 100644
  1 +//
  2 +// CNHistoryTrackParam.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +///历史轨迹参数model
  13 +@interface CNHistoryTrackParam : NSObject
  14 +@property (nonatomic, copy) NSString *entityName;
  15 +@property (nonatomic, assign) NSUInteger startTime;
  16 +@property (nonatomic, assign) NSUInteger endTime;
  17 +@property (nonatomic, assign) BOOL isProcessed;
  18 +@property (nonatomic, strong) BTKQueryTrackProcessOption *processOption;
  19 +@property (nonatomic, assign) BTKTrackProcessOptionSupplementMode supplementMode;
  20 +
  21 +@end
  22 +
  23 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/Tool/CNHistoryTrackParam.m 0 → 100644
  1 +//
  2 +// CNHistoryTrackParam.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNHistoryTrackParam.h"
  10 +
  11 +@implementation CNHistoryTrackParam
  12 +
  13 +@end
... ...
CNLiveSportsModule/Classes/Tool/CNHistoryTrackPoint.h 0 → 100644
  1 +//
  2 +// CNHistoryTrackPoint.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +
  13 +@interface CNHistoryTrackPoint : NSObject
  14 +@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
  15 +@property (nonatomic, assign) NSUInteger loctime;
  16 +@property (nonatomic, assign) NSUInteger direction;
  17 +@property (nonatomic, assign) double speed;
  18 +@end
  19 +
  20 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/Tool/CNHistoryTrackPoint.m 0 → 100644
  1 +//
  2 +// CNHistoryTrackPoint.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNHistoryTrackPoint.h"
  10 +
  11 +@implementation CNHistoryTrackPoint
  12 +
  13 +@end
... ...
CNLiveSportsModule/Classes/Tool/CNHistoryViewModel.h 0 → 100644
  1 +//
  2 +// CNHistoryViewModel.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import "CNHistoryTrackParam.h"
  11 +
  12 +NS_ASSUME_NONNULL_BEGIN
  13 +typedef void (^HistoryQueryCompletionHandler) (NSArray *points);
  14 +
  15 +@interface CNHistoryViewModel : NSObject<BTKTrackDelegate>
  16 +@property (nonatomic, copy) HistoryQueryCompletionHandler completionHandler;
  17 +
  18 +- (void)queryHistoryWithParam:(CNHistoryTrackParam *)param;
  19 +
  20 +@end
  21 +
  22 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/Tool/CNHistoryViewModel.m 0 → 100644
  1 +//
  2 +// CNHistoryViewModel.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/5.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNHistoryViewModel.h"
  10 +#import "CNHistoryTrackPoint.h"
  11 +
  12 +#define GLOBAL_QUEUE dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  13 +
  14 +@interface CNHistoryViewModel()
  15 +@property (nonatomic, strong) NSMutableArray *points;
  16 +@property (nonatomic, strong) dispatch_group_t historyDispatchGroup;
  17 +@property (nonatomic, assign) NSUInteger firstResponseSize;
  18 +@property (nonatomic, assign) NSUInteger total;
  19 +@property (nonatomic, strong) CNHistoryTrackParam *param;
  20 +@end
  21 +
  22 +// 轨迹查询每页的上限为5000条,但是若请求纠偏甚至绑路后的轨迹,比较耗时。综合考虑,我们选取每页1000条
  23 +static NSUInteger const kHistoryTrackPageSize = 1000;
  24 +
  25 +@implementation CNHistoryViewModel
  26 +-(instancetype)init {
  27 + self = [super init];
  28 + if (self) {
  29 + _points = [NSMutableArray array];
  30 + _historyDispatchGroup = dispatch_group_create();
  31 + }
  32 + return self;
  33 +}
  34 +
  35 +- (void)queryHistoryWithParam:(CNHistoryTrackParam *)param {
  36 + // 清空已有数据
  37 + [self.points removeAllObjects];
  38 +
  39 + self.param = param;
  40 + // 发送第一次请求,确定size和total,以决定后续是否还需要发请求,以及发送请求的pageSize和pageIndex
  41 + dispatch_async(dispatch_get_global_queue(0, 0), ^{
  42 + BTKQueryHistoryTrackRequest *request = [[BTKQueryHistoryTrackRequest alloc] initWithEntityName:param.entityName startTime:param.startTime endTime:param.endTime isProcessed:param.isProcessed processOption:param.processOption supplementMode:param.supplementMode outputCoordType:BTK_COORDTYPE_GCJ02 sortType:BTK_TRACK_SORT_TYPE_ASC pageIndex:1 pageSize:kHistoryTrackPageSize serviceID:BDMapServiceID tag:1];
  43 + [[BTKTrackAction sharedInstance] queryHistoryTrackWith:request delegate:self];
  44 + });
  45 +}
  46 +
  47 +-(void)onQueryHistoryTrack:(NSData *)response {
  48 +
  49 + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil];
  50 +
  51 +
  52 +// NSLog(@"%@",dict);
  53 +
  54 + if (nil == dict) {
  55 + NSLog(@"HISTORY TRACK查询格式转换出错");
  56 + if (self.completionHandler) {
  57 + self.completionHandler(@[]);
  58 + }
  59 + return;
  60 + }
  61 + if (0 != [dict[@"status"] intValue]) {
  62 + NSLog(@"HISTORY TRACK查询返回错误");
  63 + if (self.completionHandler) {
  64 + self.completionHandler(@[]);
  65 + }
  66 + return;
  67 + }
  68 + // 每次回调得到的历史轨迹点,都加到数组中
  69 + for (NSDictionary *point in dict[@"points"]) {
  70 + CNHistoryTrackPoint *p = [[CNHistoryTrackPoint alloc] init];
  71 + p.coordinate = CLLocationCoordinate2DMake([point[@"latitude"] doubleValue], [point[@"longitude"] doubleValue]);
  72 + p.loctime = [point[@"loc_time"] unsignedIntValue];
  73 + p.direction = [point[@"direction"] unsignedIntValue];
  74 + p.speed = [point[@"speed"] doubleValue];
  75 +
  76 +
  77 +
  78 + [self.points addObject:p];
  79 +
  80 + }
  81 +
  82 + // 对于第一次回调结果,根据total和size,确认还需要发送几次请求,并行发送这些请求
  83 + // 使用dispatch_group同步多次请求,当所有请求均收到响应后,points属性中存储的就是所有的轨迹点了
  84 + // 根据请求的是否是纠偏后的结果,处理方式稍有不同:
  85 + // 若是纠偏后的轨迹,直接使用direction字段即可,该方向是准确的;
  86 + // 若是原始的轨迹,direction字段可能不准,我们自己根据相邻点计算出方向。
  87 + // 最好都是请求纠偏后的轨迹,简化客户端处理步骤
  88 + if ([dict[@"tag"] unsignedIntValue] == 1) {
  89 + self.firstResponseSize = [dict[@"size"] unsignedIntValue];
  90 + self.total = [dict[@"total"] unsignedIntValue];
  91 + for (size_t i = 0; i < self.total / self.firstResponseSize; i++) {
  92 + dispatch_group_enter(self.historyDispatchGroup);
  93 +
  94 + BTKQueryHistoryTrackRequest *request = [[BTKQueryHistoryTrackRequest alloc] initWithEntityName:self.param.entityName startTime:self.param.startTime endTime:self.param.endTime isProcessed:self.param.isProcessed processOption:self.param.processOption supplementMode:self.param.supplementMode outputCoordType:BTK_COORDTYPE_BD09LL sortType:BTK_TRACK_SORT_TYPE_ASC pageIndex:(2 + i) pageSize:kHistoryTrackPageSize serviceID:BDMapServiceID tag:(2 + i)];
  95 + [[BTKTrackAction sharedInstance] queryHistoryTrackWith:request delegate:self];
  96 + }
  97 + dispatch_group_notify(self.historyDispatchGroup, GLOBAL_QUEUE, ^{
  98 + // 将所有查询到的轨迹点,按照loc_time升序排列,注意是稳定排序。
  99 + // 因为绑路时会补充道路形状点,其loc_time与原始轨迹点一样,相同的loc_time在排序后必须保持原始的顺序,否则direction不准。
  100 + [self.points sortWithOptions:NSSortStable usingComparator:^NSComparisonResult(CNHistoryTrackPoint * _Nonnull obj1, CNHistoryTrackPoint * _Nonnull obj2) {
  101 + if (obj1.loctime < obj2.loctime) {
  102 + return NSOrderedAscending;
  103 + } else if (obj1.loctime > obj2.loctime) {
  104 + return NSOrderedDescending;
  105 + } else {
  106 + return NSOrderedSame;
  107 + }
  108 + }];
  109 + // 如果我们请求的是原始轨迹,最好自己计算每个轨迹点的方向,因为此时返回的direction字段可能不准确。
  110 + if (FALSE == self.param.isProcessed) {
  111 + // 根据相邻两点之间的坐标,计算方向
  112 + for (size_t i = 0; i < self.points.count - 1; i++) {
  113 + CNHistoryTrackPoint *point1 = (CNHistoryTrackPoint *)self.points[i];
  114 + CNHistoryTrackPoint *point2 = (CNHistoryTrackPoint *)self.points[i + 1];
  115 + double lat1 = [self getRadianFromDegree:point1.coordinate.latitude];
  116 + double lon1 = [self getRadianFromDegree:point1.coordinate.longitude];
  117 + double lat2 = [self getRadianFromDegree:point2.coordinate.latitude];
  118 + double lon2 = [self getRadianFromDegree:point2.coordinate.longitude];
  119 + double deltaOfLon = lon2 - lon1;
  120 + double y = sin(deltaOfLon) * cos(lat2);
  121 + double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaOfLon);
  122 + double radianDirection = atan2(y, x);
  123 + double degreeDirection = [self getDegreeFromRadian:radianDirection];
  124 + ((CNHistoryTrackPoint *)self.points[i]).direction = [self mapGeometryDirectionToGPSDirection:degreeDirection];
  125 + }
  126 + }
  127 + if (self.completionHandler) {
  128 + self.completionHandler(self.points);
  129 + }
  130 + });
  131 + } else {
  132 + dispatch_group_leave(self.historyDispatchGroup);
  133 + }
  134 +}
  135 +
  136 +- (double)getRadianFromDegree:(double)degree {
  137 + return degree * M_PI / 180.0;
  138 +}
  139 +
  140 +- (double)getDegreeFromRadian:(double)radian {
  141 + return radian * 180.0 / M_PI;
  142 +}
  143 +
  144 +- (double)mapGeometryDirectionToGPSDirection:(double)geometryDirection {
  145 + double gpsDirection = geometryDirection;
  146 + if (geometryDirection < 0) {
  147 + gpsDirection = geometryDirection + 360.0;
  148 + }
  149 + return gpsDirection;
  150 +}
  151 +@end
... ...
CNLiveSportsModule/Classes/Tool/CNLinePointNode.h 0 → 100644
  1 +//
  2 +// CNLinePointNode.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/15.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +NS_ASSUME_NONNULL_BEGIN
  12 +
  13 +@interface CNLinePointNode : NSObject
  14 +@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
  15 +
  16 +@end
  17 +
  18 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/Tool/CNLinePointNode.m 0 → 100644
  1 +//
  2 +// CNLinePointNode.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/15.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNLinePointNode.h"
  10 +
  11 +@implementation CNLinePointNode
  12 +
  13 +@end
... ...
CNLiveSportsModule/Classes/View/CNMapView.h 0 → 100644
  1 +//
  2 +// CNMapView.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/4.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件
  11 +#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件
  12 +#import <BMKLocationkit/BMKLocationComponent.h>//定位功能
  13 +
  14 +@protocol CNMapViewDelegate <NSObject>
  15 +
  16 +- (void)quiteVC;
  17 +
  18 +@end
  19 +NS_ASSUME_NONNULL_BEGIN
  20 +
  21 +@interface CNMapView : UIView
  22 +
  23 +@property (nonatomic, weak) id<CNMapViewDelegate> delegate;
  24 +@property (nonatomic, strong) BMKMapView *mapView; //当前界面的mapView
  25 +@property (nonatomic, assign) BOOL noNeedLocation;
  26 +@property (nonatomic, assign) BOOL hiddenSubView;
  27 +@property (nonatomic, assign) float tempHeight;
  28 +@property (nonatomic, copy) NSArray *dataJsonARR;
  29 +@property (nonatomic, strong) BMKUserLocation *userLocation; //当前位置对象
  30 +
  31 +//定位
  32 +@property (nonatomic, strong) BMKLocationManager *locationManager;//定位管理
  33 +
  34 +@property (nonatomic, assign) float originH;
  35 +- (void)drawLine:(BOOL)isStop fArr:(NSArray *)arr1 lArr:(NSArray *)arr2;
  36 +@end
  37 +
  38 +NS_ASSUME_NONNULL_END
... ...
CNLiveSportsModule/Classes/View/CNMapView.m 0 → 100644
  1 +//
  2 +// CNMapView.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/4.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNMapView.h"
  10 +#import "CNHistoryTrackPoint.h"
  11 +#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>
  12 +
  13 +@interface BMKSportNode : NSObject
  14 +@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
  15 +@property (nonatomic, assign) CGFloat angle;
  16 +@property (nonatomic, assign) CGFloat distance;
  17 +@property (nonatomic, assign) CGFloat speed;
  18 +@end
  19 +@implementation BMKSportNode
  20 +
  21 +@end
  22 +
  23 +@interface CNMapView()
  24 +<
  25 +BMKMapViewDelegate,
  26 +BMKLocationManagerDelegate
  27 +>
  28 +@property (nonatomic, strong) NSMutableArray *sportNodes;
  29 +@property (nonatomic, assign) NSUInteger sportNodeNum;
  30 +@property (nonatomic, strong) BMKPolyline *pathPolyLine; //当前界面的多边形(运动轨迹)
  31 +
  32 +@property (nonatomic, strong) BMKPointAnnotation *startAnnotation; //当前界面的标注
  33 +@property (nonatomic, strong) BMKPointAnnotation *endAnnotation; //当前界面的标注
  34 +
  35 +@property (nonatomic, assign) CLLocationCoordinate2D mineLocationCoordinate;
  36 +@property (nonatomic, assign) BOOL isLocation;//定位是否成功
  37 +
  38 +@property (nonatomic, strong) UIButton *resetBtn; //重新定位按钮
  39 +@property (nonatomic, strong) NSMutableArray *minePoints;
  40 +@property (nonatomic, strong) BMKPolyline *fminePolyLine;
  41 +@property (nonatomic, strong) BMKPolyline *lminePolyLine;
  42 +
  43 +@end
  44 +@implementation CNMapView
  45 +
  46 +-(instancetype)initWithFrame:(CGRect)frame{
  47 + self = [super initWithFrame:frame];
  48 + if (self) {
  49 + _sportNodes = [NSMutableArray array];
  50 + _minePoints = [NSMutableArray array];
  51 + [self addSubview:self.mapView];
  52 + CGPoint p = self.mapView.compassPosition;
  53 + p.y += 100;
  54 + self.mapView.compassPosition = p;
  55 + [self.mapView addSubview:self.resetBtn];
  56 + [self.resetBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  57 + make.left.equalTo(self.mapView.mas_left).offset(15);
  58 + make.bottom.equalTo(self.mapView.mas_bottom).offset(-50);
  59 + }];
  60 + }
  61 + return self;
  62 +}
  63 +
  64 +-(void)setDataJsonARR:(NSArray *)dataJsonARR{
  65 + _dataJsonARR = dataJsonARR;
  66 + [_sportNodes removeAllObjects];
  67 + for (CNHistoryTrackPoint *point in dataJsonARR) {
  68 + BMKSportNode *sportNode = [[BMKSportNode alloc] init];
  69 + sportNode.coordinate = point.coordinate;//CLLocationCoordinate2DMake([dictionary[@"lat"] doubleValue], [dictionary[@"lon"] doubleValue]);
  70 + [_sportNodes addObject:sportNode];
  71 + }
  72 + _sportNodeNum = _sportNodes.count;
  73 + [self start];//添加路线
  74 +}
  75 +
  76 +-(void)drawLine:(BOOL)isStop fArr:(NSArray *)arr1 lArr:(NSArray *)arr2{
  77 +// for (CNHistoryTrackPoint *point in points) {
  78 + [_minePoints addObjectsFromArray:arr1];
  79 + [_minePoints addObjectsFromArray:arr2];
  80 + if (isStop) {
  81 + CLLocationCoordinate2D paths1[arr1.count];
  82 + for (NSUInteger i = 0; i < arr1.count; i ++) {
  83 + CNHistoryTrackPoint *point = arr1[i];
  84 + paths1[i] = point.coordinate;
  85 + }
  86 + _fminePolyLine = [BMKPolyline polylineWithCoordinates:paths1 count:arr1.count];
  87 + //初始化标注类BMKPointAnnotation的实例
  88 + _startAnnotation = [[BMKPointAnnotation alloc] init];
  89 + //设置标注的经纬度坐标
  90 + _startAnnotation.coordinate = paths1[0];
  91 + // [self.mapView setCenterCoordinate:paths[0] animated:YES];
  92 + //设置标注的标题
  93 + _startAnnotation.title = @"起点";
  94 + //初始化标注类BMKPointAnnotation的实例
  95 + _endAnnotation = [[BMKPointAnnotation alloc] init];
  96 + if (arr2.count > 0) {
  97 + CLLocationCoordinate2D paths2[arr2.count];
  98 + for (NSUInteger i = 0; i < arr2.count; i ++) {
  99 + CNHistoryTrackPoint *point = arr2[i];
  100 + paths2[i] = point.coordinate;
  101 + }
  102 + _lminePolyLine = [BMKPolyline polylineWithCoordinates:paths2 count:arr2.count];
  103 + //设置标注的经纬度坐标
  104 + _endAnnotation.coordinate = paths2[arr2.count-1];
  105 + //设置标注的标题
  106 + _endAnnotation.title = @"终点";
  107 +
  108 + }else{
  109 + //设置标注的经纬度坐标
  110 + _endAnnotation.coordinate = paths1[arr1.count-1];
  111 + //设置标注的标题
  112 + _endAnnotation.title = @"终点";
  113 + }
  114 +
  115 + dispatch_async(dispatch_get_main_queue(), ^{
  116 +
  117 +
  118 + [self->_mapView addOverlay:self->_fminePolyLine];
  119 + [self->_mapView addOverlay:self->_lminePolyLine];
  120 + //将标注添加到当前地图View中
  121 + [self->_mapView addAnnotation:self->_startAnnotation];
  122 + //将标注添加到当前地图View中
  123 + [self->_mapView addAnnotation:self->_endAnnotation];
  124 + [self mapViewFitPoints:self.minePoints];
  125 + });
  126 + }
  127 +}
  128 +
  129 +#pragma mark - private
  130 +- (void)start{
  131 + CLLocationCoordinate2D paths[_sportNodeNum];
  132 + for (NSUInteger i = 0; i < _sportNodeNum; i ++) {
  133 + BMKSportNode *node = _sportNodes[i];
  134 + paths[i] = node.coordinate;
  135 + }
  136 + _pathPolyLine = [BMKPolyline polylineWithCoordinates:paths count:_sportNodeNum];
  137 + //初始化标注类BMKPointAnnotation的实例
  138 + _startAnnotation = [[BMKPointAnnotation alloc] init];
  139 + //设置标注的经纬度坐标
  140 + _startAnnotation.coordinate = paths[0];
  141 +// [self.mapView setCenterCoordinate:paths[0] animated:YES];
  142 + //设置标注的标题
  143 + _startAnnotation.title = @"起点";
  144 + //初始化标注类BMKPointAnnotation的实例
  145 + _endAnnotation = [[BMKPointAnnotation alloc] init];
  146 + //设置标注的经纬度坐标
  147 + _endAnnotation.coordinate = paths[_sportNodeNum-1];
  148 + //设置标注的标题
  149 + _endAnnotation.title = @"终点";
  150 +
  151 + dispatch_async(dispatch_get_main_queue(), ^{
  152 + /**
  153 + 向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay:
  154 + 方法来生成标注对应的View
  155 +
  156 + @param overlay 要添加的overlay
  157 + */
  158 + [self.mapView removeOverlays:self.mapView.overlays];
  159 + [self.mapView removeAnnotations:self.mapView.annotations];
  160 + [self->_mapView addOverlay:self->_pathPolyLine];
  161 + //将标注添加到当前地图View中
  162 + [self->_mapView addAnnotation:self->_startAnnotation];
  163 + //将标注添加到当前地图View中
  164 + [self->_mapView addAnnotation:self->_endAnnotation];
  165 + [self mapViewFitPolyLine:self->_pathPolyLine];
  166 + });
  167 +}
  168 +
  169 +- (void)mapViewFitPoints:(NSArray *) points {
  170 + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY;
  171 + if (points.count < 1) {
  172 + return;
  173 + }
  174 + CNHistoryTrackPoint *p = points[0];
  175 + CLLocationCoordinate2D coor = p.coordinate;
  176 + BMKMapPoint pt = BMKMapPointForCoordinate(coor);
  177 + // BMKMapPoint pt = polyLine.points[0];
  178 + // 左上角顶点
  179 + leftTopX = pt.x;
  180 + leftTopY = pt.y;
  181 + // 右下角顶点
  182 + rightBottomX = pt.x;
  183 + rightBottomY = pt.y;
  184 + for (int i = 1; i < points.count; i++) {
  185 + CNHistoryTrackPoint *p = points[i];
  186 + CLLocationCoordinate2D coor = p.coordinate;
  187 + BMKMapPoint pt = BMKMapPointForCoordinate(coor);
  188 + // BMKMapPoint pt = polyLine.points[i];
  189 + leftTopX = pt.x < leftTopX ? pt.x : leftTopX;
  190 + leftTopY = pt.y < leftTopY ? pt.y : leftTopY;
  191 + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX;
  192 + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY;
  193 + }
  194 + BMKMapRect rect;
  195 + rect.origin = BMKMapPointMake(leftTopX, leftTopY);
  196 + rect.size = BMKMapSizeMake(rightBottomX - leftTopX, rightBottomY - leftTopY);
  197 + UIEdgeInsets padding = UIEdgeInsetsMake(100 , 50, 200, 50);
  198 + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
  199 +}
  200 +
  201 +
  202 +//根据polyline设置地图范围
  203 +- (void)mapViewFitPolyLine:(BMKPolyline *) polyLine {
  204 + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY;
  205 + if (polyLine.pointCount < 1) {
  206 + return;
  207 + }
  208 + BMKMapPoint pt = polyLine.points[0];
  209 + // 左上角顶点
  210 + leftTopX = pt.x;
  211 + leftTopY = pt.y;
  212 + // 右下角顶点
  213 + rightBottomX = pt.x;
  214 + rightBottomY = pt.y;
  215 + for (int i = 1; i < polyLine.pointCount; i++) {
  216 + BMKMapPoint pt = polyLine.points[i];
  217 + leftTopX = pt.x < leftTopX ? pt.x : leftTopX;
  218 + leftTopY = pt.y < leftTopY ? pt.y : leftTopY;
  219 + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX;
  220 + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY;
  221 + }
  222 + BMKMapRect rect;
  223 + rect.origin = BMKMapPointMake(leftTopX, leftTopY);
  224 + rect.size = BMKMapSizeMake(rightBottomX - leftTopX, rightBottomY - leftTopY);
  225 + UIEdgeInsets padding = UIEdgeInsetsMake(kNavigationBarHeight+50 , 50, self.originH+50, 50);
  226 + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
  227 +
  228 +}
  229 +
  230 +-(void)setTempHeight:(float)tempHeight{
  231 + _tempHeight = tempHeight;
  232 + if (self.pathPolyLine) {
  233 +// [self mapViewFitPolyLine:self.pathPolyLine];
  234 + [self mapViewFitPolyLine:self.pathPolyLine height:tempHeight];
  235 + }
  236 +}
  237 +
  238 +-(void)setHiddenSubView:(BOOL)hiddenSubView{
  239 + _hiddenSubView = hiddenSubView;
  240 + if (hiddenSubView) {
  241 + self.resetBtn.hidden = YES;
  242 + }
  243 +}
  244 +
  245 +//根据polyline设置地图范围
  246 +- (void)mapViewFitPolyLine:(BMKPolyline *) polyLine height:(float)height{
  247 + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY;
  248 + if (polyLine.pointCount < 1) {
  249 + return;
  250 + }
  251 + BMKMapPoint pt = polyLine.points[0];
  252 + // 左上角顶点
  253 + leftTopX = pt.x;
  254 + leftTopY = pt.y;
  255 + // 右下角顶点
  256 + rightBottomX = pt.x;
  257 + rightBottomY = pt.y;
  258 + for (int i = 1; i < polyLine.pointCount; i++) {
  259 + BMKMapPoint pt = polyLine.points[i];
  260 + leftTopX = pt.x < leftTopX ? pt.x : leftTopX;
  261 + leftTopY = pt.y < leftTopY ? pt.y : leftTopY;
  262 + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX;
  263 + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY;
  264 + }
  265 + BMKMapRect rect;
  266 + rect.origin = BMKMapPointMake(leftTopX, leftTopY);
  267 + rect.size = BMKMapSizeMake(rightBottomX - leftTopX,rightBottomY - leftTopY);
  268 + UIEdgeInsets padding = UIEdgeInsetsMake(kNavigationBarHeight+20, 50, SCREEN_HEIGHT-height+20, 50);
  269 + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
  270 +}
  271 +
  272 +-(void)setNoNeedLocation:(BOOL)noNeedLocation{
  273 + _noNeedLocation = noNeedLocation;
  274 + @try {
  275 + [self.locationManager stopUpdatingHeading];
  276 + [self.locationManager stopUpdatingLocation];
  277 + } @catch (NSException *exception) {
  278 + NSLog(@"CNMapView.m 1111111111崩溃了");
  279 + }
  280 +}
  281 +#pragma mark -- 定位delegate
  282 +//权限改变
  283 +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
  284 + if (status == kCLAuthorizationStatusDenied) {
  285 + MJWeakSelf
  286 + QMUIAlertAction *action1 = [QMUIAlertAction actionWithTitle:@"确定" style:QMUIAlertActionStyleCancel handler:^(__kindof QMUIAlertController *aAlertController, QMUIAlertAction *action) {
  287 + if ([weakSelf.delegate respondsToSelector:@selector(quiteVC)]) {
  288 + [weakSelf.delegate quiteVC];
  289 + }
  290 + }];
  291 + QMUIAlertController *alertController = [QMUIAlertController alertControllerWithTitle:@"" message:@"无法获取你的位置信息。\n 请到手机系统的[隐私]->[定位服务]中打开定位服务,并允许网家家使用定位服务" preferredStyle:QMUIAlertControllerStyleAlert];
  292 + [alertController addAction:action1];
  293 + [alertController showWithAnimated:YES];
  294 + }
  295 +}
  296 +
  297 +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager doRequestAlwaysAuthorization:(CLLocationManager * _Nonnull)locationManager{
  298 + [locationManager requestAlwaysAuthorization];
  299 +}
  300 +
  301 +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error {
  302 + NSLog(@"定位失败");
  303 + self.isLocation = NO;
  304 +}
  305 +// 定位SDK中,方向变更的回调
  306 +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateHeading:(CLHeading * _Nullable)heading{
  307 + if (!heading) {
  308 + return;
  309 + }
  310 + self.userLocation.heading = heading;
  311 + [self.mapView updateLocationData:self.userLocation];
  312 +}
  313 +
  314 +// 定位SDK中,位置变更的回调
  315 +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
  316 + if (error) {
  317 + self.isLocation = NO;
  318 + NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
  319 + // [QMUITips showInfo:@"位置更新失败" inView:self.view hideAfterDelay:0.5];
  320 + }else{
  321 + self.mineLocationCoordinate = location.location.coordinate;
  322 + self.isLocation = YES;
  323 + }
  324 + if (!location) {
  325 + return;
  326 + }
  327 + // [QMUITips showInfo:@"位置更新" inView:self.view hideAfterDelay:0.5];
  328 + if (self.noNeedLocation) {
  329 + return;
  330 + }
  331 + self.userLocation.location = location.location;
  332 + [self.mapView updateLocationData:self.userLocation];//动态更新我的位置数据
  333 +}
  334 +
  335 +#pragma mark - 地图Delegate
  336 +- (void)mapViewDidFinishLoading:(BMKMapView *)mapView {
  337 +// [self start];//添加路线
  338 + if (self.noNeedLocation) {
  339 + return;
  340 + }
  341 + [self.locationManager startUpdatingLocation];
  342 + [self.locationManager startUpdatingHeading];
  343 +}
  344 +/**
  345 + 根据overlay生成对应的BMKOverlayView
  346 +
  347 + @param mapView 地图View
  348 + @param overlay 指定的overlay
  349 + @return 生成的覆盖物View
  350 + */
  351 +- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
  352 + if ([overlay isKindOfClass:[BMKPolyline class]]) {
  353 + BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:overlay];
  354 + polylineView.lineWidth = 2;
  355 + polylineView.strokeColor = [RGBOF(0x5BC4A4) colorWithAlphaComponent:1];
  356 + return polylineView;
  357 + }
  358 + return nil;
  359 +}
  360 +/**
  361 + 根据anntation生成对应的annotationView
  362 +
  363 + @param mapView 地图View
  364 + @param annotation 指定的标注
  365 + @return 生成的标注View
  366 + */
  367 +
  368 +- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
  369 + if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {
  370 +
  371 + NSString *AnnotationViewID = @"baiduAnnotation";
  372 + BMKAnnotationView *annotationView = nil;
  373 + if (annotationView == nil) {
  374 + annotationView = [[BMKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
  375 + }
  376 + UIImageView *bgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 68, 68)];
  377 + bgView.image = [UIImage imageNamed:@"map-fw"];
  378 + UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 30, 38)];
  379 + if (annotation == _startAnnotation) {
  380 + imageView.image = [UIImage imageNamed:@"map_location-start"];
  381 + } else if (annotation == _endAnnotation){
  382 + imageView.image = [UIImage imageNamed:@"map_location-finish"];
  383 + }
  384 + UIView *underView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 15, 7)];
  385 + underView.backgroundColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:0.5];
  386 + underView.centerX = imageView.centerX+2;
  387 + underView.centerY = imageView.centerY+38/2-3;
  388 + underView.layer.cornerRadius = 6;
  389 + underView.layer.masksToBounds = YES;
  390 + bgView.centerX = underView.centerX;
  391 + bgView.centerY = underView.centerY - 8;
  392 + [annotationView addSubview:bgView];
  393 + [annotationView addSubview:underView];
  394 + [annotationView addSubview:imageView];
  395 + annotationView.frame = CGRectMake(0, -38/2+5, 30, 38);
  396 + annotationView.enabled3D = YES;
  397 + annotationView.hidePaopaoWhenSingleTapOnMap = YES;
  398 + annotationView.hidePaopaoWhenDoubleTapOnMap = YES;
  399 + annotationView.hidePaopaoWhenTwoFingersTapOnMap = YES;
  400 + annotationView.hidePaopaoWhenSelectOthers = YES;
  401 + return annotationView;
  402 + }
  403 + return nil;
  404 +}
  405 +
  406 +#pragma mark - lazy
  407 +-(BMKMapView *)mapView{
  408 + if (!_mapView) {
  409 + _mapView = [[BMKMapView alloc] initWithFrame:self.frame];
  410 + _mapView.delegate = self;
  411 + //设置地图比例尺级别
  412 + _mapView.zoomLevel = 17;
  413 + _mapView.showMapScaleBar = NO;//显示比例尺
  414 + _mapView.showsUserLocation = YES;//显示定位图层
  415 + // //显示我的位置,我的位置图标和地图都不会旋转
  416 + _mapView.userTrackingMode = BMKUserTrackingModeHeading;
  417 + // //更换我的位置图标
  418 + // // self.mapView是BMKMapView对象
  419 + BMKLocationViewDisplayParam *param = [[BMKLocationViewDisplayParam alloc] init];
  420 + // //定位图标名称,需要将该图片放到 mapapi.bundle/images 目录下
  421 + // // param.locationViewImgName = @"icon_nav_bus";
  422 + // //用户自定义定位图标,V4.2.1以后支持
  423 + param.locationViewImage = [UIImage imageNamed:@"map_dw"];
  424 + // //根据配置参数更新定位图层样式
  425 + //设置显示精度圈,默认YES
  426 + param.isAccuracyCircleShow = NO;
  427 + //精度圈 边框颜色
  428 +// param.accuracyCircleStrokeColor = kWhiteColor;
  429 +// //精度圈 填充颜色
  430 +// param.accuracyCircleFillColor = kWhiteColor;
  431 + [_mapView updateLocationViewWithParam:param];
  432 +
  433 + }
  434 + return _mapView;
  435 +}
  436 +-(BMKLocationManager *)locationManager{
  437 + if (!_locationManager) {
  438 + //初始化实例
  439 + _locationManager = [[BMKLocationManager alloc] init];
  440 + //设置delegate
  441 + _locationManager.delegate = self;
  442 + //设置返回位置的坐标系类型
  443 + _locationManager.coordinateType = BMKLocationCoordinateTypeGCJ02;
  444 + //设置距离过滤参数
  445 + _locationManager.distanceFilter = 1.0f;
  446 + //设置预期精度参数
  447 + _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  448 + //设置应用位置类型
  449 + _locationManager.activityType = CLActivityTypeFitness;
  450 + //设置是否自动停止位置更新
  451 + _locationManager.pausesLocationUpdatesAutomatically = NO;
  452 + //设置是否允许后台定位
  453 + _locationManager.allowsBackgroundLocationUpdates = YES;
  454 + //设置位置获取超时时间
  455 +// _locationManager.locationTimeout = 10;
  456 + //设置获取地址信息超时时间
  457 + // _locationManager.reGeocodeTimeout = 3;
  458 + }
  459 + return _locationManager;
  460 +}
  461 +
  462 +-(BMKUserLocation *)userLocation{
  463 + if (!_userLocation) {
  464 + _userLocation = [[BMKUserLocation alloc] init];
  465 + }
  466 + return _userLocation;
  467 +}
  468 +
  469 +-(UIButton *)resetBtn{
  470 + if (!_resetBtn) {
  471 + _resetBtn = [[UIButton alloc] init];
  472 + [_resetBtn setImage:[UIImage imageNamed:@"where_select"] forState:UIControlStateNormal];
  473 + [_resetBtn addTarget:self action:@selector(clickRestBtn) forControlEvents:UIControlEventTouchUpInside];
  474 + }
  475 + return _resetBtn;
  476 +}
  477 +
  478 +- (void)clickRestBtn{
  479 + [self resetPosition];
  480 +}
  481 +- (void)resetPosition{
  482 + if (self.isLocation) {
  483 + [self.mapView setCenterCoordinate:self.userLocation.location.coordinate animated:YES];
  484 + }else{//没自动定位到位置,需要手动定位
  485 + @try {
  486 + [self.locationManager stopUpdatingLocation];
  487 + } @catch (NSException *exception) {
  488 + NSLog(@"CNMapView.m 崩溃了");
  489 + }
  490 +
  491 + [QMUITips showLoadingInView:self];
  492 + MJWeakSelf
  493 + [self.locationManager requestLocationWithReGeocode:NO withNetworkState:YES completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) {
  494 + [QMUITips hideAllTips];
  495 + BOOL isError = false;
  496 + if (error)
  497 + {
  498 + isError = YES;
  499 + // NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
  500 + }
  501 + if (location) {//得到定位信息,添加annotation
  502 + if (location.location) {
  503 + NSLog(@"LOC = %@",location.location);
  504 + //把地图放到位置中心点
  505 + weakSelf.mineLocationCoordinate = location.location.coordinate;
  506 + [weakSelf.mapView setCenterCoordinate:weakSelf.mineLocationCoordinate animated:YES];
  507 + //实现该方法,否则定位图标不出现
  508 + weakSelf.userLocation.location = location.location;
  509 + [weakSelf.mapView updateLocationData:weakSelf.userLocation];
  510 + }
  511 + }else{
  512 + isError = YES;
  513 + }
  514 + if ([error.localizedDescription containsString:@"网络"] && [error.localizedDescription containsString:@"失败"]) {
  515 + [QMUITips showInfo:@"网络错误,请检查网络。" inView:self.mapView hideAfterDelay:1.5];
  516 + }else{
  517 + if (isError) {
  518 + [QMUITips showInfo:@"无法获取您的位置信息。" inView:self.mapView hideAfterDelay:1.5];
  519 + }
  520 + }
  521 + if (self.noNeedLocation) {
  522 + return;
  523 + }
  524 + [self.locationManager startUpdatingLocation];
  525 + [self.locationManager startUpdatingHeading];
  526 + }];
  527 +
  528 + }
  529 +}
  530 +@end
... ...
CNLiveSportsModule/Classes/View/CNReUpLoadTableViewCell.h 0 → 100644
  1 +//
  2 +// CNReUpLoadTableViewCell.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/27.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +@class CNTrackUploadFailModel;
  11 +#define kCNReUpLoadTableViewCell @"CNReUpLoadTableViewCell"
  12 +@class CNReUpLoadTableViewCell;
  13 +@protocol CNReUpLoadTableViewCellDelegate <NSObject>
  14 +- (void)needToReloadTable:(CNReUpLoadTableViewCell *)cell index:(NSInteger)index;
  15 +
  16 +@end
  17 +@interface CNReUpLoadTableViewCell : UITableViewCell
  18 +@property (nonatomic, weak) id <CNReUpLoadTableViewCellDelegate> delegate;
  19 +@property (nonatomic, assign) NSInteger index;
  20 +@property (nonatomic, strong) CNTrackUploadFailModel *model;
  21 +@property (nonatomic, copy) void(^deleteClickBlock)(NSInteger index);
  22 +
  23 +@end
... ...
CNLiveSportsModule/Classes/View/CNReUpLoadTableViewCell.m 0 → 100644
  1 +//
  2 +// CNReUpLoadTableViewCell.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/27.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNReUpLoadTableViewCell.h"
  10 +#import "CNTrackUploadFailModel.h"
  11 +#import "UIColor+CNLiveExtension.h"
  12 +#import "CNLiveSportsDetailModel.h"
  13 +#import "CNHistoryTrackParam.h"
  14 +#import "CNHistoryViewModel.h"
  15 +#import "CNHistoryTrackPoint.h"
  16 +#import "CNTrackLoaclDataManager.h"
  17 +
  18 +@interface CNReUpLoadTableViewCell ()
  19 +
  20 +@property (nonatomic, strong) UIView *bgView;
  21 +@property (nonatomic, strong) UILabel *dateLabel;
  22 +@property (nonatomic, strong) UILabel *timeLabel;
  23 +@property (nonatomic, strong) UILabel *addressLabel;
  24 +@property (nonatomic, strong) UILabel *distanceLabel;
  25 +
  26 +@property (nonatomic, strong) QMUIButton *durationBtn;
  27 +@property (nonatomic, strong) QMUIButton *speedBtn;
  28 +@property (nonatomic, strong) QMUIButton *stepNumberBtn;
  29 +@property (nonatomic, strong) UIView *line;
  30 +@property (nonatomic, strong) QMUIButton *reUploadBtn;
  31 +@property (nonatomic, strong) QMUIButton *deleteBtn;
  32 +
  33 +@property (nonatomic, strong) UILabel *desLabel;
  34 +
  35 +@end
  36 +
  37 +@implementation CNReUpLoadTableViewCell
  38 +
  39 +static const NSInteger margin = 20;
  40 +
  41 +#pragma mark - Init
  42 +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
  43 + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  44 + if (self) {
  45 + self.contentView.backgroundColor = [UIColor colorWithRed:248/255.0 green:248/255.0 blue:248/255.0 alpha:1.0];
  46 + [self setupUI];
  47 + }
  48 + return self;
  49 +}
  50 +
  51 +#pragma mark - UI
  52 +- (void)setupUI{
  53 + [self.contentView addSubview:self.bgView];
  54 + [self.contentView addSubview:self.line];
  55 +
  56 + [self.contentView addSubview:self.deleteBtn];
  57 + [self.contentView addSubview:self.reUploadBtn];
  58 + [self.contentView addSubview:self.dateLabel];
  59 + [self.contentView addSubview:self.timeLabel];
  60 + [self.contentView addSubview:self.desLabel];
  61 +
  62 + [self.contentView addSubview:self.addressLabel];
  63 + [self.contentView addSubview:self.distanceLabel];
  64 +
  65 + [self.contentView addSubview:self.durationBtn];
  66 + [self.contentView addSubview:self.speedBtn];
  67 + [self.contentView addSubview:self.stepNumberBtn];
  68 +
  69 +
  70 +}
  71 +
  72 +- (void)layoutSubviews{
  73 + [super layoutSubviews];
  74 + [_bgView mas_makeConstraints:^(MASConstraintMaker *make) {
  75 + make.left.top.equalTo(self).offset(10);
  76 + make.right.equalTo(self.mas_right).offset(-10);
  77 + make.bottom.equalTo(self.mas_bottom).offset(-10);
  78 + }];
  79 + _bgView.layer.cornerRadius = 5;
  80 + _bgView.layer.masksToBounds = YES;
  81 +
  82 +
  83 + [_deleteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  84 + make.right.equalTo(self.mas_right).offset(-margin);
  85 + make.bottom.equalTo(self.mas_bottom).offset(-margin);
  86 + make.size.mas_equalTo(CGSizeMake(65, 26));
  87 + }];
  88 + _deleteBtn.layer.cornerRadius = 26/2;
  89 + _deleteBtn.layer.masksToBounds = YES;
  90 + _deleteBtn.layer.borderWidth = 1;
  91 + _deleteBtn.layer.borderColor = [UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0].CGColor;
  92 +
  93 + [_reUploadBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  94 + make.right.equalTo(self.deleteBtn.mas_left).offset(-margin);
  95 + make.bottom.equalTo(self.mas_bottom).offset(-margin);
  96 + make.size.mas_equalTo(CGSizeMake(75, 26));
  97 + }];
  98 + _reUploadBtn.layer.cornerRadius = 26/2;
  99 + _reUploadBtn.layer.masksToBounds = YES;
  100 + _reUploadBtn.layer.borderWidth = 1;
  101 + _reUploadBtn.layer.borderColor = [UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0].CGColor;
  102 +
  103 +
  104 +
  105 + [_line mas_makeConstraints:^(MASConstraintMaker *make) {
  106 + make.bottom.equalTo(self.reUploadBtn.mas_top).with.offset(-margin/2);
  107 + make.left.equalTo(self.contentView.mas_left).with.offset(margin);
  108 + make.right.equalTo(self.contentView.mas_right).with.offset(-margin);
  109 + make.height.offset(0.5);
  110 + }];
  111 +
  112 + //日期
  113 + [_dateLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  114 + make.left.equalTo(self).offset(margin);
  115 + make.top.left.equalTo(self).offset(25);
  116 +// make.height.offset(20);
  117 + }];
  118 +
  119 + //时间
  120 + [_timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  121 + make.top.equalTo(self.dateLabel);
  122 + make.left.equalTo(self.dateLabel.mas_right).with.offset(margin);
  123 +// make.height.offset(20);
  124 + }];
  125 +
  126 + //描述
  127 + [_desLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  128 + make.right.equalTo(self.mas_right).offset(-margin);
  129 + make.centerY.equalTo(self.dateLabel);
  130 + }];
  131 +
  132 + //地址
  133 + [_addressLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  134 + make.top.equalTo(self.dateLabel.mas_bottom).with.offset(10);
  135 + make.left.equalTo(self.dateLabel.mas_left);
  136 + make.right.equalTo(self.mas_right).with.offset(-margin);
  137 +// make.height.offset(25);
  138 + }];
  139 +
  140 + //距离
  141 + [_distanceLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  142 + make.top.equalTo(self.addressLabel.mas_bottom).with.offset(10);
  143 + make.left.equalTo(self.addressLabel.mas_left);
  144 + make.right.equalTo(self.contentView.mas_right).with.offset(-margin);
  145 +// make.height.offset(40);
  146 + }];
  147 +
  148 + [_durationBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  149 + make.bottom.equalTo(self.line.mas_top).with.offset(-10);
  150 + make.left.equalTo(self.addressLabel.mas_left);
  151 + make.height.offset(25);
  152 +
  153 + }];
  154 +
  155 + [_speedBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  156 + make.bottom.equalTo(self.line.mas_top).with.offset(-10);
  157 + make.left.equalTo(self.durationBtn.mas_right).with.offset(30);
  158 + make.height.offset(25);
  159 + }];
  160 +
  161 + //步数
  162 + [_stepNumberBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  163 + make.bottom.equalTo(self.line.mas_top).with.offset(-10);
  164 + make.left.equalTo(self.speedBtn.mas_right).with.offset(30);
  165 + make.height.offset(25);
  166 +
  167 + }];
  168 +}
  169 +- (void)dealloc{
  170 +
  171 +}
  172 +#pragma mark - Data
  173 +- (void)setModel:(CNTrackUploadFailModel *)model{
  174 + _model = model;
  175 + _dateLabel.text = [CNLiveTimeTools getDateByTimeStamp:model.startTime formatter:@"MM月dd日"];
  176 + _timeLabel.text = [CNLiveTimeTools getDateByTimeStamp:model.startTime formatter:@"HH:mm"];
  177 + _addressLabel.text = model.eventName;
  178 + _distanceLabel.attributedText = [self setupDistanceString:model.totalKM];
  179 + [_durationBtn setTitle:[CNLiveTimeTools getMMSSFromSS:model.totalTime] forState:UIControlStateNormal];
  180 + [_speedBtn setTitle:model.speed forState:UIControlStateNormal];
  181 + [_stepNumberBtn setTitle:model.totalStep forState:UIControlStateNormal];
  182 +}
  183 +
  184 +- (void)awakeFromNib {
  185 + [super awakeFromNib];
  186 + // Initialization code
  187 +}
  188 +
  189 +- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
  190 + [super setSelected:selected animated:animated];
  191 +
  192 + // Configure the view for the selected state
  193 +}
  194 +
  195 +#pragma mark - Private Methods
  196 +//时间 地点
  197 +- (NSMutableAttributedString *)setupDistanceString:(NSString *)str{
  198 + NSString *strs = [NSString stringWithFormat:@"%@ 公里",str];
  199 + NSMutableAttributedString *attri = [[NSMutableAttributedString alloc] initWithString:strs];
  200 +
  201 + [attri addAttribute:NSForegroundColorAttributeName value:CNLiveColorWithHexString(@"#333333") range:NSMakeRange(0, strs.length)];
  202 + [attri addAttribute:NSFontAttributeName value:UIFontCNMake(26) range:NSMakeRange(0, str.length)];
  203 + [attri addAttribute:NSFontAttributeName value:UIFontCNMake(14) range:NSMakeRange(str.length, strs.length-str.length)];
  204 +
  205 + return attri;
  206 +}
  207 +
  208 +- (void)deleteBtnAction{
  209 + if (self.deleteClickBlock) {
  210 + self.deleteClickBlock(self.index);
  211 + }
  212 +}
  213 +
  214 +- (void)reUploadAction{
  215 + if (![CNLiveNetworking isNetworking]) {
  216 + [QMUITips showInfo:@"暂无网络" inView:AppKeyWindow hideAfterDelay:1.5];
  217 + return;
  218 + }
  219 + NSDictionary *dict = [self.model.endCoordsDictStr mj_JSONObject];
  220 + CLLocationCoordinate2D coordinate;
  221 + coordinate.latitude = [dict[@"lat"] doubleValue];
  222 + coordinate.longitude = [dict[@"long"] doubleValue];
  223 + //请求自己的历史轨迹
  224 + [self queryCurrentRunningEndPoint:^(NSArray *points) {
  225 + __block BOOL isSuccess = NO;//是否到达了终点
  226 + [points enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  227 + CNHistoryTrackPoint *minePoint = obj;
  228 + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
  229 + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude];
  230 + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation];
  231 + if (distance < 50) {//表示到达终点了
  232 + isSuccess = YES;
  233 + *stop = YES;
  234 + }
  235 + }];
  236 + if (isSuccess) {//到达了终点
  237 + __block NSMutableArray *mutArr = [NSMutableArray arrayWithArray:points];
  238 + __block int successCount = 0;
  239 + NSArray *arr = [self.model.pointsArrStr mj_JSONObject];
  240 + NSMutableArray<CNLiveSportsCoordinatesModel *> *models = [CNLiveSportsCoordinatesModel mj_objectArrayWithKeyValuesArray:arr];
  241 + for (CNLiveSportsCoordinatesModel *pointNode in models) {
  242 + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:[pointNode.latitude doubleValue] longitude:[pointNode.longitude doubleValue]];
  243 + [mutArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  244 + CNHistoryTrackPoint *minePoint = obj;
  245 + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude];
  246 + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation];
  247 + if (distance < 50) {//表示这个点已经完成
  248 + [mutArr removeObjectsInRange:NSMakeRange(0, idx+1)];
  249 + successCount ++;
  250 + *stop = YES;
  251 + }
  252 + }];
  253 + }
  254 + if (successCount*1.000/models.count*1.000 > 0.70) {//大于70%则认为任务完成
  255 + [self uploadService:YES];
  256 + }else{
  257 + [self uploadService:NO];
  258 + }
  259 + }else{//没有到达终点,直接算未完成
  260 + [self uploadService:NO];
  261 + }
  262 + }];
  263 +}
  264 +
  265 +//请求
  266 +- (void)uploadService:(BOOL)isSuccessTrack{
  267 + NSString *strUrl = CNSportsChinaSaveRecordUrl;
  268 + NSDictionary *dict = @{
  269 + @"eventId":self.model.eventId,
  270 + @"sid":CNUserShareModelUid,
  271 + @"employTime":self.model.totalTime,
  272 + @"mileage":self.model.totalKM,
  273 + @"pace":self.model.speed,
  274 + @"step":self.model.totalStep,
  275 + //@"roadmap":imgUrlStr,
  276 + @"startTime":self.model.startTime,
  277 + @"endTime":self.model.endTime,
  278 + @"isPause":self.model.isStop.length>0?@"1":@"0",
  279 + @"pauseTime":self.model.isStop.length>0?self.model.stopTime:@"",
  280 + @"continueTime":self.model.isStop.length>0?self.model.reStartTime:@"",
  281 + @"completeStatus":isSuccessTrack?@"1":@"0"
  282 + };
  283 + [CNLiveNetworking requestNetworkWithMethod:CNLiveRequestMethodPOST URLString:strUrl Param:dict CacheType:CNLiveNetworkCacheTypeNetworkOnly CompletionBlock:^(NSURLSessionTask *requestTask, id responseObject, NSError *error) {
  284 + if (error) {
  285 + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5];
  286 + //弹窗,是否暂存,是否重试
  287 +// [self alertEndSelect:isSuccessTrack img:imgUrlStr];
  288 + }else{
  289 + if ([responseObject isKindOfClass:[NSDictionary class]]) {
  290 + NSString *resultCode = [NSString stringWithFormat:@"%@", responseObject[@"errorCode"]];
  291 + if ([resultCode isEqualToString:@"0"]) {
  292 + //删除数据库中的逻辑辅助数据
  293 + [[CNTrackLoaclDataManager shareManager] deleteFUploadModel:self.model];
  294 + [QMUITips showInfo:@"重新上传成功" inView:AppKeyWindow hideAfterDelay:1.5];
  295 + if ([self.delegate respondsToSelector:@selector(needToReloadTable:index:)]) {
  296 + [self.delegate needToReloadTable:self index:self.index];
  297 + }
  298 + }else{
  299 + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5];
  300 + }
  301 + }else{
  302 + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5];
  303 + }
  304 + }
  305 + }];
  306 +}
  307 +
  308 +#pragma mark -- 自己的历史轨迹
  309 +- (void)queryCurrentRunningEndPoint:(void(^)(NSArray *))handle{
  310 + NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:0];
  311 + if ([self.model.isStop isEqualToString:@"yes"]) {
  312 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  313 + [paramInfo setStartTime:[self.model.startTime integerValue]];
  314 + [paramInfo setEndTime:[self.model.stopTime integerValue]];
  315 + [paramInfo setEntityName:CNUserShareModelUid];
  316 + [paramInfo setIsProcessed:true];
  317 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  318 + processOption.radiusThreshold = 100;
  319 + processOption.denoise = true;
  320 + processOption.vacuate = true;
  321 + processOption.mapMatch = false;
  322 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  323 + paramInfo.processOption = processOption;
  324 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  325 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  326 + vm.completionHandler = ^(NSArray *points) {
  327 + [tempArray addObjectsFromArray:points];
  328 + if (self.model.reStartTime.length > 0) {
  329 + CNHistoryTrackParam * paramInfo2 =[[CNHistoryTrackParam alloc]init];
  330 + [paramInfo2 setStartTime:[self.model.reStartTime integerValue]];
  331 + [paramInfo2 setEndTime:[self.model.endTime integerValue]];
  332 + [paramInfo2 setEntityName:CNUserShareModelUid];
  333 + [paramInfo2 setIsProcessed:true];
  334 + BTKQueryTrackProcessOption *processOption2 = [[BTKQueryTrackProcessOption alloc] init];
  335 + processOption2.radiusThreshold = 100;
  336 + processOption2.denoise = true;
  337 + processOption2.vacuate = true;
  338 + processOption2.mapMatch = false;
  339 + processOption2.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  340 + paramInfo2.processOption = processOption;
  341 + paramInfo2.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  342 + CNHistoryViewModel *vm2 = [[CNHistoryViewModel alloc] init];
  343 + vm2.completionHandler = ^(NSArray *points) {
  344 + [tempArray addObjectsFromArray:points];
  345 + handle(tempArray);
  346 + };
  347 + [vm2 queryHistoryWithParam:paramInfo2];
  348 + }else{
  349 + handle(tempArray);
  350 + }
  351 + };
  352 + [vm queryHistoryWithParam:paramInfo];
  353 + }else{
  354 + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init];
  355 + [paramInfo setStartTime:[self.model.startTime integerValue]];
  356 + [paramInfo setEndTime:[self.model.endTime integerValue]];
  357 + [paramInfo setEntityName:CNUserShareModelUid];
  358 + [paramInfo setIsProcessed:true];
  359 + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init];
  360 + processOption.radiusThreshold = 100;
  361 + processOption.denoise = true;
  362 + processOption.vacuate = true;
  363 + processOption.mapMatch = false;
  364 + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING;
  365 + paramInfo.processOption = processOption;
  366 + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING;
  367 + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init];
  368 + vm.completionHandler = ^(NSArray *points) {
  369 + [tempArray addObjectsFromArray:points];
  370 + handle(tempArray);
  371 + };
  372 + [vm queryHistoryWithParam:paramInfo];
  373 + }
  374 +
  375 +}
  376 +#pragma mark - Lazy loading
  377 +-(UIView *)bgView{
  378 + if (!_bgView) {
  379 + _bgView = [[UIView alloc] init];
  380 + _bgView.backgroundColor = kWhiteColor;
  381 + }
  382 + return _bgView;
  383 +}
  384 +
  385 +- (UILabel *)dateLabel{
  386 + if(_dateLabel == nil){
  387 + _dateLabel = [[UILabel alloc] init];
  388 + _dateLabel.textColor = CNLiveColorWithHexString(@"666666");
  389 + _dateLabel.font = UIFontCNMake(14);
  390 +
  391 + }
  392 + return _dateLabel;
  393 +
  394 +}
  395 +
  396 +- (UILabel *)timeLabel{
  397 + if(_timeLabel == nil){
  398 + _timeLabel = [[UILabel alloc] init];
  399 + _timeLabel.textColor = CNLiveColorWithHexString(@"888888");
  400 + _timeLabel.font = UIFontCNMake(14);
  401 + _timeLabel.userInteractionEnabled = YES;
  402 +
  403 + }
  404 + return _timeLabel;
  405 +
  406 +}
  407 +
  408 +- (UILabel *)addressLabel{
  409 + if(_addressLabel == nil){
  410 + _addressLabel = [[UILabel alloc] init];
  411 + _addressLabel.textColor = CNLiveColorWithHexString(@"333333");
  412 + _addressLabel.font = UIFontCNMake(12);
  413 + _addressLabel.userInteractionEnabled = YES;
  414 +
  415 + }
  416 + return _addressLabel;
  417 +
  418 +}
  419 +
  420 +- (UILabel *)distanceLabel{
  421 + if(_distanceLabel == nil){
  422 + _distanceLabel = [[UILabel alloc] init];
  423 + _distanceLabel.textColor = CNLiveColorWithHexString(@"333333");
  424 + _distanceLabel.font = UIFontCNMake(30);
  425 + _distanceLabel.userInteractionEnabled = YES;
  426 +
  427 + }
  428 + return _distanceLabel;
  429 +
  430 +}
  431 +
  432 +- (QMUIButton *)durationBtn{
  433 + if(_durationBtn == nil){
  434 + _durationBtn = [QMUIButton buttonWithType:UIButtonTypeCustom];
  435 + _durationBtn.titleLabel.font = UIFontCNMake(13);
  436 + [_durationBtn setTitleColor:CNLiveColorWithHexString(@"666666") forState:UIControlStateNormal];
  437 + [_durationBtn setTitle:@"00:00:00" forState:UIControlStateNormal];
  438 + [_durationBtn setImage:[UIImage imageNamed:@"sports_china_wdjl_time"] forState:UIControlStateNormal];
  439 + _durationBtn.adjustsImageWhenHighlighted = NO;
  440 + _durationBtn.imagePosition = QMUIButtonImagePositionRight;
  441 + _durationBtn.spacingBetweenImageAndTitle = 5;
  442 + _durationBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
  443 +
  444 + }
  445 + return _durationBtn;
  446 +
  447 +}
  448 +
  449 +- (QMUIButton *)speedBtn{
  450 + if(_speedBtn == nil){
  451 + _speedBtn = [QMUIButton buttonWithType:UIButtonTypeCustom];
  452 + _speedBtn.titleLabel.font = UIFontCNMake(13);
  453 + [_speedBtn setTitleColor:CNLiveColorWithHexString(@"666666") forState:UIControlStateNormal];
  454 + [_speedBtn setTitle:@"0" forState:UIControlStateNormal];
  455 + [_speedBtn setImage:[UIImage imageNamed:@"sports_china_wdjl_speed"] forState:UIControlStateNormal];
  456 + _speedBtn.adjustsImageWhenHighlighted = NO;
  457 + _speedBtn.imagePosition = QMUIButtonImagePositionRight;
  458 + _speedBtn.spacingBetweenImageAndTitle = 5;
  459 + _speedBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
  460 +
  461 + }
  462 + return _speedBtn;
  463 +
  464 +}
  465 +
  466 +- (QMUIButton *)stepNumberBtn{
  467 + if(_stepNumberBtn == nil){
  468 + _stepNumberBtn = [QMUIButton buttonWithType:UIButtonTypeCustom];
  469 + _stepNumberBtn.titleLabel.font = UIFontCNMake(13);
  470 + [_stepNumberBtn setTitleColor:CNLiveColorWithHexString(@"666666") forState:UIControlStateNormal];
  471 + [_stepNumberBtn setTitle:@"0" forState:UIControlStateNormal];
  472 + [_stepNumberBtn setImage:[UIImage imageNamed:@"sports_china_wdjl_step"] forState:UIControlStateNormal];
  473 + _stepNumberBtn.adjustsImageWhenHighlighted = NO;
  474 + _stepNumberBtn.imagePosition = QMUIButtonImagePositionRight;
  475 + _stepNumberBtn.spacingBetweenImageAndTitle = 5;
  476 + _stepNumberBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
  477 +
  478 + }
  479 + return _stepNumberBtn;
  480 +
  481 +}
  482 +
  483 +- (UIView *)line{
  484 + if(_line == nil){
  485 + _line = [[UIView alloc] init];
  486 + _line.backgroundColor = CNLiveColorWithHexString(@"ebebeb");
  487 +
  488 + }
  489 + return _line;
  490 +
  491 +}
  492 +
  493 +- (QMUIButton *)deleteBtn{
  494 + if(_deleteBtn == nil){
  495 + _deleteBtn = [QMUIButton buttonWithType:UIButtonTypeCustom];
  496 + [_deleteBtn setTitle:@"删 除" forState:UIControlStateNormal];
  497 + _deleteBtn.titleLabel.font = UIFontCNMake(12);
  498 + [_deleteBtn setTitleColor:[UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0] forState:UIControlStateNormal];
  499 + [_deleteBtn addTarget:self action:@selector(deleteBtnAction) forControlEvents:UIControlEventTouchUpInside];
  500 + }
  501 + return _deleteBtn;
  502 +}
  503 +
  504 +-(QMUIButton *)reUploadBtn{
  505 + if(_reUploadBtn == nil){
  506 + _reUploadBtn = [QMUIButton buttonWithType:UIButtonTypeCustom];
  507 + [_reUploadBtn setTitle:@"重新上传" forState:UIControlStateNormal];
  508 + _reUploadBtn.titleLabel.font = UIFontCNMake(12);
  509 + [_reUploadBtn setTitleColor:[UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0] forState:UIControlStateNormal];
  510 + [_reUploadBtn addTarget:self action:@selector(reUploadAction) forControlEvents:UIControlEventTouchUpInside];
  511 + }
  512 + return _reUploadBtn;
  513 +}
  514 +
  515 +-(UILabel *)desLabel{
  516 + if(_desLabel == nil){
  517 + _desLabel = [[UILabel alloc] init];
  518 + _desLabel.textColor = [UIColor colorWithRed:254/255.0 green:78/255.0 blue:78/255.0 alpha:1.0];
  519 + _desLabel.font = UIFontCNMake(12);
  520 + _desLabel.userInteractionEnabled = YES;
  521 + _desLabel.text = @"上传失败";
  522 + }
  523 + return _desLabel;
  524 +}
  525 +@end
... ...
CNLiveSportsModule/Classes/View/CNRunEndCircleProgress.h 0 → 100755
  1 +//
  2 +// CNRunEndCircleProgress.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/14.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +
  10 +#import <UIKit/UIKit.h>
  11 +#import "CNRunEndCountingLabel.h"
  12 +
  13 +#define CNCircleDegreeToRadian(d) ((d)*M_PI)/180.0
  14 +#define CNCircleRGB(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
  15 +#define CNCircleSelfWidth self.frame.size.width
  16 +#define CNCircleSelfHeight self.frame.size.height
  17 +
  18 +@interface CNRunEndCircleProgress : UIView
  19 +
  20 +//图形定制
  21 +@property (nonatomic, strong) UIColor *pathBackColor;/**<线条背景色*/
  22 +@property (nonatomic, strong) UIColor *pathFillColor;/**<线条填充色*/
  23 +@property (nonatomic, strong) UIImageView *pointImage;/**<小圆点图片*/
  24 +@property (nonatomic, strong) CNRunEndCountingLabel *progressLabel;
  25 +
  26 +//角度相关
  27 +@property (nonatomic, assign) CGFloat startAngle;/**<起点角度。角度从水平右侧开始为0,顺时针为增加角度。直接传度数 如-90 */
  28 +@property (nonatomic, assign) CGFloat reduceAngle;/**<减少的角度 直接传度数 如30*/
  29 +@property (nonatomic, assign) CGFloat strokeWidth;/**<线宽*/
  30 +
  31 +@property (nonatomic, assign) CGFloat duration;/**<动画时长*/
  32 +
  33 +@property (nonatomic, assign) BOOL showPoint;/**<是否显示小圆点*/
  34 +@property (nonatomic, assign) BOOL showProgressText;/**<是否显示文字*/
  35 +@property (nonatomic, assign) BOOL increaseFromLast;/**<是否从上次数值开始动画,默认为NO*/
  36 +
  37 +//进度
  38 +@property (nonatomic, assign) CGFloat progress;/**<进度 0-1 */
  39 +
  40 +/**
  41 + 初始化
  42 +
  43 + @param frame 使用自动布局时传CGRectZero
  44 + @param pathBackColor 背景线条色
  45 + @param pathFillColor 填充线条色
  46 + @param startAngle 开始角度
  47 + @param strokeWidth 线条宽度
  48 + @return CNCircleProgress
  49 + */
  50 +- (instancetype)initWithFrame:(CGRect)frame
  51 + pathBackColor:(UIColor *)pathBackColor
  52 + pathFillColor:(UIColor *)pathFillColor
  53 + startAngle:(CGFloat)startAngle
  54 + strokeWidth:(CGFloat)strokeWidth;
  55 +
  56 +@end
... ...
CNLiveSportsModule/Classes/View/CNRunEndCircleProgress.m 0 → 100755
  1 +//
  2 +// CNRunEndCircleProgress.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/14.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +
  10 +#import "CNRunEndCircleProgress.h"
  11 +
  12 +@interface CNRunEndCircleProgress ()<CAAnimationDelegate>
  13 +
  14 +@property (nonatomic, strong) CAShapeLayer *backLayer;
  15 +@property (nonatomic, strong) CAShapeLayer *progressLayer;
  16 +
  17 +@property (nonatomic, assign) CGFloat realWidth;//实际边长
  18 +@property (nonatomic, assign) CGFloat radius;//半径
  19 +@property (nonatomic, assign) CGFloat lastProgress;/**<上次进度 0-1 */
  20 +@property (nonatomic, strong) CAAnimation *lastPointAnimation;
  21 +
  22 +@end
  23 +
  24 +
  25 +@implementation CNRunEndCircleProgress
  26 +
  27 +- (instancetype)init {
  28 + if (self = [super init]) {
  29 + [self initialization];
  30 + }
  31 + return self;
  32 +}
  33 +
  34 +- (instancetype)initWithFrame:(CGRect)frame {
  35 + if (self = [super initWithFrame:frame]) {
  36 + [self initialization];
  37 + }
  38 + return self;
  39 +}
  40 +
  41 +- (void)awakeFromNib {
  42 + [super awakeFromNib];
  43 + [self initialization];
  44 +}
  45 +
  46 +//初始化
  47 +- (instancetype)initWithFrame:(CGRect)frame
  48 + pathBackColor:(UIColor *)pathBackColor
  49 + pathFillColor:(UIColor *)pathFillColor
  50 + startAngle:(CGFloat)startAngle
  51 + strokeWidth:(CGFloat)strokeWidth {
  52 + if (self = [super initWithFrame:frame]) {
  53 + [self initialization];
  54 + self.pathBackColor = pathBackColor;
  55 + self.pathFillColor = pathFillColor;
  56 + _startAngle = CNCircleDegreeToRadian(startAngle);
  57 + _strokeWidth = strokeWidth;
  58 + }
  59 + return self;
  60 +}
  61 +
  62 +//初始化数据
  63 +- (void)initialization {
  64 + self.backgroundColor = [UIColor greenColor];//[UIColor colorWithRed:250/255.0 green:112/255.0 blue:112/255.0 alpha:1.0];
  65 + _pathBackColor = [UIColor lightGrayColor];
  66 + _pathFillColor = [UIColor redColor];
  67 +
  68 + _strokeWidth = 10;//线宽默认为10
  69 + _startAngle = CNCircleDegreeToRadian(0);//圆起点位置
  70 + _reduceAngle = CNCircleDegreeToRadian(0);//整个圆缺少的角度
  71 +
  72 + _duration = 1.5;//动画时长
  73 + _showPoint = YES;//小圆点
  74 + _showProgressText = YES;//文字
  75 +
  76 + //初始化layer
  77 + [self initSubviews];
  78 +}
  79 +
  80 +#pragma Get
  81 +- (CAShapeLayer *)backLayer {
  82 + if (!_backLayer) {
  83 + _backLayer = [CAShapeLayer layer];
  84 + _backLayer.fillColor = [UIColor clearColor].CGColor;//填充色
  85 + _backLayer.lineWidth = _strokeWidth;
  86 + _backLayer.strokeColor = _pathBackColor.CGColor;
  87 + _backLayer.lineCap = @"round";
  88 + }
  89 + return _backLayer;
  90 +}
  91 +
  92 +- (CAShapeLayer *)progressLayer {
  93 + if (!_progressLayer) {
  94 + _progressLayer = [CAShapeLayer layer];
  95 + _progressLayer.fillColor = [UIColor clearColor].CGColor;//填充色
  96 + _progressLayer.lineWidth = _strokeWidth;
  97 + _progressLayer.strokeColor = _pathFillColor.CGColor;
  98 + _progressLayer.lineCap = @"round";
  99 + }
  100 + return _progressLayer;
  101 +}
  102 +
  103 +- (UIImageView *)pointImage {
  104 + if (!_pointImage) {
  105 + _pointImage = [[UIImageView alloc] init];
  106 + NSBundle *mainBundle = [NSBundle bundleForClass:[self class]];
  107 + NSBundle *resourcesBundle = [NSBundle bundleWithPath:[mainBundle pathForResource:@"CNCircleProgress" ofType:@"bundle"]];
  108 + _pointImage.image = [UIImage imageNamed:@"circle_point1" inBundle:resourcesBundle compatibleWithTraitCollection:nil];
  109 + }
  110 + return _pointImage;
  111 +}
  112 +
  113 +- (CNRunEndCountingLabel *)progressLabel {
  114 + if (!_progressLabel) {
  115 + _progressLabel = [[CNRunEndCountingLabel alloc] init];
  116 + _progressLabel.textColor = [UIColor blackColor];
  117 + _progressLabel.textAlignment = NSTextAlignmentCenter;
  118 + _progressLabel.font = [UIFont systemFontOfSize:22];
  119 + _progressLabel.text = @"0%";
  120 + }
  121 + return _progressLabel;
  122 +}
  123 +
  124 +- (CAAnimation *)pathAnimation {
  125 + CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  126 + pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  127 + pathAnimation.duration = _duration;
  128 + pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  129 + pathAnimation.fromValue = [NSNumber numberWithFloat:_increaseFromLast==YES?_lastProgress:0];
  130 + pathAnimation.toValue = [NSNumber numberWithFloat:_progress];
  131 + pathAnimation.fillMode = kCAFillModeForwards;
  132 + pathAnimation.removedOnCompletion = NO;
  133 + return pathAnimation;
  134 +}
  135 +
  136 +- (CAAnimation *)pointAnimation {
  137 + CAKeyframeAnimation *pointAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  138 + pointAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  139 + pointAnimation.fillMode = kCAFillModeForwards;
  140 + pointAnimation.calculationMode = @"paced";
  141 + pointAnimation.removedOnCompletion = NO;
  142 + pointAnimation.duration = _duration;
  143 + pointAnimation.delegate = self;
  144 +
  145 + BOOL clockwise = NO;
  146 + if (_progress<_lastProgress && _increaseFromLast == YES) {
  147 + clockwise = YES;
  148 + }
  149 + UIBezierPath *imagePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(_realWidth/2.0, _realWidth/2.0) radius:_radius startAngle:_increaseFromLast==YES?(2*M_PI-_reduceAngle)*_lastProgress+_startAngle:_startAngle endAngle:(2*M_PI-_reduceAngle)*_progress+_startAngle clockwise:!clockwise];
  150 + pointAnimation.path = imagePath.CGPath;
  151 +
  152 + return pointAnimation;
  153 +}
  154 +
  155 +#pragma Set
  156 +- (void)setStartAngle:(CGFloat)startAngle {
  157 + if (_startAngle != CNCircleDegreeToRadian(startAngle)) {
  158 + _startAngle = CNCircleDegreeToRadian(startAngle);
  159 + [self setNeedsLayout];
  160 + }
  161 +}
  162 +
  163 +- (void)setReduceAngle:(CGFloat)reduceAngle {
  164 + if (_reduceAngle != CNCircleDegreeToRadian(reduceAngle)) {
  165 + if (reduceAngle>=360) {
  166 + return;
  167 + }
  168 + _reduceAngle = CNCircleDegreeToRadian(reduceAngle);
  169 + [self setNeedsLayout];
  170 + }
  171 +}
  172 +
  173 +- (void)setStrokeWidth:(CGFloat)strokeWidth {
  174 + if (_strokeWidth != strokeWidth) {
  175 + _strokeWidth = strokeWidth;
  176 + _radius = _realWidth/2.0 - _strokeWidth/2.0;
  177 + [self setNeedsLayout];
  178 + }
  179 +}
  180 +
  181 +- (void)setPathBackColor:(UIColor *)pathBackColor {
  182 + if (_pathBackColor != pathBackColor) {
  183 + _pathBackColor = pathBackColor;
  184 + self.backLayer.strokeColor = _pathBackColor.CGColor;
  185 + }
  186 +}
  187 +
  188 +- (void)setPathFillColor:(UIColor *)pathFillColor {
  189 + if (_pathFillColor != pathFillColor) {
  190 + _pathFillColor = pathFillColor;
  191 + self.progressLayer.strokeColor = _pathFillColor.CGColor;
  192 + }
  193 +}
  194 +
  195 +- (void)setShowPoint:(BOOL)showPoint {
  196 + if (_showPoint != showPoint) {
  197 + _showPoint = showPoint;
  198 + if (_showPoint) {
  199 + self.pointImage.hidden = NO;
  200 + [self updatePointPosition];
  201 + } else {
  202 + self.pointImage.hidden = YES;
  203 + }
  204 + }
  205 +}
  206 +
  207 +-(void)setShowProgressText:(BOOL)showProgressText {
  208 + if (_showProgressText != showProgressText) {
  209 + _showProgressText = showProgressText;
  210 + if (_showProgressText) {
  211 + self.progressLabel.hidden = NO;
  212 + } else {
  213 + self.progressLabel.hidden = YES;
  214 + }
  215 + }
  216 +}
  217 +
  218 +- (void)setProgress:(CGFloat)progress {
  219 + _progress = MAX(MIN(1, progress), 0);
  220 + __weak typeof(self) weakSelf = self;
  221 + dispatch_async(dispatch_get_main_queue(), ^{
  222 + __strong typeof(weakSelf) strongSelf = weakSelf;
  223 + [strongSelf startAnimation];
  224 + });
  225 +}
  226 +
  227 +#pragma Methods
  228 +- (void)startAnimation {
  229 +
  230 + [self.progressLayer addAnimation:[self pathAnimation] forKey:@"strokeEndAnimation"];
  231 +
  232 + if (_showPoint) {
  233 + CAAnimation *pointAnimation = [self pointAnimation];
  234 + [self.pointImage.layer addAnimation:pointAnimation forKey:@"pointAnimation"];
  235 + self.lastPointAnimation = pointAnimation;
  236 +
  237 + if (!_increaseFromLast && _progress == 0.0) {
  238 + [self.pointImage.layer removeAllAnimations];
  239 + }
  240 + }
  241 +
  242 + if (_showProgressText && _increaseFromLast) {
  243 + [self.progressLabel countingFrom:_lastProgress*100 to:_progress*100 duration:_duration];
  244 + } else if (_showProgressText) {
  245 + [self.progressLabel countingFrom:0 to:_progress*100 duration:_duration];
  246 + }
  247 +
  248 + _lastProgress = _progress;
  249 +}
  250 +
  251 +- (UIBezierPath *)getNewBezierPath {
  252 + return [UIBezierPath bezierPathWithArcCenter:CGPointMake(_realWidth/2.0, _realWidth/2.0) radius:_radius startAngle:_startAngle endAngle:(2*M_PI-_reduceAngle+_startAngle) clockwise:YES];
  253 +}
  254 +
  255 +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
  256 + if (flag && anim == [self.pointImage.layer animationForKey:@"pointAnimation"]) {
  257 + [self updatePointPosition];
  258 + }
  259 +}
  260 +
  261 +- (void)updatePointPosition {
  262 + CGFloat currentEndAngle = (2*M_PI-_reduceAngle)*_progress+_startAngle;
  263 + [_pointImage.layer removeAllAnimations];
  264 + _pointImage.center = CGPointMake(_realWidth/2.0+_radius*cosf(currentEndAngle), _realWidth/2.0+_radius*sinf(currentEndAngle));
  265 +}
  266 +
  267 +#pragma initSubviews
  268 +- (void)initSubviews {
  269 + [self.layer addSublayer:self.backLayer];
  270 + [self.layer addSublayer:self.progressLayer];
  271 +
  272 + [self addSubview:self.pointImage];
  273 + [self addSubview:self.progressLabel];
  274 +}
  275 +
  276 +#pragma layout
  277 +- (void)layoutSubviews {
  278 + [super layoutSubviews];
  279 +
  280 + self.realWidth = MIN(CNCircleSelfWidth, CNCircleSelfHeight);
  281 + self.radius = _realWidth/2.0 - _strokeWidth/2.0;
  282 +
  283 + self.backLayer.frame = CGRectMake(0, 0, _realWidth, _realWidth);
  284 + self.backLayer.lineWidth = _strokeWidth;
  285 + self.backLayer.path = [self getNewBezierPath].CGPath;
  286 +
  287 + self.progressLayer.frame = CGRectMake(0, 0, _realWidth, _realWidth);
  288 + self.progressLayer.lineWidth = _strokeWidth;
  289 + self.progressLayer.path = [self getNewBezierPath].CGPath;
  290 + self.progressLayer.strokeEnd = 0.0;
  291 +
  292 + self.progressLabel.frame = CGRectMake(0, 0, _realWidth, _realWidth);
  293 +
  294 + self.pointImage.frame = CGRectMake(0, 0, _strokeWidth, _strokeWidth);
  295 + [self updatePointPosition];
  296 +
  297 +}
  298 +
  299 +-(void)dealloc{
  300 + NSLog(@"");
  301 +}
  302 +@end
... ...
CNLiveSportsModule/Classes/View/CNRunEndCountingLabel.h 0 → 100755
  1 +//
  2 +// ZZCountingLabel.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/14.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface CNRunEndCountingLabel : UILabel
  12 +
  13 +@property (nonatomic, assign) CGFloat duration;
  14 +
  15 +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue;
  16 +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue duration:(CGFloat)duration;
  17 +
  18 +@end
... ...
CNLiveSportsModule/Classes/View/CNRunEndCountingLabel.m 0 → 100755
  1 +//
  2 +// ZZCountingLabel.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/14.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNRunEndCountingLabel.h"
  10 +
  11 +@interface CNRunEndCountingLabel ()
  12 +
  13 +@property (nonatomic, strong) CADisplayLink *playLink;
  14 +@property (nonatomic, assign) NSInteger displayPerSecond;
  15 +
  16 +@property (nonatomic, assign) CGFloat fromValue;
  17 +@property (nonatomic, assign) CGFloat toValue;
  18 +
  19 +@property (nonatomic, assign) CGFloat increaseValue;
  20 +@property (nonatomic, assign) CGFloat perValue;
  21 +
  22 +@end
  23 +
  24 +@implementation CNRunEndCountingLabel
  25 +
  26 +- (instancetype)init {
  27 + if (self = [super init]) {
  28 + [self initValues];
  29 + }
  30 + return self;
  31 +}
  32 +
  33 +- (instancetype)initWithFrame:(CGRect)frame {
  34 + if (self = [super initWithFrame:frame]) {
  35 + [self initValues];
  36 + }
  37 + return self;
  38 +}
  39 +
  40 +- (void)awakeFromNib {
  41 + [super awakeFromNib];
  42 + [self initValues];
  43 +}
  44 +
  45 +- (void)initValues {
  46 + _duration = 2.0;
  47 + _displayPerSecond = 30;
  48 +}
  49 +
  50 +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue {
  51 + [self countingFrom:fromValue to:toValue duration:_duration];
  52 +}
  53 +
  54 +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue duration:(CGFloat)duration {
  55 +
  56 + _fromValue = fromValue;
  57 + _toValue = toValue;
  58 + _duration = duration;
  59 +
  60 + _increaseValue = _fromValue;
  61 + _perValue = (_toValue - _fromValue)/(_duration==0?1:(_displayPerSecond*_duration));
  62 +
  63 + if (self.playLink) {
  64 + [self.playLink invalidate];
  65 + self.playLink = nil;
  66 + }
  67 +
  68 + CADisplayLink *playLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(countingAction)];
  69 + if (@available(iOS 10.0, *)) {
  70 + playLink.preferredFramesPerSecond = _displayPerSecond;
  71 + } else {
  72 + playLink.frameInterval = 60/(_displayPerSecond==0?1:_displayPerSecond);
  73 + }
  74 +
  75 + [playLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
  76 + [playLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];
  77 + self.playLink = playLink;
  78 +
  79 +}
  80 +
  81 +- (void)countingAction {
  82 + _increaseValue += _perValue;
  83 +
  84 + if (_fromValue < _toValue) {
  85 + if (_increaseValue >= _toValue) {
  86 + [self stopDisplayLink];
  87 + }
  88 + } else {
  89 + if (_increaseValue <= _toValue) {
  90 + [self stopDisplayLink];
  91 + }
  92 + }
  93 +
  94 + dispatch_async(dispatch_get_main_queue(), ^{
  95 + self.text = [NSString stringWithFormat:@"%.0f%%",_increaseValue];
  96 + });
  97 +}
  98 +
  99 +- (void)stopDisplayLink {
  100 +
  101 + [self.playLink invalidate];
  102 + self.playLink = nil;
  103 +
  104 + _increaseValue = _toValue;
  105 +}
  106 +
  107 +@end
... ...
CNLiveSportsModule/Classes/View/CNTrackTableView.h 0 → 100644
  1 +//
  2 +// CNTrackTableView.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/19.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +
  12 +
  13 +@interface CNTrackTableView : UITableView
  14 +@property (nonatomic, strong) UIView *view;
  15 +@property (nonatomic, assign) CGFloat receiverHeight;
  16 +@end
  17 +
  18 +
... ...
CNLiveSportsModule/Classes/View/CNTrackTableView.m 0 → 100644
  1 +//
  2 +// CNTrackTableView.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by open on 2019/6/19.
  6 +// Copyright © 2019 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNTrackTableView.h"
  10 +
  11 +@implementation CNTrackTableView
  12 +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {//从底部往上区域手势事件不响应
  13 + if (![self.layer containsPoint:point]) {
  14 + return NO;
  15 + }
  16 + if (self.view) {
  17 + if ([self.view.layer containsPoint:point]) {
  18 + return YES;
  19 + }
  20 + }
  21 + if (point.y < self.receiverHeight) {
  22 + return NO;
  23 + }
  24 + return YES;
  25 +}
  26 +
  27 +@end
... ...