false, 'name' => 'download_category', 'autoRelation' => [], 'createTime' => 'create_at', 'updateTime' => 'update_at', 'dateFormat' => 'Y-m-d H:i:s', ]; } /** * 子分类(pid 指向自身) */ public function children() { return $this->hasMany(self::class, 'pid', 'id') ->where('status', 1) ->order('sort', 'desc'); } /** * 分类下的资源 */ public function resources() { return $this->hasMany(Resource::class, 'cid', 'id') ->where('status', 1) ->where('is_audit', 1); } /** * 平铺分类列表转带前缀的下拉选项(供新增/编辑表单的上级分类 select 使用) * 直接复用父类 BaseModel::cateTree($cate, $name='title', $lefthtml='|— ', $pid=0, $level=0), * 返回的 title 自带层级前缀,无需在子类重复声明(会与父类签名冲突 fatal error)。 */ /** * 将平铺分类列表转换为嵌套树(供 layui.treeTable 使用) * 返回形如 [['id'=>..,'children'=>[...]], ...] */ public static function toNestedTree(array $list): array { $map = []; foreach ($list as &$item) { $item['children'] = []; $map[$item['id']] = &$item; } unset($item); $tree = []; foreach ($list as &$item) { if (!empty($item['pid']) && isset($map[$item['pid']])) { $map[$item['pid']]['children'][] = &$item; } else { $tree[] = &$item; } } unset($item); // 清理空的 children,保持返回结构干净 return self::cleanEmptyChildren($tree); } protected static function cleanEmptyChildren(array $tree): array { foreach ($tree as &$node) { if (!empty($node['children'])) { $node['children'] = self::cleanEmptyChildren($node['children']); } else { unset($node['children']); } } return $tree; } /** * 删除前保护:存在子分类或资源时禁止删除 */ public static function onBeforeDelete($model) { $childCount = self::where('pid', $model->id)->count(); if ($childCount > 0) { throw new \think\Exception('该分类下还存在 ' . $childCount . ' 个子分类,请先处理子分类'); } $resCount = \addon\download\model\Resource::where('cid', $model->id)->count(); if ($resCount > 0) { throw new \think\Exception('该分类下还存在 ' . $resCount . ' 个资源,请先移走或删除这些资源'); } } }