'顶部导航条', self::TYPE_SIDEBAR_MENU => '侧边栏菜单', self::TYPE_INNER_PAGE_TAB => '页面内标签页', ]; private static array $aStatusLabels = [ self::STATUS_OPEN => '开启', self::STATUS_CLOSE => '关闭', ]; public function getMapAll() { $aMap = [ 'sComponentType' => self::$aComponentLabels, 'iStatus' => self::$aStatusLabels ]; return $aMap; } protected function casts(): array { return [ 'dtUpdatedAt' => 'datetime:Y-m-d H:i:s', // 自动转换为 Carbon 对象 'dtCreatedAt' => 'datetime:Y-m-d H:i:s', // 写入时自动 password_hash 加密 ]; } /** * 递归获取当前菜单的所有上级祖先节点(包含自身) * 结果按从根节点到当前节点的顺序排列(即:[一级, 二级, 三级, 当前]) * * @return \Illuminate\Support\Collection */ public function cGetAncestorsAndSelf(): \Illuminate\Support\Collection { $cPath = collect([$this]); $oCurrent = $this; // 使用循环代替递归进行反向溯源,性能更佳,防止极端情况下的堆栈溢出 while ($oCurrent->iParentId != 0) { // 高标准注意:这里如果能做内存缓存或走预加载更佳,但由于是单条数据向上,走主键查询性能损耗可控 $oParent = self::where('id', $oCurrent->iParentId)->available()->first(); if (!$oParent) { break; // 防御性编程:万一数据链断了,及时跳出 } $cPath->prepend($oParent); // 往前插入,保证顺序是 [父, 子, 孙] $oCurrent = $oParent; } return $cPath; } public function children() { // 这里的 iParentId 是外键,id 是当前表的主键 return $this->hasMany(self::class, 'iParentId', 'id'); } /** * 你的本地作用域(Scope),确保 scopeAvailable 存在 * 顺便提一句,高标准设计中,状态字段建议内聚在 scope 里 */ public function scopeAvailable($query) { // 假设你的可用状态字段是 iStatus 且 1 为可用,请根据实际字段调整 return $query->where('iStatus', 1); } /** * 高标准设计:递归预加载所有下级(无限级核心) * 只要这一条 Eager Loading,Laravel 会自动用最少的 SQL 把整棵树一次性读入内存 */ public function childrenRecursive() { return $this->children() ->available() ->orderBy('iSort', 'asc') ->with('childrenRecursive'); // 完美的自我套娃 } /** * 业务逻辑内聚:深度优先穿透获取最终 URL * 职责:如果有下级,永远优先往下找第一个合法的下级;如果没有下级或下级全挂了,退回自身。 */ public function sGetFinalUrl(): string { // 1. 如果有下级集合(已经过 available 过滤),尝试向下穿透 if ($this->relationLoaded('childrenRecursive') && $this->childrenRecursive->isNotEmpty()) { foreach ($this->childrenRecursive as $oChild) { // 递归向下寻找子节点的最终 URL $sChildUrl = $oChild->sGetFinalUrl(); // 只要子节点或者孙子节点能返回一个有效 URL,立刻中断并返回它(最左原则) if (!empty($sChildUrl)) { return $sChildUrl; } } } // 2. 兜底逻辑:没有下级,或者所有下级分支都没配置有效路由,返回自身的 URL // return $this->sPermissionSlug; return Route::has($this->sPermissionSlug) ? route($this->sPermissionSlug) : ''; } }