1
0

2 Коммитууд a55cf617e7 ... 9ffe4cf446

Эзэн SHA1 Мессеж Огноо
  public 9ffe4cf446 Merge branch 'master' of http://47.112.106.152:10880/tangyuanwang/zhijiayun 3 өдөр өмнө
  public 51af387be6 [智价云] 授权登录更新 3 өдөр өмнө

+ 110 - 0
app/Models/OpenPlat/Component.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace App\Models\OpenPlat;
+
+
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 授权方信息以及刷新令牌
+ * 
+ */
+class Component extends Model
+{
+
+    // 与模型关联的表名
+    protected $table = 'openplat_component';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+
+    public  function _inintlaze()
+    {
+        parent::_inintlaze();
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']                = time();
+        $data['update_time']                = time();
+        // 写入数据表
+        $id                                    = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if (!$id)                          return 0;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id, $data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result                                = $this->query()->where(['id' => $id])->update($data);
+        // 如果操作失败
+        if (!$result)                      return 0;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     * 
+     */
+    public function getList($force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('manager:openplat:component:list');
+        // 不存在数据
+        if (!$list) {
+            // 从数据库获取数据
+            $data              = $this->query()->where([['status', '=', 0]])->get(['authorizer_appid as appid', 'authorizer_refresh_token as refresh_token', 'company_id', 'func_scope', 'status', 'insert_time', 'update_time'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['appid']] = $value;
+            }
+            // 存起来
+            cache(['manager:openplat:component:list' => $list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   int      $appid     appid
+     * @param   string   $field     指定字段
+     * 
+     */
+    public function getOne($appid, $field = '')
+    {
+        // 获取列表数据
+        $list                   = $this->getList();
+        // 获取数据
+        $one                    = isset($list[$appid]) ? $list[$appid] : [];
+        // 返回值
+        return                  empty($field) ? $one : (isset($one[$field]) ? $one[$field] : null);
+    }
+}

+ 521 - 0
app/Servers/Wechat/OpenPlat.php

@@ -0,0 +1,521 @@
+<?php
+
+namespace App\Servers\Wechat;
+
+use EasyWeChat\Factory;
+use App\Models\OpenPlat\Component;
+use Illuminate\Support\Facades\Http;
+use EasyWeChat\Kernel\AccessToken;
+use Ixudra\Curl\Facades\Curl;
+use App\Facades\Servers\Logs\Log;
+
+/**
+ * 微信第三方平台
+ * 
+ */
+class OpenPlat
+{
+    // 应用实例
+    private \EasyWeChat\OpenPlatform\Application  $app;
+
+    // 返回结果
+    public function __construct()
+    {
+        // 应用实例
+        $this->app        = $this->getApp();
+    }
+
+
+    /**
+     * 获取应用实例
+     * 
+     * @return \EasyWeChat\OpenPlatform\Application
+     * 
+     */
+    public function getApp()
+    {
+        // 返回应用实例
+        $app                = Factory::openPlatform(config('wechat.openplat', []));
+        $appEnv         = config('app.env');
+        // 如果非正式服
+        if ($appEnv != 'production') {
+            // 获取线上的代码
+            $result         = Curl::to(config('wechat.openplat.release_host_url','').'openplat/install/get_component_access_token')->asJsonResponse(true)->get();
+            // 设置
+            if( !empty($result['data']['component_access_token']) )  $app->access_token->setToken($result['data']['component_access_token'],3600);
+        }
+        // 返回结果
+        return              $app;
+    }
+
+    
+    /**
+     * 获取授权账号刷新令牌
+     * 
+     * @param string $appId appid
+     * 
+     * @return string
+     *
+     */
+    public function getRefreshToken($appId)
+    {
+        // 获取授权账号刷新令牌
+        $refreshToken   = (new Component())->getOne($appId,'refresh_token');
+        // $refreshToken   = (new Component())->where([['authorizer_appid','=',$appId]])->value('authorizer_refresh_token');
+        // 返回令牌
+        return          (string) $refreshToken;
+    }
+
+    /**
+     * 获取授权公众号实例
+     * 
+     * @param string $appId appid
+     * 
+     * @return \EasyWeChat\OpenPlatform\Authorizer\OfficialAccount\Application
+     * 
+     */
+    public function getOfficial(string $appId)
+    {
+        $refreshToken   = $this->getRefreshToken($appId);
+        // 返回应用实例
+        $official       = $this->app->officialAccount($appId, $refreshToken);
+        $appEnv         = config('app.env');
+        if ($appEnv != 'production') {
+            $response = Http::post(config('wechat.openplat.release_host_url','').'openplat/install/get_official_access_token',[
+                'app_id' => $appId,
+            ]);
+            $body           = json_decode($response->body(),true);
+            $data           = $body['data'];
+            $official->access_token->setToken($data['authorizer_access_token'],7200);
+        }
+        // 返回应用实例
+        return          $official;
+    }
+
+    /**
+     * 获取授权小程序实例
+     * 
+     * @param string $appId appid
+     * 
+     * @return \EasyWeChat\OpenPlatform\Authorizer\MiniProgram\Application
+     * 
+     */
+    public function getMini(string $appId)
+    {
+        $appEnv         = config('app.env');
+        $refreshToken   = $this->getRefreshToken($appId);
+        // 返回应用实例
+        $mini           = $this->app->miniProgram($appId, $refreshToken);
+        if ($appEnv != 'production') {
+            $response = Http::post(config('wechat.openplat.release_host_url','').'openplat/install/get_access_token',[
+                'app_id' => $appId,
+            ]);
+            $body           = json_decode($response->body(),true);
+            $data           = $body['data'];
+            $setResult      = $mini->access_token->setToken($data['authorizer_access_token'],7200);
+        }
+        // 返回应用实例
+        return          $mini;
+    }
+
+
+    /**
+     * 手机号授权
+     * @param  string   $code           授权码
+     *
+     */
+    public function getUserPhone($code,$appId){
+        $Mini                               = $this->getMini($appId);
+        // 获取手机号
+        $result							    = $Mini->phone_number->getUserPhoneNumber($code);
+        // 判断结果
+        if( !empty($result['errcode']) )    return ['error'=>$result['errcode'].'=>'.$result['errmsg']];
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result['phone_info'];
+    }
+    /**
+     * 获取用户openid
+     * @param  string   $code           授权码
+     *
+     */
+    public function jscode2session($code,$appId){
+        
+        $token                              = $this->app->access_token->getToken();
+        $params                             = [
+                                                'appid' => $appId,
+                                                'component_access_token'=>$token['component_access_token'],
+                                                'grant_type' => 'authorization_code',
+                                                'component_appid' => config('wechat.openplat.app_id',''),
+                                                'js_code' => $code,
+                                            ];
+
+        $params                             = http_build_query($params);
+        $result                             = Curl::to('https://api.weixin.qq.com/sns/component/jscode2session?'.$params)->asJsonResponse(true)->get();
+        // 判断结果
+        if( !empty($result['errcode']) )    return ['error'=>$result['errcode'].'=>'.$result['errmsg']];
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 提交小程序体验版
+     * @param  string   $appId           app_id
+     *
+     */
+    public function commit($appId,$templateId, $extJson, $version, $description){
+        $Mini                               = $this->getMini($appId);
+        // 获取手机号
+        $result							    = $Mini->code->commit($templateId, $extJson, $version, $description);
+        // 判断结果
+        if( !empty($result['errcode']) )    return ['error'=>$result['errcode'].'=>'.$result['errmsg']];
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 生产小程序体验版二维码
+     * @param  string   $code           授权码
+     *
+     */
+    public function getTrialQRCode($appId,$fileName,$path=null){
+        $Mini                               = $this->getMini($appId);
+        // 获取手机号
+        $result							    = $Mini->code->getQrCode($path);
+        file_put_contents($fileName, $result);
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+
+    /**
+     * 获取user  公众号
+     * @param  string   $code           通过 前端授权code获取用户openid
+     *
+     *
+     */
+    public function userFromCode($code,$appId){
+        $Mini                               = $this->getOfficial($appId);
+        // 获取手机号
+        $result							    = $Mini->oauth->userFromCode($code);
+        // 判断结果
+        if( !empty($result['errcode']) )    return ['error'=>$result['errcode'].'=>'.$result['errmsg']];
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 配置小程序服务器域名
+     * @param  array    $params           配置数据
+     * @param  string   $appId            app_id
+     */
+    public function modify($appId,$params){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->domain->modify($params);
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 获取UrlLink
+     * @param  string   $path           通过 URL Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query 。path 为空时会跳转小程序主页
+     * @param  string   $query          通过 URL Link 进入小程序时的query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~%
+     *
+     */
+    public function getUrlLink($appId,$path,$query=''){
+        $Mini                           = $this->getMini($appId);
+        // 组合参数
+        $params['path']                 = $path;
+        $params['query']                = $query;
+        $params['expire_type']          = 1;    // 默认值0.小程序 URL Link 失效类型,失效时间:0,失效间隔天数:1
+        $params['expire_interval']      = 30;   // 到期失效的URL Link的失效间隔天数
+        $params['env_version']          = config('app.env','production') == 'production' ?  'release' : 'trial';
+        // 获取结果
+        $result                         = $Mini->url_link->generate($params);
+        // 成功返回
+        if( $result['errcode'] == 0 )   return $result['url_link'];
+        // 失败
+        return                          '';
+    }
+    /**
+     * 获取小程序 scheme 链接
+     * @author 唐远望
+     * @version 1.0
+     * @date 2025-08-28
+     *
+     */
+    public function getScheme($appId,$path, $query = '')
+    {
+        $Mini                           = $this->getMini($appId);
+        $token = $Mini->access_token->getToken();
+        $params = [
+            'jump_wxa' => [
+                'path' => $path,
+                'query' => $query,
+            ],
+            'expire_time' => time() + 86400 * 30 //最长有效期为 30 天
+        ];
+        // 直接发送 JSON 数据
+        $result = Curl::to('https://api.weixin.qq.com/wxa/generatescheme?access_token=' . $token['authorizer_access_token'])
+            ->withContentType('application/json') // 设置 Content-Type
+            ->withData(json_encode($params))      // 将数组转换为 JSON 字符串
+            ->asJsonResponse(true)
+            ->post();
+        // 判断结果
+        if (!empty($result['errcode'])) {
+            //写入日志
+            Log::error('getScheme','获取小程序 scheme 码失败',['errcode' => $result['errcode'], 'errmsg' => $result['errmsg']]);
+            return '';
+        }
+        // 返回结果
+        return $result['openlink'];
+    }
+
+
+
+    /**
+     * 获取小程序码
+     *
+     * @param  string   $scene                  小程序码的场景值
+     * @param  array    $optional               其他参数
+     *                  page                    小程序码的页面路径
+     *                  width                   小程序码的宽度
+     *
+     */
+    public function getUnlimit($appId,string $scene, array $optional = []){
+        $Mini                                   = $this->getMini($appId);
+        // 小程序版本,体验还是正式版
+        $optional['env_version']                = config('app.env') == 'production' ?  'release' : 'trial';
+        // 执行生成
+        $result                                 = $Mini->app_code->getUnlimit($scene, $optional);
+        // 判断结果
+        if( $result instanceof \EasyWeChat\Kernel\Http\StreamResponse ) return $result->getBody()->getContents();
+        // 错误
+        return                                  ['error'=>$result['errcode'].'=>'.$result['errmsg']];
+    }
+    /**
+     * 发布最后一个审核通过的小程序代码版本
+     *
+     * @param  string   $appId            app_id
+     */
+    public function release($appId){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->code->release();
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 发布最后一个审核通过的小程序代码版本
+     *
+     * @param  string   $appId            app_id
+     */
+    public function submitAudit($appId,$data){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->code->submitAudit($data);
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 获取类目名称信息
+     *
+     * @param  string   $appId            app_id
+     */
+    public function getAllCategoryName($appId){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->code->getCategory();
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 获取永久素材
+     *
+     * @param  string   $appId            app_id
+     * @param  int      $mediaId          素材id
+     */
+    public function getMaterial($appId,$mediaId){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->material->get($mediaId);
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 设置小程序用户隐私保护指引
+     *
+     * @param  string   $appId           app_id
+     * @param  array    $params          params
+     */
+    public function setPrivacySetting($appId,$params){
+        $Mini                               = $this->getMini($appId);
+        // 设置小程序用户隐私保护指引
+        $result							    = $Mini->privacy->set($params);
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 获取小程序信息
+     *
+     * @param  string   $appId           app_id
+     */
+    public function getAccountBasicInfo($appId){
+        $Mini                               = $this->getMini($appId);
+        // 设置小程序用户隐私保护指引
+        $result							    = $Mini->account->getBasicInfo();
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 获取小程序版本信息
+     *
+     * @param  string   $appId           app_id
+     */
+    public function getVersionInfo($appId){
+        $Mini                               = $this->getMini($appId);
+        // 设置小程序用户隐私保护指引
+        $result							    = $Mini->base->getVersionInfo();
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 配置小程序业务域名
+     * @param  array    $params           配置数据
+     * @param  string   $appId            app_id
+     */
+    public function modifyJumpDomain($appId,$params){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->domain->setWebviewDomain($params['setWebviewDomain'],$params['action']);
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 查询最后一个审核结果
+     *
+     * @param  string   $appId            app_id
+     */
+    public function getLatestAuditStatus($appId){
+        $Mini                               = $this->getMini($appId);
+        // 配置小程序服务器域名
+        $result							    = $Mini->code->getLatestAuditStatus();
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              $result;
+    }
+    /**
+     * 小程序获取缓存的AccessToken
+     *
+     */
+    public function getAccessToken($appId){
+        // 返回应用实例
+        $Mini                           = $this->getMini($appId);
+        // 获取access_token
+        $accessToken					= $Mini->access_token->getToken();
+        return                          $accessToken;
+    }
+    /**
+     * 公众号获取缓存的AccessToken
+     *
+     */
+    public function getOfficialAccessToken($appId){
+        // 返回应用实例
+        $official                       = $this->getOfficial($appId);
+        // 获取access_token
+        $accessToken					= $official->access_token->getToken();
+        return                          $accessToken;
+    }
+    /**
+     * 代小程序上传发货物流信息
+     *
+     */
+    public function deliver($appId,$data=[]){
+        $Mini                           = $this->getMini($appId);
+        // 获取access_token
+        $accessToken					= $Mini->access_token->getToken();
+        $params                             = [
+            'order_key'                     =>[
+                    "order_number_type"     => $data['order_number_type'],
+                    "mchid"                 => $data['mchid'],
+                    "transaction_id"        => $data['transaction_id'] ?? null,
+            ],
+            'delivery_mode'                 => $data['delivery_mode'],
+            'logistics_type'                => $data['logistics_type'],
+            'shipping_list'                 =>[
+                [
+                    "tracking_no"               => $data['tracking_no'],
+                    "express_company"           => $data['express_company'],
+                    "item_desc"                 => $data['item_desc'],
+                    'contact'                       => [
+                        'consignor_contact'         => $data['consignor_contact'] ?? null,
+                        'receiver_contact'          => $data['receiver_contact'] ?? null,
+                    ],
+                ]
+            ],
+            'upload_time'                   => date('Y-m-d\TH:i:s.vP',$data['upload_time']),
+            'payer'                         => [
+                'openid'                    => $data['openid'],
+            ],
+        ];
+        // 上传物流信息
+        //$result							    = $Mini->shipping->uploadShippingInfo($params);
+        $token                        = [
+            'access_token'                  => $accessToken['authorizer_access_token']
+        ];
+        try {
+            $token                              = http_build_query($token);
+            $params                             = json_encode($params, JSON_UNESCAPED_UNICODE);
+            $result                             = Curl::to('https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?'.$token)->withData($params)->asJsonResponse(true)->post();
+            // 判断结果
+            if( !empty($result['errcode']) ){
+                Log::error('wechat/deliver','发货失败,出现错误'.json_encode($result).'参数'.json_encode($params));
+                return ['code'=>'error','msg'=>'发货失败','data'=>$result];
+            }
+        } catch (\Exception $e) {
+            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
+                $r = $e->getResponse();
+                // 记录错误信息
+                Log::error('wechat/deliver','发货失败,出现错误'.$r->getBody().'参数'.json_encode($params));
+            }
+            return ['code'=>'error','msg'=>'发货失败','data'=>['msg'=>$e->getMessage(),'params'=>$params]];
+        }
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              ['code'=>'success','msg'=>'发货成功'];
+    }
+    /**
+     * 申请物流信息
+     *
+     */
+    public function applyMsgPlugin($appId,$data=[]){
+        // 返回应用实例
+        $Mini                           = $this->getMini($appId);
+        // 获取access_token
+        $accessToken					= $Mini->access_token->getToken();
+        $params                         = [
+            'access_token'    =>    $accessToken['authorizer_access_token'],
+        ];
+
+        $params                             = http_build_query($params);
+        $result                             = Curl::to('https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/open_openmsg?'.$params)->asJsonResponse(true)->get();
+        // 判断结果
+        if( !empty($result['errcode']) )    return ['code'=>'error','msg'=>$result['errcode'].'=>'.$result['errmsg']];
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              ['code'=>'success','msg'=>'申请成功'];
+    }
+    /**
+     * 获取快递公司列表
+     *
+     */
+    public function getExpressCompanyList($appId){
+        // 返回应用实例
+        $Mini                           = $this->getMini($appId);
+        // 获取access_token
+        $accessToken					= $Mini->access_token->getToken();
+        $params                         = [
+            'access_token'    =>    $accessToken['authorizer_access_token'],
+        ];
+        $data                           =   $params;
+        $params                             = http_build_query($params);
+        $data                             = json_encode($data, JSON_UNESCAPED_UNICODE);
+        $result                             = Curl::to('https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list?'.$params)->withData($data)->asJsonResponse(true)->post();
+        // 判断结果
+        if( !empty($result['errcode']) )    return ['code'=>'error','msg'=>$result['errcode'].'=>'.$result['errmsg']];
+        // 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+        return                              ['code'=>'success','msg'=>'成功','data'=>$result['delivery_list']];
+    }
+}