moshaorui 2 달 전
부모
커밋
685536a0df
100개의 변경된 파일5743개의 추가작업 그리고 903개의 파일을 삭제
  1. 10 2
      .env.dev
  2. 94 0
      app/Admin/Controllers/BaseProductCategoryController.php
  3. 248 0
      app/Admin/Controllers/BaseProductController.php
  4. 83 0
      app/Admin/Controllers/BaseProductParameterController.php
  5. 85 0
      app/Admin/Controllers/BaseVideoCategoryController.php
  6. 160 0
      app/Admin/Controllers/BaseVideoController.php
  7. 154 0
      app/Admin/Controllers/DistAdminDistributorController.php
  8. 148 0
      app/Admin/Controllers/DistAdminUserController.php
  9. 144 0
      app/Admin/Controllers/DistAppearanceController.php
  10. 155 0
      app/Admin/Controllers/DistAppearanceTemplateController.php
  11. 180 0
      app/Admin/Controllers/DistAppearanceVariableController.php
  12. 142 0
      app/Admin/Controllers/DistInquiryController.php
  13. 181 0
      app/Admin/Controllers/DistMessageController.php
  14. 201 0
      app/Admin/Controllers/DistSiteController.php
  15. 17 6
      app/Admin/Controllers/HomeController.php
  16. 0 284
      app/Admin/Controllers/SiteAlbumController.php
  17. 0 85
      app/Admin/Controllers/SiteAlbumFolderController.php
  18. 51 0
      app/Admin/Forms/AceLeft.php
  19. 225 0
      app/Admin/Forms/AppearanceImPortForm.php
  20. 47 0
      app/Admin/Forms/InquiryAssignment.php
  21. 38 0
      app/Admin/Repositories/BaseIso3166.php
  22. 29 0
      app/Admin/Repositories/BaseProduct.php
  23. 52 30
      app/Admin/Repositories/BaseProductCategory.php
  24. 84 0
      app/Admin/Repositories/BaseProductImage.php
  25. 25 0
      app/Admin/Repositories/BaseProductParameter.php
  26. 5 2
      app/Admin/Repositories/BaseVideo.php
  27. 34 0
      app/Admin/Repositories/BaseVideoCategory.php
  28. 464 0
      app/Admin/Repositories/DistAdminDistributor.php
  29. 41 0
      app/Admin/Repositories/DistAdminUser.php
  30. 80 0
      app/Admin/Repositories/DistAppearance.php
  31. 33 0
      app/Admin/Repositories/DistAppearanceBak.php
  32. 50 0
      app/Admin/Repositories/DistAppearancePublishList.php
  33. 184 0
      app/Admin/Repositories/DistAppearanceTemplate.php
  34. 70 0
      app/Admin/Repositories/DistAppearanceTemplateLog.php
  35. 57 0
      app/Admin/Repositories/DistAppearanceVariable.php
  36. 64 0
      app/Admin/Repositories/DistInquiry.php
  37. 21 0
      app/Admin/Repositories/DistMessage.php
  38. 18 0
      app/Admin/Repositories/SiteAppearanceTemplate.php
  39. 21 0
      app/Admin/Repositories/SiteAppearanceVariable.php
  40. 16 0
      app/Admin/Repositories/SiteBanner.php
  41. 61 0
      app/Admin/Repositories/SiteMenu.php
  42. 2 2
      app/Admin/Repositories/Test.php
  43. 0 4
      app/Admin/bootstrap.php
  44. 31 4
      app/Admin/routes.php
  45. 0 15
      app/Exceptions/Form/TradFile.php
  46. 0 74
      app/Exceptions/Form/TradImage.php
  47. 1 0
      app/Http/Kernel.php
  48. 36 0
      app/Http/Middleware/DistAuth.php
  49. 1 2
      app/Libraries/CommonHelper.php
  50. 16 0
      app/Models/BaseIso3166.php
  51. 43 0
      app/Models/BaseProduct.php
  52. 50 0
      app/Models/BaseProductCategory.php
  53. 30 0
      app/Models/BaseProductImage.php
  54. 35 0
      app/Models/BaseProductParameter.php
  55. 39 0
      app/Models/BaseVideo.php
  56. 29 0
      app/Models/BaseVideoCategory.php
  57. 63 0
      app/Models/DistAdminDistributor.php
  58. 9 0
      app/Models/DistAdminMenu.php
  59. 4 4
      app/Models/DistAdminRoleUser.php
  60. 21 0
      app/Models/DistAdminUser.php
  61. 3 2
      app/Models/DistAdminUsersSetting.php
  62. 32 0
      app/Models/DistAppearance.php
  63. 126 0
      app/Models/DistAppearanceBak.php
  64. 14 0
      app/Models/DistAppearancePublishList.php
  65. 98 0
      app/Models/DistAppearanceTemplate.php
  66. 17 0
      app/Models/DistAppearanceTemplateLog.php
  67. 122 0
      app/Models/DistAppearanceVariable.php
  68. 38 0
      app/Models/DistInquiry.php
  69. 50 0
      app/Models/DistMessage.php
  70. 62 0
      app/Models/DistProduct.php
  71. 79 0
      app/Models/DistProductCategory.php
  72. 32 0
      app/Models/DistProductImage.php
  73. 14 0
      app/Models/DistProductParameter.php
  74. 26 0
      app/Models/DistReadStatus.php
  75. 38 0
      app/Models/DistVideo.php
  76. 29 0
      app/Models/DistVideoCategory.php
  77. 0 27
      app/Models/SiteAlbumFolder.php
  78. 16 0
      app/Models/SiteAppearanceTemplate.php
  79. 17 0
      app/Models/SiteAppearanceVariable.php
  80. 26 0
      app/Models/SiteBanner.php
  81. 131 0
      app/Models/SiteMenu.php
  82. 44 0
      app/Models/SitePages.php
  83. 24 0
      app/Models/SitePagesTag.php
  84. 19 0
      app/Models/SitePagesTagRelationship.php
  85. 19 0
      app/Models/Test.php
  86. 44 0
      app/Models/User.php
  87. 1 13
      config/admin.php
  88. 70 7
      config/dictionary.php
  89. 0 31
      database/migrations/2024_12_31_064946_updata_distributor_table.php
  90. 0 232
      dcat_admin_ide_helper.php
  91. 1 5
      lang/en/admin.php
  92. 0 30
      lang/en/global.php
  93. 2 8
      lang/zh_CN/admin.php
  94. 0 30
      lang/zh_CN/global.php
  95. 0 4
      lang/zh_CN/menu.php
  96. 230 0
      lang/zh_TW/admin.php
  97. 19 0
      lang/zh_TW/auth.php
  98. 22 0
      lang/zh_TW/extension.php
  99. 79 0
      lang/zh_TW/global.php
  100. 17 0
      lang/zh_TW/menu.php

+ 10 - 2
.env.dev

@@ -9,6 +9,12 @@ APP_URL=http://localhost
 #是否https
 ADMIN_HTTPS=false
 
+#后台网站主域名,不含http://www.
+TOP_DOMAIN=mietubl.com.cn
+#分销商前端站点IP,用于提醒分销商绑定域名IP
+DIST_SITE_IP = 127.0.0.1
+#分销商前端站点端口,用于访问站点
+DIST_SITE_PORT = 8888
 #以下不用改
 LOG_CHANNEL=stack
 LOG_DEPRECATIONS_CHANNEL=null
@@ -42,7 +48,6 @@ MAIL_PASSWORD=null
 MAIL_ENCRYPTION=null
 MAIL_FROM_ADDRESS="hello@example.com"
 MAIL_FROM_NAME="${APP_NAME}"
-
 #以下不用改
 AWS_ACCESS_KEY_ID=
 AWS_SECRET_ACCESS_KEY=
@@ -69,12 +74,15 @@ OSS_ACCESS_KEY_ID=LTAI5tCYd6zdBrSN9W9hZRUd
 OSS_ACCESS_KEY_SECRET=q0pp2qlDXdxi490qMDbDuWBd7SPMNn
 OSS_BUCKET=mietubl-dev
 OSS_ENDPOINT=oss-cn-hongkong.aliyuncs.com
-
 #内网上传,上线时开
 #OSS_INTERNAL=oss-cn-hongkong-internal.aliyuncs.com
 #加速域名,上线时开
 #OSS_DOMAIN=mietubl-dev.oss-accelerate.aliyuncs.com
 
 
+MAIL_TO_NAME=""
+MAIL_TO_ADDRESS=""
 
+MAIL_CC_NAME=""
+MAIL_CC_ADDRESS=""
 

+ 94 - 0
app/Admin/Controllers/BaseProductCategoryController.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\BaseProductCategory;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use App\Admin\Repositories\BaseProductParameter;
+
+class BaseProductCategoryController extends AdminController
+{
+
+    public function index(Content $content)
+    {
+        return $content
+            ->header(admin_trans( 'admin.proudct_category'))
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(BaseProductCategory::with('baseProductParameter'), function (Grid $grid) {
+            $grid->view('admin.grid-custom.table');
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            $grid->column('id')->display(function () {
+                return $this->_index+1;
+            });
+            $grid->column('name')->display(function ($name) {
+                $level = $this->level; // 获取当前行的 level 字段值
+                $prefix = str_repeat('&nbsp; ', $level * 2). ' <i class="fa fa-angle-right"></i>&nbsp; '; // 生成 level * 3 个加号
+                return $prefix . ' ' . html_entity_decode($name); // 拼接加号和名称
+            });;
+            $grid->column('parent_id');
+            $grid->column('baseProductParameter.name',admin_trans_label('attribute_name'));
+            $grid->column('order');
+            $grid->column('enabled')->switch();
+            $grid->column('created_at');
+            $grid->column('updated_at')->sortable();
+            //过滤器
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->like('name')->width(2);
+                $filter->equal('enabled', admin_trans_label('enabled'))->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            //工具栏
+            $grid->disableViewButton();
+            $grid->showQuickEditButton();
+            $grid->enableDialogCreate();
+            $grid->disableEditButton();
+
+            $grid->disablePerPages();
+            //$grid->quickSearch('name');
+        });
+
+    }
+
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new BaseProductCategory(), function (Form $form) {
+            $form->select('parent_id', admin_trans_field('parent'))
+                ->options(BaseProductCategory::selectMainOptions())
+                ->saving(function ($v) {
+                    return (int) $v;
+                });
+            $form->text('name')->required();
+            $form->select('parameter_id', admin_trans_field('attribute_name'))->options(BaseProductParameter::selectOptions())->required();
+            $form->textarea('remark')->rows(2);
+            $form->number('order')
+                ->default(0)
+                ->rules('numeric');
+            $form->switch('enabled')->default(1);
+          //  $form->display('created_at');
+          //  $form->display('updated_at');
+        });
+    }
+}

+ 248 - 0
app/Admin/Controllers/BaseProductController.php

@@ -0,0 +1,248 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\BaseProduct;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Form;
+use Dcat\Admin\Form\NestedForm;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use App\Admin\Repositories\BaseProductCategory;
+use App\Admin\Repositories\BaseProductImage;
+use Illuminate\Http\Request;
+use App\Libraries\CommonHelper;
+class BaseProductController extends AdminController
+{
+
+    public function title()
+    {
+        return admin_trans( 'admin.products_list');
+    }
+
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(BaseProduct::with(['baseProductCategory','images']), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+
+            $grid->column('id')->display(function () {
+                return $this->_index+1;
+            });
+            $grid->column('title');
+            $grid->column('sku');
+            $grid->column('base_product_category.name',admin_trans_label('category_name'));
+            $grid->column('images')->display(function ($images) {
+                $images = $images->toArray();
+                $dataImages = array_column($images, 'image_url');
+                // 限制最多显示2个缩略图
+                $dataImages = array_slice($dataImages, 0, 1);
+                return CommonHelper::displayImage($dataImages,100);
+            });
+            $grid->column('order')->sortable();
+            $grid->column('enabled')->switch();
+            $grid->column('created_at')->sortable();
+            $grid->column('updated_at')->sortable();
+            // 筛选
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('sku')->width(2);
+                $filter->like('title')->width(2);
+                $filter->equal('category_id',admin_trans_label('category_name'))->select(BaseProductCategory::selectOptions())->width(3);
+                $filter->equal('enabled')->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            //排序
+            $grid->model()->orderBy('created_at','desc');
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, BaseProduct::with(['baseProductCategory','images']), function (Show $show) {
+            $show->field('title');
+            $show->field('sku');
+            $show->field('base_product_category.name',admin_trans_label('category_name'));
+            $show->field('issuance_date');
+            $show->field('parameters',admin_trans_label('attribute_name'))->as(function ($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['key'] . '</td>';    // 商品名称
+                        $table .= '<td style="vertical-align: middle !important;">' . $item['value'] . '</td>'; // 数量
+                        $table .= '</tr>';
+                    }
+                    $table .= '</table>';
+                    return $table;
+                }
+                return ''; // 当没有数组数据时
+            })->unescape();
+            $show->field('images')->as(function ($images) {
+                // 开始生成 HTML
+                $dataImages = array_column($images, 'image_url');
+                return CommonHelper::displayImage($dataImages,150);
+            })->unescape();
+            $show->field('content')->unescape();
+            $show->field('seo_title');
+            $show->field('seo_keywords');
+            $show->field('seo_description');
+            $show->field('order');
+            $show->field('enabled')->using(admin_trans_array(config('dictionary.enabled')));
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(BaseProduct::with('images'), function (Form $form) {
+            $form->select('category_id', admin_trans_label('category_name'))
+                ->options(BaseProductCategory::selectOptions())
+                ->required();
+            $form->text('title')->required();
+            $form->text('sku')->required();
+            $form->date('issuance_date');
+            $form->table('parameters',admin_trans_label('attribute_name'), function (Form\NestedForm $table) {
+                $table->text('key')->required();
+                $table->text('value')->required();
+            });
+            // 多图上传
+            $form->multipleImage('images', admin_trans_label('images'))
+                ->retainable()//禁止删OSS图
+                ->sortable() // 可拖动排序
+                ->removable() // 可移除图片
+                ->autoUpload() // 自动上传
+                ->uniqueName()
+                ->limit(config('admin.upload.oss_image.limit'))
+                ->accept(config('admin.upload.oss_image.accept'))
+                ->maxSize(config('admin.upload.oss_image.max_size'))
+                ->dir(config("admin.upload.directory.image").'/product/'.date("Ymd"))
+                ->customFormat(function ($images) {
+                    // 数据格式化为数组['1.jpg','2.jpg'] 编辑时用到
+                    return array_column($images, 'image_url');
+                })
+                ->saving(function ($images) use ($form) {
+                    $id = $form->getKey();
+                    $reslut =  BaseProductImage::formatData($id,$images);
+                    return $reslut;
+                });
+            $form->editor('content');
+            $form->text('seo_title');
+            $form->text('seo_keywords');
+            $form->text('seo_description');
+            $form->number('order')
+                ->default(0)
+                ->rules('numeric');
+            $form->switch('enabled')->default(1);
+
+            //插入参数联动JS
+            $this->addParametersJs();
+            //新建时插入JS
+            $form->creating(function (Form $form) {
+                CommonHelper::seoReplace('title',false);
+            });
+            //保存前回调
+            $form->saving(function ($form) {
+                //检查sku是否重复
+                $baseProduct = new BaseProduct();
+                if ($form->isCreating()) {
+                    $count = $baseProduct->model()->where('sku', $form->sku)->count();
+                } else {
+                    $count = $baseProduct->model()->where('sku', $form->sku)->where('id', '!=', $form->getKey())->count();
+                }
+                if ($count > 0) {
+                    return $form->response()->error('sku already exists');
+                }
+            });
+        });
+    }
+
+    /*
+     * 以json型式返回产品参数
+     */
+    public static function parameter(Request $request)
+    {
+        $id = $request->query('q');
+        $content = BaseProductCategory::getParameter($id);
+        return $content;
+    }
+
+    /**
+     * 分类与参数联动JS
+     * @return void
+     */
+    private function addParametersJs()
+    {
+        $prefix = config('admin.route.prefix');
+        //插入JS
+        Admin::script(
+            <<<JS
+var fill_param = function (key,val) {
+    lastForm = $(".has-many-table-parameters-form:last");
+    lastForm.find('input').eq(0).val(key);
+    lastForm.find('input').eq(1).val(val);
+}
+
+$('select[name="category_id"]').on('change', function() {
+    var category_id = $(this).val();
+    // 清空现有的表格行
+    $('.has-many-table-parameters-form').remove();
+    if (category_id > 0) {
+        $.ajax({
+            url: '/{$prefix}/base-product/parameter',
+            data: { q: category_id},
+            dataType: 'json',
+            type: 'GET',              // GET
+            success: function(data) { // success
+                if (Array.isArray(data) && data.length === 0) {
+                    return null;
+                }
+                // 动态添加新数据到表格
+                $.each(data, function(index, item) {
+                    $(".has-many-table-parameters").find(".add").click();
+                    fill_param(item.key,item.value);
+                });
+            },
+            error: function(error) {  // 错误时执行的代码
+                console.log('error:', error);
+            }
+        });
+    }
+
+});
+JS
+        );
+    }
+}

+ 83 - 0
app/Admin/Controllers/BaseProductParameterController.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\BaseProductParameter;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Form\NestedForm;
+
+class BaseProductParameterController extends AdminController
+{
+    public function index(Content $content)
+    {
+        return $content
+            ->header(admin_trans( 'admin.product_attribute'))
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new BaseProductParameter(), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            $grid->column('id')->display(function () {
+                return $this->_index+1;
+            });
+            $grid->column('name');
+            $grid->column('order');
+            $grid->column('enabled')->switch();
+            $grid->column('created_at');
+            $grid->column('updated_at')->sortable();
+            // 允许筛选
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('name')->width(2);
+                $filter->equal('enabled', )->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            //按钮
+            $grid->disableViewButton();
+            $grid->showQuickEditButton();
+            $grid->enableDialogCreate();
+            $grid->disableEditButton();
+            //$grid->quickSearch('name');
+            //排序
+            $grid->model()->orderBy("order",'desc')->orderBy('id', 'desc');
+        });
+    }
+
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new BaseProductParameter(), function (Form $form) {
+            $form->text('name')->required();
+            $form->table('content',admin_trans_label('attribute'), function (NestedForm $table) {
+                $table->text('key')->required();
+                $table->text('value');
+            })->setLabelClass('control-label')->default([
+                ['key' => '', 'value' => ''],
+            ]);
+            $form->number('order')
+                ->default(0)
+                ->rules('numeric');
+            $form->switch('enabled')->default(1);
+        });
+    }
+}

+ 85 - 0
app/Admin/Controllers/BaseVideoCategoryController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\BaseProductCategory;
+use App\Admin\Repositories\BaseVideoCategory;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+
+class BaseVideoCategoryController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans( 'admin.video_category');
+    }
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new BaseVideoCategory(), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            $grid->column('id')->display(function () {
+                return $this->_index+1;
+            });
+            $grid->column('name');
+            //$grid->column('parent_id');
+            $grid->column('order');
+            $grid->column('enabled')->switch();
+            $grid->column('created_at');
+            $grid->column('updated_at')->sortable();
+            //$grid->quickSearch('name');
+            // 允许筛选
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('name')->width(2);
+                $filter->equal('enabled', admin_trans_label('enabled'))->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            //按钮
+            $grid->disableViewButton();
+            $grid->showQuickEditButton();
+            $grid->enableDialogCreate();
+            $grid->disableEditButton();
+            //排序
+            $grid->model()->orderBy('order', 'desc')->orderBy('id','desc');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new BaseVideoCategory(), function (Form $form) {
+            //$form->display('id');
+            $form->text('name');
+            $form->number('order')
+                ->default(0)
+                ->rules('numeric');
+            $form->switch('enabled')->default(1);
+        });
+    }
+}

+ 160 - 0
app/Admin/Controllers/BaseVideoController.php

@@ -0,0 +1,160 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\BaseProductCategory;
+use App\Admin\Repositories\BaseVideo;
+use App\Admin\Repositories\BaseVideoCategory;
+use App\Libraries\CommonHelper;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+
+class BaseVideoController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans( 'admin.video_list');
+    }
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(BaseVideo::with(['baseVideoCategory']), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            $grid->column('id')->display(function () {
+                return $this->_index+1;
+            });
+            $grid->column('title')->width('25%');
+            $grid->column('base_video_category.name',admin_trans_label('category_name'));
+            $grid->column('cover_image')->display(function ($image) {
+                // 开始生成 HTML
+                $dataImages = [$image];
+                return CommonHelper::displayImage($dataImages,100);
+            });
+            $grid->column('order');
+            $grid->column('enabled')->switch();
+            $grid->column('created_at')->sortable();
+            $grid->column('updated_at')->sortable();
+            // 筛选
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('sku')->width(2);
+                $filter->like('title')->width(2);
+                $filter->equal('category_id',admin_trans_label('category'))->select(BaseVideoCategory::selectOptions())->width(2);
+                $filter->equal('enabled', admin_trans_label('enabled'))->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            //排序
+            $grid->model()->orderBy("order",'desc')->orderBy('id','desc');
+            //按钮
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, BaseVideo::with(['baseVideoCategory']), function (Show $show) {
+            $show->field('title');
+            $show->field('base_video_category.name',admin_trans_field('category_name'));
+            $show->field('cover_image')->as(function ($image) {
+                // 开始生成 HTML
+                $dataImages = [$image];
+                return CommonHelper::displayImage($dataImages,150);
+            })->unescape();
+            $show->html(function () {
+                $content = $this->video_url;
+                return view('admin::show.field', [
+                    'wrapped'=>true,
+                    'escape'=>false,
+                    'width'=>['label' => '2','field'=>'8'],
+                    'label'=>admin_trans_label('video_url'),
+                    'content'=>$content
+                ]);
+            });
+            $show->field('video_url',admin_trans_label('video_player'))->as(function ($value) {
+                $html = '
+                <iframe width="560" height="315" src="'.$value.'"
+                        title="YouTube video player"
+                        frameborder="0"
+                        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+                        allowfullscreen>
+                 </iframe>';
+                return $html;
+            })->unescape();
+            $show->field('remark')->unescape();
+            $show->field('order');
+            $show->field('enabled')->using(admin_trans_array(config('dictionary.enabled')));
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new BaseVideo(), function (Form $form) {
+            //$form->display('id');
+            $help = admin_trans_label('video_help');
+            $inputFormat = admin_trans_label('input_format');
+            $form->text('title')->required();
+            $form->select('category_id', admin_trans_field('category_name'))
+                ->options(BaseVideoCategory::selectOptions())
+                ->required();
+            $form->image("cover_image")
+                ->retainable()//禁止删OSS图
+                ->autoUpload()
+                ->uniqueName()
+                ->accept(config('admin.upload.oss_image.accept'))
+                ->maxSize(config('admin.upload.oss_image.max_size'))
+                ->dir(config("admin.upload.directory.image").'/video/'.date("Ymd"));//
+            $form->text("video_url")
+                ->required()
+                ->help('<a href="/help/youtube_url/index.html" target="_blank">'.$help. ' </a>, '.$inputFormat.' : https://www.youtube.com/embed/xxxxxxxx');
+            $form->editor('remark');
+            $form->number('order')
+                ->default(0)
+                ->rules('numeric');
+            $form->switch('enabled')->default(1);
+            $form->saving(function (Form $form) {
+                //替换youtube URL
+                if (strpos($form->video_url, '<iframe') !== false) {
+                    // 使用正则表达式提取 src 属性的值
+                    if (preg_match('/<iframe[^>]+src="([^"]+)"/', $form->video_url, $matches)) {
+                        $src = $matches[1];
+                        $form->video_url = $src;
+                    }
+                }
+            });
+        });
+    }
+
+}

+ 154 - 0
app/Admin/Controllers/DistAdminDistributorController.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Grid\InitAppearance;
+use App\Admin\Repositories\BaseIso3166;
+use App\Admin\Repositories\DistAdminDistributor;
+use App\Admin\Repositories\DistAppearance;
+use App\Libraries\CommonHelper;
+use App\Models\DistProductCategory;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+use Illuminate\Support\Facades\DB;
+
+class DistAdminDistributorController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans( 'admin.distro_list');
+    }
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+
+        return Grid::make(DistAdminDistributor::with(['appearance']), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            //指定视图,去掉删除按钮
+            $grid->view('admin.grid.table');
+            $grid->column('id')->sortable();
+            $grid->column('client_code',admin_trans_label('client_code'))->width('15%');
+            $grid->column('dist_email',admin_trans_label('email'));
+            $grid->column('country',);
+            $grid->column('enabled')->switch();
+            $grid->column('created_at')->sortable();
+            // 过滤
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('dist_code',admin_trans_label('client_code') )->width(2);
+                $filter->equal('secondary_domain')->width(2);
+                $filter->equal('enabled')->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            // 排序
+            $grid->model()->orderBy("id",'desc');
+            //按钮
+            $grid->showQuickEditButton();
+            $grid->enableDialogCreate();
+            $grid->disableEditButton();
+            $grid->disableDeleteButton();
+            //批量操作
+            $grid->batchActions(function (Grid\Tools\BatchActions $batch) {
+                $batch->disableDelete();
+                $batch->add(new InitAppearance());
+            });
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, DistAdminDistributor::with(['appearance']), function (Show $show) {
+            $show->field('client_code',admin_trans_label('client_code'));
+            $show->field('dist_email',admin_trans_label('email'));
+            $show->field('dist_contact_number',admin_trans_label('contact_number'));
+            $show->field('country');
+            $show->field('country_alpha_2');
+            $show->field('country_lang');
+            $show->field('address');
+            $show->field('created_at');
+            $show->field('updated_at');
+            $show->field('enabled')->using(admin_trans_array(config('dictionary.enabled')));
+            // 按钮
+            $show->disableDeleteButton();
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new DistAdminDistributor(), function (Form $form) {
+            $form->text('client_code',admin_trans_label('client_code'))->width(9,3)->required();
+            $form->text('dist_email',admin_trans_label('email'))->width(9,3);
+            $form->text('dist_contact_number',admin_trans_label('contact_number'))->width(9,3);
+            $form->select('country')
+                ->options(BaseIso3166::selectOptions())
+                ->width(9,3)->required();
+            $form->text('country_lang')->width(9,3)->required()->help(admin_trans_label('country_lang_tips'));
+            $form->text('address')->width(9,3);
+            $form->switch('enabled')->width(9,3)->default(1);
+            $form->hidden('country_alpha_2');
+            //保存前回调
+            $form->saving(function (Form $form) {
+                $form->country_alpha_2 = BaseIso3166::getAlpha2($form->country);
+            });
+            //保存后回调
+            $form->saved(function (Form $form, $result) {
+                if ($form->isCreating()) {
+                    //创建后创建默认分类
+                    $newId = $form->getKey();
+                    //初始化分销商
+                    DistAdminDistributor::initDist($newId);
+                    return $form->response()->success(admin_trans_label('distributor_create_success'));
+                }
+            });
+        });
+    }
+
+    /*
+     * 新增事件事务
+     */
+    public function store()
+    {
+        try {
+            DB::beginTransaction();
+            $result =  parent::store();
+            DB::commit();
+            return $result;
+        } catch (\Exception $e) {
+            DB::rollBack();
+            throw $e;
+        }
+    }
+}

+ 148 - 0
app/Admin/Controllers/DistAdminUserController.php

@@ -0,0 +1,148 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Renderable\DistDistributorTable;
+use App\Admin\Repositories\DistAdminUser;
+use App\Models\DistAdminDistributor;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+
+class DistAdminUserController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans( 'admin.distro_user');
+    }
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(DistAdminUser::with(['distributor']), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            //指定表格视图,去掉右上角的操作按钮
+            $grid->view('admin.grid.table');
+            //设置列表
+            $grid->column('id')->sortable();
+            $grid->column('username');
+            $grid->column('name');
+            $grid->column('distributor.client_code',admin_trans_label('distributor_code'))->width('15%');
+            //$grid->column('language')->using(config('dictionary.languages'));
+            $grid->column('enabled')->switch();
+            $grid->column('created_at');
+            $grid->column('updated_at')->sortable();
+            //设置过滤器
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('username')->width(2);
+                $filter->equal('name',)->width(2);
+                $filter->like('distributor.client_code', admin_trans_label('distributor_code'))->width(2);
+                $filter->equal('enabled', )->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            //排序
+            $grid->model()->orderBy("id",'desc');
+            //按钮
+            $grid->showQuickEditButton();
+            $grid->enableDialogCreate();
+            $grid->disableEditButton();
+            $grid->disableDeleteButton();
+            $grid->disableBatchDelete();
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, DistAdminUser::with(['distributor']), function (Show $show) {
+            $show->row(function ($show) {
+                $show->width(6)->field('username');
+                $show->width(6)->field('name');
+                $show->width(6)->field('distributor.client_code', admin_trans_label('distributor_code'));
+                $show->width(6)->field('enabled')->using(config('dictionary.enabled'));
+                $show->width(6)->field('created_at');
+                $show->width(6)->field('updated_at');
+            });
+
+            // 按钮
+            $show->disableDeleteButton();
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(DistAdminUser::with(['distributor']), function (Form $form) {
+            //$form->display('id');
+            $form->text('username')->help(admin_trans_label('username_tips'))->required();
+            $form->password('password')->customFormat(function ($v) {
+                return "";
+            });
+            $form->text('name',)->help(admin_trans_label('name_tips'))->required();
+            //$form->select('language')->options(config('dictionary.languages'))->required();
+            $form->selectTable('dist_id', admin_trans_label('distributor'))
+                ->title('distId')
+                ->from(DistDistributorTable::make())
+                ->model(DistAdminDistributor::class, 'id', 'client_code')
+                ->required();
+            $form->switch('enabled')->default(1);
+            //保存前回调
+            $form->saving(function (Form $form) {
+                //判断用户名是否重复
+                $count = DistAdminUser::findCountByUsername($form->getKey(), $form->username);
+                if ($count > 0) {
+                    return $form->response()->error('Username already exists');
+                }
+                if($form->isCreating() && ($form->password === null || $form->password === '')) {
+                    return $form->response()->error('Password cannot be empty');
+                }
+                //密码加密
+                if ($form->password) {
+                    $form->password = bcrypt($form->password);
+                } else {
+                    $form->deleteInput('password');
+                }
+            });
+            //保存后回调
+            $form->saved(function (Form $form, $result) {
+                if ($form->isCreating()) {
+                    //添加角色
+                    $newId = $form->getKey();
+                    if (! $newId) {
+                        return $form->response()->error('Failed to save data');
+                    }
+                    DistAdminUser::addRoleUser($newId, config('dictionary.dist_role_id'));//分销商角色ID 2
+                }
+            });
+        });
+    }
+}

+ 144 - 0
app/Admin/Controllers/DistAppearanceController.php

@@ -0,0 +1,144 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Grid\AppearanceImport;
+use App\Admin\Repositories\DistAppearance;
+use App\Libraries\CommonHelper;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+
+class DistAppearanceController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans( 'admin.template_list');
+    }
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new DistAppearance(), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            $grid->column('id')->sortable();
+            // 标题
+            $grid->column('title');
+            // 文件夹
+            $grid->column('folder')->help('Folder names under the directory:/resources/appearance');
+            // 封面图
+            $grid->column('cover_image')->display(function ($image) {
+                $dataImages = [$image];
+                return CommonHelper::displayImage($dataImages,100);
+            });
+            // 排序
+            $grid->column('order');
+            //是否导入
+            $grid->column('imported')->using(config('dictionary.whether'))->label([
+                0 => 'default',
+                1 => 'success',
+            ]);
+            //是否启用
+            $grid->column('enabled')->switch();
+            // 时间
+            $grid->column('created_at');
+            $grid->column('updated_at')->sortable();
+            // 过滤器
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('title')->width(2);
+                $filter->equal('enabled', )->select(admin_trans_array(config('dictionary.enabled')))->width(2);
+            });
+            // 操作
+            $grid->actions(function (Grid\Displayers\Actions $actions) {
+                $actions->disableDelete();
+                $actions->append(new AppearanceImport());
+            });
+            $grid->model()->orderBy('order', 'desc')->orderBy('id', 'desc');
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new DistAppearance(), function (Show $show) {
+            //$show->field('id');
+            $show->field('title');
+            $show->field('folder');
+            $show->field('cover_image')->as(function ($image) {
+                // 开始生成 HTML
+                $dataImages = [$image];
+                return CommonHelper::displayImage($dataImages,100);
+            })->unescape();
+            $show->field('describe');
+            $show->field('order');
+            $show->field('enabled')->using(admin_trans_array(config('dictionary.enabled')));
+            $show->field('created_at');
+            $show->field('updated_at');
+            $show->disableDeleteButton();
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new DistAppearance(), function (Form $form) {
+            //$form->display('id');
+            $form->text('title');
+            $form->text('folder');
+            $form->image("cover_image")
+                ->retainable()//禁止删OSS图
+                ->autoUpload()
+                ->uniqueName()
+                ->accept(config('admin.upload.oss_image.accept'))
+                ->maxSize(config('admin.upload.oss_image.max_size'))
+                ->dir(config("admin.upload.directory.image").'/appearance/'.date("Ymd"));//
+            $form->textarea('describe');
+            $form->number('order')
+                ->default(0)
+                ->rules('numeric');
+            $form->switch('enabled')->default(0)->readOnly();
+            $form->saving(function (Form $form) {
+                if ($form->isCreating() && $form->input('enabled') == 1) {
+                    return $form->response()->error('Please create the template first, then import it, and finally enable it.');
+                }
+                if (!$form->isCreating()) {
+                    if ($form->input('enabled') == 1 && $form->model()->imported == 0) {
+                        return $form->response()->error('Please select the import option first, then enable it.');
+                    }
+                }
+            });
+            $form->disableDeleteButton();
+        });
+    }
+}

+ 155 - 0
app/Admin/Controllers/DistAppearanceTemplateController.php

@@ -0,0 +1,155 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\DistAdminDistributor;
+use App\Admin\Repositories\DistAppearance;
+use App\Admin\Repositories\DistAppearancePublishList;
+use App\Admin\Repositories\DistAppearanceTemplate;
+use App\Admin\Repositories\DistAppearanceTemplateLog;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+use App\Admin\Forms\AceLeft;
+use Illuminate\Http\Request;
+use Illuminate\Support\Str;
+use Dcat\Admin\Widgets\Card;
+
+
+class DistAppearanceTemplateController extends AdminController
+{
+    /*
+     * monaco editor 编辑代码
+     */
+    public function ace(Content $content,Request $request) {
+        $content->view('admin.pages-custom.ace_content');
+        if ($request->isMethod('post') || false == empty($request->get('act'))) {
+            if($request->get('act') == 'tree') {
+                //获取代码树形结构
+                $appearanceId = $request->get('appearance_id');
+                $distId = $request->get('dist_id');
+                return $this->showTree($appearanceId, $distId);
+            } elseif ($request->get('act') == 'content') {
+                //得到文件内容
+                $appearanceId = $request->get('appearance_id');
+                $distId = $request->get('dist_id');
+                $templateCode = $request->get('id');
+                return DistAppearanceTemplate::getContent($appearanceId,$distId,$templateCode);
+            } elseif ($request->get('act') == 'content_save') {
+                //保存文件内容
+                $appearanceId = $request->get('appearance_id');
+                $distId = $request->get('dist_id');
+                $templateCode = $request->get('template_code');
+                $content = $request->get('content');
+                return DistAppearanceTemplate::saveContent($appearanceId,$distId,$templateCode, $content);
+            } else if ($request->get('act') == 'add_del_tree') {
+                //新建或删除文件
+                $fileId = $request->get('file_id');
+                $appearanceId = $request->get('appearance_id');
+                $distId = $request->get('dist_id');
+                $fileName = $request->get('file_name_input');
+                $filePath = $request->get('file_path_name');
+                $type = $request->get('type');
+                return DistAppearanceTemplate::addDelTree($appearanceId,$distId,$fileId,$fileName, $filePath,$type);
+            }elseif ($request->get('act') == 'publish') {
+                //发报
+                $appearanceId = $request->get('appearance_id');
+                $distId = $request->get('dist_id');
+                DistAppearancePublishList::publish($appearanceId,$distId);
+                //清缓存
+                DistAdminDistributor::clearCache($distId);
+                return ['status'=>1];
+            } else if ($request->get('act') == 'get_appearance_id') {
+                //返回appearance_id
+                $distId = $request->get('dist_id');
+                $row = DistAdminDistributor::getOneById($distId);
+                return $row ? $row->appearance_id : '';
+            } else if ($request->get('act') == 'fetch_template_logs') {
+                //返回模版修改日志
+                $fileId = $request->get('file_id');
+                $appearanceId = $request->get('appearance_id');
+                $distId = $request->get('dist_id');
+                $rows = DistAppearanceTemplateLog::fetchTemplateLogs($appearanceId,$distId,$fileId);
+                return response()->json($rows);
+            } else if ($request->get('act') == 'fetch_template_log_content') {
+                //返回模版修改日志内容
+                $logId = $request->get('log_id');
+                $rows = DistAppearanceTemplateLog::fetchTemplateLogContent($logId);
+                $rows->previous_content = htmlspecialchars($rows->previous_content);
+                return response()->json($rows);
+            } else if ($request->get('act') == 'restore_template_log') {
+                //还原模版修改日志
+                $logId = $request->get('log_id');
+                DistAppearanceTemplateLog::restoreTemplateLog($logId);
+                return ['status'=>1];
+            }
+        }
+
+        $leftForm = new AceLeft();
+        return $content
+            ->header('Template Editor')
+            ->body(admin_view('admin.pages-custom.ace',['leftForm'=>$leftForm]));
+    }
+
+    /*
+     * 显示代码树
+     */
+    private function showTree($appearanceId, $distId) {
+        $appearanceId = empty($appearanceId) ? 0 : $appearanceId;
+        $distId = empty($distId) ? 0 : $distId;
+        $appearanceRow = DistAppearance::getOneById($appearanceId);
+
+        $tree = DistAppearanceTemplate::getTemplateTree($appearanceId, $distId);
+        //print_r($tree);exit;
+        $html = '<ul class="list-group list-group-flush">';
+        $i = 0;
+        foreach ($tree as $key => $value) {
+            $fa = 'fa-angle-down';
+            $file_name = $value['file_name'];
+            $file_name = empty($file_name) ? 'root' : $file_name;
+            $file_name = '<span class="custom-blue-bold">'. $file_name.'</span>';
+            if ($i == 0) {
+                $file_name .= " ({$distId} - {$appearanceId})";
+            }
+            $file_name = $file_name . '<span class="float-right"><a href="javascript:void(0)" title="Add File" data-toggle="modal" data-target="#addFileModal" file_path_name="'. $value['file_name']. '"><i class="feather icon-plus" style="font-size: 12px"></i></a></span>';
+            $html .= '<li class="list-group-item has-submenu">';
+            $html .= '<div style="padding-top: 5px;padding-bottom: 0px"><i class="fa '.$fa.'"></i> '. $file_name.'</div>';
+            $html .= $this->treeBuilder($value);
+            $html .= '</li>';
+            $i++;
+        }
+        $html .= '</ul>';
+        return $html;
+    }
+
+    private function treeBuilder($value) {
+        $html = '';
+        if (!empty($value['children'])) {
+            $html = '<ul class="submenu">';
+            foreach ($value['children'] as $k => $v) {
+                $fa = 'fa-angle-down';
+                $file_name = $v['file_name'];
+                if (empty($v['children'])) {
+                    $fa = 'fa-angle-right';
+                    $file_name = '<a href="#" class="file-action" file_id="'. $v['template_code'].'" title="'.$file_name.'">'. $file_name.'</a>'. '<span class="float-right"><a href="javascript:void(0)" title="delete File" class="delFileButton" file_id="'. $v['id'].'" file_name="'. $v['file_name'].'"><i class="feather icon-x"></i></a></span>';
+                } else {
+                    $file_name = '<span class="custom-blue-bold">'. $file_name.'</span>';
+                }
+                $html .= '<li class="list-group-item"><i class="fa '.$fa.'"></i> '. $file_name;
+                if (!empty($v['children'])) {
+                    $html .= $this->treeBuilder($v);
+                }
+                $html .=  '</li>';
+
+            }
+            $html .= '</ul>';
+        }
+        return $html;
+    }
+
+
+
+}

+ 180 - 0
app/Admin/Controllers/DistAppearanceVariableController.php

@@ -0,0 +1,180 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Renderable\DistDistributorTable;
+use App\Admin\Repositories\DistAppearance;
+use App\Admin\Repositories\DistAppearanceVariable;
+use App\Libraries\CommonHelper;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Widgets\Dropdown;
+
+
+class DistAppearanceVariableController extends AdminController
+{
+
+    public function index(Content $content)
+    {
+        return $content->full()->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $templateCode = isset($_GET['templateCode']) ? $_GET['templateCode'] : 0;
+        $appearanceId = isset($_GET['appearanceId']) ? intval($_GET['appearanceId']) : 0;
+        $distId = isset($_GET['distId']) ? intval($_GET['distId']) : 0;
+        if (empty($appearanceId)) {
+            die(' <h3>Please select the theme.<h3>');
+        }
+        return Grid::make(DistAppearanceVariable::with(['distributor','appearance']), function (Grid $grid) use ($templateCode, $appearanceId, $distId) {
+            $grid->column('id')->sortable();
+            $grid->column('distributor.company_name','Distributor Name')->display(function ($company_name) {
+                if (empty($company_name)) {
+                    return '-';
+                }
+                return $company_name;
+            });
+            $grid->column('appearance.title','Appearance');
+            //变量名
+            $grid->column('variable_name');
+            //变量类型
+            $grid->column('variable_type')->using(['1' => 'text', '2' => 'textarea', '3' => 'json']);
+            //是否是站点变量
+            $grid->column('templateCode','site variable')->display(function ($templateIds) {
+                if ($templateIds == 0) {
+                    return 'Yes';
+                } else {
+                    return 'No';
+                }
+            })->label([
+                '0' => 'success',
+                '1' => 'default',
+            ]);;
+            //搜索
+            $grid->quickSearch(['variable_name']);
+            //工具栏
+            $grid->disableViewButton();
+            $grid->showQuickEditButton();
+            $grid->enableDialogCreate();
+            $grid->disableEditButton();
+            $addUrl = 'templateCode='. $templateCode . '&appearanceId='. $appearanceId . '&distId='. $distId;
+            //排序
+            $grid->model()->where('appearance_id', $appearanceId)->where('dist_id', $distId)->whereIn('template_code', [0, $templateCode])->orderBy("id",'asc');
+            //增加js 向新增按钮添加参数还有编辑按钮添加参数
+
+
+            CommonHelper::replaceAddEditerUrl('.dialog-create', '.quick-edit', $addUrl);
+
+            /*
+            Admin::script(
+<<<JS
+var button = $('.dialog-create');
+var currentUrl = button.attr('data-url');
+if (currentUrl.indexOf('?') === -1) {
+    button.attr('data-url', currentUrl + '{$addUrl}');
+} else {
+    button.attr('data-url', currentUrl + '{$addUrl}');
+}
+
+$('.quick-edit').each(function() {
+    var currentUrl = $(this).attr('data-url');
+    if (currentUrl.indexOf('?') === -1) {
+        $(this).attr('data-url', currentUrl + '{$addUrl}');
+    } else {
+        // 如果已经有查询参数,添加 &id=123
+        $(this).attr('data-url', currentUrl + '{$addUrl}');
+    }
+});
+JS
+            );
+            */
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+//    protected function detail($id)
+//    {
+//        return Show::make($id, DistAppearanceVariable::with(['distributor','appearance']), function (Show $show) {
+//            $show->field('id');
+//            $show->field('distributor.company_name','Distributor Name')->as(function ($company_name) {
+//                if (empty($company_name)) {
+//                    return 'Site Variable';
+//                }
+//                return $company_name;
+//            });
+//            $show->field('appearance.title','Appearance Title');
+//            $show->field('variable_type')->using(['1' => 'text', '2' => 'textarea', '3' => 'json']);
+//            $show->field('variable_name');
+//            $show->field('variable_value');
+//
+//            $show->field('created_at');
+//            $show->field('updated_at');
+//        });
+//    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        $templateCode = isset($_GET['templateCode']) ? $_GET['templateCode'] : 0;
+        $appearanceId = isset($_GET['appearanceId']) ? intval($_GET['appearanceId']) : 0;
+        $distId = isset($_GET['distId']) ? intval($_GET['distId']) : 0;
+        return Form::make(new DistAppearanceVariable(), function (Form $form) use ($templateCode, $appearanceId, $distId) {
+            $form->hidden('appearance_id')->value($appearanceId);
+            $form->hidden('dist_id')->value($distId);
+            $form->hidden('template_code')->value($templateCode);
+            $form->hidden('variable_code');
+            //编辑时当template_id为0时,site_variable为默认值1,否则为0
+            $variableDefaul = 0;
+            if (!$form->isCreating()) {
+                if ($form->model()->template_id == 0) {
+                    $variableDefaul = 1;
+                }
+            }
+            $form->switch('site_variable')->value($variableDefaul)->width(9,3);
+            $form->radio('variable_type')->options([
+                '1'=>'text',
+                '2'=>'textarea',
+                '3'=>'json'
+            ])->width(9,3)->default(1);
+            $form->text('variable_name')->width(9,3);
+            $form->textarea('variable_value')->rows(12)->width(9,3);
+            $form->ignore(['site_variable']);
+
+            $form->submitted(function (Form $form) {
+                if ($form->input('site_variable') == 1) {
+                    $form->template_code = 0;
+                }
+                if ($form->isCreating()) {
+                    $form->variable_code = uniqueCode();
+                }
+                //检查json格式是否正确
+                if ($form->input('variable_type') == 3) {
+                    if (!isValidJson($form->input('variable_value'))) {
+                        return $form->response()->error('The JSON format is incorrect');
+                    }
+                }
+            });
+
+        });
+    }
+}

+ 142 - 0
app/Admin/Controllers/DistInquiryController.php

@@ -0,0 +1,142 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\DistInquiry;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+use App\Admin\Actions\Grid\InquiryAssignment;
+
+class DistInquiryController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans( 'admin.inquiry_list');
+    }
+
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header($this->title())
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(DistInquiry::with(['distributor']), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            //指定视图,去掉删除按钮
+            $grid->view('admin.grid.table');
+            //字段
+            $grid->column('id')->display(function () {
+                return $this->_index+1;
+            });
+            $grid->column('order_number')->width('15%');
+            $grid->column('customer_name')->width('15%');
+            $grid->column('company_name')->width('10%');
+            $grid->column('whats_app')->width('10%');;
+            $grid->column('consulting_products')->width('10%');
+            $grid->column('distributor.client_code', admin_trans_label('distributor_code'))->width('12%');
+            $grid->column('status')->using(admin_trans_array(config('dictionary.inquiryStatus')))->label([
+                0 => 'default',
+                1 => 'info',
+                2 => 'success',
+            ])->width('10%');
+            $grid->column('created_at')->width('10%');
+            //$grid->column('updated_at')->sortable();
+            //筛选
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('order_number')->width(2);
+                $filter->equal('company_name')->width(2);
+                $filter->equal('customer_name')->width(2);
+                $filter->like('distributor.client_code',admin_trans_label('distributor_code'))->width(2);
+                $inquiryStatus = admin_trans_array(config('dictionary.inquiryStatus'));
+                $filter->equal('status')->select($inquiryStatus)->width(2);
+            });
+            //排序
+            $grid->model()->orderBy("id",'desc');
+            //按钮
+            $grid->showQuickEditButton();
+            $grid->disableCreateButton();
+            $grid->disableEditButton();
+            $grid->disableDeleteButton();
+            $grid->disableBatchDelete();
+            $grid->showBatchActions(true);
+            //批量操作
+            $grid->tools([new InquiryAssignment()]);
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new DistInquiry(), function (Show $show) {
+            $show->field('order_number');
+            $show->field('customer_name');
+            $show->field('company_name');
+            $show->field('whats_app');
+            $show->field('email');
+            $show->field('consulting_products');
+            $show->field('freight_forwarder')->using(admin_trans_array(config('dictionary.freight_forwarder')));
+            $show->field('business_model');
+            $show->field('referer_url');
+            $show->field('content')->as(function ($content) {
+                return "<pre>{$content}</pre>";
+            })->unescape();
+            $show->field('ip_address');
+            $show->field('status')->using(admin_trans_array(config('dictionary.inquiryStatus')));
+            $show->field('created_at');
+            $show->field('updated_at');
+            $show->divider();
+            $show->field('allocate_time');
+            $show->field('distributor.distributor_code',admin_trans_label('distributor_code'));
+            //按钮
+            $show->disableDeleteButton();
+            $show->disableEditButton();
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new DistInquiry(), function (Form $form) {
+            $form->display('order_number');
+            $form->text('customer_name');
+            $form->text('company_name');
+            $form->text('whats_app');
+            $form->email('email');
+            $form->text('consulting_products');
+            $form->select('freight_forwarder')->options(admin_trans_array(config('dictionary.freight_forwarder')));
+            $form->text('business_model');
+            $form->text('referer_url');
+            $form->textarea('content')->rows(10);
+        });
+    }
+}

+ 181 - 0
app/Admin/Controllers/DistMessageController.php

@@ -0,0 +1,181 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Repositories\DistMessage;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Admin;
+
+use App\Distributor\Repositories\DistAdminDistributor;
+
+class DistMessageController extends AdminController
+{
+    public function title()
+    {
+        return admin_trans('admin.messages');
+
+    }
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header(admin_trans( 'admin.messages'))
+            ->description(admin_trans('admin.all'))
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new DistMessage(), function (Grid $grid) {
+            $grid->column('id')->sortable();
+            $grid->column('title', admin_trans_field('message_title'));
+            $grid->column('content');
+            //$grid->column('sender_id');
+            $grid->column('target_type')->display(function ($value) {
+                if ($value === 'all') {
+                    return admin_trans_label('all_users');
+                } elseif ($value === 'users') {
+                    return admin_trans_label('specified_users');
+                }
+                return $value;
+            });
+            //$grid->column('target_ids');
+            $grid->column('created_at');
+            $grid->column('updated_at')->sortable();
+
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->equal('id');
+
+            });
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new DistMessage(), function (Show $show) use ($id) {
+            $show->field('id');
+            $show->field('title');
+            $show->field('content');
+            //$show->field('sender_id');
+            $show->field('target_type')->as(function ($value) {
+                if ($value === 'all') {
+                    return admin_trans_label('all_users');
+                } elseif ($value === 'users') {
+                    return admin_trans_label('specified_users');
+                }
+                return $value;
+            });
+            //$show->field('target_ids');
+//            $show->field('target_ids');
+            // 获取 target_ids 并显示对应的 company_name
+            $message = DistMessage::find($id);
+            $targetIds = json_decode($message->target_ids, true);
+
+            if ($targetIds) {
+                $companyNames = DistAdminDistributor::getCompanyNamesByIds($targetIds);
+                $show->field('target_ids')->as(function () use ($companyNames) {
+                    return implode(', ', $companyNames);
+                });
+            } else {
+               // $show->field('target_ids', 'Target IDs')->as('No specified users');
+            }
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        //插入JS
+        Admin::script(
+            <<<JS
+    $(document).ready(function() {
+                var targetType = $('select[name="target_type"]');
+                var targetIds = $('div.form-group.row.form-field:has(select[name="target_ids[]"])');
+
+                // 初始化时根据 target_type 的值显示或隐藏 target_ids
+                toggleTargetIds(targetType.val());
+
+                // 监听 target_type 的变化
+                targetType.change(function() {
+                    toggleTargetIds($(this).val());
+                });
+
+                function toggleTargetIds(value) {
+                   // alert(value);
+                    if (value === 'users') {
+                        targetIds.show();
+                    } else {
+                        targetIds.hide();
+                    }
+                }
+            });
+
+JS
+        );
+
+        return Form::make(new DistMessage(), function (Form $form) {
+            $form->display('id')->rules('required');;
+            $form->text('title',admin_trans_field('message_title'))->rules('required');;
+            $form->textarea('content')->rules('required');;
+//            $form->text('sender_id')->rules('required');
+
+// 检查当前操作是创建还是编辑
+            if ($form->isEditing()) {
+                // 如果是编辑操作,设置 target_type 为只读
+                $form->select('target_type')->options([
+                    'all' => admin_trans_label('all_users'),
+                    'users' => admin_trans_label('specified_users'),
+                ])->rules('required')->readonly();
+            } else {
+                // 如果是创建操作,正常显示 target_type
+                $form->select('target_type')->options([
+                    'all' => admin_trans_label('all_users'),
+                    'users' => admin_trans_label('specified_users'),
+                ])->rules('required');
+            }
+
+            $form->multipleSelect('target_ids')
+               ->options(DistAdminDistributor::tags_all())
+                ->saving(function ($value) {
+
+                    return $value;
+                    //dd($value);
+                    // 转化成json字符串保存到数据库
+                    //return json_encode($value);
+                });
+
+            $form->display('created_at');
+            $form->display('updated_at');
+            $form->disableViewCheck();
+            $form->disableCreatingCheck();
+            $form->disableEditingCheck();
+
+
+        });
+    }
+}

+ 201 - 0
app/Admin/Controllers/DistSiteController.php

@@ -0,0 +1,201 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Grid\InitAppearance;
+use App\Admin\Repositories\DistAdminDistributor;
+use App\Admin\Repositories\DistAppearance;
+use App\Libraries\CommonHelper;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Show;
+use Illuminate\Support\Facades\DB;
+
+class DistSiteController extends AdminController
+{
+    /**
+     * page index
+     */
+    public function index(Content $content)
+    {
+        return $content
+            ->header(admin_trans( 'admin.site_management'))
+            ->description('')
+            ->breadcrumb(['text'=>'list','url'=>''])
+            ->body($this->grid());
+    }
+
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+
+        return Grid::make(DistAdminDistributor::with(['appearance']), function (Grid $grid) {
+            //默认分页条数
+            $grid->paginate(config('admin.per_page'));
+            //指定视图,去掉删除按钮
+            $grid->view('admin.grid.table');
+
+            $grid->column('id')->sortable();
+            $grid->column('client_code',admin_trans_label('distributor_code'))->width('15%');
+            $grid->column('site_name');
+            $grid->column('appearance.title' ,admin_trans_field('appearance'));
+            $grid->column('domain_type')->using(admin_trans_array(config('dictionary.domain_type')));
+            $grid->column('secondary_domain');
+            $grid->column('custom_domain');
+            $grid->column('updated_at')->sortable();
+            // 过滤
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->panel();
+                $filter->expand();
+                $filter->equal('dist_code',admin_trans_label('client_code') )->width(2);
+                $filter->equal('site_name' )->width(2);
+            });
+            // 排序
+            $grid->model()->where('enabled',1)->orderBy("id",'desc');
+            //按钮
+            $grid->enableDialogCreate();
+            $grid->disableDeleteButton();
+            $grid->disableCreateButton();
+            //批量操作
+            $grid->batchActions(function (Grid\Tools\BatchActions $batch) {
+                $batch->disableDelete();
+            });
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, DistAdminDistributor::with(['appearance']), function (Show $show) {
+            $show->field('domain_type',admin_trans_label('domain_type'))->using(admin_trans_array(config('dictionary.domain_type')));
+            $show->field('secondary_domain');
+            $show->field('custom_domain');
+            $show->divider();
+            $show->field('site_name');
+            $show->field('appearance.title' ,admin_trans_field('appearance'));
+            $show->field('copy_right');
+            $show->field('logo')->as(function ($image) {
+                // 开始生成 HTML
+                $dataImages = [$image];
+                return CommonHelper::displayImage($dataImages,100);
+            })->unescape();
+            $show->field('seo_title');
+            $show->field('seo_keywords');
+            $show->field('seo_description');
+
+            $show->divider();
+            $show->field('company_name');
+            $show->field('company_address');
+            $show->field('country');
+            $show->field('contact_number');
+            $show->field('service_hotline');
+            $show->field('whats_app');
+            $show->field('facebook');
+            $show->field('instagram');
+            $show->field('youtube');
+            $show->field('linkedin');
+            $show->field('tiktok');
+            $show->field('copy_right');
+            $show->field('statistics_js');
+            $show->field('enabled')->using(admin_trans_array(config('dictionary.enabled')));
+            $show->field('created_at');
+            $show->field('updated_at');
+
+            // 按钮
+            $show->disableDeleteButton();
+
+
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new DistAdminDistributor(), function (Form $form) {
+            $form->column(6, function (Form $form) {
+                $form->radio('domain_type')->width(9,3)
+                    ->options([0=>admin_trans_field('secondary_domain'),1=>admin_trans_field('custom_domain')])
+                    ->default(0)
+                    ->required();
+                $form->text('secondary_domain')->width(9,3)
+                    ->required()
+                    ->help('Please enter the domain name, such as demo.'.env('TOP_DOMAIN'));
+                $form->text('custom_domain')->width(9,3)->help('Please enter the domain name, such as www.example.com');
+                $form->text('site_name')->width(9,3)->required();
+                $form->text('seo_title')->width(9,3)->required();
+                $form->text('seo_keywords')->width(9,3);
+                $form->textarea('seo_description')->rows(2)->width(9,3);
+                $form->select('appearance_id',admin_trans_field('appearance'))->width(9,3)->options(DistAppearance::selectOptions())->required();
+                $form->cutImage("logo")
+                    ->aspectRatio(130/50)// 设置裁剪框比例
+                    ->retainable()//禁止删OSS图
+                    ->autoUpload()
+                    ->uniqueName()
+                    ->accept(config('distributor.upload.oss_image.accept'))
+                    ->maxSize(config('distributor.upload.oss_image.max_size'))
+                    ->dir(config("distributor.upload.directory.image").'/logo')
+                    ->width(4,3);
+            });
+            $form->column(6, function (Form $form) {
+                $form->text('company_name')->width(9,3);
+                $form->text('company_address',)->width(9,3);
+                $form->text('service_hotline')->width(9,3);
+                $form->text('dist_email',admin_trans_label('email'))->width(9,3);
+                $form->text('whats_app')->width(9,3);
+                $form->text('facebook')->width(9,3);
+                $form->text('instagram')->width(9,3);
+                $form->text('youtube')->width(9,3);
+                $form->text('linkedin')->width(9,3);
+                $form->text('tiktok')->width(9,3);
+                $form->text('copy_right')->width(9,3);
+                $form->textarea('statistics_js')->width(9,3);
+            });
+
+            //保存前回调
+            $form->saving(function (Form $form) {
+                if (!$form->isCreating()) {
+                    //如果appearance_id有变化,则更新模版与变量
+                    if ($form->model()->appearance_id != $form->input('appearance_id')) {
+                        $id = $form->model()->id;
+                        //更新模版与变量
+                        DistAppearance::switchTheme($form->input('appearance_id'), $id);
+                    }
+                }
+            });
+
+            //
+            //保存后回调
+            $form->saved(function (Form $form, $result) {
+                $newId = $form->getKey();
+                if ($form->isCreating()) {
+                    //创建后创建默认分类
+                    $appearanceId = $form->input('appearance_id');
+                    //更新模版与变量
+                    DistAppearance::switchTheme($appearanceId, $newId);
+                }
+                //更新缓存
+                DistAdminDistributor::clearCache($newId);
+            });
+
+            $form->disableDeleteButton();
+        });
+    }
+
+
+}

+ 17 - 6
app/Admin/Controllers/HomeController.php

@@ -30,15 +30,26 @@ class HomeController extends Controller
                    // ->row($alert->info())
                     ->row(function (Row $row) {
                         $row->column(12, function (Column $column) {
-                            $column->row(self::title());
+                            $column->row(\App\Distributor\Controllers\Dashboard::title());
                         });
+
+//                        $row->column(6, function (Column $column) {
+////                            $column->row(function (Row $row) {
+////                                $row->column(6, new Examples\NewUsers());
+////                                $row->column(6, new Examples\NewDevices());
+////                            });
+//                           // $column->row(Dashboard::author());
+//                            //$column->row(new Examples\Tickets());
+//                        });
+//
+//                        $row->column(6, function (Column $column) {
+//
+//
+//                        //    $column->row(new Examples\Sessions());
+//                            //$column->row(new Examples\ProductOrders());
+//                        });
                     });
 
         return $content;
     }
-
-    public static function title()
-    {
-        return view('admin.dashboard.title');
-    }
 }

+ 0 - 284
app/Admin/Controllers/SiteAlbumController.php

@@ -1,284 +0,0 @@
-<?php
-
-namespace App\Admin\Controllers;
-
-use App\Admin\Repositories\SiteAlbum;
-use App\Admin\Repositories\SiteAlbumFolder;
-use App\Libraries\CommonHelper;
-use App\Models\SiteAlbumFolder as SiteAlbumFolderModel;
-use Dcat\Admin\Form;
-use Dcat\Admin\Grid;
-use Dcat\Admin\Show;
-use Dcat\Admin\Http\Controllers\AdminController;
-use Dcat\Admin\Layout\Content;
-use Dcat\Admin\Admin;
-use App\Admin\Repositories\NullRepository;
-use Dcat\Admin\Traits\HasUploadedFile;
-use function Symfony\Component\Translation\t;
-
-class SiteAlbumController extends AdminController
-{
-    use HasUploadedFile;
-    /**
-     * page index
-     */
-    public function index(Content $content)
-    {
-        return $content
-            ->header(admin_trans( 'admin.album'))
-            ->body($this->indexForm());
-    }
-
-    protected function indexForm()
-    {
-        return Form::make(new NullRepository(), function (Form $form) {
-            $form->block(2, function (Form\BlockForm $form) {
-                $type = [
-                    'default'  => [
-                        'icon' => true,
-                    ],
-                ];
-                $plugins = ['types'];
-
-                $menuModel = new SiteAlbumFolderModel();
-                $form->tree()
-                    ->setTitleColumn('title')
-                    ->nodes($menuModel->allNodes())
-                    ->type($type)
-                    ->plugins($plugins)
-                    ->width(12,0);
-            });
-
-            $form->block(10, function (Form\BlockForm $form)  {
-                $form->html($this->grid())->width(12);
-            });
-        });
-    }
-
-    protected function grid()
-    {
-        return Grid::make(new SiteAlbum(), function (Grid $grid) {
-            //默认分页条数
-            $grid->paginate(config('admin.per_page'));
-            $grid->column('id')->sortable();
-            $grid->column('title');
-            $grid->column('model');
-            $grid->column('order')->sortable();
-            $grid->column('enabled')->switch();
-            $grid->column('created_at')->sortable();
-
-            $grid->quickSearch(['title','model']);
-
-            $grid->disableViewButton();
-            //$grid->showQuickEditButton();
-            $grid->disablePerPages();
-            $grid->disableRefreshButton();
-
-            $grid->model()->orderBy('order', 'asc')->orderBy('id', 'desc');
-            //弹窗大小
-            $grid->setDialogFormDimensions('830px','670px');
-        });
-    }
-
-    protected function form()
-    {
-        $thisObj = $this;
-        return Form::make(new SiteAlbum(), function (Form $form) use ($thisObj) {
-
-            $form->width(9, 1);
-            $form->disableViewButton();
-            $form->disableViewCheck();
-            $form->saving(function (Form $form) use ($thisObj) {
-                //处理video
-                $videos = $form->input('video');
-                if ($videos) {
-                    foreach ($videos as $key => $value) {
-                        if (empty($value['cover']) && $value['_remove_'] != 1) {
-                            //自动生成封面
-                            $result = $thisObj->autoGenerateCover($value['video_src']);
-                            if ($result['status']) {
-                                $videos[$key]['cover'] = $result['path'];
-                            } else {
-                                return $form->response()->error($result['msg']);
-                            }
-                        }
-                    }
-                } else {
-                    $videos = [];
-                }
-                $form->input('video', $videos);
-                //处理pdf
-                $pdfs = $form->input('pdf');
-                $pdfs = empty($pdfs) ? [] : $pdfs;
-                $form->input('pdf', $pdfs);
-            });
-            $form->tab(admin_trans_label('basic_info'), function (Form $form) {
-                $form->select('folder_id')->options(SiteAlbumFolder::selectOptions())->required();
-                $form->text('title')->required();
-                $form->text('model');
-            })->tab(admin_trans_label('cover'), function (Form $form) {
-                $form->multipleImage('cover')
-                    ->retainable()//禁止删OSS图
-                    ->sortable() // 可拖动排序
-                    ->removable() // 可移除图片
-                    ->autoUpload() // 自动上传
-                    ->uniqueName()
-                    ->limit(config('admin.upload.oss_image.limit'))
-                    ->accept(config('admin.upload.oss_image.accept'))
-                    ->maxSize(config('admin.upload.oss_image.max_size'))
-                    ->dir(config("admin.upload.directory.image").'/uploads/'.date("Ymd"))
-                    ->saving(function ($images) use ($form) {
-                        return json_encode($images);
-                    });
-            })->tab(admin_trans_label('en_detail'), function (Form $form) {
-                $form->multipleImage('en_detail')
-                    ->retainable()//禁止删OSS图
-                    ->sortable() // 可拖动排序
-                    ->removable() // 可移除图片
-                    ->autoUpload() // 自动上传
-                    ->uniqueName()
-                    ->limit(config('admin.upload.oss_image.limit'))
-                    ->accept(config('admin.upload.oss_image.accept'))
-                    ->maxSize(config('admin.upload.oss_image.max_size'))
-                    ->dir(config("admin.upload.directory.image").'/uploads/'.date("Ymd"))
-                    ->saving(function ($images) use ($form) {
-                        return json_encode($images);
-                    });
-            })->tab(admin_trans_label('cn_detail'), function (Form $form) {
-                $form->multipleImage('cn_detail')
-                    ->retainable()//禁止删OSS图
-                    ->sortable() // 可拖动排序
-                    ->removable() // 可移除图片
-                    ->autoUpload() // 自动上传
-                    ->uniqueName()
-                    ->limit(config('admin.upload.oss_image.limit'))
-                    ->accept(config('admin.upload.oss_image.accept'))
-                    ->maxSize(config('admin.upload.oss_image.max_size'))
-                    ->dir(config("admin.upload.directory.image").'/uploads/'.date("Ymd"))
-                    ->saving(function ($images) use ($form) {
-                        return json_encode($images);
-                    });
-            })->tab(admin_trans_label('video'), function (Form $form) {
-                $count = 0;
-                $form->hasMany('video', function (Form\NestedForm $form)  use (&$count) {
-                    $videos = $form->model()->video;
-                    $imgArray = "";
-                    if ($videos) {
-                        $videos = json_decode($videos,true);
-                        foreach ($videos as $key => $value) {
-                            if ($value['cover'] && $key == $count-1) {
-                                $imgArray = [$value['cover']];
-                            }
-                        }
-                    }
-                    $imgHtml = CommonHelper::displayImage($imgArray);
-                    $form->html($imgHtml,admin_trans_label('image_preview'));
-                    $count++;
-
-                    $form->text('cover',admin_trans_label('video_cover'))->placeholder('为空则自动生成');
-                    $form->tradFile('video_src')
-                        ->retainable()//禁止删OSS图
-                        ->removable() // 可移除图片
-                        ->autoUpload() // 自动上传
-                        ->uniqueName()
-                        ->accept(config('admin.upload.oss_video.accept'))
-                        ->maxSize(config('admin.upload.oss_video.max_size'))
-                        ->dir(config("admin.upload.directory.video").'/uploads/'.date("Ymd"))
-                        ->chunkSize(1024)
-                        ->required();
-                })->useTable()
-                    ->customFormat(function ($data) {return json_decode($data,true);})
-                    ->setView('admin.form_custom.hasmanytable')
-                    ->saving(function ($input) {
-                        $data = [];
-                        foreach ($input as $value) {
-                            if ($value['_remove_'] != 1){
-                                $data[] = ['cover'=>$value['cover'],'video_src'=>$value['video_src']];
-                            }
-                        }
-                        return json_encode($data);
-                    });
-            })->tab(admin_trans_label('poster'), function (Form $form) {
-                $form->multipleImage('poster')
-                    ->retainable()//禁止删OSS图
-                    ->sortable() // 可拖动排序
-                    ->removable() // 可移除图片
-                    ->autoUpload() // 自动上传
-                    ->uniqueName()
-                    ->limit(config('admin.upload.oss_image.limit'))
-                    ->accept(config('admin.upload.oss_image.accept'))
-                    ->maxSize(config('admin.upload.oss_image.max_size'))
-                    ->dir(config("admin.upload.directory.image").'/uploads/'.date("Ymd"))
-                    ->saving(function ($images) use ($form) {
-                        return json_encode($images);
-                    });
-            })->tab(admin_trans_label('cert'), function (Form $form) {
-                $form->multipleImage('cert')
-                    ->retainable()//禁止删OSS图
-                    ->sortable() // 可拖动排序
-                    ->removable() // 可移除图片
-                    ->autoUpload() // 自动上传
-                    ->uniqueName()
-                    ->limit(config('admin.upload.oss_image.limit'))
-                    ->accept(config('admin.upload.oss_image.accept'))
-                    ->maxSize(config('admin.upload.oss_image.max_size'))
-                    ->dir(config("admin.upload.directory.image").'/uploads/'.date("Ymd"))
-                    ->saving(function ($images) use ($form) {
-                        return json_encode($images);
-                    });
-            })->tab(admin_trans_label('pdf'), function (Form $form) {
-                 $form->hasMany('pdf', function ($form) {
-                     $form->text('pdf_title')->required();
-                     $form->tradFile('pdf_src')
-                         ->retainable()//禁止删OSS图
-                         ->removable() // 可移除图片
-                         ->autoUpload() // 自动上传
-                         ->uniqueName()
-                         ->accept(config('admin.upload.oss_pdf.accept'))
-                         ->maxSize(config('admin.upload.oss_pdf.max_size'))
-                         ->dir(config("admin.upload.directory.pdf").'/uploads/'.date("Ymd"))
-                         ->chunkSize(1024)
-                         ->required();
-                })->useTable()
-                     ->customFormat(function ($data) {
-                         return json_decode($data,true);
-                     })
-                     ->setView('admin.form_custom.hasmanytable')
-                     ->saving(function ($input) {
-                         $data = [];
-                         foreach ($input as $value) {
-                             if ($value['_remove_'] != 1){
-                                 $data[] = ['pdf_title'=>$value['pdf_title'],'pdf_src'=>$value['pdf_src']];
-                             }
-                         }
-                         return json_encode($data);
-                     });
-            });
-        });
-    }
-
-    /*
-     * 自动生成视频封面
-     */
-    private function autoGenerateCover($videoSrc)
-    {
-        $cover = $videoSrc.'?x-oss-process=video/snapshot,t_2000,f_jpg,h_500,m_fast';
-        //TODO 上传到OSS
-        $cover = CommonHelper::ossUrl($cover);
-        $path = $this->upload($cover,'.jpg');
-        return $path;
-    }
-
-    private function upload($file,$imgType='.jpg')
-    {
-        $disk = $this->disk('oss');
-        $newName = uniqueCode("video_cover_").$imgType;
-        $dir = config("admin.upload.directory.image").'/uploads/'.date("Ymd").'/'.$newName;
-        $contents = file_get_contents($file);
-        if (!$contents) {
-            return ['status'=>false,'msg'=>'图片上传失败,请检查PHP配置'];
-        }
-        $disk->put($dir, $contents);
-        return ['status'=>true,'path'=>$dir];
-    }
-}

+ 0 - 85
app/Admin/Controllers/SiteAlbumFolderController.php

@@ -1,85 +0,0 @@
-<?php
-
-namespace App\Admin\Controllers;
-
-use App\Admin\Repositories\SiteAlbumFolder;
-use Dcat\Admin\Form;
-use Dcat\Admin\Grid;
-use Dcat\Admin\Show;
-use Dcat\Admin\Http\Controllers\AdminController;
-use Dcat\Admin\Layout\Content;
-use Dcat\Admin\Admin;
-
-class SiteAlbumFolderController extends AdminController
-{
-    /**
-     * page index
-     */
-    public function index(Content $content)
-    {
-        return $content
-            ->header(admin_trans( 'admin.folder'))
-            ->body($this->grid());
-    }
-
-    /**
-     * Make a grid builder.
-     *
-     * @return Grid
-     */
-    protected function grid()
-    {
-        return Grid::make(new SiteAlbumFolder(), function (Grid $grid) {
-            $grid->column('id')->sortable();
-            $grid->column('title')->display(function ($title) {
-                $level = $this->level; // 获取当前行的 level 字段值
-                $prefix = str_repeat('&nbsp; ', $level * 2). ' <i class="fa fa-angle-right"></i>&nbsp; '; // 生成 level * 3 个加号
-                return $prefix . ' ' . html_entity_decode($title); // 拼接加号和名称
-            });;
-            $grid->column('parent_id');
-            $grid->column('order')->sortable();
-            $grid->column('enabled')->switch();
-            $grid->column('created_at')->sortable();
-
-            $grid->disableViewButton();
-            $grid->showQuickEditButton();
-            $grid->enableDialogCreate();
-            $grid->disableEditButton();
-            $grid->disablePerPages();
-        });
-    }
-
-
-    /**
-     * Make a form builder.
-     *
-     * @return Form
-     */
-    protected function form()
-    {
-        return Form::make(new SiteAlbumFolder(), function (Form $form) {
-            $form->select('parent_id', admin_trans_field('parent'))
-                ->options(SiteAlbumFolder::selectMainOptions())
-                ->saving(function ($v) {
-                    return (int) $v;
-                });
-            $form->text('title')->required();
-            $form->radio('folder_type')
-                ->options(admin_trans_array(config('dictionary.folder_type')))
-                ->default(0)->required();
-            $form->listbox('show_tabs')->options(admin_trans_array([
-                '0' => 'cover',
-                '1' => 'en_detail',
-                '2' => 'cn_detail',
-                '3' => 'video',
-                '4' => 'poster',
-                '5' => 'cert',
-                '6' => 'pdf',
-            ]))->default([0, 1, 2, 3, 4, 5, 6])->saving(function ($v) { return json_encode($v); });
-            $form->number('order')
-                ->default(0)
-                ->rules('numeric');
-            $form->switch('enabled')->default(1);
-        });
-    }
-}

+ 51 - 0
app/Admin/Forms/AceLeft.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Admin\Forms;
+
+use App\Admin\Renderable\DistDistributorTable;
+use App\Models\DistAdminDistributor;
+use Symfony\Component\HttpFoundation\Response;
+use Dcat\Admin\Widgets\Form;
+use App\Admin\Repositories\DistAppearance;
+
+class AceLeft extends Form
+{
+    public function form()
+    {
+        //供应商选择
+        $this->selectTable('dist_id', 'Select Distributor')
+            ->width(12,12)
+            ->setLabelClass('d-flex')
+            ->title('Select Distributor')
+            ->placeholder('Select Distributor')
+            ->model(DistAdminDistributor::class, 'id', 'client_code')
+            ->from(DistDistributorTable::make());
+
+        //主题选择
+        $this->select('appearance_id','Select Appearance')
+            ->options(DistAppearance::selectOptions(true))
+            ->width(12,12)
+            ->setLabelClass('d-flex');
+
+        $this->disableSubmitButton();
+        $this->disableResetButton();
+    }
+
+    // 处理表单提交请求
+    public function handle(array $input)
+    {
+        return $this->response()->success('Processed successfully.')->refresh();
+    }
+
+    /**
+     * 返回表单数据,如不需要可以删除此方法
+     *
+     * @return array
+     */
+    public function default()
+    {
+        return [
+        ];
+    }
+
+}

+ 225 - 0
app/Admin/Forms/AppearanceImPortForm.php

@@ -0,0 +1,225 @@
+<?php
+
+namespace App\Admin\Forms;
+
+use App\Admin\Renderable\DistDistributorTable;
+use App\Admin\Repositories\DistAdminDistributor;
+use App\Admin\Repositories\DistAppearance;
+use App\Admin\Repositories\DistAppearancePublishList;
+use App\Admin\Repositories\DistAppearanceTemplate;
+use App\Admin\Repositories\DistInquiry;
+use Dcat\Admin\Models\DistAdminUser;
+use Dcat\Admin\Widgets\Form;
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use ZipArchive;
+
+class AppearanceImPortForm extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+    protected $appearanceId = 0;
+
+    // 处理请求
+    public function handle(array $input)
+    {
+        // 获取外部传递参数
+        $appearanceId = $this->payload['id'] ?? null;
+        $file = $input['file'] ?? null;
+        $appearanceRs = DistAppearance::getOneById($appearanceId);
+        if ($file && $appearanceRs) {
+            $folder = $appearanceRs->folder;
+            $extractPath = resource_path().'/appearance/tmp';
+            $path = resource_path().'/appearance/'.$folder;
+            //删除TMP文件夹下的文件
+            $this->deleteDirectoryContents($extractPath);
+            //解压
+            $unzip = $this->unzip($file,$extractPath,$path);
+            if (!$unzip['status']) {
+                return $this->response()->error($unzip['error']);
+            }
+            //导入模板
+            if (!is_dir($path)) {
+                return $this->response()->error("The directory does not exist")->refresh();
+            }
+            $this->sourcePath = $path;
+            $this->appearanceId = $appearanceId;
+            // 清空旧的
+            DistAppearanceTemplate::deleteTemplates($appearanceId, config('dictionary.base_dist_id'));
+            // 导入模板
+            $this->readDirectory($path);
+            //发报到正式环境
+            DistAppearancePublishList::publish($appearanceId,config('dictionary.base_dist_id'));
+            // 更新状态
+            DistAppearance::setStatusToImported($appearanceId);
+            return $this->response()->success('allocation successful')->refresh();
+        }
+        return $this->response()->error('No file data');
+    }
+
+    /*
+     * 下载并解压
+     */
+
+    private function unzip($savePath,$extractPath,$trulyPath)
+    {
+        // 检查 $extractPath 是否存在且是否是一个目录
+        if (!is_dir($extractPath)) {
+            mkdir($extractPath, 0755, true);
+        }
+
+        if (!is_dir($trulyPath)) {
+            mkdir($trulyPath, 0755, true);
+        }
+
+        $savePath = storage_path().'/app/'.$savePath;
+        // 检查是否支持 ZipArchive 扩展
+        if (!extension_loaded('zip')) {
+            return ['status' => false, 'error' => 'ZipArchive 扩展未加载'];
+        }
+        // 保存文件到本地
+        $zip = new ZipArchive;
+        if ($zip->open($savePath) !== TRUE) {
+            return ['status' => false, 'error' => 'ZipArchive 解压失败'];
+        }
+        if ($zip->extractTo($extractPath) !== TRUE) {
+            return ['status' => false, 'error' => "解压文件到 $extractPath 失败。"];
+        }
+        $zip->close();
+        //解压后,停0.1秒
+        usleep(200000);
+        //判断tmp下是否只有一个文件夹,如果是,移动到trulyPath
+        // 递归删除 $trulyPath 下的所有文件和文件夹
+        $deleteDirectoryContents = $this->deleteDirectoryContents($trulyPath);
+        if ($deleteDirectoryContents) {
+            return ['status' => false, 'error' => $deleteDirectoryContents];
+        }
+        // 获取 $extractPath 下的所有文件和文件夹
+        $items = scandir($extractPath);
+        // 过滤掉 '.' 和 '..'
+        $items = array_diff($items, ['.', '..']);
+        // 判断 $extractPath 是否只有一个文件夹
+        if (count($items) != 1) {
+            return ['status' => false, 'error' => "Error: unzip file does not contain exactly one folder."];
+        }
+        // 获取文件夹名称
+        $folderName = reset($items);
+        $folderPath = $extractPath . '/' . $folderName;
+        // 获取文件夹下的所有文件和文件夹
+        $folderContents = scandir($folderPath);
+        $folderContents = array_diff($folderContents, ['.', '..']);
+        // 将文件夹中的所有内容移动到 $trulyPath
+        foreach ($folderContents as $fileOrDir) {
+            $sourcePath = $folderPath . '/' . $fileOrDir;
+            $destinationPath = $trulyPath . '/' . $fileOrDir;
+            // 如果是文件,移动文件
+            if (is_file($sourcePath)) {
+                if (!rename($sourcePath, $destinationPath)) {
+                    return ['status' => false, 'error' => "Error: Failed to move file $fileOrDir\n"];
+                }
+            }
+            // 如果是目录,递归移动目录内容
+            elseif (is_dir($sourcePath)) {
+                // 创建目标文件夹
+                if (!mkdir($destinationPath)) {
+                    return ['status' => false, 'error' => "Error: Failed to create folder $fileOrDir\n"];
+                }
+                // 递归移动文件夹内容
+                $folderFiles = scandir($sourcePath);
+                $folderFiles = array_diff($folderFiles, ['.', '..']);
+                foreach ($folderFiles as $subFile) {
+                    $subSourcePath = $sourcePath . '/' . $subFile;
+                    $subDestinationPath = $destinationPath . '/' . $subFile;
+                    if (!rename($subSourcePath, $subDestinationPath)) {
+                        return ['status' => false, 'error' => "Error: Failed to move subfolder file $subFile\n"];
+                    }
+                }
+            }
+        }
+        // 删除原文件夹及其内容
+        $this->deleteDirectoryContents($folderPath);
+        return ['status' => true];
+    }
+
+    // 递归删除子目录及其内容
+    private function deleteDirectoryContents($dir)
+    {
+        // 获取目录下所有文件和文件夹
+        $items = scandir($dir);
+
+        // 过滤掉 '.' 和 '..'
+        $items = array_diff($items, ['.', '..']);
+
+        // 循环遍历目录下的每一项
+        foreach ($items as $item) {
+            $itemPath = $dir . '/' . $item;
+
+            // 如果是文件,删除文件
+            if (is_file($itemPath)) {
+                if (!unlink($itemPath)) {
+                    return "Error: Failed to delete file $itemPath\n";
+                }
+            }
+            // 如果是目录,递归删除该目录
+            elseif (is_dir($itemPath)) {
+                $this->deleteDirectoryContents($itemPath); // 递归删除目录内容
+                if (!rmdir($itemPath)) {
+                    return "Error: Failed to delete directory $itemPath\n";
+                }
+            }
+        }
+    }
+
+
+
+    public function form()
+    {
+        $this->file('file')
+            ->disk('local') // 使用本地存储
+            ->uniqueName()
+            ->autoUpload()
+            ->required()
+            ->accept('zip')
+            ->dir(config("admin.upload.directory.file").'/tmp/')
+            ->help('Please upload a zip file');
+
+    }
+    private function readDirectory($dirPath) {
+        // 检查目录是否存在
+        if (!is_dir($dirPath)) {
+            return;
+        }
+
+        // 打开目录
+        $dir = opendir($dirPath);
+
+        // 读取目录内容
+        while (($file = readdir($dir)) !== false) {
+            // 忽略当前目录和上级目录
+            if ($file == '.' || $file == '..') {
+                continue;
+            }
+
+            // 获取文件或文件夹的完整路径
+            $fullPath = $dirPath . '/' . $file;
+
+            // 如果是文件夹,递归读取
+            if (is_dir($fullPath)) {
+                $this->readDirectory($fullPath); // 递归调用
+            } else {
+                // 如果是文件,读取文件内容
+                $content = file_get_contents($fullPath);
+                $filePath = str_replace($this->sourcePath, '', $dirPath);
+                $filePath = trim($filePath, '/');
+                $fileName = basename($fullPath);
+                // 插入数据库
+                DistAppearanceTemplate::insertTemplateContent(config('dictionary.base_dist_id'), $this->appearanceId, $filePath,$fileName, $content);
+            }
+        }
+
+        // 关闭目录
+        closedir($dir);
+    }
+
+
+}

+ 47 - 0
app/Admin/Forms/InquiryAssignment.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Admin\Forms;
+
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Widgets\Form;
+use App\Admin\Repositories\DistInquiry;
+use App\Admin\Renderable\DistDistributorTable;
+use Dcat\Admin\Models\DistAdminUser;
+use Dcat\Admin\Traits\LazyWidget;
+use App\Models\DistAdminDistributor;
+
+class InquiryAssignment extends Form
+{
+    // 处理请求
+    public function handle(array $input)
+    {
+        $distId = $input['distId'] ?? null;
+        $id = $input['id'] ?? null;
+        if (empty($id)) {
+            return $this->response()->error('No data selected!');
+        }
+        //检查数据是否可分配状态
+        $ids = explode(',', $id);
+        if (DistInquiry::assessTheStatus($ids) == false) {
+            return $this->response()->error('The data cannot be assigned!');
+        }
+        if (empty($distId)) {
+            return $this->response()->error('No distributor selected!');
+        }
+        //分配数据
+        DistInquiry::assignData($ids, $distId);
+        return $this->response()->success(admin_trans_label('update_success'))->refresh();
+    }
+
+    public function form()
+    {
+//        $this->selectTable('distId', admin_trans_label('select_distributor'))
+//            ->title(admin_trans_label('select_distributor'))
+//            ->model(DistAdminDistributor::class, 'id', 'client_code')
+//            ->from(DistDistributorTable::make());
+
+        $this->select('distId',admin_trans_label('select_distributor'))->options('/api/dist')->required();
+        // 设置隐藏表单,传递用户id
+        $this->hidden('id')->attribute('id', 'inquiryIds');
+    }
+}

+ 38 - 0
app/Admin/Repositories/BaseIso3166.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\BaseIso3166 as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class BaseIso3166 extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    public static function selectOptions()
+    {
+        $result = [];
+        $rows = Model::orderBy('id', 'asc')->get();
+        foreach ($rows as $row) {
+            $result[$row->country_name_en] = $row->country_name_en . ' - '. $row->country_name_zh;
+        }
+        return $result;
+    }
+
+    /*
+     * 通过英文国家名得到国家简称
+     */
+    public static function getAlpha2($countryNameEn)
+    {
+        $row = Model::where('country_name_en', $countryNameEn)->first();
+        if (empty($row)) {
+            return '';
+        }
+        return $row->alpha_2;
+    }
+}

+ 29 - 0
app/Admin/Repositories/BaseProduct.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\BaseProduct as Model;
+use Dcat\Admin\Form;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class BaseProduct extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    /*
+     * 重写删除方法
+     */
+    public function delete(Form $form, array $originalData)
+    {
+        collect(explode(',', $form->getKey()))->filter()->each(function ($id) {
+            Model::find($id)->images()->delete();//把图片也删了
+            Model::find($id)->delete();
+        });
+        return true;
+    }
+}

+ 52 - 30
app/Admin/Repositories/SiteAlbumFolder.php → app/Admin/Repositories/BaseProductCategory.php

@@ -2,11 +2,16 @@
 
 namespace App\Admin\Repositories;
 
-use App\Models\SiteAlbumFolder as Model;
+use App\Models\BaseProductCategory as Model;
+use App\Models\BaseProductParameter;
 use Dcat\Admin\Repositories\EloquentRepository;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Support\Facades\Session;
 
-class SiteAlbumFolder extends EloquentRepository
+class BaseProductCategory extends EloquentRepository
 {
+
     /**
      * Model.
      *
@@ -14,27 +19,22 @@ class SiteAlbumFolder extends EloquentRepository
      */
     protected $eloquentClass = Model::class;
 
-    /*
- * 改写列表显示返回的数据
- */
-    public function get(Grid\Model|\Dcat\Admin\Grid\Model $model)
-    {
-        // 获取模型对象
-        $obj = $this->model();
-        // 获取数据
-        $tree = $obj->orderBy('order', 'desc')->orderBy('id', 'desc')->get();
-        $treeData = $tree->toArray();
 
-        // 构建树形结构
-        $data=buildTree($treeData);
 
-        // 转换成一维数组
-        $data=flattenTree($data);
 
-        return $model->makePaginator(
-            count($data), // 传入总记录数
-            $data // 传入数据二维数组
-        );
+    // 调用模型方法
+    public static function selectOptions(\Closure $closure = null)
+    {
+        if (!$closure) {
+            $closure = function ($query) {
+                $query = $query->where('enabled', 1);
+                $query =  $query->orderBy('order', 'desc')->orderBy('id', 'desc');
+                return $query;
+            };
+        }
+
+        $selectOptions =  Model::class::selectOptions($closure);
+        return $selectOptions;
     }
 
     public static function selectMainOptions(\Closure $closure = null)
@@ -55,20 +55,42 @@ class SiteAlbumFolder extends EloquentRepository
         return $selectOptions;
     }
 
-    // 调用模型方法
-    public static function selectOptions(\Closure $closure = null)
+
+    public static function getParameter($categoryId)
     {
-        if (!$closure) {
-            $closure = function ($query) {
-                $query = $query->where('enabled', 1);
-                $query =  $query->orderBy('order', 'desc')->orderBy('id', 'desc');
-                return $query;
-            };
+        $categoryRow =  Model::Class::find($categoryId);
+        if ($categoryRow->baseProductParameter) {
+            return $categoryRow->baseProductParameter->content;
+        } else {
+            return "[]";
         }
+    }
 
-        $selectOptions =  Model::class::selectOptions($closure);
-        return $selectOptions;
+    /*
+     * 改写列表显示返回的数据
+     */
+    public function get(Grid\Model|\Dcat\Admin\Grid\Model $model)
+    {
+        // 获取模型对象
+        $obj = $this->model();
+        // 获取数据
+        $tree = $obj->orderBy('order', 'desc')->orderBy('id', 'desc')->get();
+        $treeData = $tree->toArray();
+        foreach ($tree as $key => $value) {
+            $treeData[$key]['baseProductParameter.name'] = $value->baseProductParameter->name?? '';
+        }
+        // 构建树形结构
+        $data=buildTree($treeData);
+
+        // 转换成一维数组
+        $data=flattenTree($data);
+
+        return $model->makePaginator(
+            count($data), // 传入总记录数
+            $data // 传入数据二维数组
+        );
     }
 
 
+
 }

+ 84 - 0
app/Admin/Repositories/BaseProductImage.php

@@ -0,0 +1,84 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\BaseProductImage as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+use Carbon\Carbon;
+
+class BaseProductImage extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+
+    public static function deleteByProductId($productId)
+    {
+        Model::where('product_id', $productId)->delete();
+    }
+
+    public static function saveProductImages($productId, $imageUrls)
+    {
+        if (empty($productId) || empty($imageUrl)) {
+            return false;
+        }
+        // 准备数据集合
+        $data = [];
+        foreach ($imageUrls as $imageUrl) {
+            $data[] = [
+                'product_id' => $productId,
+                'image_url' => $imageUrl,
+                'created_at' => Carbon::now(),
+                'updated_at' => Carbon::now(),
+            ];
+        }
+        // 批量插入
+        return Model::insert($data);
+    }
+
+    //格式化数据,用于多图上传
+    public static function formatData($productId, $images)
+    {
+        $existingImages = Model::where('product_id', $productId)->get();
+        // 用于存储结果的数组
+        $result = [];
+        // 处理条件1:如果数据在 base_product_image 中有,但在 $images 上无
+        foreach ($existingImages as $existingImage) {
+            if (!in_array($existingImage->image_url, $images)) {
+                $result[] = [
+                    'id' => $existingImage->id,
+                    'image_url' => $existingImage->image_url,
+                    '_remove_' => 1,
+                ];
+            }
+        }
+        // 处理条件2:如果数据在 base_product_image 中无,但在 $images 有
+        $i = 1;
+        foreach ($images as $image) {
+            $found = $existingImages->firstWhere('image_url', $image);
+            if (!$found) {
+                $result[] = [
+                    'id' => 0,
+                    'image_url' => $image,
+                    'order' => $i,
+                ];
+            }
+            //更新库中排序
+            foreach ($existingImages as $existingImage) {
+                if ($existingImage->image_url == $image) {
+                    $existingImage->order = $i;
+                    $existingImage->save();
+                }
+            }
+            $i++;
+        }
+
+        return $result;
+    }
+
+
+}

+ 25 - 0
app/Admin/Repositories/BaseProductParameter.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\BaseProductParameter as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class BaseProductParameter extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    /*
+     * Select options for filter
+     */
+    public static function selectOptions() {
+        return Model::query()->where('enabled','=','1')->get()->pluck('name', 'id');
+    }
+
+
+}

+ 5 - 2
app/Admin/Repositories/NullRepository.php → app/Admin/Repositories/BaseVideo.php

@@ -2,10 +2,10 @@
 
 namespace App\Admin\Repositories;
 
-use App\Models\NullModel as Model;
+use App\Models\BaseVideo as Model;
 use Dcat\Admin\Repositories\EloquentRepository;
 
-class NullRepository extends EloquentRepository
+class BaseVideo extends EloquentRepository
 {
     /**
      * Model.
@@ -13,4 +13,7 @@ class NullRepository extends EloquentRepository
      * @var string
      */
     protected $eloquentClass = Model::class;
+
+
+
 }

+ 34 - 0
app/Admin/Repositories/BaseVideoCategory.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\BaseVideoCategory as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class BaseVideoCategory extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    // 调用模型方法
+    public static function selectOptions(\Closure $closure = null,$root = false)
+    {
+        if (!$closure) {
+            $closure = function ($query) {
+                $query = $query->where('enabled', 1);
+                $query =  $query->orderBy('order', 'desc')->orderBy('id', 'desc');
+                return $query;
+            };
+        }
+
+        $selectOptions =  Model::class::selectOptions($closure);
+        if ($root == false) {
+            unset($selectOptions[0]);
+        }
+        return $selectOptions;
+    }
+}

+ 464 - 0
app/Admin/Repositories/DistAdminDistributor.php

@@ -0,0 +1,464 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAdminDistributor as Model;
+use App\Models\DistProductCategory;
+use App\Models\DistProduct;
+use App\Models\SitePagesTag;
+use App\Models\SitePages;
+use App\Models\SitePagesTagRelationship;
+use Carbon\Carbon;
+use Dcat\Admin\Repositories\EloquentRepository;
+use App\Models\SiteBanner;
+
+class DistAdminDistributor extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    /*
+     * 查找最新的N个标签
+     */
+    public static function selectOptionsNew($limit=30)
+    {
+        return Model::orderBy('created_at', 'desc')->limit($limit)->pluck('client_code', 'id');
+    }
+
+    /*
+     * 清缓存
+     */
+    public static function clearCache($distId,$timeOut = 2)
+    {
+        //使用二级域名清缓存
+        $domain = self::getDomain($distId,0);
+        $url = $domain . '/?__clear_cache=1';
+        curlGet($url,$timeOut);
+    }
+
+    /*
+     * 得到指定分销商的域名
+     * type 0:当前域名 1:二级域名 2:自定义域名
+     */
+    public static function getDomain($distId,$type=0)
+    {
+        $model = new Model();
+        return $model->getDomain($distId,$type);
+    }
+    /*
+     * 获取一个标签
+     */
+    public static function getOneById($id)
+    {
+        return Model::where('id', $id)->first();
+    }
+
+    /*
+     * 始始化分销商
+     */
+    public static function initDist($distId)
+    {
+        //初始化数据,现在用默认,以后有可能不同主题不同
+        self::default($distId);
+    }
+
+    //默认
+    public static function default($distId)
+    {
+        //生成默认的banner
+        $siteBanner = new SiteBanner();
+        $bannerRow = $siteBanner->create([
+            'title' => 'Default Banner',
+            'image_url' => 'static/common/images/banner-1.jpg',
+            'show' => 1,
+            'order' => 0,
+            'position' => 1,
+            'dist_id'=>$distId,
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+        ]);
+
+        //生成默认产品分类
+        $distProductCategory = new DistProductCategory();
+        $categoryRow = $distProductCategory->create([
+            'parent_id' => 0,
+            'name' => 'Default Category',
+            'order' => 0,
+            'enabled' => 1,
+            'dist_id'=>$distId,
+            'seo_title' => 'Default Category',
+            'slug' => 'default-category',
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+        ]);
+        //生成默认产品
+        $distProduct = new DistProduct();
+        $productRow = $distProduct->create([
+            'category_id' => $categoryRow->id,
+            'title' => 'Default Product',
+            'sku' => 'sku001',
+            'order' => 0,
+            'enabled' => 1,
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'default-product',
+            'seo_title' => 'Default Product',
+            'issuance_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+        ]);
+        $productRow->save();
+        //生成默认tab
+        $sitePagesTag = new SitePagesTag();
+        $tagRow = $sitePagesTag->create([
+            'name' => 'News',
+            'dist_id'=>$distId,
+            'slug' => 'news',
+            'seo_title' => 'News',
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+        ]);
+        //生成默认页面
+        $sitePages = new SitePages();
+        $pageRow = $sitePages->create([
+            'title' => 'Default Page',
+            'status' => 1,
+            'author' => 'admin',
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'default-page',
+            'seo_title' => 'Default Page',
+            'post_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+            'page_type' => 0,
+        ]);
+        //生成绑定关系
+        $sitePagesTagRelationship = new SitePagesTagRelationship();
+        $sitePagesTagRelationship->create([
+            'tag_id' => $tagRow->id,
+            'pages_id' => $pageRow->id,
+        ]);
+        //生成about-us
+        $aboutUs = $sitePages->create([
+            'title' => 'About Us',
+            'status' => 1,
+            'author' => 'admin',
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'about-us',
+            'seo_title' => 'About Us',
+            'post_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+            'page_type' => 1,
+            'template_file' => config('dictionary.landing_page_default_template')
+        ]);
+        //生成privacy
+//        $privacy = $sitePages->create([
+//            'title' => 'Privacy',
+//            'status' => 1,
+//            'author' => 'admin',
+//            'dist_id'=>$distId,
+//            'content' => 'Default Content',
+//            'slug' => 'privacy',
+//            'seo_title' => 'Privacy',
+//            'post_date' => Carbon::now(),
+//            'created_at'=>Carbon::now(),
+//            'updated_at'=>Carbon::now(),
+//            'page_type' => 1,
+//            'template_file' => config('dictionary.landing_page_default_template')
+//        ]);
+        //生成sales
+        $sales = $sitePages->create([
+            'title' => 'Sales',
+            'status' => 1,
+            'author' => 'admin',
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'sales',
+            'seo_title' => 'Sales',
+            'post_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+            'page_type' => 1,
+            'template_file' => config('dictionary.landing_page_default_template')
+        ]);
+        //生成service
+        $service = $sitePages->create([
+            'title' => 'Services',
+            'status' => 1,
+            'author' => 'admin',
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'services',
+            'seo_title' => 'Services',
+            'post_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+            'page_type' => 1,
+            'template_file' => config('dictionary.landing_page_default_template')
+        ]);
+        //生成faqs
+        $faqs = $sitePages->create([
+            'title' => 'FAQs',
+            'status' => 1,
+            'author' => 'admin',
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'faqs',
+            'seo_title' => 'FAQs',
+            'post_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+            'page_type' => 1,
+            'template_file' => config('dictionary.landing_page_default_template')
+        ]);
+        //生成contact
+        $contact = $sitePages->create([
+            'title' => 'Contact us',
+            'status' => 1,
+            'author' => 'admin',
+            'dist_id'=>$distId,
+            'content' => 'Default Content',
+            'slug' => 'contact-us',
+            'seo_title' => 'Contact us',
+            'post_date' => Carbon::now(),
+            'created_at'=>Carbon::now(),
+            'updated_at'=>Carbon::now(),
+            'page_type' => 1,
+            'template_file' => config('dictionary.landing_page_contact_us_template')
+        ]);
+        //生成菜单
+        $siteMenu = new SiteMenu();
+        $menuConfig = [
+            'collections_type' => '',
+            'product_category' => '',
+            'pages_tag' => '',
+            'product' => '',
+            'pages' => '',
+            'url' => '',
+            'landing_page' => '',
+        ];
+        /*
+         * ==========================================
+         * 顶部菜单
+         * ==========================================
+         */
+        //----------------主页------------------
+        $data = [];
+        $newMenuConfig = $menuConfig;
+        $menuType = 0; //主页
+        $data[1] = [
+            'parentId' => 0,
+            'title' => 'Home',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$menuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 0,
+        ];
+
+        //----------------Products------------------
+        $menuType = 0; //主页
+        $newMenuConfig = $menuConfig;
+        $data[2] = [
+            'parentId' => 0,
+            'title' => 'Products',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$menuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 0,
+        ];
+        //----------------Products Category------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['collections_type'] = 0;
+        $newMenuConfig['product_category'] = $categoryRow->id;
+        $menuType = 1;//collections
+        $data[3] = [
+            'parentId' => 2,
+            'title' => 'Default Category',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 0,
+        ];
+        //----------------news------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['collections_type'] = 1;
+        $newMenuConfig['pages_tag'] = $tagRow->id;
+        $menuType = 1;//collections
+        $data[4] = [
+            'parentId' => 0,
+            'title' => 'News',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 0,
+        ];
+        //----------------About Us------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $aboutUs->id;
+        $menuType = 4;//pages
+        $data[5] = [
+            'parentId' => 0,
+            'title' => 'About Us',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 0,
+        ];
+        //----------------Contact------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $contact->id;
+        $menuType = 4;//pages
+        $data[6] = [
+            'parentId' => 0,
+            'title' => 'Contact',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 0,
+        ];
+        $siteMenu->createMenuBatch($data);
+
+        /*
+         * ==========================================
+         * 底部菜单
+         * ==========================================
+         */
+        //----------------SUPPORT------------------
+        $data = [];
+        $newMenuConfig = $menuConfig;
+        $menuType = 0; //主页
+        $data[1] = [
+            'parentId' => 0,
+            'title' => 'SUPPORT',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$menuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+        //----------------FAQ------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $faqs->id;
+        $menuType = 4;//pages
+        $data[2] = [
+            'parentId' => 1,
+            'title' => 'FAQ',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+        //----------------Sales------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $sales->id;
+        $menuType = 4;//pages
+        $data[3] = [
+            'parentId' => 1,
+            'title' => 'Sales',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+
+        //----------------COMPANY------------------
+        $newMenuConfig = $menuConfig;
+        $menuType = 0; //主页
+        $data[4] = [
+            'parentId' => 0,
+            'title' => 'COMPANY',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$menuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+
+        //----------------Home------------------
+        $newMenuConfig = $menuConfig;
+        $menuType = 0; //主页
+        $data[5] = [
+            'parentId' => 4,
+            'title' => 'Home',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$menuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+
+        //----------------About Us------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $aboutUs->id;
+        $menuType = 4;//pages
+        $data[6] = [
+            'parentId' => 4,
+            'title' => 'About Us',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+        //----------------Services------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $service->id;
+        $menuType = 4;//pages
+        $data[7] = [
+            'parentId' => 4,
+            'title' => 'Services',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+
+        //----------------News------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['collections_type'] = 1;
+        $newMenuConfig['pages_tag'] = $tagRow->id;
+        $menuType = 1;//collections
+        $data[8] = [
+            'parentId' => 4,
+            'title' => 'News',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+        //----------------Contact------------------
+        $newMenuConfig = $menuConfig;
+        $newMenuConfig['landing_page'] = $contact->id;
+        $menuType = 4;//pages
+        $data[9] = [
+            'parentId' => 4,
+            'title' => 'Contact',
+            'distId'=>$distId,
+            'uri' =>  $siteMenu->generateUri($menuType,$newMenuConfig,$distId),
+            'menuType' => $menuType,
+            'menuConfig' => $newMenuConfig,
+            'menuLocation' => 1,
+        ];
+
+        $siteMenu->createMenuBatch($data);
+    }
+
+
+}

+ 41 - 0
app/Admin/Repositories/DistAdminUser.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAdminUser as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+use App\Models\DistAdminRoleUser;
+class DistAdminUser extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+
+    /*
+     * 增加角色用户色关系
+     */
+    public static function addRoleUser($userId,$roleId) {
+        $distAdminRoleUser = new DistAdminRoleUser();
+        $distAdminRoleUser->role_id = $roleId;
+        $distAdminRoleUser->user_id = $userId;
+        $distAdminRoleUser->save();
+    }
+
+    /*
+     * 判断用户名是否存在
+     */
+    public static function findCountByUsername($id,$username)
+    {
+        $instance = new self();
+        if ($id) {
+            $count = $instance->Model()::where('username', $username)->where('id', '!=', $id)->count();
+        } else {
+            $count = $instance->Model()::where('username', $username)->count();
+        }
+        return $count;
+    }
+}

+ 80 - 0
app/Admin/Repositories/DistAppearance.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAppearance as Model;
+use Carbon\Carbon;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class DistAppearance extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    /*
+     * 获取一个标签
+     */
+    public static function getOneById($id)
+    {
+        return Model::where('id', $id)->first();
+    }
+
+    public static function selectOptions($valueShowId = false)
+    {
+        $data = Model::where('enabled', 1)->get();
+        $options = [];
+        foreach ($data as $item) {
+            if ($valueShowId) {
+                $options[$item->id] = $item->id.' - '.$item->title;
+            } else {
+                $options[$item->id] = $item->title;
+            }
+        }
+        return $options;
+    }
+
+    /*
+     * 设置状态为已导入
+     */
+    public static function setStatusToImported($id)
+    {
+        $row = Model::where('id', $id)->first();
+        if ($row) {
+            $row->updated_at = Carbon::now();
+            $row->imported = 1;
+            $row->save();
+        }
+        return true;
+    }
+
+    /*
+     * 切换主题操作,生成销应商主题模版与变量
+     * (如果原本就有模板与变量,不会重复生成)
+     */
+    public static function switchTheme($appearanceId,$distId) {
+        //复制原始模版到指定分销商
+        DistAppearanceTemplate::copyTemplateToDist($appearanceId, $distId);
+        DistAppearanceVariable::copyAppearanceVariable($appearanceId, $distId);
+        //发报到正式环境
+        DistAppearancePublishList::publish($appearanceId,$distId);
+        //清除缓存
+        DistAdminDistributor::clearCache($distId);
+        return true;
+    }
+
+    /*
+     * 初始化分销商模版与变量
+     */
+    public static function initTheme($appearanceId,$distId)
+    {
+        //请空模版与变量
+        DistAppearanceTemplate::deleteTemplates($appearanceId,$distId);
+        DistAppearanceVariable::deleteVariable($appearanceId, $distId);
+        //重新生成模版与变量
+        self::switchTheme($appearanceId, $distId);
+    }
+}

+ 33 - 0
app/Admin/Repositories/DistAppearanceBak.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAppearanceBak as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class DistAppearanceBak extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    /*
+     * 备份数据
+     */
+    static public function backupData($appearanceId,$distId) {
+        $model = new Model();
+        return $model->backupData($appearanceId,$distId);
+    }
+
+
+    static public function restoreDataByVersion($version)
+    {
+        $model = new Model();
+        return $model->restoreDataByVersion($version);
+    }
+
+
+}

+ 50 - 0
app/Admin/Repositories/DistAppearancePublishList.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAppearancePublishList as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class DistAppearancePublishList extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+
+    /*
+     * 更新发布版本
+     */
+    public static function publishVersion($appearanceId,$distId)
+    {
+        $model = new Model();
+        $row = $model->where('appearance_id',$appearanceId)->where('dist_id',$distId)->first();
+        if ($row) {
+            $row->template_update_code = generateVersionNumber();
+            $row->save();
+        } else {
+            $model->appearance_id = $appearanceId;
+            $model->dist_id = $distId;
+            $model->template_version = '1.0';
+            $model->template_update_code = generateVersionNumber();
+            $model->template_local_code = '';
+            $model->save();
+        }
+    }
+
+    /*
+     * 发布模版与变量
+     */
+    public static function publish($appearanceId,$distId) {
+        //同步模版到正式表
+        DistAppearanceTemplate::syncAppearanceTemplates($appearanceId,$distId);
+        //同步变量到正式表
+        DistAppearanceVariable::syncAppearanceVariables($appearanceId, $distId);
+        //发布版本号
+        DistAppearancePublishList::publishVersion($appearanceId,$distId);
+        return true;
+    }
+}

+ 184 - 0
app/Admin/Repositories/DistAppearanceTemplate.php

@@ -0,0 +1,184 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAppearanceTemplate as Model;
+use App\Models\SiteAppearanceTemplate;
+use Dcat\Admin\Repositories\EloquentRepository;
+use Illuminate\Support\Carbon;
+
+class DistAppearanceTemplate extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    public static function getContent($appearanceId,$distId,$templateCode)
+    {
+        $appearanceId = intval($appearanceId);
+        $distId = intval($distId);
+        $data = Model::where('appearance_id', $appearanceId)->where('dist_id', $distId)->where('template_code', $templateCode)->first();
+        if ($data) {
+            return $data->content;
+        }
+        return '';
+    }
+    public static function getTemplateTree($appearance_id,$dist_id)
+    {
+        $data = Model::where('appearance_id', $appearance_id)->where('dist_id', $dist_id)->orderBy('file_name', 'asc')->get(['id', 'file_name', 'file_path','template_code']);
+        return self::buildTree($data->toArray());
+    }
+
+    public static function buildTree(array $data) {
+        $result = [];
+        foreach ($data as $item) {
+            // Extract the path and file information
+            $path = $item['file_path'];
+            $id = $item['id'];
+            $file_name = $item['file_name'];
+
+            // Initialize a new entry for this path if it doesn't exist
+            if (!isset($result[$path])) {
+                $result[$path] = [
+                    'id' => 0, // default, as there's no parent ID
+                    'dist_id' => 0, // assuming dist_id for path
+                    'file_name' => trim($path, '/'), // using the directory name for file_name
+                    'children' => []
+                ];
+            }
+
+            // Add the file to the children of the respective path
+            $result[$path]['children'][] = [
+                'id' => $id,
+                'dist_id' => 0, // assuming dist_id
+                'file_name' => $file_name,
+                'template_code' => $item['template_code']
+            ];
+        }
+
+        $result = array_values($result);
+        return $result;
+    }
+
+    /*
+     * 保存模板内容
+     */
+    public static function saveContent($appearanceId,$distId,$templateCode, $content)
+    {
+        $appearanceId = intval($appearanceId);
+        $distId = intval($distId);
+        $data = Model::where('dist_id', $distId)->where('appearance_id', $appearanceId)->where('appearance_id', $appearanceId)->where('template_code', $templateCode)->first();
+        if ($data) {
+            $currentContent = $content;
+            $previousContent = $data->content;
+            //保存
+            $data->content = $content;
+            $data->save();
+            //加入模版修改日志
+            DistAppearanceTemplateLog::insertLog($appearanceId,$distId,$data->file_name,$data->file_path,$templateCode,$currentContent,$previousContent);
+            return true;
+        }
+        return false;
+    }
+
+    public static function addDelTree($appearanceId,$distId,$fileId,$fileName, $filePath,$type) {
+        if (empty($appearanceId) || empty($distId)) {
+            return ['status' => 0,'msg' => 'Missing required parameters'];
+        }
+        $model = new Model();
+        if ($type == 'add') {
+            $count = $model->where('appearance_id', $appearanceId)->where('dist_id', $distId)->where('file_name', $fileName)->count();
+            if ($count > 0) {
+                return ['status' => 0,'msg' => 'File name already exists'];
+            }
+            $filePath = empty($filePath)?'':$filePath;
+            $model = new Model();
+            $model->dist_id = $distId;
+            $model->appearance_id = $appearanceId;
+            $model->file_name = $fileName;
+            $model->file_path = $filePath;
+            $model->content = '';
+            $model->template_code = uniqueCode('');
+            $model->save();
+            return ['status' => 1];
+        } else {
+            $row = $model->where('appearance_id', $appearanceId)->where('dist_id', $distId)->where('id', $fileId)->first();
+            if ($row) {
+                $row->delete();
+                //加入模版修改日志
+                DistAppearanceTemplateLog::insertLog($appearanceId,$distId,$row->file_name,$row->file_path,$row->template_code,'',$row->content);
+                return ['status' => 1];
+            }
+            return ['status' => 0,'msg' => 'File ID not found'];
+        }
+    }
+
+    /*
+     * 请空指定模板
+     */
+    public static function deleteTemplates($appearanceId,$distId) {
+        Model::deleteTemplates($appearanceId, $distId);
+        return true;
+    }
+
+    /*
+     * 插入模版文件夹
+     */
+//    public static function insertTemplateFolder($distId,$appearanceId,$filePath,$fileName,$parentId) {
+//        $self = new self();
+//        $model = $self->model();
+//        $model->dist_id = $distId;
+//        $model->appearance_id = $appearanceId;
+//        $model->file_name = $fileName;
+//        $model->parent_id = $parentId;
+//        $model->file_type = 0;
+//        $model->file_path = $filePath;
+//        $model->template_code = uniqueCode('');
+//        $model->save();
+//        // 获取插入数据的 ID
+//        $insertedId = $model->id;
+//        return $insertedId;
+//    }
+
+    /*
+     * 插入模版文件内容
+     */
+    public static function insertTemplateContent($distId,$appearanceId,$filePath,$fileName,$content) {
+        $self = new self();
+        $model = $self->model();
+        $model->dist_id = $distId;
+        $model->appearance_id = $appearanceId;
+        $model->file_name = $fileName;
+        $model->file_path = $filePath;
+        $model->content = $content;
+        $model->template_code = uniqueCode('');
+        $model->save();
+        // 获取插入数据的 ID
+        $insertedId = $model->id;
+        return $insertedId;
+    }
+
+    /*
+     * 把原始模板复制给分销商
+     */
+    public static function copyTemplateToDist($appearanceId,$distId) {
+        return Model::copyTemplateToDist($appearanceId, $distId);
+    }
+
+
+    /*
+     * 同步模版到正式表上
+     */
+    public static function syncAppearanceTemplates($appearanceId,$distId)
+    {
+        $model = new Model();
+        return $model->syncAppearanceTemplates($appearanceId,$distId);
+    }
+
+
+
+
+}

+ 70 - 0
app/Admin/Repositories/DistAppearanceTemplateLog.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAppearanceTemplateLog as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class DistAppearanceTemplateLog extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    /*
+     *  添加模版修改日志
+     *  $currentContent 修改后的内容
+     *  $previousContent 修改前的内容
+     */
+    public static function insertLog($appearanceId,$distId,$fileName,$filePath,$templateCode,$currentContent,$previousContent)
+    {
+        $model = new Model();
+        $model->dist_id = $distId;
+        $model->file_name = $fileName;
+        $model->file_path = $filePath;
+        $model->appearance_id = $appearanceId;
+        $model->template_code = $templateCode;
+        $model->current_content = $currentContent;
+        $model->previous_content = $previousContent;
+        $model->version = generateVersionNumber();
+        $model->save();
+    }
+
+    /*
+     *  获取模版修改日志
+     */
+    public static function fetchTemplateLogs($appearanceId,$distId,$templateCode)
+    {
+        $model = new Model();
+        $model = $model->where('appearance_id','=',$appearanceId)->where('dist_id','=',$distId)->where('template_code','=',$templateCode)->orderBy('id','desc')->select('id','version','created_at')->get();
+        return $model;
+    }
+
+    /*
+     *  获取单条模版修改日志内容
+     */
+    public static function fetchTemplateLogContent($logId)
+    {
+        $model = new Model();
+        $model = $model->where('id','=',$logId)->first();
+        return $model;
+    }
+    /*
+     * 还原模版
+     */
+    public static function restoreTemplateLog($logId) {
+        $model = new Model();
+        $model = $model->where('id', '=', $logId)->first();
+        if ($model) {
+            $appearanceId = $model->appearance_id;
+            $distId = $model->dist_id;
+            $templateCode = $model->template_code;
+            $content = $model->previous_content;
+            DistAppearanceTemplate::saveContent($appearanceId, $distId, $templateCode, $content);
+        }
+    }
+
+}

+ 57 - 0
app/Admin/Repositories/DistAppearanceVariable.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistAppearanceVariable as Model;
+use Dcat\Admin\Form;
+use Dcat\Admin\Repositories\EloquentRepository;
+use App\Models\SiteAppearanceVariable;
+use Illuminate\Support\Carbon;
+
+class DistAppearanceVariable extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+
+    public static function getVariableRow($distId,$appearanceId,$templateId)
+    {
+        $model = new Model();
+        $variable = $model->where('dist_id',$distId)->where('appearance_id',$appearanceId)->whereIn('template_id',[0,$templateId])->get();
+        if($variable){
+            return $variable;
+        }else{
+            return '';
+        }
+    }
+
+    /*
+     * 把原始变量复制给分销商
+     */
+    public static function copyAppearanceVariable($appearanceId, $distId){
+        Model::copyAppearanceVariable($appearanceId, $distId);
+    }
+
+
+    /*
+     * 删除分销商主题变量
+     */
+    public static function deleteVariable($appearanceId,$distId)
+    {
+        return Model::deleteVariable($appearanceId, $distId);
+    }
+
+
+    /*
+     * 同步变量到正式表
+     */
+    public static function syncAppearanceVariables($appearanceId,$distId) {
+      $model = new Model();
+      return $model->syncAppearanceVariables($appearanceId,$distId);
+    }
+
+}

+ 64 - 0
app/Admin/Repositories/DistInquiry.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistInquiry as Model;
+use Carbon\Carbon;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class DistInquiry extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+
+    /*
+     * 检测状态是否为0,即未处理
+     */
+    public static function assessTheStatus($ids) {
+        $inquirieCount = Model::whereIn('id', $ids)->where('status', '=', 0)->count();
+        if ($inquirieCount != count($ids)) {
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * 分配询价单
+     */
+    public static function assignData($ids, $distId) {
+        $inquiries = Model::whereIn('id', $ids)->get();
+        foreach ($inquiries as $inquiry) {
+            $inquiry->dist_id = $distId;
+            $inquiry->status = 1;
+            $inquiry->allocate_time = Carbon::now();
+            $inquiry->save();
+        }
+    }
+
+
+
+    /*
+     * 供应商把询价单设置为已处理
+     */
+    public static function distSetStatusProcessed($ids)
+    {
+        $result = true;
+        foreach ($ids as $id) {
+            $id = intval($id);
+            $row = Model::find($id);
+            if ($row && $row->dist_id == getDistributorId() && $row->status == 1) {
+                $row->status = 2;
+                $row->save();
+            } else {
+                $result = false;
+            }
+        }
+        return $result;
+    }
+
+}

+ 21 - 0
app/Admin/Repositories/DistMessage.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\DistMessage as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class DistMessage extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+    public static function find($id)
+    {
+        return Model::find($id);
+    }
+}

+ 18 - 0
app/Admin/Repositories/SiteAppearanceTemplate.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\SiteAppearanceTemplate as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+use Illuminate\Support\Carbon;
+
+class SiteAppearanceTemplate extends EloquentRepository
+{
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+}

+ 21 - 0
app/Admin/Repositories/SiteAppearanceVariable.php

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

+ 16 - 0
app/Admin/Repositories/SiteBanner.php

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

+ 61 - 0
app/Admin/Repositories/SiteMenu.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Admin\Repositories;
+
+use App\Models\SiteMenu as Model;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+class SiteMenu extends EloquentRepository
+{
+
+    /**
+     * Model.
+     *
+     * @var string
+     */
+    protected $eloquentClass = Model::class;
+
+
+
+
+    /*
+     * 只能显示2层
+     */
+    public static function selectOptions(\Closure $closure = null)
+    {
+        if (!$closure) {
+            $closure = function ($query) {
+                $query =  $query->where('dist_id', getDistributorId())->orderBy('order', 'asc');
+                return $query;
+            };
+        }
+        $selectOptions =  Model::class::selectOptions($closure);
+        //只显示2层
+        foreach ($selectOptions as $key => $value) {
+            if (substr_count($value,'&nbsp;') > 2) {
+                unset($selectOptions[$key]);
+            }
+        }
+        return $selectOptions;
+    }
+
+    /*
+    * 获取一个标签
+    */
+    public static function getOneById($id)
+    {
+        return Model::where('id', $id)->where('dist_id', getDistributorId())->first();
+    }
+
+    public static function createMenuBatch($data) {
+        $model = new Model();
+        return $model->createMenuBatch($data);
+    }
+
+    //生成uri
+    public static function generateUri($menuType,$menuConfig,$distId,$isId = true) {
+        $model = new Model();
+        return $model->generateUri($menuType,$menuConfig,$distId,$isId);
+    }
+
+}

+ 2 - 2
app/Admin/Repositories/SiteAlbum.php → app/Admin/Repositories/Test.php

@@ -2,10 +2,10 @@
 
 namespace App\Admin\Repositories;
 
-use App\Models\SiteAlbum as Model;
+use App\Models\Test as Model;
 use Dcat\Admin\Repositories\EloquentRepository;
 
-class SiteAlbum extends EloquentRepository
+class Test extends EloquentRepository
 {
     /**
      * Model.

+ 0 - 4
app/Admin/bootstrap.php

@@ -2,9 +2,7 @@
 
 use App\Exceptions\Form\CutImage;
 use App\Exceptions\Form\MultipleCutImage;
-use App\Exceptions\Form\TradImage;
 use Dcat\Admin\Admin;
-use App\Exceptions\Form\TradFile;
 use Dcat\Admin\Form\Field\MultipleImage;
 use Dcat\Admin\Grid;
 use Dcat\Admin\Form;
@@ -63,5 +61,3 @@ Editor::resolving(function (Editor $editor) {
 //裁剪图片表单扩展
 Form::extend('multipleCutImage', MultipleCutImage::class);
 Form::extend('cutImage', CutImage::class);
-Form::extend('tradFile', TradFile::class);
-Form::extend('tradImage', TradImage::class);

+ 31 - 4
app/Admin/routes.php

@@ -14,15 +14,42 @@ Route::group([
 ], function (Router $router) {
     //主页
     $router->get('/', 'HomeController@index');
+    //产品
+    $router->get('base-product/parameter', 'BaseProductController@parameter');
+    $router->resource('base-product', 'BaseProductController');
+    //分类
+    $router->resource('product-category', 'BaseProductCategoryController');
+    //参数
+    $router->resource('product-parameter', 'BaseProductParameterController');
+    //视频分类
+    $router->resource('video-category', 'BaseVideoCategoryController');
+    //视频管理
+    $router->resource('base-video', 'BaseVideoController');
+    //分销商管理
+    $router->resource('dist-admin-distributor', 'DistAdminDistributorController');
+    //分销商用户管理
+    $router->resource('dist-admin-user', 'DistAdminUserController');
+    //分销商站点
+    $router->resource('dist-site', 'DistSiteController');
+    //询价管理
+    $router->resource('dist-inquiry', 'DistInquiryController');
+    //外观管理
+    $router->resource('dist-appearance', 'DistAppearanceController');
+    //模板管理
+    $router->any('dist-template/ace', [DistAppearanceTemplateController::class, 'ace']);
+    //模板变量
+    $router->resource('dist-template-var', 'DistAppearanceVariableController');
+
+    $router->resource('messages', 'DistMessageController');
 
     // 定义切换语言的路由
     $router->get('language-switch','LanguageController@index');
+
     // 不需要登录的路由
     $router->get('captcha','CaptchaController@generate');
-    //文件夹
-    $router->resource('site-folder', 'SiteAlbumFolderController');
-    //相册
-    $router->resource('site-album', 'SiteAlbumController');
+
+    //api接口
+    $router->get('api/dist', 'ApiController@dist');
 });
 
 /*

+ 0 - 15
app/Exceptions/Form/TradFile.php

@@ -1,15 +0,0 @@
-<?php
-
-namespace App\Exceptions\Form;
-
-use Dcat\Admin\Support\Helper;
-use Dcat\Admin\Form\Field\File;
-use Symfony\Component\HttpFoundation\File\UploadedFile;
-
-class TradFile extends File
-{
-    protected $view = 'admin.form_custom.trad-file';
-
-
-
-}

+ 0 - 74
app/Exceptions/Form/TradImage.php

@@ -1,74 +0,0 @@
-<?php
-
-namespace App\Exceptions\Form;
-
-use Dcat\Admin\Form\Field\File;
-use Dcat\Admin\Form\Field\ImageField;
-use Symfony\Component\HttpFoundation\File\UploadedFile;
-
-class TradImage extends File
-{
-    use ImageField;
-    protected $view = 'admin.form_custom.trad-image';
-
-    protected $rules = ['nullable', 'image'];
-
-    public function __construct($column, $arguments = [])
-    {
-        parent::__construct($column, $arguments);
-
-        $this->setupImage();
-    }
-
-
-
-    protected function setupImage()
-    {
-        if (! isset($this->options['accept'])) {
-            $this->options['accept'] = [];
-        }
-
-        $this->options['accept']['mimeTypes'] = 'image/*';
-        $this->options['isImage'] = true;
-    }
-
-    public function dimensions(array $options)
-    {
-        if (! $options) {
-            return $this;
-        }
-
-        $this->mergeOptions(['dimensions' => $options]);
-
-        foreach ($options as $k => &$v) {
-            $v = "$k=$v";
-        }
-
-        return $this->rules('dimensions:'.implode(',', $options));
-    }
-
-    /**
-     * Set ratio constraint.
-     *
-     * @param  float  $ratio  width/height
-     * @return $this
-     */
-    public function ratio($ratio)
-    {
-        if ($ratio <= 0) {
-            return $this;
-        }
-
-        return $this->dimensions(['ratio' => $ratio]);
-    }
-
-    /**
-     * @param  UploadedFile  $file
-     */
-    protected function prepareFile(UploadedFile $file)
-    {
-        $this->callInterventionMethods($file->getRealPath(), $file->getMimeType());
-
-        $this->uploadAndDeleteOriginalThumbnail($file);
-    }
-}

+ 1 - 0
app/Http/Kernel.php

@@ -63,5 +63,6 @@ class Kernel extends HttpKernel
         'signed' => \App\Http\Middleware\ValidateSignature::class,
         'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
         'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
+        'distauth' => \App\Http\Middleware\DistAuth::class,
     ];
 }

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

@@ -0,0 +1,36 @@
+<?php
+
+namespace App\Http\Middleware;
+use Closure;
+use Dcat\Admin\Admin;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+class DistAuth
+{
+    private  $excludeList = [
+        '/auth/users',
+        '/auth/roles',
+        '/auth/permissions',
+        '/auth/menu',
+        '/auth/extensions',
+        '/helpers/scaffold',
+        '/helpers/icons',
+    ];
+
+    public function handle($request, Closure $next)
+    {
+        //如果用户非管理员角色,判断是否含以上URL,含有则触发404
+        foreach ($this->excludeList as $item) {
+            if (strpos($request->url(), $item) !== false) {
+                if (!Admin::user()->isAdministrator()) {
+                    throw new NotFoundHttpException; // 触发404
+                }
+            }
+        }
+
+        //否则继续处理当前请求
+        return $next($request);
+
+    }
+
+}

+ 1 - 2
app/Libraries/CommonHelper.php

@@ -15,8 +15,7 @@ class CommonHelper
     public static function displayImage($images,$boxSize=60,$imgSize=1024)
     {
         if (empty($images) || empty($images[0])) {
-            $largeUrl = $thumbnailUrl = '/static/images/no-image.jpg';
-            $html = "<a href='$largeUrl' target='_blank'><img src='$thumbnailUrl' style='height:{$boxSize}px; margin-right:5px; border: 1px solid #ececf1;'></a>";
+            $html = "";
         } else {
 
 

+ 16 - 0
app/Models/BaseIso3166.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class BaseIso3166 extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'base_iso_3166';
+    public $timestamps = false;
+
+
+}

+ 43 - 0
app/Models/BaseProduct.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Models;
+
+use App\Traits\SortableTraitPinned;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+use Spatie\EloquentSortable\SortableTrait;
+
+class BaseProduct extends Model
+{
+    use HasDateTimeFormatter;
+    use SortableTraitPinned;
+
+    protected $table = 'base_product';
+
+    // 可选:你可以在这里自定义排序配置
+    public $sortable = [
+        'order_column_name' => 'order',  // 排序字段
+        'sort_when_creating' => true,    // 创建时自动排序
+    ];
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+        'parameters' => 'json', // 将 attributes 字段转换为数组
+    ];
+
+    public function baseProductCategory()
+    {
+        return $this->hasOne(BaseProductCategory::class,'id','category_id');
+    }
+
+    // 一对多关联
+    public function images()
+    {
+        return $this->hasMany(BaseProductImage::class, 'product_id','id')->orderBy('order', 'asc')->orderBy('id', 'asc');
+    }
+
+}

+ 50 - 0
app/Models/BaseProductCategory.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+
+class BaseProductCategory extends Model
+{
+    use HasDateTimeFormatter,
+        ModelTree {
+        ModelTree::boot as treeBoot;
+    }
+
+    //名称
+    protected $titleColumn = 'name';
+    //排序
+    protected $orderColumn = 'order';
+    //父级
+    protected $parentColumn = 'parent_id';
+
+    protected $table = 'base_product_category';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+    protected $fillable = [
+        'name', 'parent_id', 'order','enabled','parameter_id', // 假设已有的可填充字段
+    ];
+
+    /*
+     * 关联产品参数
+     */
+    public function baseProductParameter()
+    {
+        return $this->hasOne(BaseProductParameter::class,'id','parameter_id');
+    }
+
+
+//    public static function selectOptions(\Closure $closure = null)
+//    {
+//        $options = (new static())->withQuery($closure)->buildSelectOptions();
+//        return collect($options)->all();
+//    }
+}

+ 30 - 0
app/Models/BaseProductImage.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+use Illuminate\Database\Eloquent\Model;
+
+class BaseProductImage extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'base_product_image';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+    protected $fillable = [
+        'image_url',
+        'product_id',
+        'order',
+    ];
+
+    // 反向关联,属于某个产品
+    public function product()
+    {
+        return $this->belongsTo(BaseProduct::class, 'id');
+    }
+
+
+}

+ 35 - 0
app/Models/BaseProductParameter.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace App\Models;
+
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+use Spatie\EloquentSortable\SortableTrait;
+use Illuminate\Database\Eloquent\Builder;
+
+class BaseProductParameter extends Model
+{
+    use SortableTrait;
+
+    protected $table = 'base_product_parameter';
+
+
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+        'content' => 'json', // 将 attributes 字段转换为数组
+    ];
+
+
+    // 可选:你可以在这里自定义排序配置
+    public $sortable = [
+        'order_column_name' => 'order',  // 排序字段
+        'sort_when_creating' => true,    // 创建时自动排序
+    ];
+
+}

+ 39 - 0
app/Models/BaseVideo.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+use Spatie\EloquentSortable\SortableTrait;
+use App\Traits\SortableTraitPinned;
+
+class BaseVideo extends Model
+{
+	use HasDateTimeFormatter;
+    use SortableTraitPinned;
+
+    protected $table = 'base_video';
+
+    // 可选:你可以在这里自定义排序配置
+    public $sortable = [
+        'order_column_name' => 'order',  // 排序字段
+        'sort_when_creating' => true,    // 创建时自动排序
+    ];
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+    /*
+     * 分类一对多关联
+     */
+    public function baseVideoCategory()
+    {
+        return $this->hasOne(BaseVideoCategory::class,'id','category_id');
+    }
+
+
+}

+ 29 - 0
app/Models/BaseVideoCategory.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+
+class BaseVideoCategory extends Model
+{
+    use HasDateTimeFormatter,
+        ModelTree {
+        ModelTree::boot as treeBoot;
+    }
+    protected $table = 'base_video_category';
+    //名称
+    protected $titleColumn = 'name';
+    //排序
+    protected $orderColumn = 'order';
+    //父级
+    protected $parentColumn = 'parent_id';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+}

+ 63 - 0
app/Models/DistAdminDistributor.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class DistAdminDistributor extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_admin_distributor';
+
+
+
+    /*
+     * 用户一对多关联
+     */
+    public function user()
+    {
+        return $this->hasMany(DistAdminUser::class, 'dist_id', 'id');
+    }
+
+    /*
+     * 外观一对一关联
+     */
+    public function appearance()
+    {
+        return $this->hasOne(DistAppearance::class, 'id', 'appearance_id');
+    }
+
+    /*
+     * 得到分销商域名
+     * type 0:当前域名 1:二级域名 2:自定义域名
+     */
+    public function getDomain($distId,$type = 0)
+    {
+        $domain = '';
+        $row = $this->where('id', $distId)->first();
+        $http = 'http://';
+        if (env('ADMIN_HTTPS') == true) {
+            $http = 'https://';
+        }
+        if ($row) {
+            if ($type == 0) {
+                if ($row->domain_type == 0) {
+                    $domain = $http.$row->secondary_domain;
+                } else {
+                    $domain = $http.$row->custom_domain;
+                }
+            } else if ($type == 1) {
+                $domain = $http.$row->secondary_domain;
+            } else {
+                $domain = $http.$row->custom_domain;
+            }
+        }
+        if (env('DIST_SITE_PORT') != 80 && env('DIST_SITE_PORT') != 443) {
+            $domain .= ':' . env('DIST_SITE_PORT');
+        }
+        return $domain;
+    }
+
+}

+ 9 - 0
app/Models/DistAdminMenu.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace App\Models;
+use Dcat\Admin\Models\Menu;
+
+class DistAdminMenu extends Menu
+{
+    protected $table = 'dist_admin_menu';
+}

+ 4 - 4
app/Models/SiteAlbum.php → app/Models/DistAdminRoleUser.php

@@ -3,12 +3,12 @@
 namespace App\Models;
 
 use Dcat\Admin\Traits\HasDateTimeFormatter;
-
 use Illuminate\Database\Eloquent\Model;
 
-class SiteAlbum extends Model
+class DistAdminRoleUser extends Model
 {
 	use HasDateTimeFormatter;
-    protected $table = 'site_album';
-    
+    protected $table = 'dist_admin_role_users';
+
+
 }

+ 21 - 0
app/Models/DistAdminUser.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class DistAdminUser extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_admin_users';
+
+    /*
+     * 一对一关联
+     */
+    public function distributor()
+    {
+        return $this->hasOne(DistAdminDistributor::class, 'id', 'dist_id');
+    }
+}

+ 3 - 2
app/Models/NullModel.php → app/Models/DistAdminUsersSetting.php

@@ -6,8 +6,9 @@ use Dcat\Admin\Traits\HasDateTimeFormatter;
 
 use Illuminate\Database\Eloquent\Model;
 
-class NullModel extends Model
+class DistAdminUsersSetting extends Model
 {
-    use HasDateTimeFormatter;
+	use HasDateTimeFormatter;
+    protected $table = 'dist_admin_users_settings';
 
 }

+ 32 - 0
app/Models/DistAppearance.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Contracts\TreeRepository;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+use Spatie\EloquentSortable\SortableTrait;
+
+class DistAppearance extends Model
+{
+	use HasDateTimeFormatter;
+    use SortableTrait;
+
+    protected $table = 'dist_appearance';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+    // 可选:你可以在这里自定义排序配置
+    public $sortable = [
+        'order_column_name' => 'order',  // 排序字段
+        'sort_when_creating' => true,    // 创建时自动排序
+    ];
+
+
+
+}

+ 126 - 0
app/Models/DistAppearanceBak.php

@@ -0,0 +1,126 @@
+<?php
+
+namespace App\Models;
+
+use Carbon\Carbon;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class DistAppearanceBak extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_appearance_bak';
+
+    protected $fillable = [
+        'original_table',
+        'data',
+        'created_at',
+        'updated_at',
+        'dist_id',
+        'appearance_id',
+        'version'
+    ];
+
+    /*
+     * 备份数据dist_appearance_template和dist_appearance_variable到dist_appearance_bak的data字段中
+     */
+    public static function backupData($appearanceId,$distId)
+    {
+        $version = generateVersionNumber();
+        // 获取需要备份的数据
+        $templates = DistAppearanceTemplate::where('dist_id', $distId)->where('appearance_id', $appearanceId)->get();
+        $variables = DistAppearanceVariable::where('dist_id', $distId)->where('appearance_id', $appearanceId)->get();
+
+        // 备份模板数据
+        foreach ($templates as $template) {
+            self::create([
+                'dist_id' => $distId,
+                'appearance_id' => $appearanceId,
+                'original_table' => 'dist_appearance_template',
+                'data' => json_encode($template->getAttributes()),
+                'created_at' => Carbon::now(),
+                'updated_at' => Carbon::now(),
+                'version' => $version
+            ]);
+        }
+
+        // 备份变量数据
+        foreach ($variables as $variable) {
+            self::create([
+                'dist_id' => $distId,
+                'appearance_id' => $appearanceId,
+                'original_table' => 'dist_appearance_variable',
+                'data' => json_encode($variable->getAttributes()),
+                'created_at' => Carbon::now(),
+                'updated_at' => Carbon::now(),
+                'version' => $version
+            ]);
+        }
+    }
+
+
+    /*
+     * 用于恢复指定版本的备份数据
+     * @param $version 版本号
+     */
+    public function restoreDataByVersion($version)
+    {
+        DB::beginTransaction();
+
+        try {
+            // Fetch all backup records with the specified version
+            $backupRecords = DistAppearanceBak::where('version', $version)->get();
+
+            // Group records by appearance_id and dist_id
+            $groupedRecords = [];
+            foreach ($backupRecords as $record) {
+                $key = "{$record->appearance_id}-{$record->dist_id}";
+                $groupedRecords[$key][] = $record;
+            }
+
+            // Process each group
+            foreach ($groupedRecords as $key => $records) {
+                list($appearanceId, $distId) = explode('-', $key);
+
+                // Delete existing records in dist_appearance_template
+                DB::table('dist_appearance_template')
+                    ->where('appearance_id', $appearanceId)
+                    ->where('dist_id', $distId)
+                    ->delete();
+
+                // Delete existing records in dist_appearance_variable
+                DB::table('dist_appearance_variable')
+                    ->where('appearance_id', $appearanceId)
+                    ->where('dist_id', $distId)
+                    ->delete();
+
+                // Insert backup data into original tables
+                foreach ($records as $record) {
+                    $originalTable = $record->original_table;
+                    $data = json_decode($record->data, true);
+
+                    if (!is_array($data)) {
+                        continue; // Skip if data is not an array
+                    }
+
+                    // Insert data into the original table
+                    DB::table($originalTable)->insert($data);
+                }
+            }
+
+            DB::commit();
+        } catch (\Exception $e) {
+            DB::rollback();
+            Log::error('Error restoring data: ' . $e->getMessage());
+            throw $e; // Rethrow or handle the exception as needed
+        }
+    }
+
+
+
+
+
+}

+ 14 - 0
app/Models/DistAppearancePublishList.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class DistAppearancePublishList extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_appearance_publish_list';
+    
+}

+ 98 - 0
app/Models/DistAppearanceTemplate.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace App\Models;
+
+use Carbon\Carbon;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class DistAppearanceTemplate extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_appearance_template';
+
+    /*
+     * 把原始模板复制给分销商
+     */
+    public static function copyTemplateToDist($appearanceId,$distId) {
+        $appearanceId = intval($appearanceId);
+        $distId = intval($distId);
+        $count = self::where('dist_id', $distId)->where('appearance_id', $appearanceId)->count();
+        if ($count > 0) {
+            return;
+        }
+        $baseDistId = config('dictionary.base_dist_id');
+        //复制
+        DB::statement("
+INSERT INTO `dist_appearance_template` (`dist_id`, `appearance_id`, `file_name`, `file_path`, `content`, `created_at`, `updated_at`,  `template_code`)
+SELECT {$distId}, `appearance_id`, `file_name`, `file_path`, `content`, NOW(), NOW(), `template_code`
+FROM `dist_appearance_template`
+WHERE `dist_id` = {$baseDistId} AND `appearance_id` = {$appearanceId};
+        ");
+    }
+
+    public static function deleteTemplates($appearanceId,$distId) {
+        self::where('dist_id',$distId)->where('appearance_id',$appearanceId)->delete();
+        return true;
+    }
+
+
+
+    public function syncAppearanceTemplates($appearanceId,$distId)
+    {
+        $appearanceId = intval($appearanceId);
+        $distId = intval($distId);
+
+        $criteria = ['dist_id' => $distId, 'appearance_id' => $appearanceId];
+
+        $tmpModel = $this;
+        $tempRecords = $tmpModel
+            ->where($criteria)
+            ->get();
+
+        $siteModel = new SiteAppearanceTemplate();
+        $siteRecords = $siteModel
+            ->where($criteria)
+            ->get()
+            ->keyBy('id'); // Use IDs as keys for easier comparison
+
+
+        foreach ($tempRecords as $tempRecord) {
+            $siteRecord = $siteRecords->get($tempRecord->id);
+            if ($siteRecord) {
+                // If record exists in `site_appearance_template`, check for updates
+                if ($tempRecord->updated_at > $siteRecord->updated_at) {
+                    $siteModel->where('id', $siteRecord->id)
+                        ->update([
+                            'file_name' => $tempRecord->file_name,
+                            'file_path' => $tempRecord->file_path,
+                            'content' => $tempRecord->content,
+                            'updated_at' => Carbon::now(),
+                        ]);
+                }
+            } else {
+                // If record does not exist, insert it
+                $siteModel->insert([
+                    'id' => $tempRecord->id,
+                    'dist_id' => $tempRecord->dist_id,
+                    'appearance_id' => $tempRecord->appearance_id,
+                    'file_name' => $tempRecord->file_name,
+                    'file_path' => $tempRecord->file_path,
+                    'content' => $tempRecord->content,
+                    'created_at' => Carbon::now(),
+                    'updated_at' => Carbon::now(),
+                    'template_code' => $tempRecord->template_code,
+                ]);
+            }
+        }
+
+        // Delete records from `site_appearance_template` that don’t match `dist_id=1` and `appearance_id=1`
+        $siteModel
+            ->where($criteria)
+            ->whereNotIn('id', $tempRecords->pluck('id')->toArray())
+            ->delete();
+    }
+
+}

+ 17 - 0
app/Models/DistAppearanceTemplateLog.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class DistAppearanceTemplateLog extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_appearance_template_log';
+
+
+
+
+}

+ 122 - 0
app/Models/DistAppearanceVariable.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace App\Models;
+
+use Carbon\Carbon;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class DistAppearanceVariable extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_appearance_variable';
+
+    protected $fillable = ['dist_id', 'appearance_id', 'variable_name','variable_value','variable_type','created_at','updated_at','template_id'];
+
+    /*
+     * 关联到分销商表
+     */
+    public function distributor()
+    {
+        return $this->hasOne(DistAdminDistributor::class, 'id', 'dist_id');
+    }
+
+    /*
+     * 关联到外观表
+     */
+    public function appearance()
+    {
+        return $this->hasOne(DistAppearance::class, 'id', 'appearance_id');
+    }
+
+
+    /*
+     * 把原始变量复制给分销商
+     */
+    public static function copyAppearanceVariable($appearanceId, $distId){
+        $distId = intval($distId);
+        $appearanceId = intval($appearanceId);
+
+        $count = self::where('dist_id', $distId)->where('appearance_id', $appearanceId)->count();
+        if ($count > 0) {
+            return;
+        }
+        $baseDistId = config('dictionary.base_dist_id');
+        //复制
+        DB::statement("
+INSERT INTO `dist_appearance_variable` (`dist_id`, `appearance_id`, `variable_name`, `variable_value`, `variable_type`, `created_at`, `updated_at`, `template_code`,`variable_code`)
+SELECT {$distId}, `appearance_id`, `variable_name`, `variable_value`, `variable_type`, NOW(), NOW(), `template_code`,`variable_code`
+FROM `dist_appearance_variable`
+WHERE `dist_id` = {$baseDistId} AND `appearance_id` = {$appearanceId};
+        ");
+    }
+
+    public static function deleteVariable($appearanceId,$distId)
+    {
+        return self::where('appearance_id', $appearanceId)->where('dist_id', $distId)->delete();
+    }
+
+    public  function syncAppearanceVariables($appearanceId,$distId) {
+        $appearanceId = intval($appearanceId);
+        $distId = intval($distId);
+
+        // Define criteria for filtering
+        $criteria = ['dist_id' => $distId, 'appearance_id' => $appearanceId];
+
+        $tmpModel = $this;
+        // Retrieve records from both tables
+        $tempVariables = $tmpModel
+            ->where($criteria)
+            ->get();
+
+        $siteModel = new SiteAppearanceVariable();
+        $siteVariables = $siteModel
+            ->where($criteria)
+            ->get()
+            ->keyBy('id'); // Use IDs as keys for easier comparison
+
+        foreach ($tempVariables as $tempVariable) {
+            $siteVariable = $siteVariables->get($tempVariable->id);
+
+            if ($siteVariable) {
+                // If record exists in `site_appearance_variable`, check for updates
+                if ($tempVariable->updated_at > $siteVariable->updated_at) {
+                    $siteModel
+                        ->where('id', $siteVariable->id)
+                        ->update([
+                            'variable_name' => $tempVariable->variable_name,
+                            'variable_value' => $tempVariable->variable_value,
+                            'variable_type' => $tempVariable->variable_type,
+                            'template_code' => $tempVariable->template_code,
+                            'variable_code' => $tempVariable->variable_code,
+                            'updated_at' => Carbon::now(),
+                        ]);
+                }
+            } else {
+                // If record does not exist, insert it
+                $siteModel->insert([
+                    'id' => $tempVariable->id,
+                    'dist_id' => $tempVariable->dist_id,
+                    'appearance_id' => $tempVariable->appearance_id,
+                    'variable_name' => $tempVariable->variable_name,
+                    'variable_value' => $tempVariable->variable_value,
+                    'variable_type' => $tempVariable->variable_type,
+                    'template_code' => $tempVariable->template_code,
+                    'variable_code' => $tempVariable->variable_code,
+                    'created_at' => Carbon::now(),
+                    'updated_at' => Carbon::now(),
+                ]);
+            }
+        }
+
+        // Delete records from `site_appearance_variable` that don’t match `dist_id=1` and `appearance_id=1`
+        $siteModel
+            ->where($criteria)
+            ->whereNotIn('id', $tempVariables->pluck('id')->toArray())
+            ->delete();
+
+    }
+
+}

+ 38 - 0
app/Models/DistInquiry.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class DistInquiry extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_inquiry';
+
+    /*
+     * 关联到分销商
+     */
+    public function distributor()
+    {
+        return $this->hasOne(DistAdminDistributor::class,'id', 'dist_id');
+    }
+
+    /*
+     * 生成订单号
+     */
+    public static function generateOrderNumber()
+    {
+        // 获取当前日期,格式为YYYYMMDD
+        $date = now()->format('Ymd');
+
+        // 查询当天订单数量
+        $todayOrderCount = self::whereDate('created_at', Carbon::today())->count();
+
+        // 订单号:日期 + 当天订单数量 + 1
+        $orderNumber = $date . str_pad($todayOrderCount + 1, 4, '0', STR_PAD_LEFT);
+
+        return 'Q'.$orderNumber;
+    }
+}

+ 50 - 0
app/Models/DistMessage.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class DistMessage extends Model
+{
+    use HasFactory;
+
+    protected $table = 'dist_messages';
+    protected $fillable = ['title', 'content', 'sender_id', 'target_type', 'target_ids', 'created_at', 'updated_at'];
+
+    protected $casts = [
+        'target_ids' => 'json',
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+
+
+    // 消息的发送者
+    public function sender()
+    {
+        return $this->belongsTo(DistAdminDistributor::class, 'sender_id');
+    }
+
+    // 消息的阅读状态
+    public function readStatuses()
+    {
+        return $this->hasMany(DistReadStatus::class, 'message_id');
+    }
+
+    // 检查消息是否针对某用户
+    public function isForUser($userId)
+    {
+        if ($this->target_type === 'all') {
+            return true;
+        }
+
+        if ($this->target_type === 'users' && is_array($this->target_ids)) {
+            return in_array($userId, $this->target_ids);
+        }
+
+        return false;
+    }
+
+
+}

+ 62 - 0
app/Models/DistProduct.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+use App\Traits\SortableTraitPinned;
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+
+class DistProduct extends Model
+{
+	use HasDateTimeFormatter;
+    use SortableTraitPinned;
+    protected $table = 'dist_product';
+
+    // 可选:你可以在这里自定义排序配置
+    public $sortable = [
+        'order_column_name' => 'order',  // 排序字段
+        'sort_when_creating' => true,    // 创建时自动排序
+    ];
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+        'parameters' => 'json', // 将 attributes 字段转换为数组
+    ];
+
+    protected $fillable = [
+        'id',
+        'title',
+        'keywords',
+        'description',
+        'sku',
+        'category_id',
+        'issuance_date',
+        'order',
+        'enabled',
+        'content',
+        'parameters',
+        'created_at',
+        'updated_at',
+        'is_pinned',
+        'dist_id',
+        'seo_title',
+        'seo_keywords',
+        'seo_description',
+        'slug',
+    ];
+
+
+    public function distProductCategory()
+    {
+        return $this->hasOne(DistProductCategory::class,'id','category_id');
+    }
+
+    // 一对多关联
+    public function images()
+    {
+        return $this->hasMany(DistProductImage::class, 'product_id')->orderBy('order', 'asc')->orderBy('id', 'asc');
+    }
+
+}

+ 79 - 0
app/Models/DistProductCategory.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\Session;
+use Spatie\EloquentSortable\Sortable;
+use Illuminate\Database\Eloquent\Scope;
+
+use App\Distributor\Scopes;
+class DistProductCategory extends Model
+{
+    use HasDateTimeFormatter,
+        ModelTree {
+        ModelTree::boot as treeBoot;
+    }
+	use HasDateTimeFormatter;
+    protected $table = 'dist_product_category';
+
+    //名称
+    protected $titleColumn = 'name';
+    //排序
+    protected $orderColumn = 'order';
+    //父级
+    protected $parentColumn = 'parent_id';
+
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+    protected $fillable = [
+        'name', 'parent_id', 'order','enabled','dist_id','slug','created_at', 'updated_at',// 假设已有的可填充字段
+        'seo_title', 'seo_keywords', 'seo_description',
+    ];
+
+
+    protected $distributor = null;
+
+
+
+    /*
+     * 关联产品参数
+     */
+    public function distProductParameter()
+    {
+        return $this->hasOne(DistProductParameter::class,'id','parameter_id');
+    }
+
+
+    public static function selectOptions(\Closure $closure = null)
+    {
+        $options = (new static())->withQuery($closure)->buildSelectOptions();
+        return collect($options)->all();
+    }
+    public function getAllCategories($parentId = null)
+    {
+        // Retrieve categories with the specified parentId, or all if no parentId is specified
+        $query = self::query();
+
+        if ($parentId !== null) {
+            $query->where('parent_id', $parentId);
+        }
+
+        $categories = $query->orderBy($this->orderColumn)->get();
+
+        // If you want a hierarchical structure, you can recursively build it
+        $categories->each(function ($category) {
+            $category->children = $category->getAllCategories($category->id);
+        });
+
+        return $categories;
+    }
+
+}

+ 32 - 0
app/Models/DistProductImage.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class DistProductImage extends Model
+{
+    use HasDateTimeFormatter;
+    protected $table = 'dist_product_image';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+    protected $fillable = [
+        'image_url',
+        'product_id',
+        'order',
+        'created_at',
+        'updated_at'
+        ];
+
+    // 反向关联,属于某个产品
+    public function product()
+    {
+        return $this->belongsTo(DistProduct::class, 'id');
+    }
+
+}

+ 14 - 0
app/Models/DistProductParameter.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class DistProductParameter extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'dist_product_parameter';
+    
+}

+ 26 - 0
app/Models/DistReadStatus.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class DistReadStatus extends Model
+{
+    use HasFactory;
+
+    protected $table = 'dist_read_status';
+    protected $fillable = ['user_id', 'message_id', 'is_read', 'created_at', 'updated_at'];
+
+    // 阅读状态属于一个用户
+    public function user()
+    {
+        return $this->belongsTo(DistAdminDistributor::class, 'user_id');
+    }
+
+    // 阅读状态属于一条消息
+    public function message()
+    {
+        return $this->belongsTo(DistMessage::class, 'message_id');
+    }
+}

+ 38 - 0
app/Models/DistVideo.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+use Spatie\EloquentSortable\SortableTrait;
+use App\Traits\SortableTraitPinned;
+
+class DistVideo extends Model
+{
+    use HasDateTimeFormatter;
+    use SortableTraitPinned;
+
+    protected $table = 'dist_video';
+
+    // 可选:你可以在这里自定义排序配置
+    public $sortable = [
+        'order_column_name' => 'order',  // 排序字段
+        'sort_when_creating' => true,    // 创建时自动排序
+    ];
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+    /*
+     * 分类一对多关联
+     */
+    public function distVideoCategory()
+    {
+        return $this->hasOne(DistVideoCategory::class,'id','category_id');
+    }
+
+}

+ 29 - 0
app/Models/DistVideoCategory.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Dcat\Admin\Traits\ModelTree;
+use Illuminate\Database\Eloquent\Model;
+use Spatie\EloquentSortable\Sortable;
+
+class DistVideoCategory extends Model
+{
+    use HasDateTimeFormatter,
+        ModelTree {
+        ModelTree::boot as treeBoot;
+    }
+    protected $table = 'dist_video_category';
+    //名称
+    protected $titleColumn = 'name';
+    //排序
+    protected $orderColumn = 'order';
+    //父级
+    protected $parentColumn = 'parent_id';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+}

+ 0 - 27
app/Models/SiteAlbumFolder.php

@@ -1,27 +0,0 @@
-<?php
-
-namespace App\Models;
-
-use Dcat\Admin\Traits\HasDateTimeFormatter;
-
-use Dcat\Admin\Traits\ModelTree;
-use Illuminate\Database\Eloquent\Model;
-
-class SiteAlbumFolder extends Model
-{
-	use HasDateTimeFormatter;
-    protected $table = 'site_album_folder';
-
-    use HasDateTimeFormatter,
-        ModelTree {
-        ModelTree::boot as treeBoot;
-    }
-
-    public function allNodes()
-    {
-        return $this->callQueryCallbacks(new static())
-            ->orderBy($this->getOrderColumn(), 'desc')
-            ->get();
-    }
-
-}

+ 16 - 0
app/Models/SiteAppearanceTemplate.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class SiteAppearanceTemplate extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'site_appearance_template';
+
+
+
+}

+ 17 - 0
app/Models/SiteAppearanceVariable.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class SiteAppearanceVariable extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'site_appearance_variable';
+
+    protected $fillable = ['dist_id', 'appearance_id', 'variable_name','variable_value','variable_type','created_at','updated_at','template_id'];
+
+
+}

+ 26 - 0
app/Models/SiteBanner.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class SiteBanner extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'site_banner';
+
+    protected $fillable = [
+        'image_url',
+        'order',
+        'banner_url',
+        'title',
+        'show',
+        'position',
+        'created_at',
+        'updated_at',
+        'dist_id',
+    ];
+
+}

+ 131 - 0
app/Models/SiteMenu.php

@@ -0,0 +1,131 @@
+<?php
+
+namespace App\Models;
+
+
+use Carbon\Carbon;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Dcat\Admin\Traits\ModelTree;
+
+class SiteMenu extends Model
+{
+	use HasDateTimeFormatter;
+    use ModelTree;
+
+    protected $table = 'site_menu';
+
+    protected $parentColumn = 'parent_id';
+
+    // 排序字段名称,默认值为 order
+    protected $orderColumn = 'order';
+
+    // 标题字段名称,默认值为 title
+    protected $titleColumn = 'title';
+
+    protected $casts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+        'menu_config' => 'json', // 将 menu_config 字段转换为数组
+    ];
+
+    protected $fillable = [
+        'parent_id',
+        'order',
+        'title',
+        'uri',
+        'show',
+        'menu_type',
+        'menu_config',
+        'menu_location',
+        'dist_id',
+    ];
+
+
+    /**
+     * @return 批量生成菜单
+     */
+    public function createMenuBatch($data) {
+        $parentIdArray = [];
+        $i = 0;
+        foreach ($data as $item) {
+            $parentId = $item['parentId'] == 0 ? 0 : $parentIdArray[$item['parentId']];
+            $i++;
+            $row = $this->create([
+                'parent_id' => $parentId,
+                'title' => $item['title'],
+                'order' => $i,
+                'dist_id'=>$item['distId'],
+                'uri' => $item['uri'],
+                'menu_type' => $item['menuType'],
+                'menu_config' => $item['menuConfig'],
+                'menu_location' => $item['menuLocation'],//0顶部 1底部
+                'show'  => 1,
+                'created_at'=>Carbon::now(),
+                'updated_at'=>Carbon::now(),
+            ]);
+            $parentIdArray[$i] = $row->id;
+        }
+    }
+
+
+    public  function generateUri($menuType,$menuConfig,$distId,$isId = true) {
+        switch ($menuType) {
+            case 0: //选择产品
+                $uri ="/";
+                break;
+            case 1: //集合
+                if ($menuConfig['collections_type'] == 0) {
+                    $distProductCategory = new DistProductCategory();
+                    $row = $distProductCategory->where('dist_id', $distId)->where('id', $menuConfig['product_category'])->first();
+                    //产品分类
+                    $slug = $isId ? $row->id : $row->slug;
+                    $uri = $row ? config('dictionary.site_url.product_category').'/'.$slug : "/";
+                } else if ($menuConfig['collections_type'] == 1) {
+                    $sitePagesTag = new SitePagesTag();
+                    $row = $sitePagesTag->where('dist_id', $distId)->where('id', $menuConfig['pages_tag'])->first();
+                    $slug = $isId ? $row->id : $row->slug;
+                    //文章标签
+                    $uri = $row ? config('dictionary.site_url.tags').'/'.$slug : "/";
+                } else if ($menuConfig['collections_type'] == 2) {
+                    $distProductCategory = new DistVideoCategory();
+                    $row = $distProductCategory->where('dist_id', $distId)->where('id', $menuConfig['video_category'])->first();
+                    $slug = $isId ? $row->id : $row->slug;
+                    $uri = $row ? config('dictionary.site_url.video_category').'/'.$slug : "/";
+                }
+                break;
+            case 2: //选择产品
+                $distProduct = new DistProduct();
+                $row = $distProduct->where('dist_id', $distId)->where('id', $menuConfig['product'])->first();
+                $slug = $isId ? $row->id : $row->slug;
+                $uri = $row ? config('dictionary.site_url.products').'/' .$slug : "/";
+                break;
+            case 3: //选择页面
+                $sitePages = new SitePages();
+                $row = $sitePages->where('dist_id', $distId)->where('id', $menuConfig['pages'])->first();
+                $slug = $isId ? $row->id : $row->slug;
+                $uri = $row ? config('dictionary.site_url.pages').'/'.$slug : "/";
+                break;
+            case 4: //选择页面
+                $sitePages = new SitePages();
+                $row = $sitePages->where('dist_id', $distId)->where('id', $menuConfig['landing_page'])->first();
+                $slug = $isId ? $row->id : $row->slug;
+                $uri = $row ? config('dictionary.site_url.pages').'/'.$slug : "/";
+                break;
+            case 5: //视频
+                $distVideo = new DistVideo();
+                $row = $distVideo->where('dist_id', $distId)->where('id', $menuConfig['videos'])->first();
+                $slug = $isId ? $row->id : $row->slug;
+                $uri = $row ? config('dictionary.site_url.video').'/'.$slug : "/";
+                break;
+            case 10: //url
+                $uri = $menuConfig['url'];
+                break;
+        }
+        return $uri;
+    }
+
+
+
+}

+ 44 - 0
app/Models/SitePages.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class SitePages extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'site_pages';
+
+    protected $fillable = [
+        'title',
+        'content',
+        'status',
+        'author',
+        'post_date',
+        'dist_id',
+        'cover_image',
+        'slug',
+        'seo_title',
+        'seo_keywords',
+        'seo_description',
+        'page_type',
+        'template_file'
+    ];
+
+    /**
+     * 定义你的关联模型.
+     *
+     * @return BelongsToMany
+     */
+    public function pagesTag()
+    {
+
+        $pivotTable = 'site_pages_tag_relationship'; // 中间表
+
+        $relatedModel = SitePagesTag::class; // 关联模型类名
+
+        return $this->belongsToMany($relatedModel, $pivotTable, 'pages_id', 'tag_id');
+    }
+}

+ 24 - 0
app/Models/SitePagesTag.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Models;
+
+use App\Traits\DistSlugTrait;
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class SitePagesTag extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'site_pages_tag';
+    public $timestamps = false;
+    protected $fillable = [
+        'name',
+        'slug',
+        'dist_id',
+        'created_at',
+        'seo_title',
+        'seo_keywords',
+        'seo_description'
+    ];
+}

+ 19 - 0
app/Models/SitePagesTagRelationship.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+
+class SitePagesTagRelationship extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'site_pages_tag_relationship';
+    public $timestamps = false;
+
+    protected $fillable = [
+        'pages_id',
+        'tag_id',
+    ];
+}

+ 19 - 0
app/Models/Test.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Models;
+
+use Dcat\Admin\Traits\HasDateTimeFormatter;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class Test extends Model
+{
+	use HasDateTimeFormatter;
+    protected $table = 'test';
+
+    public function __construct()
+    {
+        parent::__construct();
+    }
+}

+ 44 - 0
app/Models/User.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Models;
+
+// use Illuminate\Contracts\Auth\MustVerifyEmail;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Foundation\Auth\User as Authenticatable;
+use Illuminate\Notifications\Notifiable;
+use Laravel\Sanctum\HasApiTokens;
+
+class User extends Authenticatable
+{
+    use HasApiTokens, HasFactory, Notifiable;
+
+    /**
+     * The attributes that are mass assignable.
+     *
+     * @var array<int, string>
+     */
+    protected $fillable = [
+        'name',
+        'email',
+        'password',
+    ];
+
+    /**
+     * The attributes that should be hidden for serialization.
+     *
+     * @var array<int, string>
+     */
+    protected $hidden = [
+        'password',
+        'remember_token',
+    ];
+
+    /**
+     * The attributes that should be cast.
+     *
+     * @var array<string, string>
+     */
+    protected $casts = [
+        'email_verified_at' => 'datetime',
+    ];
+}

+ 1 - 13
config/admin.php

@@ -213,7 +213,7 @@ return [
     |--------------------------------------------------------------------------
     */
     'helpers' => [
-        'enable' => true,
+        'enable' => false,
     ],
 
     /*
@@ -280,8 +280,6 @@ return [
         // Image and file upload path under the disk above.
         'directory' => [
             'image' => 'images',
-            'video' => 'videos',
-            'pdf'   => 'pdfs',
             'file'  => 'files',
         ],
         //editor tinyMCE上传路径
@@ -295,16 +293,6 @@ return [
             'limit' => 20, // 上传文件数量限制
         ],
 
-        'oss_video' => [
-            'accept' => 'mp4',//允许上传的文件类型
-            'max_size' => 50000, // 上传文件大小限制,单位kB
-            'limit' => 20, // 上传文件数量限制
-        ],
-        'oss_pdf' => [
-            'accept' => 'pdf,dpf,doc,docx,xls,xlsx,ppt,pptx',//允许上传的文件类型
-            'max_size' => 50000, // 上传文件大小限制,单位kB
-            'limit' => 20, // 上传文件数量限制
-        ],
     ],
 
     /*

+ 70 - 7
config/dictionary.php

@@ -16,22 +16,85 @@ return [
     //默认语言
     'default_language' => 'en',
 
+    //分销商角色ID
+    'dist_role_id' => '2',
 
+    //基础分销商ID,默认为1,此分销商为测试用,模版与变量为基础版本,用于复制给其他分销商用
+    'base_dist_id' => '1',
+
+    //用户配置
+    'users_settings' => [
+        'visibility' => '1',//可见性,默认值0不可见,1可见
+    ],
 
     //是否启用
     'enabled' => [
-        '1' => 'yes',
-        '0' => 'no',
+        '1' => 'Yes',
+        '0' => 'No',
+    ],
+    //是否
+    'whether' => [
+        '1' => 'Yes',
+        '0' => 'No',
+    ],
+    //询价状态
+    'inquiryStatus' => [
+        '0' => 'new',
+        '1' => 'pending',
+        '2' => 'processed',
+    ],
+    //菜单类型
+    'menu_type' => [
+        '0' => 'home_page',
+        '1' => 'collections',
+        '2' => 'products',
+        '3' => 'pages',
+        '4' => 'landing_page',
+        '5' => 'videos',
+        '10' => 'url',
     ],
 
-
-    //文件夹类型
-    'folder_type' => [
-        '0' => 'product',//产品
-        '1' => 'other',//其他
+    'collections_type' => [
+        '0' => 'product_category',
+        '1' => 'pages_tag',
+        '2' => 'video_category',
+    ],
+    //文章状态
+    'pages_status' => [
+        '0' => 'draft',
+        '1' => 'published',
+    ],
+    //
+    'visibility' => [
+        '1' => 'visible',
+        '0' => 'hidden',
+    ],
+    //站点URL配置
+    'site_url' => [
+        'pages' => '/pages',
+        'tags' => '/collections',
+        'products' => '/products',
+        'product_category' => '/products/categories',
+        'video' => '/videos',
+        'video_category' => '/videos/categories',
+        'contact' => '/contact'
     ],
 
+    //临时变量
+    'temp_value' => [
+        'location' => 0, //用于SiteMenuController中location变量
+    ],
+    'freight_forwarder' => [
+        0 => 'No',
+        1 => 'Yes',
+    ],
+    'domain_type' => [
+        0 => 'secondary_domain',
+        1 => 'custom_domain',
+    ],
 
+    'landing_page_default_template' => 'pages_detail.liquid',
+    'landing_page_contact_us_template' => 'pages_sp_contact.liquid',
 
 
 ];

+ 0 - 31
database/migrations/2024_12_31_064946_updata_distributor_table.php

@@ -1,31 +0,0 @@
-<?php
-
-use Illuminate\Database\Migrations\Migration;
-use Illuminate\Database\Schema\Blueprint;
-use Illuminate\Support\Facades\Schema;
-
-return new class extends Migration
-{
-    /**
-     * Run the migrations.
-     * 增加一个字段 owned_appearances 用于记录拥有的主题
-     *
-     * @return void
-     */
-    public function up()
-    {
-        Schema::table('dist_admin_distributor', function (Blueprint $table) {
-            $table->string('owned_appearances', length: 500)->comment('拥有的主题');
-        });
-    }
-
-    /**
-     * Reverse the migrations.
-     *
-     * @return void
-     */
-    public function down()
-    {
-        //
-    }
-};

+ 0 - 232
dcat_admin_ide_helper.php

@@ -1,232 +0,0 @@
-<?php
-
-/**
- * A helper file for Dcat Admin, to provide autocomplete information to your IDE
- *
- * This file should not be included in your code, only analyzed by your IDE!
- *
- * @author jqh <841324345@qq.com>
- */
-namespace Dcat\Admin {
-    use Illuminate\Support\Collection;
-
-    /**
-     * @property Grid\Column|Collection id
-     * @property Grid\Column|Collection name
-     * @property Grid\Column|Collection type
-     * @property Grid\Column|Collection version
-     * @property Grid\Column|Collection detail
-     * @property Grid\Column|Collection created_at
-     * @property Grid\Column|Collection updated_at
-     * @property Grid\Column|Collection is_enabled
-     * @property Grid\Column|Collection parent_id
-     * @property Grid\Column|Collection order
-     * @property Grid\Column|Collection icon
-     * @property Grid\Column|Collection uri
-     * @property Grid\Column|Collection extension
-     * @property Grid\Column|Collection permission_id
-     * @property Grid\Column|Collection menu_id
-     * @property Grid\Column|Collection slug
-     * @property Grid\Column|Collection http_method
-     * @property Grid\Column|Collection http_path
-     * @property Grid\Column|Collection role_id
-     * @property Grid\Column|Collection user_id
-     * @property Grid\Column|Collection value
-     * @property Grid\Column|Collection username
-     * @property Grid\Column|Collection password
-     * @property Grid\Column|Collection avatar
-     * @property Grid\Column|Collection remember_token
-     * @property Grid\Column|Collection language
-     * @property Grid\Column|Collection email
-     * @property Grid\Column|Collection token
-     * @property Grid\Column|Collection tokenable_type
-     * @property Grid\Column|Collection tokenable_id
-     * @property Grid\Column|Collection abilities
-     * @property Grid\Column|Collection last_used_at
-     * @property Grid\Column|Collection expires_at
-     * @property Grid\Column|Collection folder_id
-     * @property Grid\Column|Collection parameters
-     * @property Grid\Column|Collection cover
-     * @property Grid\Column|Collection en_detail
-     * @property Grid\Column|Collection cn_detail
-     * @property Grid\Column|Collection poster
-     * @property Grid\Column|Collection cert
-     * @property Grid\Column|Collection pdf
-     * @property Grid\Column|Collection video
-     * @property Grid\Column|Collection folder_type
-     * @property Grid\Column|Collection show_tabs
-     * @property Grid\Column|Collection enabled
-     *
-     * @method Grid\Column|Collection id(string $label = null)
-     * @method Grid\Column|Collection name(string $label = null)
-     * @method Grid\Column|Collection type(string $label = null)
-     * @method Grid\Column|Collection version(string $label = null)
-     * @method Grid\Column|Collection detail(string $label = null)
-     * @method Grid\Column|Collection created_at(string $label = null)
-     * @method Grid\Column|Collection updated_at(string $label = null)
-     * @method Grid\Column|Collection is_enabled(string $label = null)
-     * @method Grid\Column|Collection parent_id(string $label = null)
-     * @method Grid\Column|Collection order(string $label = null)
-     * @method Grid\Column|Collection icon(string $label = null)
-     * @method Grid\Column|Collection uri(string $label = null)
-     * @method Grid\Column|Collection extension(string $label = null)
-     * @method Grid\Column|Collection permission_id(string $label = null)
-     * @method Grid\Column|Collection menu_id(string $label = null)
-     * @method Grid\Column|Collection slug(string $label = null)
-     * @method Grid\Column|Collection http_method(string $label = null)
-     * @method Grid\Column|Collection http_path(string $label = null)
-     * @method Grid\Column|Collection role_id(string $label = null)
-     * @method Grid\Column|Collection user_id(string $label = null)
-     * @method Grid\Column|Collection value(string $label = null)
-     * @method Grid\Column|Collection username(string $label = null)
-     * @method Grid\Column|Collection password(string $label = null)
-     * @method Grid\Column|Collection avatar(string $label = null)
-     * @method Grid\Column|Collection remember_token(string $label = null)
-     * @method Grid\Column|Collection language(string $label = null)
-     * @method Grid\Column|Collection email(string $label = null)
-     * @method Grid\Column|Collection token(string $label = null)
-     * @method Grid\Column|Collection tokenable_type(string $label = null)
-     * @method Grid\Column|Collection tokenable_id(string $label = null)
-     * @method Grid\Column|Collection abilities(string $label = null)
-     * @method Grid\Column|Collection last_used_at(string $label = null)
-     * @method Grid\Column|Collection expires_at(string $label = null)
-     * @method Grid\Column|Collection folder_id(string $label = null)
-     * @method Grid\Column|Collection parameters(string $label = null)
-     * @method Grid\Column|Collection cover(string $label = null)
-     * @method Grid\Column|Collection en_detail(string $label = null)
-     * @method Grid\Column|Collection cn_detail(string $label = null)
-     * @method Grid\Column|Collection poster(string $label = null)
-     * @method Grid\Column|Collection cert(string $label = null)
-     * @method Grid\Column|Collection pdf(string $label = null)
-     * @method Grid\Column|Collection video(string $label = null)
-     * @method Grid\Column|Collection folder_type(string $label = null)
-     * @method Grid\Column|Collection show_tabs(string $label = null)
-     * @method Grid\Column|Collection enabled(string $label = null)
-     */
-    class Grid {}
-
-    class MiniGrid extends Grid {}
-
-    /**
-     * @property Show\Field|Collection id
-     * @property Show\Field|Collection name
-     * @property Show\Field|Collection type
-     * @property Show\Field|Collection version
-     * @property Show\Field|Collection detail
-     * @property Show\Field|Collection created_at
-     * @property Show\Field|Collection updated_at
-     * @property Show\Field|Collection is_enabled
-     * @property Show\Field|Collection parent_id
-     * @property Show\Field|Collection order
-     * @property Show\Field|Collection icon
-     * @property Show\Field|Collection uri
-     * @property Show\Field|Collection extension
-     * @property Show\Field|Collection permission_id
-     * @property Show\Field|Collection menu_id
-     * @property Show\Field|Collection slug
-     * @property Show\Field|Collection http_method
-     * @property Show\Field|Collection http_path
-     * @property Show\Field|Collection role_id
-     * @property Show\Field|Collection user_id
-     * @property Show\Field|Collection value
-     * @property Show\Field|Collection username
-     * @property Show\Field|Collection password
-     * @property Show\Field|Collection avatar
-     * @property Show\Field|Collection remember_token
-     * @property Show\Field|Collection language
-     * @property Show\Field|Collection email
-     * @property Show\Field|Collection token
-     * @property Show\Field|Collection tokenable_type
-     * @property Show\Field|Collection tokenable_id
-     * @property Show\Field|Collection abilities
-     * @property Show\Field|Collection last_used_at
-     * @property Show\Field|Collection expires_at
-     * @property Show\Field|Collection folder_id
-     * @property Show\Field|Collection parameters
-     * @property Show\Field|Collection cover
-     * @property Show\Field|Collection en_detail
-     * @property Show\Field|Collection cn_detail
-     * @property Show\Field|Collection poster
-     * @property Show\Field|Collection cert
-     * @property Show\Field|Collection pdf
-     * @property Show\Field|Collection video
-     * @property Show\Field|Collection folder_type
-     * @property Show\Field|Collection show_tabs
-     * @property Show\Field|Collection enabled
-     *
-     * @method Show\Field|Collection id(string $label = null)
-     * @method Show\Field|Collection name(string $label = null)
-     * @method Show\Field|Collection type(string $label = null)
-     * @method Show\Field|Collection version(string $label = null)
-     * @method Show\Field|Collection detail(string $label = null)
-     * @method Show\Field|Collection created_at(string $label = null)
-     * @method Show\Field|Collection updated_at(string $label = null)
-     * @method Show\Field|Collection is_enabled(string $label = null)
-     * @method Show\Field|Collection parent_id(string $label = null)
-     * @method Show\Field|Collection order(string $label = null)
-     * @method Show\Field|Collection icon(string $label = null)
-     * @method Show\Field|Collection uri(string $label = null)
-     * @method Show\Field|Collection extension(string $label = null)
-     * @method Show\Field|Collection permission_id(string $label = null)
-     * @method Show\Field|Collection menu_id(string $label = null)
-     * @method Show\Field|Collection slug(string $label = null)
-     * @method Show\Field|Collection http_method(string $label = null)
-     * @method Show\Field|Collection http_path(string $label = null)
-     * @method Show\Field|Collection role_id(string $label = null)
-     * @method Show\Field|Collection user_id(string $label = null)
-     * @method Show\Field|Collection value(string $label = null)
-     * @method Show\Field|Collection username(string $label = null)
-     * @method Show\Field|Collection password(string $label = null)
-     * @method Show\Field|Collection avatar(string $label = null)
-     * @method Show\Field|Collection remember_token(string $label = null)
-     * @method Show\Field|Collection language(string $label = null)
-     * @method Show\Field|Collection email(string $label = null)
-     * @method Show\Field|Collection token(string $label = null)
-     * @method Show\Field|Collection tokenable_type(string $label = null)
-     * @method Show\Field|Collection tokenable_id(string $label = null)
-     * @method Show\Field|Collection abilities(string $label = null)
-     * @method Show\Field|Collection last_used_at(string $label = null)
-     * @method Show\Field|Collection expires_at(string $label = null)
-     * @method Show\Field|Collection folder_id(string $label = null)
-     * @method Show\Field|Collection parameters(string $label = null)
-     * @method Show\Field|Collection cover(string $label = null)
-     * @method Show\Field|Collection en_detail(string $label = null)
-     * @method Show\Field|Collection cn_detail(string $label = null)
-     * @method Show\Field|Collection poster(string $label = null)
-     * @method Show\Field|Collection cert(string $label = null)
-     * @method Show\Field|Collection pdf(string $label = null)
-     * @method Show\Field|Collection video(string $label = null)
-     * @method Show\Field|Collection folder_type(string $label = null)
-     * @method Show\Field|Collection show_tabs(string $label = null)
-     * @method Show\Field|Collection enabled(string $label = null)
-     */
-    class Show {}
-
-    /**
-     * @method \App\Exceptions\Form\MultipleCutImage multipleCutImage(...$params)
-     * @method \App\Exceptions\Form\CutImage cutImage(...$params)
-     * @method \Dcat\Admin\Form\Extend\Distpicker\Form\Distpicker distpicker(...$params)
-     * @method \Dcat\Admin\Form\Extend\Diyforms\Form\DiyForm diyForm(...$params)
-     */
-    class Form {}
-
-}
-
-namespace Dcat\Admin\Grid {
-    /**
-     * @method $this distpicker(...$params)
-     */
-    class Column {}
-
-    /**
-     * @method \Dcat\Admin\Form\Extend\Distpicker\Filter\DistpickerFilter distpicker(...$params)
-     */
-    class Filter {}
-}
-
-namespace Dcat\Admin\Show {
-    /**
-     * @method $this diyForm(...$params)
-     */
-    class Field {}
-}

+ 1 - 5
lang/en/admin.php

@@ -43,7 +43,7 @@ return [
         '401' => 'Unauthorized !',
         '419' => 'Page expired !',
     ],
-    'site_name'             => 'Mietubl Album System',
+    'site_name'             => 'Mietubl Online Marketing System',
     'online'                => 'Online',
     'login'                 => 'Login',
     'logout'                => 'Logout',
@@ -258,8 +258,4 @@ return [
     'inquiry_list' => 'Inquiry List',
     'banner_list' => 'Banner List',
     'crop_the_image' => 'Crop the Image',
-
-    #相册模块
-    'folder'=>'Folder',
-    'album' => 'Album',
 ];

+ 0 - 30
lang/en/global.php

@@ -93,22 +93,6 @@ return [
         'target_type'           => 'Type',
         'target_ids'            => 'Target Ids',
         'message_title'         => 'Message Title',
-
-        #相册模块
-        'folder_type'           => 'Folder Type',
-        'show_tabs'             => 'Show Tabs',
-        'model'                 => 'Model',
-        'folder_id'             => 'Folder',
-        'cover'                 => 'Cover',
-        'en_detail'             => 'English Detail',
-        'cn_detail'             => 'Chinese Detail',
-        'video'                 => 'Video',
-        'poster'                => 'Poster',
-        'cert'                  => 'Cert',
-        'pdf'                   => 'PDF',
-        'pdf_title'             => 'PDF Title',
-        'pdf_src'               => 'PDF Src',
-        'video_src'             => 'Video Src',
     ],
     'labels' => [
         'list'                  => 'List',
@@ -205,20 +189,6 @@ return [
         'visual_edit'           => 'Visual Edit',
         'top_menu'              => 'Top Menu',
         'bottom_menu'           => 'Bottom Menu',
-
-        //相册模块
-        'product'               => 'Product',
-        'other'                 => 'Other',
-        'cover'                 => 'Cover',
-        'en_detail'             => 'English Detail',
-        'cn_detail'             => 'Chinese Detail',
-        'video'                 => 'Video',
-        'poster'                => 'Poster',
-        'cert'                  => 'Cert',
-        'pdf'                   => 'PDF',
-        'basic_info'            => 'Basic Info',
-        'image_preview'         => 'Image Preview',
-        'video_cover'           => 'Video Cover',
     ],
     'options' => [
         //

+ 2 - 8
lang/zh_CN/admin.php

@@ -44,7 +44,7 @@ return [
         '401' => '请登录!',
         '419' => '对不起,当前页面已失效,请刷新浏览器。',
     ],
-    'site_name'             => '美特柏相册系统',
+    'site_name'             => '美特柏建站营销系统',
     'home'                  => '主页',
     'online'                => '在线',
     'login'                 => '登录',
@@ -258,11 +258,5 @@ return [
     'banner_list' => '轮播图列表',
     'landing_page' => '独立页',
     'messages' => '消息',
-    'crop_the_image' => '裁剪图片',
-
-
-
-    #相册模块
-    'folder'  => '文件夹',
-    'album'  => '相册',
+    'crop_the_image' => '裁剪图片'
 ];

+ 0 - 30
lang/zh_CN/global.php

@@ -99,23 +99,6 @@ return [
         'video_category' => '视频分类',
         'is_read' => '是否已读',
         'time' => '时间',
-
-        #相册模块
-        'folder_type'           => '文件夹类型',
-        'show_tabs'             => '显示标签',
-        'model'                 => '型号',
-        'folder_id'             => '文件夹',
-        'cover'                 => '主图',
-        'en_detail'             => '英文详情',
-        'cn_detail'             => '中文详情',
-        'video'                 => '视频',
-        'poster'                => '海报',
-        'cert'                  => '证书',
-        'pdf'                   => 'PDF',
-        'pdf_title'             => 'PDF标题',
-        'pdf_src'               => 'PDF文件',
-        'video_src'             => '视频文件',
-
     ],
     'labels' => [
         'list'         => '列表',
@@ -213,19 +196,6 @@ return [
         'visual_edit'           => '可视化编辑',
         'top_menu'              => '顶部菜单',
         'bottom_menu'           => '底部菜单',
-        //相册模块
-        'product'               => '产品',
-        'other'                 => '其他',
-        'cover'                 => '主图',
-        'en_detail'             => '英文详情',
-        'cn_detail'             => '中文详情',
-        'video'                 => '视频',
-        'poster'                => '海报',
-        'cert'                  => '证书',
-        'pdf'                   => 'PDF',
-        'basic_info'            => '基本信息',
-        'image_preview'         => '图片预览',
-        'video_cover'           => '视频封面',
     ],
     'options' => [
         //

+ 0 - 4
lang/zh_CN/menu.php

@@ -53,9 +53,5 @@ return [
         'landing_page' => '独立页',
         'messages' => '消息',
         'banner'  =>'轮播图',
-
-        #相册
-        'folder' => '文件夹',
-        'album' => '相册',
     ],
 ];

+ 230 - 0
lang/zh_TW/admin.php

@@ -0,0 +1,230 @@
+<?php
+
+return [
+    'scaffold' => [
+        'header'            => '代碼生成器',
+        'choose'            => '選擇已有數據表',
+        'table'             => '表名',
+        'model'             => '模型',
+        'controller'        => '控制器',
+        'repository'        => '數據倉庫',
+        'add_field'         => '添加欄位',
+        'pk'                => '主鍵',
+        'soft_delete'       => '軟刪除',
+        'create_migration'  => '創建表遷移文件',
+        'create_model'      => '創建模型',
+        'create_repository' => '創建數據倉庫',
+        'create_controller' => '創建控制器',
+        'run_migrate'       => '執行遷移文件',
+        'create_lang'       => '創建翻譯文件',
+        'field'             => '欄位',
+        'translation'       => '翻譯',
+        'comment'           => '註解',
+        'default'           => '預設值',
+        'field_name'        => '欄位名',
+        'type'              => '類型',
+        'nullable'          => '允許null',
+        'key'               => '索引',
+        'translate_title'   => '翻譯標題',
+        'sync_translation_with_comment' => '同步翻譯與註釋',
+    ],
+    'client' => [
+        'delete_confirm'    => '確認刪除?',
+        'confirm'           => '確認',
+        'cancel'            => '取消',
+        'refresh_succeeded' => '刷新成功!',
+        'close'             => '關閉',
+        'submit'            => '提交',
+        'selected_options'  => '已選中:num個選項',
+        'exceed_max_item'   => '已超出最大可選數量',
+        'no_preview'        => '預覽失敗',
+
+        '500' => '系統繁忙,請稍後再試!',
+        '403' => '對不起,您無訪問權限,請聯繫管理員。',
+        '401' => '請先登入!',
+        '419' => '對不起,當前頁面已失效,請刷新瀏覽器。',
+    ],
+    'site_name'             => '美特柏建站營銷系統',
+    'home'                  => '首頁',
+    'online'                => '在線',
+    'login'                 => '登入',
+    'logout'                => '登出',
+    'setting'               => '設置',
+    'name'                  => '名稱',
+    'username'              => '用戶名',
+    'old_password'          => '舊密碼',
+    'password'              => '密碼',
+    'password_confirmation' => '確認密碼',
+    'old_password_error'    => '舊密碼輸入錯誤',
+    'remember_me'           => '記住我',
+    'user_setting'          => '用戶設置',
+    'avatar'                => '頭像',
+    'list'                  => '列表',
+    'new'                   => '新增',
+    'create'                => '創建',
+    'delete'                => '刪除',
+    'remove'                => '移除',
+    'edit'                  => '編輯',
+    'quick_edit'            => '快速編輯',
+    'continue_editing'      => '繼續編輯',
+    'continue_creating'     => '繼續新增',
+    'view'                  => '查看',
+    'detail'                => '詳細',
+    'browse'                => '瀏覽',
+    'reset'                 => '重置',
+    'export'                => '匯出',
+    'batch_delete'          => '批次刪除',
+    'save'                  => '儲存',
+    'refresh'               => '重新整理',
+    'order'                 => '排序',
+    'expand'                => '展開',
+    'collapse'              => '收起',
+    'filter'                => '篩選',
+    'search'                => '搜索',
+    'close'                 => '關閉',
+    'show'                  => '詳情',
+    'entries'               => '條',
+    'captcha'               => '驗證碼',
+    'action'                => '操作',
+    'title'                 => '標題',
+    'description'           => '簡介',
+    'back'                  => '返回',
+    'back_to_list'          => '返回列表',
+    'submit'                => '送出',
+    'menu'                  => '目錄',
+    'input'                 => '輸入',
+    'succeeded'             => '成功',
+    'failed'                => '失敗',
+    'delete_confirm'        => '確認刪除?',
+    'delete_succeeded'      => '刪除成功!',
+    'delete_failed'         => '刪除失敗!',
+    'update_succeeded'      => '更新成功!',
+    'update_failed'         => '更新失敗 !',
+    'save_succeeded'        => '儲存成功!',
+    'save_failed'           => '儲存失敗 !',
+    'refresh_succeeded'     => '刷新成功!',
+    'login_successful'      => '登入成功!',
+    'choose'                => '選擇',
+    'choose_file'           => '選擇檔案',
+    'choose_image'          => '選擇圖片',
+    'more'                  => '更多',
+    'deny'                  => '權限不足',
+    'administrator'         => '管理員',
+    'roles'                 => '角色',
+    'permissions'           => '權限',
+    'slug'                  => '標誌',
+    'created_at'            => '建立時間',
+    'updated_at'            => '更新時間',
+    'alert'                 => '警告',
+    'parent_id'             => '父級',
+    'icon'                  => '圖示',
+    'uri'                   => '路徑',
+    'operation_log'         => '操作記錄',
+    'parent_select_error'   => '父級選擇錯誤',
+    'default'               => '預設',
+    'table'                 => '表格',
+    'no_data'               => '暫無數據',
+    'routes'                => '路由',
+    'alias'                 => '別名',
+    'route_action'          => '處理器',
+    'middleware'            => '中間件',
+    'import'                => '導入',
+    'is_not_import'         => '未導入',
+    'selected_options'      => '已選中:num個選項',
+    'method'                => '方法',
+    'user'                  => '用戶',
+    'pagination'            => [
+        'range' => '從 :first 到 :last ,總共 :total 條',
+    ],
+    'role'                  => '角色',
+    'permission'            => '權限',
+    'route'                 => '路由',
+    'confirm'               => '確認',
+    'cancel'                => '取消',
+    'selectall'             => '全選',
+    'http'                  => [
+        'method' => 'HTTP方法',
+        'path'   => 'HTTP路徑',
+    ],
+    'all_methods_if_empty'  => '所有方法預設為空',
+    'all'                   => '全部',
+    'current_page'          => '現在頁面',
+    'selected_rows'         => '選擇的行',
+    'upload'                => '上傳',
+    'new_folder'            => '新建資料夾',
+    'time'                  => '時間',
+    'size'                  => '大小',
+    'between_start'         => '起始',
+    'between_end'           => '結束',
+    'next_page'             => '下一頁',
+    'prev_page'             => '上一頁',
+    'next_step'             => '下一步',
+    'prev_step'             => '上一步',
+    'done'                  => '完成',
+    'listbox'               => [
+        'text_total'         => '總共 {0} 項',
+        'text_empty'         => '空列表',
+        'filtered'           => '{0} / {1}',
+        'filter_clear'       => '顯示全部',
+        'filter_placeholder' => '過濾',
+    ],
+    'responsive'      => [
+        'display_all' => '顯示全部',
+        'display'     => '欄位',
+        'focus'       => '聚焦',
+    ],
+    'uploader' => [
+        'add_new_media'          => '添加檔案',
+        'drag_file'              => '或將檔案拖移到這裡',
+        'max_file_limit'         => ':attribute不能超過:max.',
+        'exceed_size'            => '檔案大小過大',
+        'interrupt'              => '暫停上傳',
+        'upload_failed'          => '上傳失敗,請再試一次',
+        'selected_files'         => '選中:num個檔案,共:size。',
+        'selected_has_failed'    => '已成功上傳:success個檔案,:fail個檔案上傳失敗,<a class="retry"  href="javascript:"";">重新上傳</a>失敗檔案或<a class="ignore" href="javascript:"";">忽略</a>',
+        'selected_success'       => '共:num个(:size),已上傳:success個。',
+        'dot'                    => ',',
+        'failed_num'             => '失敗:fail個。',
+        'pause_upload'           => '暫停上傳',
+        'go_on_upload'           => '繼續上傳',
+        'start_upload'           => '開始上傳',
+        'upload_success_message' => '已成功上傳:success個檔案',
+        'go_on_add'              => '繼續添加',
+        'Q_TYPE_DENIED'          => '對不起,無法上傳該類型檔案',
+        'Q_EXCEED_NUM_LIMIT'     => '对不起,超出上傳數量限制,最多只能上傳:num個檔案',
+        'F_EXCEED_SIZE'          => '对不起,當前選擇的檔案過大',
+        'Q_EXCEED_SIZE_LIMIT'    => '对不起,檔案大小超出限制',
+        'F_DUPLICATE'            => '檔案重複',
+        'confirm_delete_file'    => '您確定要刪除該檔案嗎?',
+        'dimensions'             => '圖片規格不正確',
+    ],
+    'import_extension_confirm'  => '確認導入擴展?',
+    'quick_create'              => '快速新增',
+    'grid_items_selected'       => '已選擇 {n} 項',
+    'nothing_updated'           => '沒有任何資料被更改',
+    'welcome_back'              => '歡迎回來,請登入帳號',
+    'documentation'             => '文檔',
+    'demo'                      => '範例',
+    'extensions'                => '擴展',
+    'version'                   => '版本',
+    'current_version'           => '当前版本',
+    'latest_version'            => '當前版本',
+    'upgrade_to_version'        => '更新至版本 :version',
+    'enable'                    => '啟用',
+    'disable'                   => '禁用',
+    'uninstall'                 => '卸載',
+    'confirm_uninstall'         => '您確定要卸載當前擴展嗎?此操作將會移除擴展數據!',
+    'marketplace'               => '應用市場',
+    'theme'                     => '主題',
+    'application'               => '應用',
+    'install_from_local'        => '本地安装',
+    'install_succeeded'         => '本地安裝',
+    'invalid_extension_package' => '安裝包異常',
+    'copied'                    => '已複製',
+    'auth_failed'               => '帳號或密碼錯誤',
+    'validation'               => [
+        'match'     => '與 :attribute 不匹配。',
+        'minlength' => ':attribute 長度不能少於 :min。',
+        'maxlength' => ':attribute 長度不能超過 :max。',
+    ],
+];

+ 19 - 0
lang/zh_TW/auth.php

@@ -0,0 +1,19 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | 認證語言行
+    |--------------------------------------------------------------------------
+    |
+    | 以下語言行在認證期間使用,用於顯示給使用者的各種消息。
+    | 您可以根據應用程式的需求自由修改這些語言行。
+    |
+    */
+
+    'failed' => '這些憑據與我們的記錄不匹配。',
+    'password' => '提供的密碼不正確。',
+    'throttle' => '嘗試登入次數過多。請在 :seconds 秒後再試。',
+
+];

+ 22 - 0
lang/zh_TW/extension.php

@@ -0,0 +1,22 @@
+<?php
+
+return [
+    'labels' => [
+        'Extensions' => '擴展',
+    ],
+    'fields' => [
+        'alias'       => '別名',
+        'description' => '說明',
+        'authors'     => '作者',
+        'homepage'    => '首頁',
+        'require'     => '依賴',
+        'require_dev' => '開發環境依賴',
+        'name'        => '名稱',
+        'version'     => '版本',
+        'enable'      => '啟用',
+        'config'      => '設定',
+        'imported'    => '導入',
+    ],
+    'options' => [
+    ],
+];

+ 79 - 0
lang/zh_TW/global.php

@@ -0,0 +1,79 @@
+<?php
+
+return [
+    'fields' => [
+        'id'                    => 'ID',
+        'name'                  => '名稱',
+        'username'              => '用戶名',
+        'email'                 => '電郵',
+        'http_path'             => 'HTTP路徑',
+        'password'              => '密碼',
+        'password_confirmation' => '確認密碼',
+        'created_at'            => '創建時間',
+        'updated_at'            => '更新時間',
+        'permissions'           => '權限',
+        'slug'                  => '標識',
+        'user'                  => '用戶',
+        'order'                 => '排序',
+        'ip'                    => 'IP',
+        'method'                => '方法',
+        'uri'                   => 'URI',
+        'roles'                 => '角色',
+        'path'                  => '路徑',
+        'input'                 => '輸入',
+        'type'                  => '類型',
+        'productslist'          => '產品列表',
+        'title'                 => '產品標題',
+        'keywords'              => '關鍵字',
+        'description'           => '描述',
+        'sku'                   => '商品sku',
+        'category_id'           => '分類ID',
+        'issuance_date'         => '發布日期',
+        'enabled'               => '啟用',
+        'content'               => '內容',
+        'parameters'            => '產品參數',
+        'is_pinned'             => '置顶',
+        'parent_id'             => '上級ID',
+        'remark'                => '備註',
+        'parameter_id'          => '參數',
+        'products_list'         => '產品列表',
+        'images'                => '圖片',
+        'parent'                => '上級',
+        'key'                   => '參數名',
+        'value'                 => '參數值',
+        'cover_image'           => '封面圖片',
+        'category_name'         => '分類名稱',
+        'parameter_name'        => '參數名稱',
+        'video_url'             => '視頻URL地址',
+        'contact_number'        => '聯繫電話',
+        'service_hotline'       => '服務熱線',
+    ],
+    'labels' => [
+        'list'     => '列表',
+        'edit'     => '編輯',
+        'detail'   => '詳細',
+        'create'   => '創建',
+        'root'     => '頂級',
+        'scaffold' => '代碼生成器',
+        'category_name'         => '分類名稱',
+        'parameter_name'        => '參數名稱',
+        'order_tips'            => '請輸入數字,數字越大前台展示排名越靠前',
+        'category'              => '分類',
+        'enabled'               => '是否啟用',
+        "Yes" => "是",
+        "No" => "否",
+        'cover_image'           => '封面圖片',
+        'video_url'             => '視頻URL地址',
+        'select_products_to_import' => '選擇產品後點擊導入按鈕.',
+        'company_name'          => '公司名稱',
+        'site_name'             => '站點名稱',
+        'level_domain'          => '域名',
+        'country'               => '國家',
+        'contact_number'        => '聯繫電話',
+        'service_hotline'       => '服務熱線',
+        'appearance'            => '外觀'
+    ],
+    'options' => [
+        //
+    ],
+];

+ 17 - 0
lang/zh_TW/menu.php

@@ -0,0 +1,17 @@
+<?php
+
+return [
+    'titles' => [
+        'index'         => '首頁',
+        'admin'         => '系統',
+        'users'         => '管理員',
+        'roles'         => '角色',
+        'permission'    => '權限',
+        'menu'          => '菜單',
+        'operation_log' => '操作日誌',
+        'helpers'       => '開發工具',
+        'extensions'    => '擴展',
+        'scaffold'      => '代碼生成器',
+        'icons'         => '圖示',
+    ],
+];

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.