zory hace 3 semanas
padre
commit
8e85874dde

+ 42 - 0
app/controller/admin/Store.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace app\controller\admin;
+
+use app\extra\basic\Base;
+use app\middleware\AuthMiddleware;
+use LinFly\Annotation\Attributes\Route\Controller;
+use LinFly\Annotation\Attributes\Route\GetMapping;
+use LinFly\Annotation\Attributes\Route\Middleware;
+use support\Request;
+use support\Response;
+use Webman\RedisQueue\Redis;
+
+
+/**
+ * POI门店
+ */
+#[Controller("/api/store"),Middleware(AuthMiddleware::class)]
+class Store extends Base
+{
+
+    /**
+     * 同步POI门店
+     * @param Request $request
+     * @return Response
+     */
+    #[GetMapping('sync')]
+    public function syncStore(Request $request): Response
+    {
+        try {
+            Redis::send("sync-store",[
+                "appid"     => sConf("wechat.appid"),
+                "secret"    => sConf("wechat.secret"),
+                "account"   => sConf("wechat.shop_id"),
+            ]);
+            return success("发起成功");
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+}

+ 80 - 0
app/extra/dyLife/BasicLife.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace app\extra\dyLife;
+
+use support\think\Cache;
+
+class BasicLife
+{
+    /**
+     * 网关
+     * @var string
+     */
+    protected string $gateway = "https://open.douyin.com/";
+    /**
+     * 配置信息
+     * @var array
+     */
+    protected array $config = [];
+
+    /**
+     * 默认header
+     * @var string[]
+     */
+    protected array $header = [
+        "content-type"  => "application/json"
+    ];
+
+    /**
+     * AccessToken前缀
+     * @var string
+     */
+    protected string $prefix = "dy_[appid]_access_token";
+
+    /**
+     * 设置配置信息
+     * @param array $config
+     * @return $this
+     */
+    public function config(array $config = []): static
+    {
+        $this->config = $config;
+        return $this;
+    }
+
+    /**
+     * 释放授权
+     * @return $this
+     */
+    public function token(): static
+    {
+        $this->header = [
+            "access-token" => $this->getAccessToken()
+        ];
+        return $this;
+    }
+
+
+    public function getAccessToken()
+    {
+        try {
+            $accessToken = Cache::get($this->getPrefix());
+            if (!empty($accessToken)) return $accessToken;
+            $result = (new Token)->config($this->config)->getAccessToken();
+            if (empty($result)) return "获取Token失败";
+            Cache::set($this->getPrefix(),$result['access_token'],$result['expires_in']);
+            return $result['access_token'];
+        } catch (\Throwable $throwable) {
+            return "";
+        }
+    }
+
+    /**
+     * @return string
+     */
+    protected function getPrefix(): string
+    {
+        return str_replace("[appid]",$this->config['appid'],$this->prefix);
+    }
+
+}

+ 82 - 0
app/extra/dyLife/SignUtil.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace app\extra\dyLife;
+
+class SignUtil
+{
+
+    private $secret;
+    private $key;
+    private $iv;
+
+    public function init(string $secret = "") {
+        $this->secret = $secret;
+        $this->key = $this->parseSecret($secret);
+        $this->iv = substr($this->key, 16);
+        return $this;
+    }
+
+    /**
+     * @Description AES解密
+     * @param string $data base64后的密文
+     * @return string 明文
+     */
+    public function decryptAES($data) {
+        try {
+            $encrypted = $this->decode($data); // 先用base64解密
+            $decrypted = openssl_decrypt(
+                $encrypted,
+                'AES-256-CBC',
+                $this->key,
+                OPENSSL_RAW_DATA,
+                $this->iv
+            );
+            return $decrypted;
+        } catch (\Exception $e) {
+//            error_log($e->getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * base64编码
+     */
+    public function encode($data) {
+        return base64_encode($data);
+    }
+
+    /**
+     * base64解码
+     */
+    public function decode($data) {
+        return base64_decode($data);
+    }
+
+    private function parseSecret($secret) {
+        $secret = $this->fillSecret($secret);
+        $secret = $this->cutSecret($secret);
+        return $secret;
+    }
+
+    private function cutSecret($secret) {
+        if (strlen($secret) <= 32) {
+            return $secret;
+        }
+        $rightCnt = (int)((strlen($secret) - 32) / 2);
+        $leftCnt = strlen($secret) - 32 - $rightCnt;
+        return substr($secret, $leftCnt, 32);
+    }
+
+    private function fillSecret($secret) {
+        if (strlen($secret) >= 32) {
+            return $secret;
+        }
+        $rightCnt = (int)((32 - strlen($secret)) / 2);
+        $leftCnt = 32 - strlen($secret) - $rightCnt;
+        $sb = str_repeat('#', $leftCnt);
+        $sb .= $secret;
+        $sb .= str_repeat('#', $rightCnt);
+        return $sb;
+    }
+
+}

+ 33 - 0
app/extra/dyLife/Token.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace app\extra\dyLife;
+
+use yzh52521\EasyHttp\Http;
+
+class Token extends BasicLife
+{
+
+
+    /**
+     * 获取AccessToken
+     * https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/server/basic-abilities/interface-request-credential/non-user-authorization/get-client_token
+     * @param string $grantType
+     * @return array
+     */
+    public function getAccessToken(string $grantType = 'client_credential'): array
+    {
+        $data = [
+            "client_key"        => $this->config['appid'],
+            "client_secret"     => $this->config['secret'],
+            "grant_type"        => $grantType
+        ];
+        $url = $this->gateway."oauth/client_token/";
+        $result = Http::asJson()->post($url,$data)->array();
+        if(!empty($result['data']))
+        {
+            return $result['data'];
+        }
+        return [];
+    }
+
+}

+ 50 - 0
app/extra/dyLife/data/BaseData.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\extra\dyLife\data;
+
+use app\extra\dyLife\BasicLife;
+use yzh52521\EasyHttp\Http;
+
+class BaseData extends BasicLife
+{
+
+    /**
+     * 获取来客绑定的所有门店
+     * 一页最多50条
+     */
+    public function getStoreData(string $account,int $page = 1,int $size = 50)
+    {
+        $data = [
+            "account_id"    => $account,
+            "page"          => $page,
+            "size"          => $size
+        ];
+        $url = "{$this->gateway}goodlife/v1/shop/poi/query/";
+        $result = Http::asJson()->withHeaders($this->header)->get($url,$data)->array();
+        if(!empty($result['data']))
+        {
+            return $result['data'];
+        }
+        return [];
+    }
+
+
+    /**
+     * 获取来客绑定的所有分类
+     */
+    public function getStoreCategoryData(string $account)
+    {
+        $data = [
+            "account_id"            => $account,
+            "query_category_type"   => 1
+        ];
+        $url = "{$this->gateway}goodlife/v1/goods/category/get/";
+        $result = Http::asJson()->withHeaders($this->header)->get($url,$data)->array();
+        if(!empty($result['data']))
+        {
+            return $result['data'];
+        }
+        return [];
+    }
+
+}

+ 51 - 0
app/model/saas/SaasStore.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace app\model\saas;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property integer $store_id 来客id
+ * @property integer $poi_id 
+ * @property string $poi_name 
+ * @property string $poi_address 
+ * @property float $longitude 
+ * @property float $latitude 
+ * @property integer $is_default 
+ * @property integer $status 
+ * @property mixed $create_at
+ */
+class SaasStore extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "saas_store";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 60 - 0
app/queue/redis/SyncStore.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace app\queue\redis;
+
+use app\extra\dyLife\data\BaseData;
+use app\model\saas\SaasStore;
+use Webman\RedisQueue\Consumer;
+
+class SyncStore implements Consumer
+{
+
+    /**
+     * 消费队列名
+     * @var string
+     */
+    public string $queue = "sync-store";
+
+    /**
+     * 连接配置
+     * @var string
+     */
+    public string $connection = "default";
+
+    public function consume($data): bool
+    {
+        $page = 1;
+        $hasMore = true;
+        $mode = (new SaasStore);
+        while ($hasMore) {
+            $result = (new BaseData)->config(['appid' => $data['appid'],'secret' => $data['secret']])->token()->getStoreData($data['account'],$page,2);
+            if (empty($result)) {
+                $hasMore = false;
+                break;
+            }
+            $totalPage = ceil($result['total'] / 2);
+            if ($page >= $totalPage) {
+                $hasMore = false;
+            }
+            foreach ($result['pois'] as $key=>$val) {
+                $poi = $mode->where("poi_id",$val['poi']['poi_id'])->findOrEmpty();
+                if ($poi->isEmpty()) {
+                    $inData = $val['poi'];
+                    $amap = json_decode(file_get_contents("https://restapi.amap.com/v3/geocode/regeo?output=json&location={$val['poi']['longitude']},{$val['poi']['latitude']}&key=1f677969233c2e0b5770bf1752254a57"),true);
+                    if ($amap['status'] == "1" && isset($amap['regeocode']['addressComponent'])) {
+                        $inData['poi_city'] = "{$amap['regeocode']['addressComponent']['province']}/{$amap['regeocode']['addressComponent']['city']}/{$amap['regeocode']['addressComponent']['district']}";
+                    }
+                    $inData['poi_address'] = $val['poi']['address'];
+                    $inData['poi_account_id'] = $val['account']['poi_account']['account_id'];
+                    $inData['store_id'] = $val['account']['parent_account']['account_id'];
+                    echo "写入新数据===".getDateFull()."===".json_encode($inData)."\n";
+                    $poi->strict(false)->insertGetId($inData);
+                }
+            }
+            echo getDateFull()."-页码:{$page}\n";
+            $page ++;
+        }
+        return true;
+    }
+
+}