'boolean', 'notify_chat' => 'boolean', 'published_at' => 'datetime', ]; /** * 类型标签配置(中文名 + Tailwind 颜色类) */ public const TYPE_CONFIG = [ 'feature' => ['label' => '🆕 新功能', 'color' => 'emerald'], 'fix' => ['label' => '🐛 修复', 'color' => 'rose'], 'improve' => ['label' => '⚡ 优化', 'color' => 'blue'], 'other' => ['label' => '📌 其他', 'color' => 'slate'], ]; // ═══════════════ 查询作用域 ═══════════════ /** * 只查询已发布的日志 */ public function scopePublished(Builder $query): Builder { return $query->where('is_published', true)->orderByDesc('published_at'); } /** * 懒加载:查询比指定 ID 更旧的已发布日志(游标分页) * * @param int $afterId 已加载的最后一条 ID */ public function scopeAfter(Builder $query, int $afterId): Builder { return $query->where('id', '<', $afterId); } // ═══════════════ 访问器 ═══════════════ /** * 获取类型对应的中文标签 */ public function getTypeLabelAttribute(): string { return self::TYPE_CONFIG[$this->type]['label'] ?? '📌 其他'; } /** * 获取类型对应的 Tailwind 颜色名 */ public function getTypeColorAttribute(): string { return self::TYPE_CONFIG[$this->type]['color'] ?? 'slate'; } /** * 将 Markdown 内容渲染为 HTML(使用 Laravel 内置 Str::markdown) */ public function getContentHtmlAttribute(): string { return Str::markdown($this->content, [ 'html_input' => 'strip', // 去掉原始 HTML,防止 XSS 'allow_unsafe_links' => false, ]); } /** * 获取内容纯文本摘要(用于列表预览,截取前 150 字) */ public function getSummaryAttribute(): string { // 去掉 Markdown 标记后截取纯文本 $plain = strip_tags(Str::markdown($this->content)); return Str::limit($plain, 150); } }