'integer', 'sort' => 'integer', 'status' => 'integer', 'icon' => 'integer', 'created_at' => 'datetime:Y-m-d H:i:s', 'updated_at' => 'datetime:Y-m-d H:i:s', ]; protected $appends = ['icon_url']; /** * 关联图标 */ public function icon(): HasOne { return $this->hasOne(SysFileModel::class, 'id', 'icon'); } // 图标链接 public function icon_url(): Attribute { return Attribute::make( get: fn () => $this->icon->preview_url, ); } /** * 父分类 */ public function parent(): BelongsTo { return $this->belongsTo(self::class, 'parent_id', 'id'); } /** * 子分类 */ public function children(): HasMany { return $this->hasMany(self::class, 'parent_id', 'id')->orderBy('sort'); } /** * 分类下的商品 */ public function products(): HasMany { return $this->hasMany(ProductModel::class, 'category_id', 'id'); } /** * 获取分类树(树表展示 / 级联下拉选项复用) * * @param bool $onlyEnabled 是否仅返回启用分类 * @return array */ public static function getTreeData(bool $onlyEnabled = false): array { $query = static::query()->orderBy('sort')->orderBy('id'); if ($onlyEnabled) { $query->where('status', self::STATUS_NORMAL); } return static::buildTree($query->get()->toArray()); } /** * 将扁平分类列表组装为树 * * @param array> $items * @param int $parentId * @return array> */ public static function buildTree(array $items, int $parentId = 0): array { $tree = []; foreach ($items as $item) { if ((int) $item['parent_id'] !== $parentId) { continue; } $children = static::buildTree($items, (int) $item['id']); if ($children !== []) { $item['children'] = $children; } $tree[] = $item; } return $tree; } }