瀏覽代碼

feat(extensions): 添加阿里云物流扩展

- 新增阿里云物流查询扩展,提供全国快递物流查询功能
- 创建数据库迁移文件,定义物流数据表结构
-编写配置文件和扩展类,实现与六扇门框架的集成
- 开发物流查询客户端,封装物流信息获取方法
-编写单元测试,确保功能正常工作
runphp 7 月之前
父節點
當前提交
e1141c0097
共有 10 個文件被更改,包括 360 次插入4 次删除
  1. 1 4
      .gitignore
  2. 70 0
      README.md
  3. 32 0
      composer.json
  4. 46 0
      config.php
  5. 96 0
      database/migrations/20250727172015_wuliu.php
  6. 16 0
      info.php
  7. 16 0
      src/Config.php
  8. 14 0
      src/Extension.php
  9. 48 0
      src/WuLiuClient.php
  10. 21 0
      test/WuLiuClientTest.php

+ 1 - 4
.gitignore

@@ -1,6 +1,3 @@
 composer.phar
 /vendor/
-
-# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
-# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
-# composer.lock
+.idea/

+ 70 - 0
README.md

@@ -0,0 +1,70 @@
+# 全国快递物流查询
+
+扩展说明
+
+参考:
+https://market.aliyun.com/apimarket/detail/cmapi021863#sku=yuncode15863000017
+
+```php
+
+<?php
+error_reporting(E_ALL || ~E_NOTICE);
+$host = "https://wuliu.market.alicloudapi.com";//api访问链接
+$path = "/kdi";//API访问后缀
+$method = "GET";
+$appcode = "你自己的AppCode";//开通服务后 买家中心-查看AppCode
+$headers = array();
+array_push($headers, "Authorization:APPCODE " . $appcode);
+$querys = "no=780098068058&type=zto";  //参数写在这里
+$bodys = "";
+$url = $host . $path . "?" . $querys;
+
+$curl = curl_init();
+curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
+curl_setopt($curl, CURLOPT_URL, $url);
+curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+curl_setopt($curl, CURLOPT_FAILONERROR, false);
+curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($curl, CURLOPT_HEADER, true);
+if (1 == strpos("$" . $host, "https://")) {
+    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+}
+$out_put = curl_exec($curl);
+
+$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+
+list($header, $body) = explode("\r\n\r\n", $out_put, 2);
+if ($httpCode == 200) {
+    print("正常请求计费(其他均不计费)<br>");
+    print($body);
+} else {
+    if ($httpCode == 400 && strpos($header, "Invalid Param Location") !== false) {
+        print("参数错误");
+    } elseif ($httpCode == 400 && strpos($header, "Invalid AppCode") !== false) {
+        print("AppCode错误");
+    } elseif ($httpCode == 400 && strpos($header, "Invalid Url") !== false) {
+        print("请求的 Method、Path 或者环境错误");
+    } elseif ($httpCode == 403 && strpos($header, "Unauthorized") !== false) {
+        print("服务未被授权(或URL和Path不正确)");
+    } elseif ($httpCode == 403 && strpos($header, "Quota Exhausted") !== false) {
+        print("套餐包次数用完");
+    } elseif ($httpCode == 403 && strpos($header, "Api Market Subscription quota exhausted") !== false) {
+        print("套餐包次数用完,请续购套餐");
+    } elseif ($httpCode == 500) {
+        print("API网关错误");
+    } elseif ($httpCode == 0) {
+        print("URL错误");
+    } else {
+        print("参数名错误 或 其他错误");
+        print($httpCode);
+        $headers = explode("\r\n", $header);
+        $headList = array();
+        foreach ($headers as $head) {
+            $value = explode(':', $head);
+            $headList[$value[0]] = $value[1];
+        }
+        print($headList['x-ca-error-message']);
+    }
+}
+```

+ 32 - 0
composer.json

@@ -0,0 +1,32 @@
+{
+  "name": "six-shop/aliyun-wuliu",
+  "description": "阿里云物流扩展",
+  "type": "sixshop-extension",
+  "keywords": [
+    "sixshop",
+    "thinkphp"
+  ],
+  "require": {
+    "php": ">=8.3",
+    "six-shop/core": ">=0.5 <1.0",
+    "symfony/http-client": ">=7.3"
+  },
+  "authors": [
+    {
+      "name": "hui he",
+      "email": "runphp@qq.com"
+    }
+  ],
+  "license": "MIT",
+  "autoload": {
+    "psr-4": {
+      "SixShop\\AliyunWuliu\\": "src"
+    }
+  },
+  "extra": {
+    "sixshop": {
+      "id": "aliyun-wuliu",
+      "class": "SixShop\\AliyunWuliu\\Extension"
+    }
+  }
+}

+ 46 - 0
config.php

@@ -0,0 +1,46 @@
+<?php
+declare(strict_types=1);
+
+return json_decode(<<<'JSON'
+[
+  {
+      "type": "input",
+    "title": "AppKey",
+    "field": "app_key",
+    "props": {
+      "placeholder": "请输入AppKey"
+    },
+    "_fc_id": "id_Fj8wmdlxp75qacc",
+    "name": "ref_F5uymdlxp75qadc",
+    "display": true,
+    "hidden": false,
+    "_fc_drag_tag": "input"
+  },
+  {
+      "type": "input",
+    "title": "AppSecret",
+    "field": "app_secret",
+    "props": {
+      "placeholder": "请输入AppSecret"
+    },
+    "_fc_id": "id_Fk7hmdlxp75raec",
+    "name": "ref_Fo16mdlxp75rafc",
+    "display": true,
+    "hidden": false,
+    "_fc_drag_tag": "input"
+  },
+  {
+      "type": "input",
+    "title": "AppCode",
+    "field": "app_code",
+    "props": {
+      "placeholder": "请输入AppCode"
+    },
+    "_fc_id": "id_F0wwmdlxp75ragc",
+    "name": "ref_F8mxmdlxp75rahc",
+    "display": true,
+    "hidden": false,
+    "_fc_drag_tag": "input"
+  }
+]
+JSON, true);

+ 96 - 0
database/migrations/20250727172015_wuliu.php

@@ -0,0 +1,96 @@
+<?php
+declare(strict_types=1);
+
+use think\migration\db\Column;
+use think\migration\Migrator;
+
+class Wuliu extends Migrator
+{
+    /**
+     * Change Method.
+     *
+     * Write your reversible migrations using this method.
+     *
+     * More information on writing migrations is available here:
+     * http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
+     *
+     * The following commands can be used in this method and Phinx will
+     * automatically reverse them when rolling back:
+     *
+     *    createTable
+     *    renameTable
+     *    addColumn
+     *    renameColumn
+     *    addIndex
+     *    addForeignKey
+     *
+     * Remember to call "create()" or "update()" and NOT "save()" when working
+     * with the Table class.
+     */
+    public function change()
+    {
+
+//        {
+//            "status": "0",/* status 0:正常查询 201:快递单号错误 203:快递公司不存在 204:快递公司识别失败 205:没有信息 207:该单号被限制,错误单号 */
+//	"msg": "ok",
+//	"result": {
+//            "number": "780098068058",
+//		"type": "zto",
+//		"list": [{
+//                "time": "2018-03-09 11:59:26",
+//			"status": "【石家庄市】快件已在【长安三部】 签收,签收人: 本人,感谢使用中通快递,期待再次为您服务!"
+//		}, {
+//                "time": "2018-03-09 09:03:10",
+//			"status": "【石家庄市】 快件已到达 【长安三部】(0311-85344265),业务员 容晓光(15908220064) 正在第1次派件, 请保持电话畅通,并耐心等待"
+//		}, {
+//                "time": "2018-03-08 23:43:44",
+//			"status": "【石家庄市】 快件离开 【石家庄】 发往 【长安三部】"
+//		}, {
+//                "time": "2018-03-08 21:00:44",
+//			"status": "【石家庄市】 快件到达 【石家庄】"
+//		}, {
+//                "time": "2018-03-07 01:38:45",
+//			"status": "【广州市】 快件离开 【广州中心】 发往 【石家庄】"
+//		}, {
+//                "time": "2018-03-07 01:36:53",
+//			"status": "【广州市】 快件到达 【广州中心】"
+//		}, {
+//                "time": "2018-03-07 00:40:57",
+//			"status": "【广州市】 快件离开 【广州花都】 发往 【石家庄中转】"
+//		}, {
+//                "time": "2018-03-07 00:01:55",
+//			"status": "【广州市】 【广州花都】(020-37738523) 的 马溪 (18998345739) 已揽收"
+//		}],
+//		"deliverystatus": "3", /* 0:快递收件(揽件)1.在途中 2.正在派件 3.已签收 4.派送失败 5.疑难件 6.退件签收  */
+//		"issign": "1",                      /*  1.是否签收                  */
+//		"expName": "中通快递",              /*  快递公司名称                */
+//		"expSite": "www.zto.com",           /*  快递公司官网                */
+//		"expPhone": "95311",                /*  快递公司电话                */
+//		"courier": "容晓光",                /*  快递员 或 快递站(没有则为空)*/
+//        "courierPhone":"15908220064",       /*  快递员电话 (没有则为空)     */
+//        "updateTime":"2019-08-27 13:56:19", /*  快递轨迹信息最新时间        */
+//        "takeTime":"2天20小时14分",         /*  发货到收货消耗时长 (截止最新轨迹)  */
+//        "logo":"https://img3.fegine.com/express/zto.jpg" /* 快递公司LOGO */
+//	}
+//}
+
+        $table = $this->table('extension_wuliu', ['comment' => '物流数据']);
+        $table
+            ->addColumn('number', 'string', ['limit' => 50, 'default' => '', 'comment' => '快递单号'])
+            ->addColumn('type', 'string', ['limit' => 32, 'default' => '', 'comment' => '快递公司'])
+            ->addColumn('list', 'json', ['default' => '[]', 'comment' => '物流信息'])
+            ->addColumn(Column::tinyInteger('delivery_status')->setUnsigned()->setDefault(0)
+                ->setComment('物流状态 0:快递收件(揽件)1.在途中 2.正在派件 3.已签收 4.派送失败 5.疑难件 6.退件签收' ))
+            ->addColumn(Column::tinyInteger('is_sign')->setUnsigned()->setDefault(0)->setComment('是否签收'))
+            ->addColumn('exp_name', 'string', ['limit' => 100, 'default' => '', 'comment' => '快递公司名称'])
+            ->addColumn('exp_site', 'string', ['limit' => 255, 'default' => '', 'comment' => '快递公司官网'])
+            ->addColumn('exp_phone', 'string', ['limit' => 32, 'default' => '', 'comment' => '快递公司电话'])
+            ->addColumn('courier', 'string', ['limit' => 32, 'default' => '', 'comment' => '快递员'])
+            ->addColumn('courier_phone', 'string', ['limit' => 32, 'default' => '', 'comment' => '快递员电话'])
+            ->addColumn(Column::string('take_time')->setDefault('')->setComment('发货到收货消耗时长'))
+            ->addColumn('logo', 'string', ['limit' => 255, 'default' => '', 'comment' => '快递公司LOGO'])
+            ->addTimestamps()
+            ->addIndex('number')
+            ->create();
+    }
+}

+ 16 - 0
info.php

@@ -0,0 +1,16 @@
+<?php
+declare(strict_types=1);
+return [
+  'id' => 'alicloud_wuliu',
+  'name' => '全国快递物流查询',
+  'is_core' => false,
+  'category' => 'other',
+  'description' => '全国快递物流查询(阿里云)',
+  'version' => '1.0.0',
+  'core_version' => '^1.0',
+  'author' => 'runphp',
+  'email' => 'runphp@qq.com',
+  'website' => 'https://market.aliyun.com/apimarket/detail/cmapi021863#sku=yuncode15863000017',
+  'image' => '',
+  'license' => 'MIT',
+];

+ 16 - 0
src/Config.php

@@ -0,0 +1,16 @@
+<?php
+declare(strict_types=1);
+
+namespace SixShop\AliyunWuliu;
+
+use SixShop\System\Trait\ConfigTrait;
+
+class Config
+{
+    use ConfigTrait;
+
+    public function getAppCode(): string
+    {
+        return $this->getConfig('app_code');
+    }
+}

+ 14 - 0
src/Extension.php

@@ -0,0 +1,14 @@
+<?php
+declare(strict_types=1);
+
+namespace SixShop\AliyunWuliu;
+
+use SixShop\Core\ExtensionAbstract;
+
+class Extension extends ExtensionAbstract
+{
+    protected function getBaseDir(): string
+    {
+        return dirname(__DIR__);
+    }
+}

+ 48 - 0
src/WuLiuClient.php

@@ -0,0 +1,48 @@
+<?php
+declare(strict_types=1);
+
+namespace SixShop\AliyunWuliu;
+
+use SixShop\Core\Helper;
+use Symfony\Component\HttpClient\HttpClient;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+
+class WuLiuClient
+{
+
+    private const string GATEWAY = 'https://wuliu.market.alicloudapi.com/';
+
+    private HttpClientInterface $httpClient;
+
+    public function __construct(private Config $config)
+    {
+        $this->httpClient = HttpClient::create([
+            'base_uri' => self::GATEWAY,
+            'headers' => [
+                'Authorization' => 'APPCODE ' . $this->config->getAppCode(),
+            ]
+        ]);
+    }
+
+    /**
+     * 获取物流信息
+     * @param string $no 快递单号
+     * @param string $type 快递公司编码
+     * @return array
+     */
+    public function kdi(string $no, string $type = ''): array
+    {
+        $response = $this->httpClient->request('GET', 'kdi', [
+            'query' => [
+                'no' => $no,
+                'type' => $type,
+            ]
+        ]);
+        $result = json_decode($response->getContent(), true);
+        if ($result['status'] == 0) {
+            return $result['result'];
+        } else {
+            Helper::throw_logic_exception($result['msg']);
+        }
+    }
+}

+ 21 - 0
test/WuLiuClientTest.php

@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\AliyunWuliu;
+
+use PHPUnit\Framework\TestCase;
+
+class WuLiuClientTest extends TestCase
+{
+    private WuLiuClient $client;
+    protected function setUp(): void
+    {
+        $this->client = app(WuLiuClient::class);
+    }
+
+
+    public function testKdi(): void
+    {
+        $result = $this->client->kdi('DPK202576722639');
+        $this->assertIsArray($result);
+    }
+}