BikeController.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Mead
  5. * Date: 2019/8/19
  6. * Time: 2:11 PM
  7. */
  8. namespace App\Http\Controllers\V1;
  9. use App\Handlers\Activities\RidingCardActivityHandler;
  10. use App\Handlers\BikeControl;
  11. use App\Handlers\BikeHandler;
  12. use App\Handlers\BikeStatusInfoSyncHandler;
  13. use App\Handlers\ConvertHandler;
  14. use App\Http\Requests\BikeCloseOrderRequest;
  15. use App\Http\Requests\BikeNoRequest;
  16. use App\Http\Requests\BikeOpenStoreOrderRequest;
  17. use App\Http\Requests\LocationRequest;
  18. use App\Jobs\SendSMSBikeTemporaryWaitOverThirtyJob;
  19. use App\Maps\CacheMap;
  20. use App\Models\AreaSetting;
  21. use App\Models\Bike;
  22. use App\Models\Order;
  23. use App\Models\OrderBikeOperate;
  24. use App\Models\User;
  25. use App\Repositories\AreaRepository;
  26. use App\Repositories\AreaSettingRepository;
  27. use App\Repositories\BikeRepository;
  28. use App\Repositories\LocationLogRepository;
  29. use App\Repositories\OrderRepository;
  30. use App\Repositories\ParkingRepository;
  31. use App\Repositories\RentOrderRepository;
  32. use App\Repositories\UserRepository;
  33. use App\Transformers\BikeTransformer;
  34. use App\Transformers\OrderTransformer;
  35. use Carbon\Carbon;
  36. use Illuminate\Support\Facades\Cache;
  37. use Illuminate\Support\Facades\DB;
  38. use Illuminate\Support\Facades\Log;
  39. use Illuminate\Support\Facades\Redis;
  40. use Symfony\Component\HttpKernel\Exception\HttpException;
  41. class BikeController extends BaseController
  42. {
  43. /**
  44. * 获取附近车
  45. * @param LocationRequest $request
  46. * @return mixed
  47. * User: Mead
  48. */
  49. public function index(LocationRequest $request)
  50. {
  51. $lat = $request->get('lat');
  52. $lng = $request->get('lng');
  53. try {
  54. // 查找最近车的bike_no
  55. $options = ['WITHDIST' => true, 'SORT' => 'ASC', 'WITHCOORD' => true];
  56. $redis = Redis::connection();
  57. $nearby_bikes = $redis->georadius(Bike::REDIS_BIKE_LOCATION_TAG, $lng, $lat, 1, 'km', $options);
  58. $bikes = [];
  59. if (count($nearby_bikes)) {
  60. $bikes = array_map(function ($val) {
  61. return [
  62. 'bike_no' => $val[0],
  63. 'distance' => $val[1],
  64. 'latitude' => $val[2][1],
  65. 'longitude' => $val[2][0],
  66. ];
  67. }, $nearby_bikes);
  68. }
  69. return $this->response->array($bikes);
  70. } catch (\Exception $exception) {
  71. $this->errorException($exception->getMessage());
  72. }
  73. }
  74. /**
  75. * 获取单个车的信息
  76. * @param $bike_no
  77. * @param BikeRepository $bikeRepository
  78. * @return \Dingo\Api\Http\Response
  79. * User: Mead
  80. */
  81. public function show($bike_no, BikeRepository $bikeRepository)
  82. {
  83. try {
  84. $bike = $bikeRepository->byBikeNo($bike_no);
  85. return $this->response->item($bike, BikeTransformer::class);
  86. } catch (\Exception $exception) {
  87. return $this->errorException('获取单车数据异常');
  88. }
  89. }
  90. /**
  91. * 响铃
  92. * @param BikeNoRequest $request
  93. * @return mixed
  94. * User: Mead
  95. */
  96. public function findBike($bike_no, BikeRepository $bikeRepository)
  97. {
  98. try {
  99. if (!$bikeRepository->byNoIsBikeCanRide($bike_no)) {
  100. return $this->errorNoValidation('车找不到或车暂停使用');
  101. }
  102. $box_no = $bikeRepository->byNoGetBoxNO($bike_no);
  103. $re = BikeControl::bellBike($box_no);
  104. return $this->response->array([
  105. 'is_ok' => $re
  106. ]);
  107. } catch (\Exception $exception) {
  108. return $this->errorException($exception->getMessage());
  109. }
  110. }
  111. /**
  112. * 用车订单(开车)
  113. * User: Mead
  114. */
  115. public function openLock(BikeOpenStoreOrderRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository, RentOrderRepository $rentOrderRepository, AreaSettingRepository $areaSettingRepository, AreaRepository $areaRepository, UserRepository $userRepository)
  116. {
  117. $bike_no = $request->get('bike_no');
  118. $bike_id = $bikeRepository->byBikeNoGetId($bike_no);
  119. $area_id = $request->get('area_id');
  120. $lat = $request->get('lat');
  121. $lng = $request->get('lng');
  122. $cache_key = "RIDE_ORDER_{$bike_no}";
  123. if (Cache::has($cache_key)) {
  124. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  125. }
  126. Cache::put($cache_key, 1, Carbon::now()->addSeconds(5));
  127. if (!$bike_id) {
  128. return $this->errorNoValidation('非法请求');
  129. }
  130. // 判断用户押金,授权,认证,手机号状态是否正常
  131. $user = $this->user;
  132. if ((int)$user->is_deposit === User::DEPOSIT_NO) {
  133. return $this->errorNoValidation('请您先交纳押金');
  134. }
  135. if ((int)$user->deposit_type === User::DEPOSIT_CARD && (int)$user->is_deposit === User::DEPOSIT_OK) {
  136. // 押金类型为免押金卡 判断是否过期
  137. if (!$userRepository->isDepositCardExpired($user->id)) {
  138. return $this->errorNoValidation('免押金卡已到期,请您先交纳押金');
  139. }
  140. }
  141. if ((int)$user->is_bind_mobile === User::BIND_MOBILE_NO) {
  142. return $this->errorNoValidation('请先绑定您的手机号');
  143. }
  144. if ((int)$user->is_card_certified === User::CARD_NO) {
  145. return $this->errorNoValidation('请您先完善实名认证');
  146. }
  147. if ((int)$user->is_match_ride_age === User::RIDE_BIKE_AGE_NO) {
  148. return $this->errorNoValidation('未成年人禁止骑车');
  149. }
  150. // $area = $areaRepository->byIdGetModelRedis($area_id);
  151. // if ($area) {
  152. // return $this->errorNoValidation('暂无运营区域!');
  153. // }
  154. $setting = $areaSettingRepository->byAreaId($area_id);
  155. if ($setting['is_advance_recharge'] && $user->wallet_money <= 0) {
  156. return $this->errorNoValidation('余额不足,请先充值');
  157. }
  158. // 判断用户是否有为支付的订单
  159. if ($orderRepository->byUserIdCheckIsExistRideOrder($user->id)) {
  160. return $this->errorNoValidation('您有未完成的订单,请先处理');
  161. }
  162. if ($setting['is_open_day_rent'] && $rentOrderRepository->byUserIdCheckIsExistNoPayOrder($user->id)) {
  163. return $this->errorNoValidation('您有未支付的租车订单,请先处理');
  164. }
  165. // 判断车的状态是正常
  166. if (!$bikeRepository->isBikeCanRide($bike_id)) {
  167. return $this->errorNoValidation('该车暂不能用');
  168. }
  169. // 判断用户是否在车的距离范围内
  170. $bike = $bikeRepository->byIdGetModel($bike_id);
  171. //以车的区域为主
  172. if ($bike->put_area_id !== $area_id) {
  173. $area_id = $bike->put_area_id;
  174. $setting = $areaSettingRepository->byAreaId($area_id);
  175. if ($setting['is_advance_recharge'] && $user->wallet_money <= 0) {
  176. return $this->errorNoValidation('余额不足,请先充值');
  177. }
  178. if ($setting['is_open_day_rent'] && $rentOrderRepository->byUserIdCheckIsExistNoPayOrder($user->id)) {
  179. return $this->errorNoValidation('您有未支付的租车订单,请先处理');
  180. }
  181. }
  182. $options = ['SORT' => 'ASC'];
  183. $redis = Redis::connection();
  184. $nearby_bikes = $redis->georadius(Bike::REDIS_BIKE_LOCATION_TAG, $lng, $lat, 1, 'km', $options);
  185. if (!in_array($bike->bike_no, $nearby_bikes)) {
  186. // return $this->errorNoValidation('小主,咱俩有点远!');
  187. }
  188. $box_no = $bikeRepository->byNoGetBoxNO($bike_no);
  189. try {
  190. $order = DB::transaction(function () use ($bikeRepository, $user, $bike_no, $bike_id, $area_id, $lat, $lng, $box_no) {
  191. $users = User::find($user['id']);
  192. // 创建订单
  193. $data = [
  194. 'user_id' => $user['id'],
  195. 'no' => Order::makeNo(),
  196. 'bike_no' => $bike_no,
  197. 'bike_id' => $bike_id,
  198. 'area_id' => $area_id,
  199. 'phone_detail' => $users->userPhoneDetail->detail ?? '',
  200. 'start_use_bike_time' => now(),
  201. 'start_use_bike_location' => [
  202. 'latitude' => $lat,
  203. 'longitude' => $lng,
  204. ],
  205. 'status' => Order::STATUS_RIDE_BIKE
  206. ];
  207. $order = Order::create($data);
  208. // 开锁
  209. BikeControl::openLock($box_no);
  210. // 记录日志信息
  211. OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_OPEN_BIKE, $bike_id, $user->id, $lat, $lng);
  212. // 更新车的信息(真在骑行中)
  213. $bikeRepository->byIdUpdateRideOk($bike_id);
  214. // 更新orders redis
  215. (new BikeStatusInfoSyncHandler())->toBikeRideStatus(BikeStatusInfoSyncHandler::ROLE_USER, $bike_no, [
  216. 'id' => $order->id,
  217. 'bike_id' => $order->bike_id,
  218. 'area_id' => $order->area_id
  219. ]);
  220. return $order;
  221. });
  222. BikeControl::openLock($box_no);
  223. if (!$user->register_area_id) {
  224. $user->register_area_id = $area_id;
  225. $user->save();
  226. }
  227. } catch (\Exception $exception) {
  228. return $this->errorNoValidation($exception->getMessage());
  229. }
  230. return $this->response->item($order, OrderTransformer::class);
  231. }
  232. /**
  233. * 结束订单
  234. * User: Mead
  235. */
  236. public function closeLock(BikeCloseOrderRequest $request, OrderRepository $orderRepository, AreaSettingRepository $areaSettingRepository, BikeRepository $bikeRepository, LocationLogRepository $locationLogRepository)
  237. {
  238. try {
  239. $bike_no = $request->get('bike_no');
  240. $order_no = $request->get('order_no');
  241. $lat = $request->get('lat');
  242. $lng = $request->get('lng');
  243. $order = $orderRepository->byNoGetRideOrder($order_no);
  244. if (!$order) {
  245. return $this->errorNoValidation('订单不存在或订单已结算');
  246. }
  247. $user_id = $this->user->id;
  248. $cache_key = "RIDE_CLOSE_ORDER_{$user_id}";
  249. if (Cache::has($cache_key)) {
  250. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  251. }
  252. Cache::put($cache_key, 1, Carbon::now()->addSeconds(3));
  253. // 30秒内关车,关闭订单
  254. $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time));
  255. if ($second < AreaSetting::CLOSE_BIKE_TIME) {
  256. // 检查用户是否恶意临时关锁
  257. if ($orderRepository->checkUserMoreCloseOrder($this->user->id)) {
  258. return $this->errorNoValidation('您今天太频繁操作车辆');
  259. }
  260. }
  261. $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no);
  262. //获取车的最后位置
  263. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no);
  264. //运动中不能锁车
  265. if ($location['speed']) {
  266. BikeControl::nowBikeLocation($box_no);
  267. // return $this->errorNoValidation('运动中不能关锁', 450);
  268. }
  269. // 更新车的信息
  270. $bikeModel = $bikeRepository->byIdGetModel($order->bike_id);
  271. $bikeModel->is_riding = Bike::RIDING_NO;
  272. $bikeModel->last_use_bike_end_time = date('Y-m-d H:i:s');
  273. $bikeModel->save();
  274. // 删除redis订单
  275. if ($location['lat'] <= 0) {
  276. $location['lat'] = $lat;
  277. $location['lng'] = $lng;
  278. }
  279. // 删除临时停车key
  280. $key = sprintf(CacheMap::BIKE_TEM_WAIT, $bike_no);
  281. app()->redis->del($key);
  282. // 判断是否经常这样操作(未做)
  283. if ($second <= AreaSetting::CLOSE_BIKE_TIME) {
  284. BikeControl::closeLock($box_no);
  285. // 记录日志信息
  286. OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_CLONE_BIKE, $order->bike_id, $this->user->id, $lat, $lng);
  287. // 关闭订单
  288. $order->status = Order::STATUS_CLOSE_ORDER;
  289. $order->end_use_bike_time = now();
  290. $order->end_use_bike_location = [
  291. 'latitude' => $lat,
  292. 'longitude' => $lng,
  293. ];
  294. $order->save();
  295. //更新redis状态
  296. (new BikeStatusInfoSyncHandler())->toBikeWaitRideStatus($bike_no, $location['lng'], $location['lat']);
  297. // 记录临时关锁
  298. return $this->response->item($order, OrderTransformer::class);
  299. } else {
  300. BikeControl::closeLock($box_no);
  301. // 记录日志信息
  302. OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_CLONE_BIKE, $order->bike_id, $this->user->id, $lat, $lng);
  303. }
  304. // 保存轨迹信息
  305. // 结束订单
  306. $setting = $areaSettingRepository->byAreaId($order->area_id);
  307. // 是否处于临时停车的状态
  308. if ((int)$order->status === Order::STATUS_PAUSE_BIKE) {
  309. $order->pause_bike_time_length += Carbon::now()->diffInMinutes(Carbon::parse($order->pause_bike_time));
  310. }
  311. $order->status = Order::STATUS_CLOSE_BIKE;
  312. $order->end_use_bike_time = now();
  313. $order->end_use_bike_location = [
  314. 'latitude' => $lat,
  315. 'longitude' => $lng,
  316. ];
  317. //计算用车时间
  318. $order->use_bike_time_length = ceil($second / 60);
  319. // 计算价格
  320. $time_money = $setting->per_money * ceil($order->use_bike_time_length / $setting->per_minute);
  321. if ($time_money < 0) {
  322. $time_money = 0;
  323. }
  324. //计算骑行距离
  325. $order->use_bike_distance_length = bcdiv($location['mileage'], 1000, 2);
  326. // 根据起始点计算
  327. // $order->use_bike_distance_length = getDistance($order->start_use_bike_location['longitude'], $order->start_use_bike_location['latitude'], $order->end_use_bike_location['longitude'], $order->end_use_bike_location['latitude']);
  328. // 判断车是否在停车的区域
  329. $order->dispatch_money = 0;
  330. if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_NO) {
  331. $BikeHandler = new BikeHandler();
  332. $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id);
  333. $bikeModel->is_in_parking = Bike::IN_PARKING_YES;
  334. if (!$is_huanche['status']) {
  335. // 不在还车点
  336. $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting);
  337. $order->dispatch_money = $dispatch_money;
  338. $bikeModel->is_in_parking = Bike::IN_PARKING_NO;
  339. }
  340. } else {
  341. //全区域内可停
  342. $bikeModel->is_in_parking = Bike::IN_PARKING_YES;
  343. }
  344. $order->time_money = $time_money;
  345. $order->pause_money = 0;
  346. $order->preferential_money = 0;
  347. $order->order_money = bcadd($time_money, $order->dispatch_money, 2);
  348. $order->pay_money = $order->order_money;
  349. $order->pay_type = Order::PAY_STATUS_NO;
  350. $order->total_money = bcadd($time_money, $order->dispatch_money, 2);
  351. $order->save();
  352. $bikeModel->save();
  353. //更新redis状态
  354. (new BikeStatusInfoSyncHandler())->toBikeWaitRideStatus($bike_no, $location['lng'], $location['lat']);
  355. //关锁
  356. BikeControl::closeLock($box_no);
  357. // 记录日志信息
  358. // OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_CLONE_BIKE, $order->bike_id, $this->user->id, $lat, $lng);
  359. return $this->response->item($order, OrderTransformer::class);
  360. } catch (HttpException $exception) {
  361. return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode());
  362. }
  363. }
  364. /**
  365. * 临时关锁
  366. * User: Mead
  367. */
  368. public function temporaryCloseLock(BikeCloseOrderRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository, LocationLogRepository $locationLogRepository)
  369. {
  370. $bike_no = $request->get('bike_no');
  371. $order_no = $request->get('order_no');
  372. $lat = $request->get('lat');
  373. $lng = $request->get('lng');
  374. try {
  375. $user = $this->user;
  376. $order = $orderRepository->byNoGetRideOrder($order_no);
  377. if (!$order) {
  378. return $this->errorBadRequest('请求非法');
  379. }
  380. $user_id = $this->user->id;
  381. $cache_key = "ORDER_TEMPORARY_CLOSE_BIKE_{$user_id}";
  382. if (Cache::has($cache_key)) {
  383. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  384. }
  385. Cache::put($cache_key, 1, Carbon::now()->addSeconds(3));
  386. //获取车的最后位置
  387. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no);
  388. $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no);
  389. // //运动中不能锁车
  390. if ($location['speed']) {
  391. BikeControl::nowBikeLocation($box_no);
  392. // return $this->errorNoValidation('运动中不能关锁', 450);
  393. }
  394. $order->status = Order::STATUS_PAUSE_BIKE;
  395. $order->pause_bike_time = now();
  396. $order->save();
  397. // 关锁
  398. BikeControl::temporaryCloseLock($box_no);
  399. // 记录日志信息
  400. OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_PAUSE_CLONE_BIKE, $order->bike_id, $user->id, $lat, $lng);
  401. //修改rides
  402. (new BikeStatusInfoSyncHandler())->toBikeTemporaryWaitRideStatus($bike_no);
  403. // 延迟分发一个临时停车超过30分 提醒队列
  404. $key = sprintf(CacheMap::BIKE_TEM_WAIT, $bike_no);
  405. app()->redis->setex($key, CacheMap::BIKE_TEM_WAIT_TIME, Carbon::now());
  406. $mobile = $user->mobile;
  407. $start_use_time = $order->start_use_bike_time;
  408. $this->dispatch(new SendSMSBikeTemporaryWaitOverThirtyJob($mobile, $bike_no, $start_use_time, $key, Carbon::now()->addMinutes(30)));
  409. return $this->response->array([
  410. 'is_close_lock' => true
  411. ]);
  412. } catch (HttpException $exception) {
  413. return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode());
  414. }
  415. }
  416. /**
  417. * 临时开锁
  418. * User: Mead
  419. */
  420. public function temporaryOpenLock(BikeCloseOrderRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository)
  421. {
  422. try {
  423. $bike_no = $request->get('bike_no');
  424. $order_no = $request->get('order_no');
  425. $lat = $request->get('lat');
  426. $lng = $request->get('lng');
  427. $user = $this->user;
  428. $order = $orderRepository->byNoGetRideOrder($order_no);
  429. if (!$order) {
  430. return $this->errorNoValidation('订单不存在或订单已结算');
  431. }
  432. $user_id = $this->user->id;
  433. $cache_key = "ORDER_TEMPORARY_OPEN_BIKE_{$user_id}";
  434. if (Cache::has($cache_key)) {
  435. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  436. }
  437. Cache::put($cache_key, 1, Carbon::now()->addSeconds(3));
  438. $order->status = Order::STATUS_RIDE_BIKE;
  439. $order->pause_bike_time_length += Carbon::now()->diffInMinutes(Carbon::parse($order->pause_bike_time));
  440. $order->save();
  441. // 开锁
  442. $box_no = $bikeRepository->byNoGetBoxNO($bike_no);
  443. BikeControl::temporaryOpnLock($box_no);
  444. // 记录日志信息
  445. OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_PAUSE_OPEN_BIKE, $order->bike_id, $user->id, $lat, $lng);
  446. (new BikeStatusInfoSyncHandler())->toBikeTemporaryRideStatus($bike_no);
  447. // 删除临时停车时得缓存key
  448. $key = sprintf(CacheMap::BIKE_TEM_WAIT, $bike_no);
  449. app()->redis->del($key);
  450. return $this->response->array([
  451. 'is_open_lock' => true
  452. ]);
  453. } catch (HttpException $exception) {
  454. return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode());
  455. }
  456. }
  457. /**
  458. * 判断是否在运营范围
  459. * Author: Mead
  460. */
  461. public function checkBikeIsRidingArea(BikeCloseOrderRequest $request, BikeRepository $bikeRepository, OrderRepository $orderRepository, LocationLogRepository $locationLogRepository, AreaRepository $areaRepository)
  462. {
  463. $bike_no = $request->get('bike_no');
  464. $order_no = $request->get('order_no');
  465. $lat = $request->get('lat');
  466. $lng = $request->get('lng');
  467. try {
  468. $order = $orderRepository->byNo($order_no);
  469. if (!$order) return $this->errorBadRequest('非法请求');
  470. $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time));
  471. if ($second < AreaSetting::CLOSE_BIKE_TIME) {
  472. //小于60秒直接锁车
  473. return [
  474. 'is_close_order' => true,
  475. ];
  476. }
  477. $user_id = $this->user['id'];
  478. $cache_key = "ORDER_CHECK_BIKE_IS_RIDINGAREA_{$user_id}";
  479. if (Cache::has($cache_key)) {
  480. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  481. }
  482. Cache::put($cache_key, 1, Carbon::now()->addSeconds(3));
  483. $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no);
  484. BikeControl::nowBikeLocation($box_no);
  485. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no);
  486. if ($location['lat'] <= 0) {
  487. $location['lat'] = $lat;
  488. $location['lng'] = $lng;
  489. }
  490. $area = $areaRepository->byIdGetModelRedis($order->area_id);
  491. //检查是否有运营区域
  492. if (!$area) {
  493. return $this->errorNoValidation('暂无运营区域!');
  494. }
  495. //检查是否在骑行区域
  496. $is_out_area = $this->isOutArea($location['lat'], $location['lng'], $area);
  497. if (!$is_out_area) {
  498. return $this->errorNoValidation('超出骑行区域,暂不能锁车');
  499. }
  500. $BikeHandler = new BikeHandler();
  501. //检查是否在禁停区
  502. $is_ban_stop_bike = $BikeHandler->byLocationCheckIsInBanStopParking($location['lat'], $location['lng'], $order->area_id);
  503. if ($is_ban_stop_bike) {
  504. return $this->errorNoValidation('禁停区域内禁止停车!');
  505. }
  506. return [
  507. 'is_close_order' => false,
  508. ];
  509. } catch (HttpException $exception) {
  510. return $this->errorNoValidation($exception->getMessage());
  511. }
  512. }
  513. /**
  514. * 检查是否在还车点
  515. * @param BikeCloseOrderRequest $request
  516. * @param OrderRepository $orderRepository
  517. * @param ParkingRepository $parkingRepository
  518. * @param AreaSettingRepository $areaSettingRepository
  519. * User: Mead
  520. */
  521. public function checkBikeIsInStopParking(BikeCloseOrderRequest $request, BikeRepository $bikeRepository, OrderRepository $orderRepository, AreaSettingRepository $areaSettingRepository, LocationLogRepository $locationLogRepository, AreaRepository $areaRepository)
  522. {
  523. $bike_no = $request->get('bike_no');
  524. $order_no = $request->get('order_no');
  525. $lat = $request->get('lat');
  526. $lng = $request->get('lng');
  527. try {
  528. $order = $orderRepository->byNo($order_no);
  529. if (!$order) return $this->errorBadRequest('非法请求');
  530. $user_id = $this->user['id'];
  531. $cache_key = "ORDER_CHECK_BIKE_IS_PARK_{$user_id}";
  532. if (Cache::has($cache_key)) {
  533. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  534. }
  535. Cache::put($cache_key, 1, Carbon::now()->addSeconds(3));
  536. $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no);
  537. BikeControl::nowBikeLocation($box_no);
  538. $setting = $areaSettingRepository->byAreaId($order->area_id);
  539. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no);
  540. if ($location['lat'] <= 0) {
  541. $location['lat'] = $lat;
  542. $location['lng'] = $lng;
  543. }
  544. // // 判断是否在运动中
  545. // if ($location['speed']) {
  546. // return $this->errorNoValidation('运动中不能关锁', 450);
  547. // }
  548. $area = $areaRepository->byIdGetModelRedis($order->area_id);
  549. //检查是否有运营区域
  550. if (!$area) {
  551. return $this->errorNoValidation('暂无运营区域!');
  552. }
  553. //检查是否在骑行区域
  554. $is_out_area = $this->isOutArea($location['lat'], $location['lng'], $area);
  555. if (!$is_out_area) {
  556. return $this->errorNoValidation('超出骑行区域,暂不能锁车');
  557. }
  558. $BikeHandler = new BikeHandler();
  559. //检查是否在禁停区
  560. $is_ban_stop_bike = $BikeHandler->byLocationCheckIsInBanStopParking($location['lat'], $location['lng'], $order->area_id);
  561. if ($is_ban_stop_bike) {
  562. return $this->errorNoValidation('禁停区域内禁止停车!');
  563. }
  564. //判断是否全区域内可停
  565. if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_OK) {
  566. return [
  567. 'is_dispatch' => true,
  568. 'is_stop_bike' => true,
  569. 'dispatch_money' => 0,
  570. ];
  571. }
  572. // 判断是否在停车点
  573. $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id);
  574. if (!$is_huanche['status']) {
  575. BikeControl::nowBikeLocation($box_no);
  576. // 不在还车点
  577. $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting);
  578. return [
  579. 'is_dispatch' => false,
  580. 'is_stop_bike' => false,
  581. 'dispatch_money' => $dispatch_money,
  582. ];
  583. }
  584. return [
  585. 'is_dispatch' => true,
  586. 'is_stop_bike' => true,
  587. 'dispatch_money' => 0,
  588. ];
  589. } catch (HttpException $exception) {
  590. return $this->errorNoValidation($exception->getMessage());
  591. }
  592. }
  593. /**
  594. * 判断是否在骑行区
  595. * @param $lat
  596. * @param $lng
  597. * @param $box_no
  598. * User: Mead
  599. */
  600. private function isOutArea($lat, $lng, $area)
  601. {
  602. try {
  603. $location = [
  604. 'latitude' => $lat,
  605. 'longitude' => $lng,
  606. ];
  607. $fences = $area['area_fence'];
  608. $centre = $area['area_centre'];
  609. $radius = $area['area_radius'];
  610. $area_fushe_fence = $area['area_fushe_fence'];
  611. // 判断是否在骑行区域
  612. $ConvertHandler = (new ConvertHandler());
  613. $is_out_area = $ConvertHandler->is_point_in_polygon($location, $fences);
  614. return $is_out_area;
  615. } catch (\Exception $exception) {
  616. return $this->errorNoValidation($exception->getMessage());
  617. }
  618. // // 判断是否骑出辐射范围
  619. // $is_out_area_nearby = true;
  620. // if (!$is_out_area) {
  621. // $is_out_area_nearby = $ConvertHandler->is_point_in_polygon($location, $area_fushe_fence);
  622. // }
  623. //
  624. // return [
  625. // 'is_out_area' => $is_out_area,
  626. // 'is_out_area_nearby' => $is_out_area_nearby
  627. // ];
  628. }
  629. }