Browse Source

自定义菜单更改

bianjunhui 22 hours ago
parent
commit
9fc06d3b83

+ 29 - 0
packages/Longyi/DynamicMenu/src/Database/Migrations/add_route_parameters_to_menu_items.php

@@ -0,0 +1,29 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('dynamic_menu_items', function (Blueprint $table) {
+            $table->text('route_parameters')->nullable()->after('route')
+                ->comment('路由参数,JSON格式存储,如:["emails","configure"]');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('dynamic_menu_items', function (Blueprint $table) {
+            $table->dropColumn('route_parameters');
+        });
+    }
+};

+ 38 - 0
packages/Longyi/DynamicMenu/src/Providers/DynamicMenuServiceProvider.php

@@ -51,6 +51,7 @@ class DynamicMenuServiceProvider extends ServiceProvider
             $existingConfig = $this->app['config']->get('menu.admin', []);
             // 合并配置
             $mergedConfig = array_merge($existingConfig, $menuConfig);
+
             // 设置配置
             $this->app['config']->set('menu.admin', $mergedConfig);
 
@@ -102,10 +103,13 @@ class DynamicMenuServiceProvider extends ServiceProvider
         $config = [];
 
         foreach ($menuItems as $item) {
+            $routeParameters = $this->parseRouteParameters($item->route_parameters);
+
             $menuItem = [
                 'key'   => $item->key,
                 'name'  => $item->name,
                 'route' => $item->route ?: 'admin.dynamicmenu.index',
+                'route_parameters' => $routeParameters,
                 'sort'  => (int) $item->sort_order,
                 'icon'  => $item->icon ?: 'icon-menu',
             ];
@@ -114,4 +118,38 @@ class DynamicMenuServiceProvider extends ServiceProvider
 
         return $config;
     }
+
+    /**
+     * 解析路由参数
+     */
+    protected function parseRouteParameters($parameters): array
+    {
+        if (empty($parameters)) {
+            return [];
+        }
+
+        // 如果已经是数组,直接返回
+        if (is_array($parameters)) {
+            return array_values(array_filter($parameters));
+        }
+
+        // 如果是 JSON 字符串,解码
+        if (is_string($parameters)) {
+            // 尝试 JSON 解码
+            $decoded = json_decode($parameters, true);
+            if (is_array($decoded)) {
+                return array_values(array_filter($decoded));
+            }
+
+            // 如果不是有效的 JSON,尝试按逗号分割
+            if (strpos($parameters, ',') !== false) {
+                return array_values(array_filter(array_map('trim', explode(',', $parameters))));
+            }
+
+            // 单个字符串参数
+            return [$parameters];
+        }
+
+        return [];
+    }
 }

+ 88 - 8
packages/Webkul/Core/src/Menu.php

@@ -91,8 +91,39 @@ class Menu
         $menuWithDotNotation = [];
 
         foreach ($this->configMenu as $item) {
-            if (strpos(request()->url(), route($item['route'])) !== false) {
-                $this->currentKey = $item['key'];
+            // 验证菜单项必须有必要的字段
+            if (!isset($item['key']) || !isset($item['name']) || !isset($item['route'])) {
+                continue;
+            }
+
+            // 安全获取路由参数
+            $routeParameters = $item['route_parameters'] ?? [];
+
+            // 检查是否有路由参数
+            if (!empty($routeParameters)) {
+                try {
+                    $url = route($item['route'], $routeParameters);
+                    if (strpos(request()->url(), $url) !== false) {
+                        $this->currentKey = $item['key'];
+                    }
+                } catch (\Exception $e) {
+                    // 如果路由生成失败,回退到原来的逻辑
+                    try {
+                        if (strpos(request()->url(), route($item['route'])) !== false) {
+                            $this->currentKey = $item['key'];
+                        }
+                    } catch (\Exception $e2) {
+                        // 忽略错误
+                    }
+                }
+            } else {
+                try {
+                    if (strpos(request()->url(), route($item['route'])) !== false) {
+                        $this->currentKey = $item['key'];
+                    }
+                } catch (\Exception $e) {
+                    // 忽略错误
+                }
             }
 
             $menuWithDotNotation[$item['key']] = $item;
@@ -101,19 +132,29 @@ class Menu
         $menu = Arr::undot(Arr::dot($menuWithDotNotation));
 
         foreach ($menu as $menuItemKey => $menuItem) {
+            // 验证顶级菜单项
+            if (!is_array($menuItem) || !isset($menuItem['key'])) {
+                continue;
+            }
+
             $subMenuItems = $this->processSubMenuItems($menuItem);
 
+            // 安全解析路由参数
+            $routeParameters = $this->parseRouteParameters($menuItem['route_parameters'] ?? []);
+
             $this->addItem(new MenuItem(
                 key: $menuItemKey,
                 name: trans($menuItem['name']),
                 route: $menuItem['route'],
-                sort: $menuItem['sort'],
-                icon: $menuItem['icon'],
+                sort: $menuItem['sort'] ?? 0,
+                icon: $menuItem['icon'] ?? '',
                 children: $subMenuItems,
+                routeParameters: $routeParameters,
             ));
         }
     }
 
+
     /**
      * Process sub menu items.
      */
@@ -121,21 +162,60 @@ class Menu
     {
         return collect($menuItem)
             ->sortBy('sort')
-            ->filter(fn ($value) => is_array($value))
+            ->filter(fn ($value, $key) => is_array($value) && isset($value['key']))
             ->map(function ($subMenuItem) {
+                // 确保子菜单项有必要的字段
+                if (!isset($subMenuItem['key']) || !isset($subMenuItem['name']) || !isset($subMenuItem['route'])) {
+                    return null;
+                }
+
                 $subSubMenuItems = $this->processSubMenuItems($subMenuItem);
 
+                // 安全解析子菜单的路由参数
+                $routeParameters = $this->parseRouteParameters($subMenuItem['route_parameters'] ?? []);
+
                 return new MenuItem(
                     key: $subMenuItem['key'],
                     name: trans($subMenuItem['name']),
                     route: $subMenuItem['route'],
-                    sort: $subMenuItem['sort'],
-                    icon: $subMenuItem['icon'],
+                    sort: $subMenuItem['sort'] ?? 0,
+                    icon: $subMenuItem['icon'] ?? '',
                     children: $subSubMenuItems,
+                    routeParameters: $routeParameters,
                 );
-            });
+            })
+            ->filter(); // 过滤掉 null 值
     }
 
+
+    /**
+     * Parse route parameters from various formats.
+     *
+     * @param mixed $parameters
+     * @return array
+     */
+    private function parseRouteParameters($parameters): array
+    {
+        if (empty($parameters)) {
+            return [];
+        }
+
+        // 如果已经是数组,直接返回
+        if (is_array($parameters)) {
+            // 过滤空值
+            return array_values(array_filter($parameters));
+        }
+
+        // 如果是 JSON 字符串,解码
+        if (is_string($parameters)) {
+            $decoded = json_decode($parameters, true);
+            if (is_array($decoded)) {
+                return array_values(array_filter($decoded));
+            }
+        }
+
+        return [];
+    }
     /**
      * Get current active menu.
      */

+ 14 - 1
packages/Webkul/Core/src/Menu/MenuItem.php

@@ -18,6 +18,7 @@ class MenuItem
         public int $sort,
         public string $icon,
         public Collection $children,
+        public array $routeParameters = [],
     ) {}
 
     /**
@@ -44,12 +45,24 @@ class MenuItem
         return $this->route;
     }
 
+    /**
+     * Get route parameters.
+     */
+    public function getRouteParameters(): array
+    {
+        return $this->routeParameters;
+    }
+
     /**
      * Get the url of the menu item.
      */
     public function getUrl(): string
     {
-        return route($this->getRoute());
+        if (empty($this->routeParameters)) {
+            return route($this->getRoute());
+        }
+
+        return route($this->getRoute(), $this->routeParameters);
     }
 
     /**