Selaa lähdekoodia

Merge branch 'refs/heads/stable-import-product'

moshaorui 17 tuntia sitten
vanhempi
sitoutus
319fafbbc3

+ 240 - 108
app/Distributor/Controllers/ImportProductController.php

@@ -3,50 +3,136 @@
 namespace App\Distributor\Controllers;
 
 
+use App\Distributor\Repositories\DistProduct;
+use App\Distributor\Repositories\NullRepository;
 use App\Distributor\Actions\Extensions\DistProductImportForm;
 use App\Distributor\Repositories\RpcAlbum;
 use App\Distributor\Repositories\RpcAlbumFolder;
-use App\Distributor\Repositories\BaseProduct;
 use App\Libraries\CommonHelper;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Form;
 use Dcat\Admin\Grid;
 use Dcat\Admin\Show;
 use Dcat\Admin\Layout\Content;
 
 class ImportProductController extends AdminDistController
 {
+
     /**
      * page index
      */
     public function index(Content $content)
     {
-        return $content
+        //记录folder_id
+        $folderId = isset($_GET['folder_id']) ? intval($_GET['folder_id']) : 0;
+        //保存临时变量
+        setTempValue('folderId', $folderId);
+        $html =  $content
             ->header(admin_trans( 'admin.product_import'))
-            ->description('<span style="color: red; font-weight: bold;">'.admin_trans_label('select_products_to_import').'</span>')
-            ->breadcrumb(['text'=>'list','url'=>''])
-            ->body($this->grid());
+            ->body($this->indexForm());
+        $html = $html->render();
+        return $this->filterHtml($html);
     }
 
+    protected function indexForm()
+    {
+        return Form::make(new NullRepository(), function (Form $form) {
+            $lang = config('app.locale');//当前语言
+            $form->action('/site-album');
+            $folderTree = RpcAlbumFolder::siteAlbumFolderAllNodes();
+            //显示左边树形菜单
+            $form->block(2, function (Form\BlockForm $form) use ($lang,$folderTree) {
+                $type = [
+                    'default'  => [
+                        'icon' => true,
+                    ],
+                ];
+                $plugins = ['types'];
+                if ($lang == 'en') {
+                    $form->tree()
+                        ->setTitleColumn('title_en')
+                        ->nodes($folderTree)
+                        ->type($type)
+                        ->plugins($plugins)
+                        ->width(12,0);
+                } else {
+                    $form->tree()
+                        ->setTitleColumn('title')
+                        ->nodes($folderTree)
+                        ->type($type)
+                        ->plugins($plugins)
+                        ->width(12,0);
+                }
+            });
+            //右边相删内容
+            $form->block(10, function (Form\BlockForm $form)  {
+                $form->html($this->grid())->width(12);
+            });
+            //以下JS代码用于点击文件夹时,自动跳转到相应页面
+            Admin::script(
+                <<<JS
+// 使用定时器检测容器是否存在
+const interval = setInterval(() => {
+    const containerUl = document.getElementsByClassName('jstree-node');
+    if (containerUl.length > 0) {
+        clearInterval(interval); // 找到容器后停止检测
+        // 以下是原有逻辑(已优化)
+        const folderId = $('select[name="folder_id"]').data('value'); // 提取 folderId 到外层,避免重复查询[1](@ref)
+        const anchors = document.querySelectorAll('a.jstree-anchor');
 
+        anchors.forEach(anchor => {
+            const id = anchor.id.split('_')[0];
+            const href = `/dist/import-product?folder_id=`+id;
 
-    //屏蔽删除
-    public function destroy($id)
-    {
-        abort(404);
+            // 绑定点击事件(阻止默认行为)
+            anchor.addEventListener('click', event => {
+                event.preventDefault();
+                window.location.href = href;
+            });
+
+            // 高亮当前节点
+            if (folderId == id) {
+                anchor.classList.add('jstree-clicked');
+            }
+        });
     }
+}, 100); // 每100ms检测一次
 
-    //屏蔽创建
-    public function create(Content $content)
-    {
-        abort(404);
+        const firstCheckbox = document.querySelector('.vs-checkbox-primary');
+        // 如果找到元素,则隐藏它
+        if (firstCheckbox) {
+            firstCheckbox.style.display = 'none';
+        }
+        //清空_previous_
+        const input = document.querySelector('input[name="_previous_"]');
+        if (input) {
+            // 清空其值
+            input.value = '';
+        }
+JS
+            );
+        });
     }
 
-    //屏蔽编辑
-    public function edit($id, Content $content)
+    /**
+     * @return void 过滤html 把form去掉,修复form引起的BUG
+     */
+    private function filterHtml($html)
     {
-        abort(404);
+        //删除第一个formID对应的JS代码
+        preg_match('/<form[^>]*id="([^"]*)"[^>]*>/', $html, $matches);
+        if (isset($matches[1])) {
+            $formId = $matches[1]; // 获取 id 的值
+            // echo "找到的 form id: " . $formId . "\n";
+            // 2. 根据 id 值,删除对应的 JavaScript 代码
+            $pattern = '/\$\(\'#' . preg_quote($formId, '/') . '\'\)\.form\(\{.*?\}\);/s';
+            $html = preg_replace($pattern, '', $html);
+        }
+        //把第一个form标签替换成div标签
+        $html = preg_replace('/<form([^>]*)>(.*?)<\/form>/s', '<div$1>$2</div>', $html, 1);
+        return $html;
     }
 
-
     /**
      * Make a grid builder.
      *
@@ -60,41 +146,47 @@ class ImportProductController extends AdminDistController
             $grid->column('id')->display(function () {
                 return $this->_index+1;
             })->width('8%');
+
             $grid->column('cover')->display(function ($images) {
                 $images = json_decode($images);
                 // 限制最多显示2个缩略图
                 $dataImages = array_slice($images, 0, 1);
                 return CommonHelper::displayImage($dataImages,100,1024,2);
             });
+
             if ($lang == 'en') {
                 $grid->column('title_en');
             } else {
                 $grid->column('title');
             }
-            $grid->column('model');
-            $grid->column('missing_content')->display(function ($missing_content) {
-                $missing_content = [];
-                if ($this->cover == '[]') {$missing_content[] = '主图';}
-                if ($this->en_detail == '[]') {$missing_content[] = '英文详情';}
-                if ($this->cn_detail == '[]') {$missing_content[] = '中文详情';}
-                if ($this->video == '[]') {$missing_content[] = '视频';}
-                if ($this->poster == '[]') {$missing_content[] = '海报';}
-                if ($this->cert == '[]') {$missing_content[] = '证书';}
-                if ($this->pdf == '[]') {$missing_content[] = 'PDF';}
-                return implode(' / ', $missing_content);
-            });
 
-            $grid->column('created_at')->sortable();
+            //$grid->column('created_at')->sortable();
             $grid->column('updated_at')->sortable();
 
+            $grid->column('imported')->display(function ($status) {
+                $status = DistProduct::isAlbumImport($this->id);
+                if ($status) {
+                    return '<span class="label label-success" style="background:#5cb85c">'.admin_trans_label('Yes').'</span>';
+                }   else {
+                    return '<span class="label label-default" style="background:#ccc">'.admin_trans_label('No').'</span>';
+                }
+            });
+
             // 筛选
-            $grid->filter(function (Grid\Filter $filter) {
+            $grid->filter(function (Grid\Filter $filter)   {
                 $filter->panel();
                 $filter->expand();
-                $filter->equal('model')->width(2);
                 $lang = config('app.locale');//当前语言
+                if ($lang == 'en') {
+                    $filter->equal('title_cn')->width(3);
+                } else {
+                    $filter->equal('title')->width(3);
+                }
                 $filter->equal('folder_id',admin_trans_label('product_category'))->select(RpcAlbumFolder::selectOptions($lang))->width(3);
+                //是否导入
+                $filter->equal('imported')->select([1 => admin_trans_label('Yes'),0 => admin_trans_label('No')])->width(3);
             });
+
             // 删除新增按钮
             $grid->disableCreateButton();
             //$grid->disableViewButton();
@@ -114,8 +206,12 @@ class ImportProductController extends AdminDistController
         });
     }
 
+
+
     protected function detail($id)
     {
+        CommonHelper::viewDownloadEnlarge();
+
         return Show::make($id, new \App\Admin\Repositories\RpcAlbum(), function (Show $show) {
             $lang = config('app.locale');//当前语言
             if ($lang == 'en') {
@@ -124,96 +220,132 @@ class ImportProductController extends AdminDistController
                 $show->field('title');
             }
 
-            $show->field('model');
-            $show->field('parameters',admin_trans_label('attribute'))->as(function ($items) {
-                $items = json_decode($items);
-                if (is_array($items)) {
-                    // 创建表格的表头
-                    $table = '<table class="table table-bordered table-condensed">';
-                    // 遍历数组并将数据填充到表格中
-                    foreach ($items as $item) {
-                        $item = (array)$item;
-                        $table .= '<tr>';
-                        $table .= '<td style="vertical-align: middle !important;width: 20%">' . $item['key'] . '</td>';    // 商品名称
-                        $table .= '<td style="vertical-align: middle !important;">' . $item['value'] . '</td>'; // 数量
-                        $table .= '</tr>';
+            if ($show->model()->model) {
+                $show->field('model');
+            }
+
+            if ($show->model()->parameters && $show->model()->parameters != '[]') {
+                $show->field('parameters',admin_trans_label('attribute'))->as(function ($items) {
+                    $items = json_decode($items);
+                    if (is_array($items)) {
+                        // 创建表格的表头
+                        $table = '<table class="table table-bordered table-condensed">';
+                        // 遍历数组并将数据填充到表格中
+                        foreach ($items as $item) {
+                            $item = (array)$item;
+                            $table .= '<tr>';
+                            $table .= '<td style="vertical-align: middle !important;width: 20%">' . $item['key'] . '</td>';    // 商品名称
+                            $table .= '<td style="vertical-align: middle !important;">' . $item['value'] . '</td>'; // 数量
+                            $table .= '</tr>';
+                        }
+                        $table .= '</table>';
+                        return $table;
                     }
-                    $table .= '</table>';
-                    return $table;
-                }
-                return ''; // 当没有数组数据时
-            })->unescape();
-            $show->field('cover')->as(function ($images) {
-                $images = json_decode($images);
-                return CommonHelper::displayImage($images,150,1024,2);
-            })->unescape();
+                    return ''; // 当没有数组数据时
+                })->unescape();
+            }
 
-            $show->field('en_detail')->as(function ($images) {
-                $images = json_decode($images);
-                $html = '<div style="text-align: center">';
-                foreach ($images as $key => $image) {
-                    $url = CommonHelper::albumUrl($image);
-                    $html .= '<img src="' . $url . '" style="max-width:90%;margin-bottom:10px">';
-                }
-                $html .= '</div>';
-                return $html;
-            })->unescape();
+            if ($show->model()->cover && $show->model()->cover != '[]') {
+                $show->field('cover')->as(function ($images) {
+                    $images = json_decode($images);
+                    return CommonHelper::displayImage($images,200,1024,2,false);
+                })->unescape();
+            }
 
-            $show->field('cn_detail')->as(function ($images) {
-                $images = json_decode($images);
-                $html = '<div style="text-align: center">';
-                foreach ($images as $key => $image) {
-                    $url = CommonHelper::albumUrl($image);
-                    $html .= '<img src="' . $url . '" style="max-width:90%;margin-bottom:10px">';
-                }
-                $html .= '</div>';
-                return $html;
-            })->unescape();
 
-            $show->field('video')->as(function ($items) {
-                $items = json_decode($items);
-                return CommonHelper::displayVideo($items,'cover','video_src','150',2);
-            })->unescape();
 
-            $show->field('poster')->as(function ($images) {
-                $images = json_decode($images);
-                return CommonHelper::displayImage($images,150,1024,2);
-            })->unescape();
+            if ($show->model()->en_detail && $show->model()->en_detail != '[]') {
+                $show->field('en_detail')->as(function ($images) {
+                    $images = json_decode($images);
+                    $html = '<div style="text-align: center">';
+                    foreach ($images as $key => $image) {
+                        $url = CommonHelper::albumUrl($image);
+                        $html .= '<img src="' . $url . '" style="max-width:90%;margin-bottom:10px">';
+                    }
+                    $html .= '</div>';
+                    return $html;
+                })->unescape();
+            }
 
-            $show->field('cert')->as(function ($images) {
-                $images = json_decode($images);
-                return CommonHelper::displayImage($images,150,1024,2);
-            })->unescape();
+            if ($show->model()->cn_detail && $show->model()->cn_detail != '[]') {
+                $show->field('cn_detail')->as(function ($images) {
+                    $images = json_decode($images);
+                    $html = '<div style="text-align: center">';
+                    foreach ($images as $key => $image) {
+                        $url = CommonHelper::albumUrl($image);
+                        $html .= '<img src="' . $url . '" style="max-width:90%;margin-bottom:10px">';
+                    }
+                    $html .= '</div>';
+                    return $html;
+                })->unescape();
+            }
 
-            $show->field('cert')->as(function ($images) {
-                $images = json_decode($images);
-                return CommonHelper::displayImage($images,150,1024,2);
-            })->unescape();
-
-            $show->field('pdf')->as(function ($items) {
-                $items = json_decode($items);
-                if (is_array($items)) {
-                    // 创建表格的表头
-                    $table = '<table class="table table-bordered table-condensed">';
-                    // 遍历数组并将数据填充到表格中
-                    foreach ($items as $item) {
-                        $table .= '<tr>';
-                        $table .= '<td style="vertical-align: middle !important;width: 20%">' . $item->pdf_title . '</td>';    // 商品名称
-                        $table .= '<td style="vertical-align: middle !important;"><a target="_blank" href="' . CommonHelper::albumUrl($item->pdf_src). '">查看</a></td>'; // 数量
-                        $table .= '</tr>';
+            if ($show->model()->video && $show->model()->video != '[]') {
+                $show->field('video')->as(function ($items) {
+                    $items = json_decode($items);
+                    return CommonHelper::displayVideo($items,'cover','video_src','150',2);
+                })->unescape();
+            }
+
+            if ($show->model()->poster && $show->model()->poster != '[]') {
+                $show->field('poster')->as(function ($images) {
+                    $images = json_decode($images);
+                    return CommonHelper::displayImage($images,200,1024,2,false);
+                })->unescape();
+            }
+
+            if ($show->model()->cert && $show->model()->cert != '[]') {
+                $show->field('cert')->as(function ($images) {
+                    $images = json_decode($images);
+                    return CommonHelper::displayImage($images,200,1024,2,false);
+                })->unescape();
+            }
+
+            if ($show->model()->pdf && $show->model()->pdf != '[]') {
+                $show->field('pdf')->as(function ($items) {
+                    $items = json_decode($items);
+                    if (is_array($items)) {
+                        // 创建表格的表头
+                        $table = '<table class="table table-bordered table-condensed">';
+                        // 遍历数组并将数据填充到表格中
+                        foreach ($items as $item) {
+                            $table .= '<tr>';
+                            $table .= '<td style="vertical-align: middle !important;width: 20%">' . $item->pdf_title . '</td>';    // 商品名称
+                            $table .= '<td style="vertical-align: middle !important;"><a target="_blank" href="' . CommonHelper::albumUrl($item->pdf_src). '">查看</a></td>'; // 数量
+                            $table .= '</tr>';
+                        }
+                        $table .= '</table>';
+                        return $table;
                     }
-                    $table .= '</table>';
-                    return $table;
-                }
-                return ''; // 当没有数组数据时
-            })->unescape();
+                    return ''; // 当没有数组数据时
+                })->unescape();
+            }
 
             // 禁用操作
             $show->disableEditButton();
             $show->disableDeleteButton();
 
-
+            $show->html(CommonHelper::viewDownloadEnlargeHtml());
         });
     }
 
+
+    //屏蔽删除
+    public function destroy($id)
+    {
+        abort(404);
+    }
+
+    //屏蔽创建
+    public function create(Content $content)
+    {
+        abort(404);
+    }
+
+    //屏蔽编辑
+    public function edit($id, Content $content)
+    {
+        abort(404);
+    }
+
 }

+ 7 - 3
app/Distributor/Controllers/SiteAlbumController.php

@@ -110,6 +110,8 @@ class SiteAlbumController extends AdminController
      */
     protected function detail($id)
     {
+        //JS图片下载放大
+        CommonHelper::viewDownloadEnlarge();
         return Show::make($id, new RpcAlbum(), function (Show $show) {
             $lang = config('app.locale');//当前语言
             //名称
@@ -149,7 +151,7 @@ class SiteAlbumController extends AdminController
             if (empty($show->model()->cover) == false && $show->model()->cover!= '[]') {
                 $show->field('cover')->as(function ($images) {
                     $images = json_decode($images);
-                    return CommonHelper::displayImage($images,150,1024,2);
+                    return CommonHelper::displayImage($images,150,1024,2,false);
                 })->unescape();
             }
             //详情
@@ -178,14 +180,14 @@ class SiteAlbumController extends AdminController
             if (empty($show->model()->poster) == false && $show->model()->poster!= '[]') {
                 $show->field('poster')->as(function ($images) {
                     $images = json_decode($images);
-                    return CommonHelper::displayImage($images,150,1024,2);
+                    return CommonHelper::displayImage($images,150,1024,2,false);
                 })->unescape();
             }
             //证书
             if (empty($show->model()->cert) == false && $show->model()->cert != '[]') {
                 $show->field('cert')->as(function ($images) {
                     $images = json_decode($images);
-                    return CommonHelper::displayImage($images,150,1024,2);
+                    return CommonHelper::displayImage($images,150,1024,2,false);
                 })->unescape();
             }
             //PDF
@@ -217,6 +219,8 @@ class SiteAlbumController extends AdminController
             // 禁用操作
             $show->disableEditButton();
             $show->disableDeleteButton();
+
+            $show->html(CommonHelper::viewDownloadEnlargeHtml());
         });
     }
 

+ 21 - 0
app/Distributor/Repositories/DistProduct.php

@@ -57,4 +57,25 @@ class DistProduct extends EloquentRepository
     {
         return Model::where('id', $id)->where('dist_id', getDistributorId())->first();
     }
+
+    /*
+     * 是否导入
+     * true 已导入
+     * false 未导入
+     */
+    public static function isAlbumImport($albumId) {
+        $count = Model::where('album_id', $albumId)->where('dist_id', getDistributorId())->count();
+        if ($count > 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * 查询已导入的相册IDS
+     */
+    public static function getImportAlbumIds() {
+        return Model::where('dist_id', getDistributorId())->where('album_id', '!=', '')->distinct('album_id')->pluck('album_id');
+    }
+
 }

+ 16 - 0
app/Distributor/Repositories/NullRepository.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Distributor\Repositories;
+
+use App\Models\NullModel as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class NullRepository extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+}

+ 14 - 3
app/Distributor/Repositories/RpcAlbum.php

@@ -69,6 +69,9 @@ class RpcAlbum extends EloquentRepository
         // 获取筛选参数
         $filterModel = $model->filter()->input('model', '');
         $folder_id = $model->filter()->input('folder_id', '');
+        $title = $model->filter()->input('title', '');
+        $title_en = $model->filter()->input('title_en', '');
+        $imported = $model->filter()->input('imported', '0');
 
         $filter = [
             'model' => $filterModel,
@@ -76,6 +79,17 @@ class RpcAlbum extends EloquentRepository
             'album_folder' => $self->albumFolder,//把查询结果限定在album_folder中
         ];
 
+        if ($title) {
+            $filter['title'] = $title;
+        } else if ($title_en) {
+            $filter['title_en'] = $title_en;
+        }
+
+        if ($imported == 1) {
+            $ids = DistProduct::getImportAlbumIds();
+            $filter['not_in_ids'] = implode(',', $ids);
+        }
+
         $result = $this->execute('siteAlbumPaginate', [
             'filter' => $filter,
             'sort' => $sort,
@@ -83,9 +97,6 @@ class RpcAlbum extends EloquentRepository
             'page' => $currentPage,
         ]);
 
-
-
-
         $data = $result['data'] ?? [];
 
         return $model->makePaginator(

+ 20 - 0
app/Distributor/Repositories/RpcAlbumFolder.php

@@ -55,4 +55,24 @@ class RpcAlbumFolder extends EloquentRepository
         $data = $result['data'] ?? [];
         return $data;
     }
+
+
+    /*
+     * 得到相册文件夹树全部节点
+     */
+    public static function siteAlbumFolderAllNodes() {
+        $self = new self();
+        $inIds = $self->albumFolder;
+        $result = $self->execute('siteAlbumFolderAllNodes', []);
+        $data = $result['data'] ?? [];
+
+        foreach ($data as $key => $value) {
+            //id或parent_id为都不在$inIds的节点,删除
+            if (!in_array($value['id'], $inIds) && !in_array($value['parent_id'], $inIds)) {
+                unset($data[$key]);
+            }
+        }
+        return $data;
+    }
+
 }

+ 220 - 2
app/Libraries/CommonHelper.php

@@ -13,7 +13,7 @@ class CommonHelper
      * $ossSource 1:本地 2:相册
      * 返回显示的HTML显示图片
      */
-    public static function displayImage($images,$boxSize=60,$imgSize=1024,$ossSource=1)
+    public static function displayImage($images,$boxSize=60,$imgSize=1024,$ossSource=1,$hasLink=true)
     {
         if (empty($images) || empty($images[0])) {
             $html = "";
@@ -55,7 +55,11 @@ class CommonHelper
             $html = '';
             foreach ($thumbnailImages as $index => $thumbnailUrl) {
                 $largeUrl = $largeImages[$index];
-                $html .= "<a href='$largeUrl' target='_blank'><img src='$thumbnailUrl' style='height:{$boxSize}px; margin-right:5px; border: 1px solid #ececf1;'></a>";
+                if ($hasLink) {
+                    $html .= "<a href='$largeUrl' target='_blank'><img src='$thumbnailUrl' style='height:{$boxSize}px; margin-right:5px; border: 1px solid #ececf1;'></a>";
+                } else {
+                    $html .= "<img src='$thumbnailUrl' style='height:{$boxSize}px; margin-right:5px; border: 1px solid #ececf1;'>";
+                }
             }
 
             return $html;
@@ -274,5 +278,219 @@ JS
             return $slug;
         }
     }
+
+
+
+    /*
+     * 用于详情页,图片下载与放大
+     */
+    public static function viewDownloadEnlarge() {
+//css
+Admin::style(
+<<<CSS
+.download-wrapper::after {
+    content: "";
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(58, 54, 54, 0.34); /* 浅灰色半透明 */
+    opacity: 0;
+    transition: opacity 0.3s ease;
+    pointer-events: none;
+    border-radius: 8px;
+}
+
+.download-wrapper {
+    position: relative;
+    display: inline-block;
+    margin: 15px;
+    overflow: hidden;
+    border-radius: 8px;
+    transition: transform 0.3s ease;
+}
+
+.download-hover {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    opacity: 0;
+    transition: opacity 0.3s ease;
+    display: flex;
+    gap: 12px;
+    z-index: 1; /* 确保按钮在遮罩层上方 */
+}
+
+.download-btn {
+    background: rgba(255, 255, 255, 0.95);
+    border: none;
+    width: 42px;
+    height: 42px;
+    border-radius: 50%;
+    cursor: pointer;
+    box-shadow: 0 3px 6px rgba(0,0,0,0.16);
+    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.download-btn.disabled {
+    background: rgba(189, 189, 189, 0.95);
+    cursor: not-allowed;
+}
+
+.download-btn i {
+    font-size: 18px;
+    color: #2196F3;
+}
+
+.download-wrapper:hover::after {
+    opacity: 1;
+}
+
+.download-wrapper:hover .download-hover {
+    opacity: 1;
+}
+
+.auto-download-image {
+    display: block;
+    transition: transform 0.3s ease;
+    max-width: 100%;
+    height: auto;
+    border-radius: 8px;
+}
+
+.download-wrapper:hover img {
+    transform: scale(1.04);
+}
+
+
+   /* 新增全屏样式 */
+        .fullscreen-overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background: rgba(0,0,0,0.95);
+            display: none;
+            z-index: 1000;
+            cursor: zoom-out;
+        }
+
+        .fullscreen-image {
+            position: absolute;
+            max-width: 90%;
+            max-height: 90%;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            border-radius: 8px;
+            animation: zoomIn 0.3s ease;
+        }
+
+        @keyframes zoomIn {
+            from { transform: translate(-50%, -50%) scale(0.8); }
+            to { transform: translate(-50%, -50%) scale(1); }
+        }
+
+        .download-wrapper:hover .download-hover {
+            opacity: 1;
+        }
+CSS );
+//js
+Admin::script(
+<<<JS
+      const fullscreenOverlay = $('.fullscreen-overlay');
+        const fullscreenImage = $('.fullscreen-image');
+
+   function initDownloadButtons() {
+    $('.box-body').find("img").each(function() {
+        // 新增判断:如果父元素是<a>或已有download-wrapper则跳过
+        if ($(this).parent().hasClass('download-wrapper') || $(this).parent().is('a')) return;
+        if ($(this).hasClass('fullscreen-image')) {
+            return;
+        }
+
+        const fileName = this.src.split('/').pop().split('?')[0];
+
+        $(this).wrap('<div class="download-wrapper"></div>')
+            .after(`<div class="download-hover">
+                                 <button class="download-btn" title="下载">
+                                   <i class="feather icon-download"></i>
+                                 </button>
+                                 <button class="download-btn zoom-btn" title="放大">
+                                   <i class="feather icon-zoom-in"></i>
+                                 </button>
+                               </div>`);
+
+        const \$btn = $(this).parent().find('.download-btn').first();
+        \$btn.click(function() {
+            const btn = $(this);
+            btn.addClass('disabled');
+
+            downloadImage(
+                btn.closest('.download-wrapper').find('img')[0].src,
+                fileName
+            ).finally(() => btn.removeClass('disabled'));
+        });
+
+                        // 全屏放大功能
+                $(this).next().find('.zoom-btn').click(function() {
+                    let imgSrc = $(this).closest('.download-wrapper').find('img').attr('src');
+                    imgSrc = imgSrc.replace(/\?.*$/, '');
+                    fullscreenImage.attr('src', imgSrc);
+                    fullscreenOverlay.fadeIn(200);
+                });
+
+    });
+}
+
+        // 关闭全屏
+        fullscreenOverlay.click(function(e) {
+            if (e.target === this) $(this).fadeOut(200);
+        });
+
+function downloadImage(url, filename) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(response => {
+                if (!response.ok) throw new Error('网络异常');
+                return response.blob()
+            })
+            .then(blob => {
+                const blobUrl = URL.createObjectURL(blob);
+                console.log(blobUrl);
+                const link = document.createElement('a');
+                link.href = blobUrl;
+                link.download = filename || 'image.jpg';
+                document.body.appendChild(link);
+                link.click();
+                setTimeout(() => {
+                    document.body.removeChild(link);
+                    URL.revokeObjectURL(blobUrl);
+                }, 100);
+                resolve();
+            })
+            .catch(error => {
+                console.error(error);
+                alert('下载失败');
+                reject(error);
+            });
+    });
+}
+
+initDownloadButtons();
+
+JS);
+    }
+
+    /*
+     * 用于详情页,图片下载与放大 HTML
+     */
+    public static function viewDownloadEnlargeHtml() {
+        return '<div class="fullscreen-overlay"><img src="" class="fullscreen-image"></div>';
+    }
+
 }
 

+ 0 - 1
lang/zh_CN/global.php

@@ -118,7 +118,6 @@ return [
         'youtube_category'      => 'Youtube 分类',
         'send_post'              => '发送帖子',
 
-
     ],
     'labels' => [
         'list'         => '列表',