Didi.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <?php
  2. namespace common\components\delivery\platform\didi;
  3. use common\components\delivery\helpers\HttpClient;
  4. class Didi
  5. {
  6. protected $baseUrl;
  7. protected $appKey; // URL参数中的appKey
  8. protected $appId; // Body参数中的appId
  9. protected $appSecret; // 签名用的secret
  10. protected $accessToken;
  11. protected $thirdUid;
  12. protected $apiVersion = '1.0.0';
  13. public function __construct($accessToken = '', $thirdUid='')
  14. {
  15. if (getenv('YII_ENV') == 'production') {
  16. $cfg = [
  17. 'base_url' => 'https://freight.xiaojukeji.com',
  18. 'app_key' => '6724e08ff1ac4afdbf1c000cfe722449',
  19. 'app_id' => 'MDdovjIS',
  20. 'secret' => 'b61603625ebcf69a6364fdc30ae47944630c738c',
  21. ];
  22. } else {
  23. $cfg = [
  24. 'base_url' => 'http://pinzhi.didichuxing.com/kop_osim',
  25. 'app_key' => '4329d266f40144829ca5fd47a025e106',
  26. 'app_id' => 'MDdovjIS',
  27. 'secret' => 'b61603625ebcf69a6364fdc30ae47944630c738c',
  28. ];
  29. }
  30. $this->baseUrl = $cfg['base_url'];
  31. $this->appKey = $cfg['app_key'];
  32. $this->appId = $cfg['app_id'];
  33. $this->appSecret = $cfg['secret'];
  34. $this->accessToken = $accessToken;
  35. $this->thirdUid = $thirdUid;
  36. }
  37. /**
  38. * 开通城市查询
  39. * @param int|null $cityId 城市id(城市编码,经纬度二传一) 国标码
  40. * @param float|null $longitude 经度 火星坐标系(高德)
  41. * @param float|null $latitude 纬度 火星坐标系(高德)
  42. * @return array
  43. */
  44. public function queryCityInfo($cityId = null, $longitude = null, $latitude = null)
  45. {
  46. // 暂时仅支持快送业务查询,bizType 固定为 12
  47. $businessParams = [
  48. 'bizType' => 12,
  49. ];
  50. if (!empty($cityId)) {
  51. $businessParams['cityId'] = (int)$cityId;
  52. }
  53. // 拉货有城市开城但部分区域不支持的情况,如不传经纬度则按照城市返回
  54. if (!empty($longitude) && !empty($latitude)) {
  55. $businessParams['longitude'] = (float)$longitude;
  56. $businessParams['latitude'] = (float)$latitude;
  57. }
  58. $payload = $this->buildRequestPayload($businessParams);
  59. $url = $this->getApiUrl('freight.open.platform.channel.standard.queryCityInfo');
  60. $headers = ["Content-Type" => "application/x-www-form-urlencoded"];
  61. $resp =HttpClient::post($url, $payload, $headers);
  62. if($resp['code'] == 200 && isset($resp['result'])){
  63. return $resp['result'];
  64. }
  65. return [];
  66. }
  67. /**
  68. * 查询钱包余额
  69. * @return array
  70. */
  71. public function walletBalance()
  72. {
  73. $payload = $this->buildRequestPayload([]);
  74. $url = $this->getApiUrl('freight.open.platform.channel.standard.walletBalance');
  75. $headers = ["Content-Type" => "application/x-www-form-urlencoded"];
  76. $resp = HttpClient::post($url, $payload, $headers);
  77. if ($resp['code'] == 200 && isset($resp['data']['balance'])) {
  78. return [
  79. 'success' => true,
  80. 'balance' => round($resp['data']['balance'], 2),
  81. 'message' => $resp['msg'] ?? '查询余额成功',
  82. ];
  83. }
  84. return [
  85. 'success' => false,
  86. 'balance' => 0,
  87. 'message' => $resp['msg'] ?? '查询余额失败',
  88. ];
  89. }
  90. /**
  91. * 构建API请求参数
  92. *
  93. * @param array $businessParams 业务参数
  94. * @return array
  95. */
  96. public function buildRequestPayload($businessParams = [])
  97. {
  98. // 1. 准备公共参数
  99. $timestamp = (int)(microtime(true) * 1000); // 毫秒级时间戳
  100. // 2. 处理业务参数 logisticsParam (JSON字符串)
  101. $logisticsParam = json_encode($businessParams, JSON_UNESCAPED_UNICODE); // 注意:根据文档,logisticsParam 是 json 字符串
  102. // 3. 生成签名
  103. $sign = $this->generateSignature($logisticsParam, $timestamp);
  104. // 4. 构建最终请求体
  105. $payload = [
  106. 'appId' => $this->appId,
  107. 'timestamp' => $timestamp,
  108. 'appSign' => $sign,
  109. 'logisticsParam' => $logisticsParam,
  110. ];
  111. // Token 可选,如果存在则添加
  112. if (!empty($this->accessToken)) {
  113. $payload['token'] = $this->accessToken;
  114. }
  115. // 默认自主模式 businessMode=0,如果有需要可扩展
  116. // $payload['businessMode'] = 0;
  117. return $payload;
  118. }
  119. /**
  120. * 生成签名
  121. * 签名规则:MD5(logisticsParam + secret + timestamp)
  122. *
  123. * @param string $logisticsParam json字符串
  124. * @param int $timestamp 毫秒时间戳
  125. * @return string
  126. */
  127. public function generateSignature($logisticsParam, $timestamp)
  128. {
  129. $str = $logisticsParam . $this->appSecret . $timestamp;
  130. return md5($str);
  131. }
  132. /**
  133. * 获取完整的API请求URL
  134. *
  135. * @param string $apiMethod API名称
  136. * @return string
  137. */
  138. public function getApiUrl($apiMethod)
  139. {
  140. // url格式:{host}/gateway?api=xxx&apiVersion=1.0.0&appKey=xxx
  141. $queryParams = [
  142. 'api' => $apiMethod,
  143. 'apiVersion' => $this->apiVersion,
  144. 'appKey' => $this->appKey,
  145. ];
  146. return $this->baseUrl . '/gateway?' . http_build_query($queryParams);
  147. }
  148. /**
  149. * 生成唯一的跑腿订单号
  150. * @param $orderId
  151. * @return string
  152. */
  153. public static function generateUniOroder($orderId, $timeStamp)
  154. {
  155. return $orderId . '-' . $timeStamp;
  156. }
  157. /**
  158. * 还原为数据库中的订单号
  159. * @param $orderId
  160. * @return false|string
  161. */
  162. public static function getSystemOrder($orderId)
  163. {
  164. $pos = strpos($orderId, '-');
  165. if ($pos !== false) { // 确实找到了
  166. $left = substr($orderId, 0, $pos); // a-b-c
  167. $right = substr($orderId, $pos + 1); // d
  168. } else {
  169. $left = $orderId; // 没有 -
  170. $right = '';
  171. }
  172. return $left;
  173. }
  174. /**
  175. * 车型
  176. * @param $number 车型编号
  177. * @return string
  178. */
  179. public function carType($number)
  180. {
  181. $map = [
  182. //拉货车型
  183. 1001 => '小面包',
  184. 1002 => '中面包',
  185. 1003 => '小型平板',
  186. 1004 => '中型平板',
  187. 1005 => '4.2米平板',
  188. 1006 => '依维柯',
  189. 1007 => '4.2米厢货',
  190. 1008 => '5.2米货车',
  191. 1009 => '6.8米货车',
  192. 1010 => '7.6米货车',
  193. 1011 => '13米货车',
  194. 1012 => '微面',
  195. 1013 => '小厢货',
  196. 1014 => '中厢货',
  197. 1015 => '小高栏',
  198. 1016 => '4.2米高栏',
  199. 1019 => '9.6米货车',
  200. 1020 => '三轮车',
  201. 1022 => '集装箱卡车',
  202. 1023 => '微平板',
  203. 1024 => '微厢货',
  204. 1025 => '微高栏',
  205. 1026 => '中高栏',
  206. 1028 => '17.5米',
  207. 1029 => '16米',
  208. 1030 => '15米',
  209. 1031 => '13.5米',
  210. //快送车型
  211. 1017 => '小轿车',
  212. 1018 => '两轮车',
  213. ];
  214. return isset($map[$number]) ? $map[$number] : $number;
  215. }
  216. }