Эх сурвалжийг харах

菜单增加extension以及show字段;
扩展功能增加导入菜单功能

jqh 5 жил өмнө
parent
commit
64c65bef96

+ 44 - 0
database/migrations/2020_11_01_083237_update_admin_menu_table.php

@@ -0,0 +1,44 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class UpdateAdminMenuTable extends Migration
+{
+    public function getConnection()
+    {
+        return config('database.connection') ?: config('database.default');
+    }
+
+    public function config($key)
+    {
+        return config('admin.'.$key);
+    }
+
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table($this->config('database.menu_table'), function (Blueprint $table) {
+            $table->tinyInteger('show')->default(1)->after('uri');
+            $table->string('extension', 50)->default('')->after('uri');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table($this->config('database.menu_table'), function (Blueprint $table) {
+            $table->dropColumn('show');
+            $table->dropColumn('extension');
+        });
+    }
+}

+ 1 - 5
resources/views/partials/menu.blade.php

@@ -5,11 +5,7 @@
 @endphp
 
 @if($builder->visible($item))
-    @if(isset($item['is_header']))
-        <li class="nav-header">
-            {{ $builder->translate($item['title']) }}
-        </li>
-    @elseif(empty($item['children']))
+    @if(empty($item['children']))
         <li class="nav-item">
             <a @if(mb_strpos($item['uri'], '://') !== false) target="_blank" @endif href="{{ $builder->getUrl($item['uri']) }}" class="nav-link {!! $builder->isActive($item) ? 'active' : '' !!}">
                 {!! str_repeat('&nbsp;', $depth) !!}<i class="fa {{ $item['icon'] ?: 'feather icon-circle' }}"></i>

+ 117 - 0
src/Extend/CanImportMenu.php

@@ -0,0 +1,117 @@
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Illuminate\Support\Arr;
+use Illuminate\Support\Facades\Validator;
+
+/**
+ * @property \Symfony\Component\Console\Output\OutputInterface $output
+ */
+trait CanImportMenu
+{
+    protected $menuValidationRules = [
+        'parent' => 'nullable',
+        'title'  => 'required',
+        'uri'    => 'nullable',
+        'icon'   => 'nullable',
+    ];
+
+    /**
+     * 添加菜单
+     *
+     * @param array $menu
+     *
+     * @throws \Exception
+     */
+    protected function addMenu(array $menu)
+    {
+        if (! Arr::isAssoc($menu)) {
+            foreach ($menu as $v) {
+                $this->addMenu($v);
+            }
+
+            return;
+        }
+
+        if (! $this->validateMenu($menu)) {
+            return;
+        }
+
+        if ($menuModel = $this->getMenuModel()) {
+            $lastOrder = $menuModel::max('order');
+
+            $menuModel::create([
+                'parent_id' => $this->getParentMenuId($menu['parent'] ?? 0),
+                'order'     => $lastOrder + 1,
+                'title'     => $menu['title'],
+                'icon'      => (string) ($icon ?? ''),
+                'uri'       => (string) ($menu['uri'] ?? ''),
+                'extension' => $this->getExtensionName(),
+            ]);
+        }
+    }
+
+    /**
+     * 根据名称获取菜单ID.
+     *
+     * @param int|string $parent
+     *
+     * @return int
+     */
+    protected function getParentMenuId($parent)
+    {
+        if (is_numeric($parent)) {
+            return $parent;
+        }
+
+        $menuModel = $this->getMenuModel();
+
+        return $menuModel::query()
+            ->where('title', $parent)
+            ->where('extension', $this->getExtensionName())
+            ->value('id') ?: 0;
+    }
+
+    /**
+     * 删除菜单.
+     */
+    protected function deleteMenu()
+    {
+        $menuModel = $this->getMenuModel();
+
+        if (! $menuModel) {
+            return;
+        }
+
+        $menuModel::query()
+            ->where('extension', $this->getExtensionName())
+            ->delete();
+    }
+
+    /**
+     * 验证菜单字段格式是否正确.
+     *
+     * @param array $menu
+     *
+     * @throws \Exception
+     *
+     * @return bool
+     */
+    public function validateMenu(array $menu)
+    {
+        /** @var \Illuminate\Validation\Validator $validator */
+        $validator = Validator::make($menu, $this->menuValidationRules);
+
+        if ($validator->passes()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    protected function getMenuModel()
+    {
+        return config('admin.database.menu_model');
+    }
+}

+ 28 - 0
src/Extend/HasExtension.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Dcat\Admin\Extend;
+
+trait HasExtension
+{
+    /**
+     * @var ServiceProvider
+     */
+    protected $extension;
+
+    public function setExtension(ServiceProvider $serviceProvider)
+    {
+        $this->extension = $serviceProvider;
+
+        return $this;
+    }
+
+    public function getExtension()
+    {
+        return $this->extension;
+    }
+
+    public function getExtensionName()
+    {
+        return $this->getExtension()->getName();
+    }
+}

+ 32 - 1
src/Extend/ServiceProvider.php

@@ -293,6 +293,13 @@ abstract class ServiceProvider extends LaravelServiceProvider
         $this->config = $this->config ? $this->unserializeConfig($this->config) : [];
     }
 
+    /**
+     * 更新扩展.
+     */
+    public function update()
+    {
+    }
+
     /**
      * 卸载扩展.
      */
@@ -442,13 +449,37 @@ abstract class ServiceProvider extends LaravelServiceProvider
      */
     public static function setting($key = null, $value = null)
     {
-        $extension = app(static::class);
+        $extension = static::instance();
 
         if ($extension && $extension instanceof ServiceProvider) {
             return $extension->config($key, $value);
         }
     }
 
+    /**
+     * 翻译.
+     *
+     * @param string $key
+     * @param array  $replace
+     * @param null   $locale
+     *
+     * @return array|string|null
+     */
+    public static function trans($key, $replace = [], $locale = null)
+    {
+        return trans(static::instance()->getName().'::'.$key, $replace, $locale);
+    }
+
+    /**
+     * 获取自身实例.
+     *
+     * @return $this
+     */
+    public static function instance()
+    {
+        return app(static::class);
+    }
+
     /**
      * 注册别名.
      */

+ 14 - 0
src/Extend/Setting.php

@@ -74,6 +74,20 @@ abstract class Setting extends Form implements LazyRenderable
     {
     }
 
+    /**
+     * 翻译.
+     *
+     * @param string $key
+     * @param array  $replace
+     * @param null   $locale
+     *
+     * @return array|string|null
+     */
+    protected function trans($key, $replace = [], $locale = null)
+    {
+        return $this->extension()->trans($key, $replace, $locale);
+    }
+
     /**
      * 填充表单数据.
      *

+ 6 - 0
src/Extend/UpdateManager.php

@@ -51,6 +51,10 @@ class UpdateManager
             return $this;
         }
 
+        if ($stopOnVersion === null) {
+            $extension->uninstall();
+        }
+
         if ($stopOnVersion && ! $this->versionManager->hasDatabaseVersion($extension, $stopOnVersion)) {
             throw new AdminException('Extension version not found');
         }
@@ -80,6 +84,8 @@ class UpdateManager
             return;
         }
 
+        $extension->update();
+
         $this->note($name);
 
         $this->versionUpdate($extension, $stopOnVersion);

+ 13 - 2
src/Extend/VersionManager.php

@@ -309,7 +309,7 @@ class VersionManager
             return;
         }
 
-        $this->updater->setUp($updateFile, function () use ($name, $version, $script) {
+        $this->updater->setUp($this->resolveUpdater($name, $updateFile), function () use ($name, $version, $script) {
             ExtensionHistory::query()->create([
                 'name'    => $name,
                 'type'    => static::HISTORY_TYPE_SCRIPT,
@@ -319,11 +319,22 @@ class VersionManager
         });
     }
 
+    protected function resolveUpdater($name, $updateFile)
+    {
+        $updater = $this->updater->resolve($updateFile);
+
+        if (method_exists($updater, 'setExtension')) {
+            $updater->setExtension($this->manager->get($name));
+        }
+
+        return $updater;
+    }
+
     protected function removeDatabaseScript($name, $version, $script)
     {
         $updateFile = $this->manager->path($name, 'updates/'.$script);
 
-        $this->updater->packDown($updateFile, function () use ($name, $version, $script) {
+        $this->updater->packDown($this->resolveUpdater($name, $updateFile), function () use ($name, $version, $script) {
             ExtensionHistory::query()
                 ->where('name', $name)
                 ->where('type', static::HISTORY_TYPE_SCRIPT)

+ 30 - 0
src/Http/Actions/Menu/Visiable.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Dcat\Admin\Http\Actions\Menu;
+
+use Dcat\Admin\Tree\RowAction;
+
+class Visiable extends RowAction
+{
+    public function handle()
+    {
+        $key = $this->getKey();
+
+        $menuModel = config('admin.database.menu_model');
+        $menu = $menuModel::find($key);
+
+        $menu->update(['show' => $menu->show ? 0 : 1]);
+
+        return $this
+            ->response()
+            ->success(trans('admin.update_succeeded'))
+            ->location('auth/menu');
+    }
+
+    public function title()
+    {
+        $icon = $this->getRow()->show ? 'icon-eye-off' : 'icon-eye';
+
+        return "&nbsp;<i class='feather $icon'></i>&nbsp;";
+    }
+}

+ 10 - 0
src/Http/Controllers/MenuController.php

@@ -3,6 +3,7 @@
 namespace Dcat\Admin\Http\Controllers;
 
 use Dcat\Admin\Form;
+use Dcat\Admin\Http\Actions\Menu\Visiable;
 use Dcat\Admin\Http\Repositories\Menu;
 use Dcat\Admin\Layout\Column;
 use Dcat\Admin\Layout\Content;
@@ -68,6 +69,14 @@ class MenuController extends AdminController
             $tree->disableQuickCreateButton();
             $tree->disableEditButton();
 
+            $tree->actions(function (Tree\Actions $actions) {
+                if ($actions->getRow()->extension) {
+                    $actions->disableDelete();
+                }
+
+                $actions->prepend(new Visiable());
+            });
+
             $tree->branch(function ($branch) {
                 $payload = "<i class='fa {$branch['icon']}'></i>&nbsp;<strong>{$branch['title']}</strong>";
 
@@ -112,6 +121,7 @@ class MenuController extends AdminController
             $form->text('title', trans('admin.title'))->required();
             $form->icon('icon', trans('admin.icon'))->help($this->iconHelp());
             $form->text('uri', trans('admin.uri'));
+            $form->switch('show', trans('admin.show'));
 
             if ($menuModel::withRole()) {
                 $form->multipleSelect('roles', trans('admin.roles'))

+ 47 - 0
src/Layout/Menu.php

@@ -160,6 +160,53 @@ class Menu
      * @return bool
      */
     public function visible($item)
+    {
+        if (! $this->checkPermission($item)) {
+            return false;
+        }
+
+        if (! $this->checkExtension($item)) {
+            return false;
+        }
+
+        $show = $item['show'] ?? null;
+        if ($show !== null && ! $show) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * 判断扩展是否启用.
+     *
+     * @param $item
+     *
+     * @return bool
+     */
+    protected function checkExtension($item)
+    {
+        $extension = $item['extension'] ?? null;
+
+        if (! $extension) {
+            return true;
+        }
+
+        if (! $extension = Admin::extension($extension)) {
+            return false;
+        }
+
+        return $extension->enabled();
+    }
+
+    /**
+     * 判断权限.
+     *
+     * @param $item
+     *
+     * @return bool
+     */
+    protected function checkPermission($item)
     {
         $permissionIds = $item['permission_id'] ?? null;
         $roles = array_column(Helper::array($item['roles'] ?? []), 'slug');

+ 1 - 1
src/Models/Menu.php

@@ -36,7 +36,7 @@ class Menu extends Model implements Sortable
      *
      * @var array
      */
-    protected $fillable = ['parent_id', 'order', 'title', 'icon', 'uri', 'permission_id'];
+    protected $fillable = ['parent_id', 'order', 'title', 'icon', 'uri', 'extension', 'show'];
 
     /**
      * Create a new Eloquent model instance.

+ 4 - 0
src/Support/DatabaseUpdater.php

@@ -82,6 +82,10 @@ class DatabaseUpdater
      */
     public function resolve($file)
     {
+        if (is_object($file)) {
+            return $file;
+        }
+
         if (! is_file($file)) {
             return;
         }