You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
6.4 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Service\v3\Implementations;
  3. use App\Constants\v3\ErrorCode;
  4. use App\Exception\ErrorCodeException;
  5. use App\Model\v3\UserCollection;
  6. use App\Service\v3\Interfaces\LocationServiceInterface;
  7. use App\Model\v3\Area;
  8. use App\Model\v3\Market;
  9. use GuzzleHttp\Client;
  10. use GuzzleHttp\Exception\GuzzleException;
  11. use Hyperf\Guzzle\ClientFactory;
  12. use Hyperf\Utils\ApplicationContext;
  13. class LocationService implements LocationServiceInterface
  14. {
  15. public function do()
  16. {
  17. // TODO: Implement do() method.
  18. }
  19. public function check()
  20. {
  21. // TODO: Implement check() method.
  22. }
  23. public function undo()
  24. {
  25. // TODO: Implement undo() method.
  26. }
  27. public function getMarketListByLocation($lng,$lat)
  28. {
  29. $cityIds = Market::query()->where(['status' => 1])->pluck('city_id');
  30. $res = Area::query()->with('markets')->whereIn('id',$cityIds)->get();
  31. foreach ($res as &$v){
  32. if(!empty($lng) && !empty($lat)) {
  33. $v->distance_num = $this->getDistance($v->lng, $v->lat, $lng, $lat);
  34. $v->distance = $v->distance_num . ' km';
  35. } else {
  36. $v->distance_num = 0;
  37. $v->distance = '';
  38. }
  39. foreach ($v->markets as &$m)
  40. {
  41. if(!empty($lng) && !empty($lat)){
  42. $m->distance_num = $this->getDistance($m->lng, $m->lat, $lng, $lat);
  43. $m->distance = $m->distance_num.' km';
  44. }else{
  45. $m->distance_num = 0;
  46. $m->distance = '';
  47. }
  48. }
  49. }
  50. $res = collect($res->toArray())->sortBy(function ($area, $key) {
  51. return $area['distance_num'];
  52. });
  53. $res = collect($res->all())->map(function ($area, $key) {
  54. $markets = collect($area['markets'])->sortBy('distance_num');
  55. $area['markets'] = $markets->values()->all();
  56. return $area;
  57. });
  58. return $res->all();
  59. }
  60. public function searchMarket($keywords,$lng,$lat,$cityId = 2163)
  61. {
  62. $res = Market::query()->where([
  63. ['name','like','%'.$keywords.'%'],
  64. ['city_id','=',$cityId]
  65. ])
  66. ->get();
  67. foreach ($res as &$m){
  68. if(!empty($lng) && !empty($lat)){
  69. $m->distance_num = $this->getDistance($m->lng, $m->lat, $lng, $lat);
  70. $m->distance = $m->distance_num.' km';
  71. }else{
  72. $m->distance_num = 0;
  73. $m->distance = '';
  74. }
  75. }
  76. $res = collect($res)->sortBy('distance_num');
  77. return $res->values()->all();
  78. }
  79. public function getNearestMarket($lng,$lat)
  80. {
  81. $markets = Market::query()->where(['status' => 1])->get()->toArray();
  82. $result = [];
  83. $distinctMin = 0;
  84. foreach ($markets as &$market){
  85. $distinct = $this->getDistance($lng,$lat,$market['lng'],$market['lat'],1);
  86. $market['distinct'] = round(($distinct/1000),2).' km';
  87. if($distinct < $distinctMin || $distinctMin === 0) {
  88. $distinctMin = $distinct;
  89. $result = $market;
  90. }
  91. }
  92. return $result;
  93. }
  94. /**
  95. * @param $lng1
  96. * @param $lat1
  97. * @param $lng2
  98. * @param $lat2
  99. * @param int $unit 单位 1: 2:公里
  100. * @param int $decimal 精度 保留小数位数
  101. * @return false|float
  102. */
  103. public function getDistance($lng1, $lat1, $lng2, $lat2, $unit = 2, $decimal = 2)
  104. {
  105. $EARTH_RADIUS = 6370.996; // 地球半径系数
  106. $PI = 3.1415926535898;
  107. $radLat1 = $lat1 * $PI / 180.0;
  108. $radLat2 = $lat2 * $PI / 180.0;
  109. $radLng1 = $lng1 * $PI / 180.0;
  110. $radLng2 = $lng2 * $PI / 180.0;
  111. $a = $radLat1 - $radLat2;
  112. $b = $radLng1 - $radLng2;
  113. $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
  114. $distance = $distance * $EARTH_RADIUS * 1000;
  115. if ($unit === 2) {
  116. $distance /= 1000;
  117. }
  118. return round($distance, $decimal);
  119. }
  120. //获取服务站信息
  121. function getMarketsInfo()
  122. {
  123. return Market::where('status',1)->get();
  124. }
  125. //获取骑行距离
  126. public function getDistanceByTencent($lng1, $lat1, $lng2, $lat2)
  127. {
  128. $url = 'https://apis.map.qq.com/ws/distance/v1/matrix/?mode=';
  129. /**
  130. * $tyep driving 驾车 walking 步行 bicycling 骑行 transit 公交
  131. */
  132. $type = 'bicycling';
  133. $key = config('map.tencent');
  134. $client = new Client();
  135. $response = $client->request('GET', $url.$type.'&from='.$lat1.','.$lng1.'&to='.$lat2.','.$lng2.'&output=json&key='.$key);
  136. $response = $response->getBody()->getContents();
  137. $resultArr = json_decode($response,true);
  138. if($resultArr['status'] > 0)
  139. {
  140. throw new ErrorCodeException(ErrorCode::LOCATION_ERROR,$resultArr['message']);
  141. }
  142. $distance = $resultArr['result']['rows'][0]['elements'][0]['distance'];
  143. return $distance;
  144. }
  145. /**
  146. * 根据关键词进行地址提示
  147. * 返回地址数据
  148. * @param $keyword
  149. * @param string $marketId
  150. * @param int $page
  151. * @param int $pageSize
  152. * @return string
  153. * @throws GuzzleException
  154. */
  155. public function placeSuggestion($keyword, $marketId = '', $page = 1, $pageSize = 10)
  156. {
  157. $apiPath = 'https://apis.map.qq.com/ws/place/v1/suggestion';
  158. $queryString = 'page_index='.urlencode($page).'&page_size='.urlencode($pageSize).'&policy=1&keyword='.urlencode($keyword).'&key='.config('map.tencent');
  159. // 获取当前市场所在城市
  160. if ($marketId) {
  161. $cityId = Market::query()->where(['id' => $marketId])->value('city_id');
  162. $cityName = Area::query()->where(['id' => $cityId])->value('name');
  163. if ($cityName) {
  164. $queryString .= '&region='.urlencode($cityName);
  165. }
  166. }
  167. $client = ApplicationContext::getContainer()->get(ClientFactory::class)->create();
  168. $response = $client->request('GET', $apiPath.'?'.$queryString);
  169. $res = $response->getBody()->getContents();
  170. $res = json_decode($res, true);
  171. if ($res['status'] != 0) {
  172. throw new ErrorCodeException($res['status'], $res['message']);
  173. }
  174. return $res;
  175. }
  176. }