This commit is contained in:
1 parent
5df6fe45e8
commit
7b8358005f
3 files changed
+137
-5
No files matched your search
@@ -11,18 +11,54 @@ interface PostListRow {
|
||||
category?: string;
|
||||
series?: string;
|
||||
}
|
||||
export const load: PageServerLoad = async ({ platform }) => {
|
||||
export const load: PageServerLoad = async ({ url, platform }) => {
|
||||
const db = platform?.env?.DB;
|
||||
|
||||
if (!db) {
|
||||
return {
|
||||
posts: []
|
||||
posts: [],
|
||||
filterTag: null
|
||||
};
|
||||
}
|
||||
|
||||
const tagIdParam = url.searchParams.get('tagId');
|
||||
const tagId = tagIdParam ? parseInt(tagIdParam, 10) : null;
|
||||
let filterTag: { id: number; name: string } | null = null;
|
||||
|
||||
if (tagId && !Number.isNaN(tagId)) {
|
||||
try {
|
||||
const tagRes = await db
|
||||
.prepare('SELECT id, name FROM tags WHERE id = ?')
|
||||
.bind(tagId)
|
||||
.first<{ id: number; name: string }>();
|
||||
if (tagRes) {
|
||||
filterTag = tagRes;
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Error fetching filter tag:', err);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let results: PostListRow[];
|
||||
try {
|
||||
if (filterTag) {
|
||||
const queryRes = await db
|
||||
.prepare(
|
||||
`SELECT p.id, p.title, p.slug, p.published_at as date, u.username as author,
|
||||
c.name as category, s.name as series
|
||||
FROM posts p
|
||||
INNER JOIN post_tags pt ON p.id = pt.post_id
|
||||
LEFT JOIN users u ON p.author_id = u.id
|
||||
LEFT JOIN categories c ON p.category_id = c.id
|
||||
LEFT JOIN series s ON p.series_id = s.id
|
||||
WHERE pt.tag_id = ?
|
||||
ORDER BY p.published_at DESC`
|
||||
)
|
||||
.bind(filterTag.id)
|
||||
.all<PostListRow>();
|
||||
results = queryRes.results;
|
||||
} else {
|
||||
const queryRes = await db
|
||||
.prepare(
|
||||
`SELECT p.id, p.title, p.slug, p.published_at as date, u.username as author,
|
||||
@@ -35,8 +71,23 @@ export const load: PageServerLoad = async ({ platform }) => {
|
||||
)
|
||||
.all<PostListRow>();
|
||||
results = queryRes.results;
|
||||
}
|
||||
} catch (err: any) {
|
||||
// Fallback query if categories table or category_id column is missing
|
||||
if (filterTag) {
|
||||
const queryRes = await db
|
||||
.prepare(
|
||||
`SELECT p.id, p.title, p.slug, p.published_at as date, u.username as author
|
||||
FROM posts p
|
||||
INNER JOIN post_tags pt ON p.id = pt.post_id
|
||||
LEFT JOIN users u ON p.author_id = u.id
|
||||
WHERE pt.tag_id = ?
|
||||
ORDER BY p.published_at DESC`
|
||||
)
|
||||
.bind(filterTag.id)
|
||||
.all<PostListRow>();
|
||||
results = queryRes.results.map((r) => ({ ...r, category: '', series: '' }));
|
||||
} else {
|
||||
const queryRes = await db
|
||||
.prepare(
|
||||
`SELECT p.id, p.title, p.slug, p.published_at as date, u.username as author
|
||||
@@ -47,6 +98,7 @@ export const load: PageServerLoad = async ({ platform }) => {
|
||||
.all<PostListRow>();
|
||||
results = queryRes.results.map((r) => ({ ...r, category: '', series: '' }));
|
||||
}
|
||||
}
|
||||
|
||||
// Format date for display
|
||||
const formattedPosts = results.map((post) => {
|
||||
@@ -62,11 +114,12 @@ export const load: PageServerLoad = async ({ platform }) => {
|
||||
});
|
||||
|
||||
return {
|
||||
posts: formattedPosts
|
||||
posts: formattedPosts,
|
||||
filterTag
|
||||
};
|
||||
} catch (err: any) {
|
||||
console.error('Error fetching admin posts list:', err);
|
||||
return { posts: [] };
|
||||
return { posts: [], filterTag };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,17 @@
|
||||
<Button href={resolve('/admin/posts/new')} variant="primary">撰写</Button>
|
||||
</div>
|
||||
|
||||
{#if data.filterTag}
|
||||
<div class="filter-banner">
|
||||
<div class="filter-info">
|
||||
<span>正在筛选{$page.data.aliases?.tag || '标签'}:</span>
|
||||
<span class="filter-tag-badge">#{data.filterTag.name}</span>
|
||||
<span class="filter-count">(共 {data.posts.length} 篇)</span>
|
||||
</div>
|
||||
<Button href={resolve('/admin/posts')} variant="action" size="sm">清除筛选</Button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if data.posts.length > 0}
|
||||
<div class="batch-actions">
|
||||
{#if selectedIds.length > 0}
|
||||
@@ -66,7 +77,17 @@
|
||||
|
||||
{#if data.posts.length === 0}
|
||||
<div class="empty-state">
|
||||
{#if data.filterTag}
|
||||
<p>
|
||||
{$page.data.aliases?.tag || '标签'} "{data.filterTag.name}" 下暂无关联{$page.data.aliases
|
||||
?.post || '文章'}
|
||||
</p>
|
||||
<Button href={resolve('/admin/posts')} variant="action" size="sm"
|
||||
>查看所有{$page.data.aliases?.post || '文章'}</Button
|
||||
>
|
||||
{:else}
|
||||
<p>还没有发布任何{$page.data.aliases?.post || '文章'}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<DataTable>
|
||||
@@ -197,4 +218,32 @@
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
.filter-banner {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 16px;
|
||||
background: rgba(0, 0, 0, 0.03);
|
||||
border-left: 3px solid var(--accent-color, #419b38);
|
||||
}
|
||||
|
||||
.filter-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 0.95rem;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.filter-tag-badge {
|
||||
font-weight: 600;
|
||||
color: var(--accent-color, #419b38);
|
||||
}
|
||||
|
||||
.filter-count {
|
||||
color: var(--text-muted, rgba(0, 0, 0, 0.6));
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import type { PageData, ActionData } from './$types';
|
||||
import { confirmState } from '$lib/stores/confirm.svelte';
|
||||
@@ -76,7 +77,19 @@
|
||||
<strong>{tag.name}</strong>
|
||||
{/if}
|
||||
</td>
|
||||
<td><span class="badge">{tag.post_count}</span></td>
|
||||
<td>
|
||||
{#if tag.post_count > 0}
|
||||
<a
|
||||
href="{resolve('/admin/posts')}?tagId={tag.id}"
|
||||
class="badge badge-link"
|
||||
title={`查看关联的 ${tag.post_count} 篇${$page.data.aliases?.post || '文章'}`}
|
||||
>
|
||||
{tag.post_count}
|
||||
</a>
|
||||
{:else}
|
||||
<span class="badge badge-empty">{tag.post_count}</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
{#if editingId === tag.id}
|
||||
<form
|
||||
@@ -201,4 +214,21 @@
|
||||
text-align: center;
|
||||
color: var(--text-muted, rgba(0, 0, 0, 0.6));
|
||||
}
|
||||
|
||||
.badge-link {
|
||||
color: var(--accent-color, #419b38);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.badge-link:hover {
|
||||
background-color: var(--accent-color, #419b38);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.badge-empty {
|
||||
color: var(--text-muted, rgba(0, 0, 0, 0.4));
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user