Kirin 2 місяців тому
батько
коміт
65bb5bf40b

+ 1 - 1
app/controller/admin/system/config/SystemConfigTab.php

@@ -47,7 +47,7 @@ class SystemConfigTab extends AdminBaseController
             'status',
             ['title', ''],
             ['en_title', ''],
-            'icon',
+            ['icon', ''],
             ['sort', 0],
             ['info', ''],
             ['pid', 0],

+ 44 - 27
route/api.php

@@ -9,43 +9,48 @@
 use app\http\middleware\AllowOriginMiddleware;
 use app\http\middleware\api\AuthTokenMiddleware;
 use app\http\middleware\api\BlockerMiddleware;
+use app\http\middleware\api\LocationMiddleware;
+use app\http\middleware\api\MemberTypeMiddleware;
 use app\http\middleware\StationOpenMiddleware;
 use think\facade\Route;
 
 Route::group('api', function () {
+    //城市列表
+    Route::get('city', 'Pub/city');
+    //城市列表
+    Route::get('cityList', 'Pub/cityList');
+    //APP版本号
+    Route::get('version', 'Pub/version');
+    //登陆相关
+    Route::group(function () {
+        //账号密码登录
+        Route::post('login', 'Login/login')->name('login');
+        //注册
+        Route::post('register', 'Login/register')->name('register');
+        //获取发短信的key
+        Route::get('verify_code', 'Login/verifyCode')->name('verifyCode');
+        //手机号登录
+        Route::post('login/mobile', 'Login/mobile')->name('loginMobile');
+        //图片验证码
+        Route::get('sms_captcha', 'Login/captcha')->name('captcha');
+        //验证码发送
+        Route::post('verify', 'Login/verify')->name('registerVerify');
+        //手机号修改密码
+        Route::post('pwd/reset', 'Login/reset')->name('resetPwd');
+        //图形验证码
+        Route::get('ajcaptcha', 'Login/ajcaptcha')->name('ajcaptcha');
+        //图形验证码
+        Route::post('ajcheck', 'Login/ajcheck')->name('ajcheck');
+    });
+    //定位接口
     Route::group(function () {
-        //城市列表
-        Route::get('city', 'Pub/city');
-        //APP版本号
-        Route::get('version', 'Pub/version');
-
-        //登陆相关
-        Route::group(function () {
-            //账号密码登录
-            Route::post('login', 'Login/login')->name('login');
-            //获取发短信的key
-            Route::get('verify_code', 'Login/verifyCode')->name('verifyCode');
-            //手机号登录
-            Route::post('login/mobile', 'Login/mobile')->name('loginMobile');
-            //图片验证码
-            Route::get('sms_captcha', 'Login/captcha')->name('captcha');
-            //验证码发送
-            Route::post('verify', 'Login/verify')->name('registerVerify');
-            //手机号修改密码
-            Route::post('pwd/reset', 'Login/reset')->name('resetPwd');
-            //图形验证码
-            Route::get('ajcaptcha', 'Login/ajcaptcha')->name('ajcaptcha');
-            //图形验证码
-            Route::post('ajcheck', 'Login/ajcheck')->name('ajcheck');
-        });
-
         //可登可不登的接口
         Route::group('', function () {
             //公共类
             Route::get('index', 'Pub/index')->name('index');//首页
         })->middleware(AuthTokenMiddleware::class, false);
 
-        //需要登录的接口
+        //用户接口
         Route::group('', function () {
             //退出登录
             Route::get('logout', 'Login/logout')->name('logout');
@@ -66,7 +71,19 @@ Route::group('api', function () {
                 //推广
             });
         })->middleware(AuthTokenMiddleware::class);
-    });
+        //装修工接口
+        Route::group('', function () {
+
+        })->middleware(AuthTokenMiddleware::class)->middleware(MemberTypeMiddleware::class, 'worker');
+        //设计师接口
+        Route::group('', function () {
+
+        })->middleware(AuthTokenMiddleware::class)->middleware(MemberTypeMiddleware::class, 'designer');
+        //业务员接口
+        Route::group('', function () {
+
+        })->middleware(AuthTokenMiddleware::class)->middleware(MemberTypeMiddleware::class, 'salesperson');
+    })->middleware(LocationMiddleware::class);
 })
     ->prefix('api.')
     ->middleware(AllowOriginMiddleware::class)

+ 36 - 0
vendor/joypack/tencent-map/README.en.md

@@ -0,0 +1,36 @@
+# tencent-map
+
+#### Description
+fork https://github.com/joypack/tencent-map
+
+#### Software Architecture
+Software architecture description
+
+#### Installation
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Instructions
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Contribution
+
+1.  Fork the repository
+2.  Create Feat_xxx branch
+3.  Commit your code
+4.  Create Pull Request
+
+
+#### Gitee Feature
+
+1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
+2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
+3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
+4.  The most valuable open source project [GVP](https://gitee.com/gvp)
+5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
+6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 37 - 0
vendor/joypack/tencent-map/README.md

@@ -0,0 +1,37 @@
+# tencent-map
+
+#### 介绍
+fork https://github.com/joypack/tencent-map
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 使用说明
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 参与贡献
+
+1.  Fork 本仓库
+2.  新建 Feat_xxx 分支
+3.  提交代码
+4.  新建 Pull Request
+
+
+#### 特技
+
+1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
+2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
+3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
+4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
+5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
+6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 33 - 0
vendor/joypack/tencent-map/composer.json

@@ -0,0 +1,33 @@
+{
+	"name" : "joypack/tencent-map",
+	"description" : "腾讯位置服务(WebService)",
+	"type" : "library",
+	"version" : "1.0.0",
+	"keywords" : [
+		"腾讯位置服务",
+		"lbs"
+	],
+	"homepage" : "https://github.com/joypack/tencent-map",
+	"authors" : [{
+			"name" : "堪笑",
+			"email" : "jixiang.f@gmail.com",
+			"role" : "Developer",
+			"homepage" : "http://cli.life"
+		}
+	],
+	"require": {
+	   "php": ">=5.6"
+	},
+	"support" : {
+		"email" : "jixiang.f@gmail.com",
+		"issues" : "https://github.com/joypack/tencent-map/issues",
+		"wiki" : "https://github.com/joypack/tencent-map/wiki"
+	},
+	"license": "Apache-2.0",
+	"autoload" : {
+		"psr-4" : {
+			"Joypack\\Tencent\\Map\\" : "src"
+		}
+	},
+	"minimum-stability" : "stable"
+}

+ 30 - 0
vendor/joypack/tencent-map/src/Bundle.php

@@ -0,0 +1,30 @@
+<?php
+namespace Joypack\Tencent\Map;
+
+/**
+ * 腾讯位置服务
+ * 基础类
+ */
+class Bundle
+{
+    // 参数实例
+    protected $option;
+    
+    // 请求实例
+    protected $request;
+    
+    // 日志实例
+    public $logger;
+    
+    public function __construct(Option $option, $log_root=null, $development=false)
+    {
+        $log_root = rtrim($log_root, '/\\');
+        
+        // 参数实例
+        $this->option = $option;
+        // 实例化日志
+        $this->logger = new Logger("{$log_root}/joypack-tencent-map", $development);
+        // 实例化请求
+        $this->request = new Request($this->logger);
+    }
+}

+ 37 - 0
vendor/joypack/tencent-map/src/Bundle/Address.php

@@ -0,0 +1,37 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Response;
+use Joypack\Tencent\Map\Bundle;
+
+/**
+ * 地址解析(地址转坐标)
+ * 本接口提供由地址描述到所述位置坐标的转换
+ * 与逆地址解析的过程正好相反。
+ */
+class Address extends Bundle
+{
+    /**
+     * 地址解析(地址转坐标)
+     * @param boolean $using_sig 使用签名方式校验
+     * @return Response
+     */
+    public function request($using_sig=false)
+    {
+        $uri = '/ws/geocoder/v1';
+        
+        
+        if($using_sig) {
+            $this->option->setSig($uri);
+        }
+        
+        $data = $this->option->getAll();
+        
+        //$this->request->logger->print($data, true);
+        
+        $this->request->uri($uri);
+        $this->request->query($data);
+        
+        return $this->request->get();
+    }
+}

+ 29 - 0
vendor/joypack/tencent-map/src/Bundle/AddressOption.php

@@ -0,0 +1,29 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Option;
+
+/**
+ * 地址解析(地址转坐标)
+ * 参数
+ */
+class AddressOption extends Option
+{
+    /**
+     * 地址
+     * @param string $value
+     */
+    public function setAddress($value)
+    {
+        $this->option['address'] = $value;
+    }
+    
+    /**
+     * 指定地址所属城市
+     * @param string $value
+     */
+    public function setRegion($value)
+    {
+        $this->option['region'] = $value;
+    }
+}

+ 37 - 0
vendor/joypack/tencent-map/src/Bundle/Ip.php

@@ -0,0 +1,37 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Response;
+use Joypack\Tencent\Map\Bundle;
+
+/**
+ * IP定位
+ * 通过终端设备IP地址获取其当前所在地理位置
+ * 精确到市级,常用于显示当地城市天气预报、初始化用户城市等非精确定位场景。
+ */
+class Ip extends Bundle
+{
+    /**
+     * IP定位
+     * @param boolean $using_sig 使用签名方式校验
+     * @return Response
+     */
+    public function request($using_sig=false)
+    {
+        $uri = '/ws/location/v1/ip';
+        
+        
+        if($using_sig) {
+            $this->option->setSig($uri);
+        }
+        
+        $data = $this->option->getAll();
+        
+        //$this->request->logger->print($data, true);
+        
+        $this->request->uri($uri);
+        $this->request->query($data);
+        
+        return $this->request->get();
+    }
+}

+ 20 - 0
vendor/joypack/tencent-map/src/Bundle/IpOption.php

@@ -0,0 +1,20 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Option;
+
+/**
+ * IP定位
+ * 参数
+ */
+class IpOption extends Option
+{
+    /**
+     * IP地址
+     * @param string $value
+     */
+    public function setIp($value)
+    {
+        $this->option['ip'] = $value;
+    }
+}

+ 37 - 0
vendor/joypack/tencent-map/src/Bundle/Location.php

@@ -0,0 +1,37 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Response;
+use Joypack\Tencent\Map\Bundle;
+
+/**
+ * 逆地址解析(坐标位置描述)
+ * 本接口提供由坐标到坐标所在位置的文字描述的转换
+ * 输入坐标返回地理位置信息和附近poi列表。
+ */
+class Location extends Bundle
+{
+    /**
+     * 逆地址解析(坐标位置描述)
+     * @param boolean $using_sig 使用签名方式校验
+     * @return Response
+     */
+    public function request($using_sig=false)
+    {
+        $uri = '/ws/geocoder/v1';
+        
+        
+        if($using_sig) {
+            $this->option->setSig($uri);
+        }
+        
+        $data = $this->option->getAll();
+        
+        //$this->request->logger->print($data, true);
+        
+        $this->request->uri($uri);
+        $this->request->query($data);
+        
+        return $this->request->get();
+    }
+}

+ 16 - 0
vendor/joypack/tencent-map/src/Bundle/LocationOption.php

@@ -0,0 +1,16 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Option;
+
+/**
+ * 逆地址解析(坐标位置描述)
+ * 参数
+ */
+class LocationOption extends Option
+{
+    public function setLocation($lat, $lng)
+    {
+        $this->option['location'] = "{$lat},{$lng}";
+    }
+}

+ 37 - 0
vendor/joypack/tencent-map/src/Bundle/Translate.php

@@ -0,0 +1,37 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Response;
+use Joypack\Tencent\Map\Bundle;
+
+/**
+ * 坐标转换
+ * 实现从其它地图供应商坐标系或标准GPS坐标系
+ * 批量转换到腾讯地图坐标系
+ */
+class Translate extends Bundle
+{
+    /**
+     * 逆地址解析(坐标位置描述)
+     * @param boolean $using_sig 使用签名方式校验
+     * @return Response
+     */
+    public function request($using_sig=false)
+    {
+        $uri = '/ws/coord/v1/translate';
+        
+        
+        if($using_sig) {
+            $this->option->setSig($uri);
+        }
+        
+        $data = $this->option->getAll();
+        
+        //$this->request->logger->print($data, true);
+        
+        $this->request->uri($uri);
+        $this->request->query($data);
+        
+        return $this->request->get();
+    }
+}

+ 58 - 0
vendor/joypack/tencent-map/src/Bundle/TranslateOption.php

@@ -0,0 +1,58 @@
+<?php
+namespace Joypack\Tencent\Map\Bundle;
+
+use Joypack\Tencent\Map\Option;
+
+/**
+ * 坐标转换
+ * 参数
+ */
+class TranslateOption extends Option
+{
+    const TYPE_GPS = 1;
+    const TYPE_SOGOU = 2;
+    const TYPE_BAIDU = 3;
+    const TYPE_MAPBAR = 4;
+    const TYPE_DEFAULT = 5;
+    const TYPE_SOGOU_MERCATOR = 6;
+    
+    /**
+     * 预转换的坐标
+     * @param string $value
+     */
+    public function setLocation($lat, $lng)
+    {
+        $this->option['locations'] = "{$lat},{$lng}";
+    }
+    
+    /**
+     * 预转换的坐标,支持批量转换
+     * @param array $locations
+     * <p>['lat,lng', [lat,lng]]</p>
+     */
+    public function setLocations(array $locations)
+    {
+        $pieces = [];
+        foreach ($locations as $item) {
+            if(is_array($item)) {
+                $pieces[] = "{$item[0]},{$item[1]}";
+            }
+        }
+        $this->option['locations'] = implode(';', $pieces);
+    }
+    
+    /**
+     * 设置坐标类型
+     * @param number $value
+     *  1 GPS坐标
+     *  2 sogou经纬度
+     *  3 baidu经纬度
+     *  4 mapbar经纬度
+     *  5 腾讯、google、高德坐标[默认]
+     *  6 sogou墨卡托
+     */
+    public function setType($value=self::TYPE_DEFAULT)
+    {
+        $this->option['type'] = $value;
+    }
+}

+ 121 - 0
vendor/joypack/tencent-map/src/Logger.php

@@ -0,0 +1,121 @@
+<?php
+namespace Joypack\Tencent\Map;
+
+/**
+ * 腾讯位置服务
+ * 日志管理
+ */
+class Logger
+{
+    protected $rootPath;
+    
+    protected $development = false;
+    
+    public function __construct($root_path, $development)
+    {
+        $this->development = $development;
+        
+        if($root_path) {
+            if(is_dir($root_path)) {
+                $this->rootPath = $root_path;
+            } else {
+                if(@mkdir($root_path, 0775, true)) {
+                    $this->rootPath = $root_path;
+                }
+            }
+        }
+    }
+    
+    public function __toString()
+    {
+        return __CLASS__;
+    }
+    
+    /**
+     * 写入 debug 日志
+     * @param string $message
+     * @param string | array $data
+     */
+    public function debug($message, $data=null)
+    {
+        $this->save($message, $data, 'DEBUG');
+    }
+    
+    /**
+     * 写入 INFO 日志
+     * @param string $message
+     * @param string | array $data
+     */
+    public function info($message, $data=null)
+    {
+        $this->save($message, $data, 'INFO');
+    }
+    
+    /**
+     * 写入 ERROR 日志
+     * @param string $message
+     * @param string | array $data
+     */
+    public function error($message, $data=null)
+    {
+        $this->save($message, $data, 'ERROR');
+    }
+    
+    /**
+     * 打印变量
+     * @param mixed $args 打印列表
+     * 最后一个元素如果是 true 则 exit
+     */
+    public function print(...$args)
+    {
+        $args = func_get_args();
+        
+        $length = count($args);
+        
+        $exit = false;
+        
+        if(is_bool($last_argument = $args[$length-1])) {
+            if($last_argument) {
+                $exit = true;
+                array_pop($args);
+            }
+        }
+        
+        echo '<pre>';
+        while ($argument = array_shift($args)) {
+            print_r($argument);
+            echo '<br/><br/>';
+        }
+        echo '</pre>';
+        
+        if($exit) {
+            exit;
+        }
+    }
+    
+    protected function save($message, $data, $level)
+    {
+        if(is_null($this->rootPath)) {
+            return;
+        }
+        
+        // 生产环境时只记录错误信息
+        if(!$this->development) {
+            if($level != 'ERROR') {
+                return;
+            }
+        }
+        
+        $date = date('Y-m-d');
+        
+        $now = date('Y-m-d H:i:s');
+        
+        $filename = "{$this->rootPath}/{$date}.log";
+        
+        if(is_array($data)) {
+            $data = json_encode($data, JSON_UNESCAPED_UNICODE);
+        }
+        
+        @file_put_contents($filename, "[{$level}] {$now} {$message} {$data}\r\n", FILE_APPEND);
+    }
+}

+ 98 - 0
vendor/joypack/tencent-map/src/Option.php

@@ -0,0 +1,98 @@
+<?php
+namespace Joypack\Tencent\Map;
+
+/**
+ * 腾讯位置服务
+ * 公共参数
+ */
+class Option
+{
+    const OUTPUT_JSON = 'json';
+    const OUTPUT_JSONP = 'jsonp';
+    
+    protected $option = [];
+    
+    protected $secret;
+    
+    public function __construct($key=null, $secret=null)
+    {
+        $this->setKey($key);
+        $this->setSecret($secret);
+    }
+    
+    public function setSecret($value)
+    {
+        $this->secret = $value;
+    }
+    
+    /**
+     * 开发密钥
+     * @param string $value
+     */
+    public function setKey($value)
+    {
+        $this->option['key'] = $value;
+    }
+    
+    /**
+     * 返回格式:支持JSON/JSONP,默认JSON
+     * @param string $value
+     */
+    public function setOutput($value=self::OUTPUT_JSON)
+    {
+        $this->option['output'] = $value;
+    }
+    
+    /**
+     * JSONP方式回调函数
+     * @param string $value
+     */
+    public function setCallback($value)
+    {
+        $this->option['callback'] = $value;
+    }
+    
+    /**
+     * 签名
+     * @param string $uri
+     */
+    public function setSig($uri)
+    {
+        $this->option['sig'] = $this->buildSig($uri, $this->getAll());
+    }
+    
+    /**
+     * 获得所有参数
+     * @return array
+     */
+    public function getAll()
+    {
+        return $this->option;
+    }
+    
+    /**
+     * 生成签名
+     * @param string $uri
+     * @return string
+     */
+    protected function buildSig($uri, $option)
+    {
+        ksort($option);
+        
+        $pieces = [];
+        foreach ($option as $key => $val)
+        {
+            $pieces[] = "{$key}={$val}";
+        }
+        
+        $str = sprintf('%s?%s', rtrim($uri, '/'), implode('&', $pieces));
+        
+        /*
+         echo '<pre>';
+         print_r("{$str}{$this->secret}");
+         die;
+         //*/
+        
+        return md5("{$str}{$this->secret}");
+    }
+}

+ 181 - 0
vendor/joypack/tencent-map/src/Request.php

@@ -0,0 +1,181 @@
+<?php
+namespace Joypack\Tencent\Map;
+
+/**
+ * 腾讯位置服务
+ * 接口请求类
+ */
+class Request
+{
+    // 接口地址
+    protected $url = 'https://apis.map.qq.com';
+    
+    protected $query = [];
+    
+    protected $field = [];
+    
+    public $logger;
+    
+    public function __construct(Logger $logger)
+    {
+        $this->logger = $logger;
+    }
+    
+    public function uri($uri)
+    {
+        $this->url .= '/' . trim($uri, '/');
+        return $this;
+    }
+    
+    public function query($name, $value=null)
+    {
+        if(is_array($name)) {
+            $this->query = array_merge($this->query, $name);
+        } else {
+            $this->query[$name] = $value;
+        }
+        return $this;
+    }
+    
+    public function field($name, $value=null)
+    {
+        if(is_array($name)) {
+            $this->field = array_merge($this->field, $name);
+        } else {
+            $this->field[$name] = $value;
+        }
+        return $this;
+    }
+    
+    /**
+     * method get
+     * @param array $query
+     * @return Response
+     */
+    public function get(array $query=[])
+    {
+        if($query) {
+            $this->query($query);
+        }
+        
+        $url = $this->mergeQuery($this->url, $this->query);
+        
+        return $this->create($url);
+    }
+    
+    public function post(array $fields=[])
+    {
+        if($fields) {
+            $this->field($fields);
+        }
+        
+        $url = $this->mergeQuery($this->url, $this->query);
+        
+        return $this->create($url, 'POST', $this->field);
+    }
+    
+    /**
+     * <p>将参数合并到 URL</p>
+     * @param string $url 请求的地址
+     * @param array $query 请求参数
+     * @param bool $recursive 是否递归合并
+     * @return mixed
+     */
+    protected function mergeQuery($url, array $query, bool $recursive=false)
+    {
+        if(empty($url)) {
+            return null;
+        }
+        
+        // 没有设置参数时直接返回地址
+        if(empty($query)) {
+            return $url;
+        }
+        
+        $parsed = parse_url($url);
+        
+        // 合并参数
+        if(isset($parsed['query'])) {
+            $url = substr($url, 0, strpos($url, '?'));
+            
+            $str_parsed = [];
+            
+            parse_str($parsed['query'], $str_parsed);
+            
+            if($recursive) {
+                $query = array_merge_recursive($str_parsed, $query);
+            } else {
+                $query = array_merge($str_parsed, $query);
+            }
+        } else {
+            $url = rtrim($url, '/?');
+        }
+        
+        // 生成 query 字符串
+        $url = "{$url}?" . http_build_query($query);
+        
+        return $url;
+        
+        // 处理锚点
+        if(isset($parsed['fragment'])) {
+            $url .= "#{$parsed['fragment']}";
+        }
+        
+        return $url;
+    }
+    
+    /**
+     * <p>创建请求</p>
+     * @param string $url 请求地址
+     * @param string $method 请求方式
+     * @param array $data POST 数据
+     * @return Response
+     */
+    protected function create($url, $data=null)
+    {
+        //$referer = "{$_SERVER['REQUEST_SCHEME']}://{$_SERVER['SERVER_NAME']}";
+        
+        //$header = [
+            //"CLIENT-IP: {$_SERVER['REMOTE_ADDR']}",
+            //"X-FORWARDED-FOR: {$_SERVER['REMOTE_ADDR']}",
+            //"Content-Type: application/json; charset=utf-8",
+            //"Accept: */*"
+        //];
+        
+        $ch = curl_init();
+        
+        curl_setopt($ch, CURLOPT_URL, $url);
+        //curl_setopt($ch, CURLOPT_HEADER, $header);
+        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+        //curl_setopt($ch, CURLOPT_REFERER, $referer);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+        
+        if(!is_null($data)) {
+            curl_setopt($ch, CURLOPT_POST, true);
+            if($data) {
+                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+            }
+        }
+        
+        $original = curl_exec($ch);
+        
+        $error = null;
+        if($errno = curl_errno($ch)) {
+            $error = curl_error($ch);
+        }
+        
+        curl_close($ch);
+        
+        $this->logger->info('请求地址', $url);
+        
+        if($data) {
+            $this->logger->info('请求数据', $data);
+        }
+        
+        $this->logger->info('响应数据', $original);
+        
+        return new Response($errno, $error, $original, $this->logger);
+    }
+}

+ 159 - 0
vendor/joypack/tencent-map/src/Response.php

@@ -0,0 +1,159 @@
+<?php
+namespace Joypack\Tencent\Map;
+
+/**
+ * 腾讯位置服务
+ * 接口响应类
+ */
+class Response
+{
+    public $error;
+    
+    public $logger;
+    
+    protected $original;
+    
+    protected $decode;
+    
+    public function __construct($errno, $error, $original, Logger $logger)
+    {
+        $this->logger = $logger;
+        
+        // 仅成功时
+        if(0 === $errno) {
+            $decode = json_decode($original, true);
+            if(is_null($decode)) {
+                // 错误
+                $this->setErrorMessage(99);
+                // 写入日志
+                $logger->error('解析失败');
+            } else {
+                $this->original = $original;
+                $this->decode = $decode;
+            }
+        } else {
+            // 错误
+            $this->setErrorMessage($errno);
+            // 写入日志
+            $logger->error($error);
+        }
+    }
+    
+    /**
+     * 返回json
+     * @return string
+     */
+    public function getOriginal()
+    {
+        return $this->original;
+    }
+    
+    /**
+     * 返回数组
+     * @return array
+     */
+    public function toArray()
+    {
+        return $this->decode;
+    }
+    
+    /**
+     * 获得某属性时
+     * @param string $prop_name
+     * @return mixed
+     */
+    public function __get($property)
+    {
+        return $this->decode[ $property ] ?? null;
+    }
+    
+    public function __toString()
+    {
+        return $this->original;
+    }
+    
+    protected function setErrorMessage($errno)
+    {
+        $errors = [
+            1=> 'UNSUPPORTED_PROTOCOL',
+            2=> 'FAILED_INIT',
+            3=> 'URL_MALFORMAT',
+            4=> 'URL_MALFORMAT_USER',
+            5=> 'COULDNT_RESOLVE_PROXY',
+            6=> 'COULDNT_RESOLVE_HOST',
+            7=> 'COULDNT_CONNECT',
+            8=> 'FTP_WEIRD_SERVER_REPLY',
+            9=> 'REMOTE_ACCESS_DENIED',
+            11=> 'FTP_WEIRD_PASS_REPLY',
+            13=> 'FTP_WEIRD_PASV_REPLY',
+            14=>'FTP_WEIRD_227_FORMAT',
+            15=> 'FTP_CANT_GET_HOST',
+            17=> 'FTP_COULDNT_SET_TYPE',
+            18=> 'PARTIAL_FILE',
+            19=> 'FTP_COULDNT_RETR_FILE',
+            21=> 'QUOTE_ERROR',
+            22=> 'HTTP_RETURNED_ERROR',
+            23=> 'WRITE_ERROR',
+            25=> 'UPLOAD_FAILED',
+            26=> 'READ_ERROR',
+            27=> 'OUT_OF_MEMORY',
+            28=> 'OPERATION_TIMEDOUT',
+            30=> 'FTP_PORT_FAILED',
+            31=> 'FTP_COULDNT_USE_REST',
+            33=> 'RANGE_ERROR',
+            34=> 'HTTP_POST_ERROR',
+            35=> 'SSL_CONNECT_ERROR',
+            36=> 'BAD_DOWNLOAD_RESUME',
+            37=> 'FILE_COULDNT_READ_FILE',
+            38=> 'LDAP_CANNOT_BIND',
+            39=> 'LDAP_SEARCH_FAILED',
+            41=> 'FUNCTION_NOT_FOUND',
+            42=> 'ABORTED_BY_CALLBACK',
+            43=> 'BAD_FUNCTION_ARGUMENT',
+            45=> 'INTERFACE_FAILED',
+            47=> 'TOO_MANY_REDIRECTS',
+            48=> 'UNKNOWN_TELNET_OPTION',
+            49=> 'TELNET_OPTION_SYNTAX',
+            51=> 'PEER_FAILED_VERIFICATION',
+            52=> 'GOT_NOTHING',
+            53=> 'SSL_ENGINE_NOTFOUND',
+            54=> 'SSL_ENGINE_SETFAILED',
+            55=> 'SEND_ERROR',
+            56=> 'RECV_ERROR',
+            58=> 'SSL_CERTPROBLEM',
+            59=> 'SSL_CIPHER',
+            60=> 'SSL_CACERT',
+            61=> 'BAD_CONTENT_ENCODING',
+            62=> 'LDAP_INVALID_URL',
+            63=> 'FILESIZE_EXCEEDED',
+            64=> 'USE_SSL_FAILED',
+            65=> 'SEND_FAIL_REWIND',
+            66=> 'SSL_ENGINE_INITFAILED',
+            67=> 'LOGIN_DENIED',
+            68=> 'TFTP_NOTFOUND',
+            69=> 'TFTP_PERM',
+            70=> 'REMOTE_DISK_FULL',
+            71=> 'TFTP_ILLEGAL',
+            72=> 'TFTP_UNKNOWNID',
+            73=> 'REMOTE_FILE_EXISTS',
+            74=> 'TFTP_NOSUCHUSER',
+            75=> 'CONV_FAILED',
+            76=> 'CONV_REQD',
+            77=> 'SSL_CACERT_BADFILE',
+            78=> 'REMOTE_FILE_NOT_FOUND',
+            79=> 'SSH',
+            80=> 'SSL_SHUTDOWN_FAILED',
+            81=> 'AGAIN',
+            82=> 'SSL_CRL_BADFILE',
+            83=> 'SSL_ISSUER_ERROR',
+            84=> 'FTP_PRET_FAILED',
+            84=> 'FTP_PRET_FAILED',
+            85=> 'RTSP_CSEQ_ERROR',
+            86=> 'RTSP_SESSION_ERROR',
+            87=> 'FTP_BAD_FILE_LIST',
+            88=> 'CHUNK_FAILED',
+            99=> 'DECODE_ERROR',
+        ];
+        $this->error = $errors[ $errno ] ?? 'UNKNOWN_ERROR';
+    }
+}