feat: 文章/分类/评论关联细节完善

- 文章列表:会员插件注入「付费」徽章列(会员/付费¥xx,停插件即消失)
- 分类:真实文章数(withCount)、名称点击跳文章列表并按分类筛选(ListPosts booted 预置筛选)
- 分类:新增封面(medialibrary)+ 介绍(description 字段/表单);前台分类页顶部展示介绍区;SEO description + BreadcrumbList 结构化数据(GEO)
- 文章编辑:MarkdownEditor 内容区加大(26rem);文章编辑页新增「评论」关系管理页(可审/拒)
- 评论列表:文章列带摘要
- 三套主题补 .category-intro 样式
- 测试更新(付费徽章列)
This commit is contained in:
ak
2026-08-12 22:44:16 +08:00
parent a22175d5b7
commit 5f74dd76e4
18 changed files with 276 additions and 34 deletions
@@ -92,6 +92,25 @@ class SeoMiddleware
}
}
// 分类页:面包屑结构化数据(GEO 友好)
if ($route && $route->getName() === 'category.show') {
$slug = $route->parameter('slug');
$category = Cache::remember('seo.category.'.$slug, now()->addHour(), function () use ($slug) {
return \App\Models\Category::query()->where('slug', $slug)->orWhere('id', (int) $slug)->first();
});
if ($category) {
return [
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => [
['@type' => 'ListItem', 'position' => 1, 'name' => $siteName, 'item' => url('/')],
['@type' => 'ListItem', 'position' => 2, 'name' => $category->name, 'item' => route('category.show', $category->slug ?: $category->id)],
],
];
}
}
return [
'@context' => 'https://schema.org',
'@type' => 'WebSite',
@@ -12,7 +12,6 @@ use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Plugins\Neatstudio\Membership\Models\MembershipPlan;
@@ -104,15 +103,32 @@ class ServiceProvider extends PluginServiceProvider
]);
});
// 后台文章表格注入:价格 / 会员列
// 后台文章表格注入:付费标识(价格/会员徽章,停用插件后消失)
$manager->addAction('filament.post_table', function (Table $table) {
$table->pushColumns([
TextColumn::make('meta.price')
->label('单篇价格')
->formatStateUsing(fn ($state) => $state > 0 ? '¥'.number_format((float) $state / 100, 2) : '—'),
IconColumn::make('meta.members_only')
->label('会员')
->boolean(),
TextColumn::make('meta.members_only')
->label('付费')
->badge()
->formatStateUsing(function ($state, $record) {
$meta = $record->meta ?? [];
$price = (int) ($meta['price'] ?? 0);
if (! empty($meta['members_only'])) {
return '会员';
}
return $price > 0 ? '付费 ¥'.number_format($price / 100, 2) : '—';
})
->color(function ($state, $record) {
$meta = $record->meta ?? [];
if (! empty($meta['members_only'])) {
return 'warning';
}
return (int) ($meta['price'] ?? 0) > 0 ? 'danger' : 'gray';
})
->placeholder('—'),
]);
});
}