|
@@ -8,18 +8,19 @@ use Longyi\DynamicMenu\Models\MenuItem;
|
|
|
use Webkul\User\Repositories\RoleRepository;
|
|
use Webkul\User\Repositories\RoleRepository;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\View;
|
|
use Illuminate\Support\Facades\View;
|
|
|
|
|
+use Illuminate\Support\Facades\Route as RouteFacade;
|
|
|
|
|
|
|
|
class MenuController extends Controller
|
|
class MenuController extends Controller
|
|
|
{
|
|
{
|
|
|
protected $roleRepository;
|
|
protected $roleRepository;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function __construct(RoleRepository $roleRepository)
|
|
public function __construct(RoleRepository $roleRepository)
|
|
|
{
|
|
{
|
|
|
$this->roleRepository = $roleRepository;
|
|
$this->roleRepository = $roleRepository;
|
|
|
$this->_config = request('_config');
|
|
$this->_config = request('_config');
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
public function index()
|
|
public function index()
|
|
|
{
|
|
{
|
|
|
try {
|
|
try {
|
|
@@ -28,34 +29,34 @@ class MenuController extends Controller
|
|
|
->orderBy('parent_id', 'ASC')
|
|
->orderBy('parent_id', 'ASC')
|
|
|
->orderBy('sort_order', 'ASC')
|
|
->orderBy('sort_order', 'ASC')
|
|
|
->get();
|
|
->get();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 获取顶级菜单项
|
|
// 获取顶级菜单项
|
|
|
- $menuItems = $allItems->filter(function($item) {
|
|
|
|
|
|
|
+ $menuItems = $allItems->filter(function($item) {
|
|
|
return is_null($item->parent_id) || $item->parent_id == 0;
|
|
return is_null($item->parent_id) || $item->parent_id == 0;
|
|
|
})->values();
|
|
})->values();
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
return view('dynamicmenu::admin.menu.index', compact('menuItems', 'allItems'));
|
|
return view('dynamicmenu::admin.menu.index', compact('menuItems', 'allItems'));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
} catch (\Exception $e) {
|
|
} catch (\Exception $e) {
|
|
|
\Log::error('MenuController 错误:' . $e->getMessage());
|
|
\Log::error('MenuController 错误:' . $e->getMessage());
|
|
|
\Log::error($e->getTraceAsString());
|
|
\Log::error($e->getTraceAsString());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
session()->flash('error', '加载菜单列表失败:' . $e->getMessage());
|
|
session()->flash('error', '加载菜单列表失败:' . $e->getMessage());
|
|
|
return redirect()->route('admin.dashboard.index');
|
|
return redirect()->route('admin.dashboard.index');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
public function create()
|
|
public function create()
|
|
|
{
|
|
{
|
|
|
$menuItems = MenuItem::orderBy('parent_id')->orderBy('sort_order')->get();
|
|
$menuItems = MenuItem::orderBy('parent_id')->orderBy('sort_order')->get();
|
|
|
return view($this->_config['view'], compact('menuItems'));
|
|
return view($this->_config['view'], compact('menuItems'));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function store(Request $request)
|
|
public function store(Request $request)
|
|
|
{
|
|
{
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$request->validate([
|
|
$request->validate([
|
|
|
'name' => 'required|string|max:255',
|
|
'name' => 'required|string|max:255',
|
|
|
'key' => 'required|string|unique:dynamic_menu_items,key',
|
|
'key' => 'required|string|unique:dynamic_menu_items,key',
|
|
@@ -65,32 +66,32 @@ class MenuController extends Controller
|
|
|
'sort_order' => 'integer',
|
|
'sort_order' => 'integer',
|
|
|
'status' => 'boolean'
|
|
'status' => 'boolean'
|
|
|
]);
|
|
]);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$data = $request->all();
|
|
$data = $request->all();
|
|
|
$data['parent_id'] = $data['parent_id'] === '' ? null : $data['parent_id'];
|
|
$data['parent_id'] = $data['parent_id'] === '' ? null : $data['parent_id'];
|
|
|
$data['created_by'] = auth()->guard('admin')->user()->id;
|
|
$data['created_by'] = auth()->guard('admin')->user()->id;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MenuItem::create($data);
|
|
MenuItem::create($data);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
session()->flash('success', '菜单项创建成功');
|
|
session()->flash('success', '菜单项创建成功');
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return redirect()->route($this->_config['redirect']);
|
|
return redirect()->route($this->_config['redirect']);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function edit($id)
|
|
public function edit($id)
|
|
|
{
|
|
{
|
|
|
try {
|
|
try {
|
|
|
$menuItem = MenuItem::with('parent')->findOrFail($id);
|
|
$menuItem = MenuItem::with('parent')->findOrFail($id);
|
|
|
$menuItems = MenuItem::orderBy('parent_id')->orderBy('sort_order')->get();
|
|
$menuItems = MenuItem::orderBy('parent_id')->orderBy('sort_order')->get();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return view($this->_config['view'], compact('menuItem', 'menuItems'));
|
|
return view($this->_config['view'], compact('menuItem', 'menuItems'));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
|
session()->flash('error', '菜单项不存在');
|
|
session()->flash('error', '菜单项不存在');
|
|
|
return redirect()->route('admin.dynamicmenu.index');
|
|
return redirect()->route('admin.dynamicmenu.index');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function update(Request $request, $id)
|
|
public function update(Request $request, $id)
|
|
|
{
|
|
{
|
|
|
try {
|
|
try {
|
|
@@ -103,14 +104,14 @@ class MenuController extends Controller
|
|
|
'sort_order' => 'integer',
|
|
'sort_order' => 'integer',
|
|
|
'status' => 'boolean'
|
|
'status' => 'boolean'
|
|
|
]);
|
|
]);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$menuItem = MenuItem::findOrFail($id);
|
|
$menuItem = MenuItem::findOrFail($id);
|
|
|
$menuItem->update($request->all());
|
|
$menuItem->update($request->all());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
session()->flash('success', '菜单项更新成功');
|
|
session()->flash('success', '菜单项更新成功');
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return redirect()->route($this->_config['redirect']);
|
|
return redirect()->route($this->_config['redirect']);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
|
session()->flash('error', '菜单项不存在');
|
|
session()->flash('error', '菜单项不存在');
|
|
|
return redirect()->back();
|
|
return redirect()->back();
|
|
@@ -120,24 +121,24 @@ class MenuController extends Controller
|
|
|
return redirect()->back()->withInput();
|
|
return redirect()->back()->withInput();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- public function destroy($id)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ public function destroy($id)
|
|
|
{
|
|
{
|
|
|
try {
|
|
try {
|
|
|
$menuItem = MenuItem::with('children')->findOrFail($id);
|
|
$menuItem = MenuItem::with('children')->findOrFail($id);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 检查是否有子菜单
|
|
// 检查是否有子菜单
|
|
|
if ($menuItem->children && $menuItem->children->count() > 0) {
|
|
if ($menuItem->children && $menuItem->children->count() > 0) {
|
|
|
session()->flash('error', '请先删除子菜单项');
|
|
session()->flash('error', '请先删除子菜单项');
|
|
|
return redirect()->back();
|
|
return redirect()->back();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$menuItem->delete();
|
|
$menuItem->delete();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
session()->flash('success', '菜单项删除成功');
|
|
session()->flash('success', '菜单项删除成功');
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return redirect()->route($this->_config['redirect']);
|
|
return redirect()->route($this->_config['redirect']);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
|
session()->flash('error', '菜单项不存在');
|
|
session()->flash('error', '菜单项不存在');
|
|
|
return redirect()->back();
|
|
return redirect()->back();
|
|
@@ -147,43 +148,147 @@ class MenuController extends Controller
|
|
|
return redirect()->back();
|
|
return redirect()->back();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function permission()
|
|
public function permission()
|
|
|
{
|
|
{
|
|
|
$roles = $this->roleRepository->all();
|
|
$roles = $this->roleRepository->all();
|
|
|
$menuItems = MenuItem::with('children')->orderBy('parent_id')->orderBy('sort_order')->get();
|
|
$menuItems = MenuItem::with('children')->orderBy('parent_id')->orderBy('sort_order')->get();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return view($this->_config['view'], compact('roles', 'menuItems'));
|
|
return view($this->_config['view'], compact('roles', 'menuItems'));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function updatePermission(Request $request)
|
|
public function updatePermission(Request $request)
|
|
|
{
|
|
{
|
|
|
$roleId = $request->input('role_id');
|
|
$roleId = $request->input('role_id');
|
|
|
$menuItemIds = $request->input('menu_items', []);
|
|
$menuItemIds = $request->input('menu_items', []);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
DB::table('menu_item_role')->where('role_id', $roleId)->delete();
|
|
DB::table('menu_item_role')->where('role_id', $roleId)->delete();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
foreach ($menuItemIds as $menuItemId) {
|
|
foreach ($menuItemIds as $menuItemId) {
|
|
|
DB::table('menu_item_role')->insert([
|
|
DB::table('menu_item_role')->insert([
|
|
|
'menu_item_id' => $menuItemId,
|
|
'menu_item_id' => $menuItemId,
|
|
|
'role_id' => $roleId
|
|
'role_id' => $roleId
|
|
|
]);
|
|
]);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
session()->flash('success', '权限更新成功');
|
|
session()->flash('success', '权限更新成功');
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return redirect()->back();
|
|
return redirect()->back();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public function getRolePermissions(Request $request)
|
|
public function getRolePermissions(Request $request)
|
|
|
{
|
|
{
|
|
|
$roleId = $request->input('role_id');
|
|
$roleId = $request->input('role_id');
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$permissions = DB::table('menu_item_role')
|
|
$permissions = DB::table('menu_item_role')
|
|
|
->where('role_id', $roleId)
|
|
->where('role_id', $roleId)
|
|
|
->pluck('menu_item_id')
|
|
->pluck('menu_item_id')
|
|
|
->toArray();
|
|
->toArray();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return response()->json($permissions);
|
|
return response()->json($permissions);
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证路由是否存在
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param Request $request
|
|
|
|
|
+ * @return \Illuminate\Http\JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function validateRoute(Request $request)
|
|
|
|
|
+ {
|
|
|
|
|
+ $request->validate([
|
|
|
|
|
+ 'route' => 'required|string'
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $routeName = trim($request->input('route'));
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是完整URL(以http://或https://开头),跳过验证
|
|
|
|
|
+ if (preg_match('/^https?:\/\//i', $routeName)) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'exists' => true,
|
|
|
|
|
+ 'message' => '外部URL,已跳过验证'
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是相对路径(以/开头),跳过验证
|
|
|
|
|
+ if (str_starts_with($routeName, '/')) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'exists' => true,
|
|
|
|
|
+ 'message' => '相对路径,已跳过验证'
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查路由是否存在
|
|
|
|
|
+ try {
|
|
|
|
|
+ $route = RouteFacade::getRoutes()->getByName($routeName);
|
|
|
|
|
+
|
|
|
|
|
+ if ($route) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'exists' => true,
|
|
|
|
|
+ 'message' => "路由 '{$routeName}' 存在",
|
|
|
|
|
+ 'methods' => $route->methods(),
|
|
|
|
|
+ 'uri' => $route->uri()
|
|
|
|
|
+ ]);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 尝试查找相似的路由名称,提供建议
|
|
|
|
|
+ $suggestions = $this->findSimilarRoutes($routeName);
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'exists' => false,
|
|
|
|
|
+ 'message' => "路由 '{$routeName}' 不存在",
|
|
|
|
|
+ 'suggestions' => $suggestions
|
|
|
|
|
+ ], 422);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ \Log::error('Route validation error: ' . $e->getMessage());
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'exists' => false,
|
|
|
|
|
+ 'message' => '路由验证失败:' . $e->getMessage()
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查找相似的路由名称
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param string $routeName
|
|
|
|
|
+ * @return array
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function findSimilarRoutes(string $routeName): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $allRoutes = RouteFacade::getRoutes();
|
|
|
|
|
+ $similarRoutes = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 提取路由的主要部分
|
|
|
|
|
+ $parts = explode('.', $routeName);
|
|
|
|
|
+ $mainPart = $parts[0] ?? '';
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($allRoutes as $route) {
|
|
|
|
|
+ $name = $route->getName();
|
|
|
|
|
+
|
|
|
|
|
+ if (!$name) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 计算相似度
|
|
|
|
|
+ similar_text($routeName, $name, $percent);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果相似度超过60%,或者包含相同的前缀
|
|
|
|
|
+ if ($percent > 60 || (isset($parts[0]) && str_contains($name, $parts[0]))) {
|
|
|
|
|
+ $similarRoutes[] = [
|
|
|
|
|
+ 'name' => $name,
|
|
|
|
|
+ 'uri' => $route->uri(),
|
|
|
|
|
+ 'similarity' => round($percent, 2)
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 按相似度排序,取前5个
|
|
|
|
|
+ usort($similarRoutes, function($a, $b) {
|
|
|
|
|
+ return $b['similarity'] <=> $a['similarity'];
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return array_slice($similarRoutes, 0, 5);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|