Kaynağa Gözat

Merge branch 'refs/heads/master' into stable

moshaorui 1 ay önce
ebeveyn
işleme
50cff416db

+ 224 - 0
app/Console/Commands/SyncBr.php

@@ -0,0 +1,224 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\File;
+use Symfony\Component\DomCrawler\Crawler;
+
+
+/**
+ * 导入相册内容到产品表
+ * php artisan sync:brsite
+ */
+class SyncBr extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'sync:brsite';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+
+    public function handle()
+    {
+        exit;
+
+        $ossHost = 'https://mietubl-website.oss-accelerate.aliyuncs.com';
+        //$ossHost = 'https://mietubl-dev.oss-accelerate.aliyuncs.com';
+        $baseUrl = 'https://mietubloficial.com.br';
+        $urlList = [
+            ['slug'=>'tws', 'url'=>'/tws/'],
+            ['slug'=>'protetor-de-tela-de-vidro-temperado', 'url'=>'/protetor-de-tela-de-vidro-temperado/'],
+            ['slug'=>'protetor-da-tela-do-tablet', 'url'=>'/protetor-da-tela-do-tablet/'],
+            ['slug'=>'maquina-de-corte-de-protetor-de-tela', 'url'=>'/maquina-de-corte-de-protetor-de-tela/'],
+
+            ['slug'=>'folhas-de-protetor-de-tela-de-hidrogel', 'url'=>'/folhas-de-protetor-de-tela-de-hidrogel/'],
+
+            ['slug'=>'lightning', 'url'=>'/lightning/'],
+            ['slug'=>'type-c', 'url'=>'/type-c/'],
+            ['slug'=>'micro-usb', 'url'=>'/micro-usb/'],
+            ['slug'=>'fones-de-ouvido-auricular-com-fio', 'url'=>'/fones-de-ouvido-auricular-com-fio/'],
+            ['slug'=>'fones-de-ouvido', 'url'=>'/fones-de-ouvido/'],
+            ['slug'=>'alto-falantes-bluetooth', 'url'=>'/alto-falantes-bluetooth/'],
+            ['slug'=>'carregador-de-parede', 'url'=>'/carregador-de-parede/'],
+            ['slug'=>'produtos-perifericos', 'url'=>'/produtos-perifericos/'],
+        ];
+
+        foreach ($urlList as $entry) {
+            try {
+                $category = DB::table('dist_product_category')
+                    ->where('slug', $entry['slug'])
+                    ->where('dist_id', 3)
+                    ->first();
+
+                if (!$category) {
+                    echo "分类未找到,slug: {$entry['slug']}\n";
+                    continue;
+                }
+                echo "分类 {$category->name} \n";
+                //continue;
+
+                if ($entry['slug'] == 'produtos-perifericos') {
+                    $detailUrls = ['https://mietubloficial.com.br/produto/mini-impressora-de-pele-para-celular-mtb-pp01/'];
+                } else {
+                    $html = file_get_contents($baseUrl . $entry['url']);
+                    $listCrawler = new Crawler($html);
+                    $detailUrls = $listCrawler->filter('.elementor-shortcode a')->extract(['href']);
+
+                }
+
+                foreach ($detailUrls as $detailUrl) {
+
+                    $detailHtml = file_get_contents($detailUrl);
+                    $detailCrawler = new Crawler($detailHtml);
+
+
+
+                    // 解析基础数据
+                    $title = $detailCrawler->filter('.product_title')->text();
+                    $content = "";
+                    try {
+                        $content = $detailCrawler->filter('.elementor-widget-woocommerce-product-content .elementor-widget-container')->html();
+                    } catch (\Exception $e) {
+                        $content = "";
+                    }
+
+                    /******************** 新增内容提取逻辑 ​********************/
+                    // 提取 SEO 描述(第一个 p 标签内容)
+                    $seo_description = $detailCrawler->filter('.woocommerce-product-details__short-description p:first-child')->text('');
+
+                    // 提取 SKU(第二个 p 标签中 Modelo: 到 <br> 的内容)
+                    $sku_html = $detailCrawler->filter('.woocommerce-product-details__short-description p:nth-child(2)')->html('');
+                    $sku = '';
+                    if (strpos($sku_html, 'Modelo:') !== false) {
+                        $pos = strpos($sku_html, "<");
+                        if ($pos !== false) {
+                            $sku_html = substr($sku_html, 0, $pos);
+                        }
+                        $sku = str_replace("Modelo: ", "", $sku_html);
+                        $sku = trim($sku);
+                    }
+                    /******************** 新增内容提取结束 ​********************/
+
+                    echo "处理产品 {$title} \n";
+
+
+                    echo '插入产品获取ID完成' . "\n";
+                    // 插入产品获取ID
+                    $productId = DB::table('dist_product')->insertGetId([
+                        'title' => $title,
+                        'content' => $content, // 初始未处理的content
+                        'slug' => '',
+                        'dist_id' => 3,
+                        'enabled' => 1,
+                        'status' => 2,
+                        'seo_description' => $seo_description,
+                        'sku' => $sku,
+                        'category_id' => $category->id,
+                        'created_at' => Carbon::now(),
+                        'updated_at' => Carbon::now(),
+                        'parameters' => json_encode([])
+                    ]);
+
+                    echo '处理content中的图片' . "\n";
+                    if ($content != "") {
+                        //去除source标签
+                        $content = preg_replace('/<source\b[^>]*>.*?<\/source>/is', '', $content);
+                        $content = preg_replace('/<source[^>]*>/', '', $content);
+
+
+                        // 处理content中的图片
+                        $dom = new \DOMDocument();
+                        libxml_use_internal_errors(true);
+                        $dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
+                        libxml_clear_errors();
+
+                        $images = $dom->getElementsByTagName('img');
+                        foreach ($images as $img) {
+                            $originalSrc = $img->getAttribute('src');
+                            $absoluteSrc = $originalSrc;
+
+                            // 下载图片
+                            $imageContent = @file_get_contents($absoluteSrc);
+                            if ($imageContent === false) {
+                                echo "图片下载失败: {$absoluteSrc}\n";
+                                continue;
+                            }
+
+                            // 生成唯一文件名
+                            $extension = pathinfo($absoluteSrc, PATHINFO_EXTENSION);
+                            $filename = md5(uniqid() . microtime()) . '.' . $extension;
+
+                            // 保存路径
+                            $imageDir = public_path("static/tpl/screen_protector_solutions/product/{$productId}");
+                            if (!File::exists($imageDir)) {
+                                File::makeDirectory($imageDir, 0755, true, true);
+                            }
+                            file_put_contents("{$imageDir}/{$filename}", $imageContent);
+
+                            // 替换为OSS路径
+                            $newSrc = "{$ossHost}/static/tpl/screen_protector_solutions/product/{$productId}/{$filename}";
+                            $img->setAttribute('src', $newSrc);
+                            // 新增:移除 srcset 和 data-mce-src 属性
+                            $img->removeAttribute('srcset');
+                            $img->removeAttribute('data-mce-src');
+                            $img->removeAttribute('sizes');
+                        }
+
+                        // 获取处理后的HTML并更新数据库
+                        $processedContent = $dom->saveHTML();
+                    } else {
+                        $processedContent = $content;
+                    }
+
+                    DB::table('dist_product')
+                        ->where('id', $productId)
+                        ->update(['content' => $processedContent,'slug'=> $productId]);
+
+                    echo '获取处理后的HTML并更新数据库' . "\n";
+
+                    echo '处理主图' . "\n";
+                    // 处理主图
+                    $mainImages = $detailCrawler->filter('.woocommerce-product-gallery__wrapper a')->extract(['href']);
+                    $imageDirPath = "static/tpl/screen_protector_solutions/product/{$productId}";
+                    $imageDir = public_path($imageDirPath);
+                    File::makeDirectory($imageDir, 0755, true, true);
+
+                    foreach ($mainImages as $index => $imgUrl) {
+                        echo "处理主图 {$imgUrl} \n";
+                        $extension = pathinfo($imgUrl, PATHINFO_EXTENSION);
+                        $filename = "{$index}_" . md5(time()) . ".{$extension}";
+                        file_put_contents("{$imageDir}/{$filename}", file_get_contents($imgUrl));
+
+                        // 插入数据库
+                        DB::table('dist_product_image')->insert([
+                            'product_id' => $productId,
+                            'image_url' => "{$ossHost}/{$imageDirPath}/{$filename}",
+                            'order' => 0,
+                            'created_at' => Carbon::now(),
+                            'updated_at' => Carbon::now(),
+                        ]);
+                    }
+                    echo "处理主图完成,下一个产品 \n";
+                    echo "------------------------------------------\n";
+                }
+            } catch (\Exception $e) {
+                echo "数据采集失败: " . $e->getMessage() . "\n";
+                continue;
+            }
+        }
+        dd('所有处理完成');
+    }
+
+}

+ 4 - 1
app/Distributor/Controllers/DistProductCategoryController.php

@@ -77,7 +77,10 @@ class DistProductCategoryController extends AdminDistController
     {
         return Form::make(new DistProductCategory(), function (Form $form) {
             $form->select('parent_id', admin_trans_field('parent'))
-                ->options(DistProductCategory::selectOptionsShowTow())
+                ->options(DistProductCategory::selectMainOptions(function ($query) {
+                    // 在这里定义查询条件
+                    $query->where('parent_id', 0);
+                }))
                 ->saving(function ($v) {
                     return (int) $v;
                 });

+ 9 - 0
app/Http/Middleware/DistAuth.php

@@ -27,6 +27,15 @@ class DistAuth
                 }
             }
         }
+        //判断是否登录,如果getDistributor不存在,则触发登录页面
+        if (Admin::user()) {
+            if (!getDistributor()) {
+                if (strpos($request->url(), 'auth/logout') == false) {
+                    // 存在时的逻辑
+                    return redirect('/dist/auth/logout');
+                }
+            }
+        }
 
         //否则继续处理当前请求
         return $next($request);

+ 2 - 1
composer.json

@@ -12,7 +12,8 @@
         "guzzlehttp/guzzle": "^7.2",
         "laravel/framework": "^9.19",
         "laravel/sanctum": "^3.0",
-        "laravel/tinker": "^2.7"
+        "laravel/tinker": "^2.7",
+        "symfony/dom-crawler": "^7.2"
     },
     "require-dev": {
         "fakerphp/faker": "^1.9.1",

+ 147 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "e553ae528c395a7344fa7214a3e381b3",
+    "content-hash": "d5c6237309a497437a44985e037d1c19",
     "packages": [
         {
             "name": "aliyuncs/oss-sdk-php",
@@ -2409,6 +2409,79 @@
             ],
             "time": "2024-09-21T08:32:55+00:00"
         },
+        {
+            "name": "masterminds/html5",
+            "version": "2.8.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Masterminds/html5-php.git",
+                "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf",
+                "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "ext-dom": "*",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Masterminds\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Matt Butcher",
+                    "email": "technosophos@gmail.com"
+                },
+                {
+                    "name": "Matt Farina",
+                    "email": "matt@mattfarina.com"
+                },
+                {
+                    "name": "Asmir Mustafic",
+                    "email": "goetas@gmail.com"
+                }
+            ],
+            "description": "An HTML5 parser and serializer.",
+            "homepage": "http://masterminds.github.io/html5-php",
+            "keywords": [
+                "HTML5",
+                "dom",
+                "html",
+                "parser",
+                "querypath",
+                "serializer",
+                "xml"
+            ],
+            "support": {
+                "issues": "https://github.com/Masterminds/html5-php/issues",
+                "source": "https://github.com/Masterminds/html5-php/tree/2.8.1"
+            },
+            "time": "2023-05-10T11:58:31+00:00"
+        },
         {
             "name": "monolog/monolog",
             "version": "2.9.3",
@@ -4109,6 +4182,79 @@
             ],
             "time": "2024-04-18T09:32:20+00:00"
         },
+        {
+            "name": "symfony/dom-crawler",
+            "version": "v7.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/dom-crawler.git",
+                "reference": "b176e1f1f550ef44c94eb971bf92488de08f7c6b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b176e1f1f550ef44c94eb971bf92488de08f7c6b",
+                "reference": "b176e1f1f550ef44c94eb971bf92488de08f7c6b",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "masterminds/html5": "^2.6",
+                "php": ">=8.2",
+                "symfony/polyfill-ctype": "~1.8",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "symfony/css-selector": "^6.4|^7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\DomCrawler\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Eases DOM navigation for HTML and XML documents",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/dom-crawler/tree/v7.2.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-11-13T16:15:23+00:00"
+        },
         {
             "name": "symfony/error-handler",
             "version": "v6.4.10",