diff --git a/src/routes/admin/categories/+page.server.ts b/src/routes/admin/categories/+page.server.ts new file mode 100644 index 0000000..f496d57 --- /dev/null +++ b/src/routes/admin/categories/+page.server.ts @@ -0,0 +1,115 @@ +async function ensureCategoriesTable(db: any) { + try { + await db.prepare(` + CREATE TABLE IF NOT EXISTS categories ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE, + slug TEXT NOT NULL UNIQUE + ) + `).run(); + try { + await db.prepare('ALTER TABLE posts ADD COLUMN category_id INTEGER').run(); + } catch { + // Column might already exist + } + } catch (e) { + console.error('Failed to ensure categories table:', e); + } +} + +export const load: PageServerLoad = async ({ platform }) => { + const db = platform?.env?.DB; + + if (!db) { + return { categories: [] }; + } + + try { + const { results } = await db.prepare( + `SELECT c.id, c.name, c.slug, COUNT(p.id) as post_count + FROM categories c + LEFT JOIN posts p ON c.id = p.category_id + GROUP BY c.id, c.name, c.slug + ORDER BY c.name ASC` + ).all(); + + return { + categories: results as unknown as { id: number; name: string; slug: string; post_count: number }[] + }; + } catch (err: any) { + if (err?.message?.includes('no such table')) { + await ensureCategoriesTable(db); + try { + const { results } = await db.prepare( + `SELECT c.id, c.name, c.slug, COUNT(p.id) as post_count + FROM categories c + LEFT JOIN posts p ON c.id = p.category_id + GROUP BY c.id, c.name, c.slug + ORDER BY c.name ASC` + ).all(); + return { categories: results as unknown as { id: number; name: string; slug: string; post_count: number }[] }; + } catch (e) { + return { categories: [] }; + } + } + console.error('Error fetching categories:', err); + return { categories: [] }; + } +}; + +export const actions: Actions = { + create: async ({ request, platform }) => { + const db = platform?.env?.DB; + if (!db) return fail(500, { error: '数据库未连接' }); + + const formData = await request.formData(); + const name = formData.get('name')?.toString().trim(); + let slug = formData.get('slug')?.toString().trim(); + + if (!name) { + return fail(400, { error: '分类名称不能为空' }); + } + + if (!slug) { + slug = name.toLowerCase().replace(/\s+/g, '-'); + } + + try { + await db.prepare('INSERT INTO categories (name, slug) VALUES (?, ?)').bind(name, slug).run(); + return { success: true }; + } catch (err: any) { + if (err?.message?.includes('no such table')) { + await ensureCategoriesTable(db); + try { + await db.prepare('INSERT INTO categories (name, slug) VALUES (?, ?)').bind(name, slug).run(); + return { success: true }; + } catch (e: any) { + return fail(500, { error: '创建分类失败: ' + e.message }); + } + } + console.error('Error creating category:', err); + if (err?.message?.includes('UNIQUE constraint failed')) { + return fail(400, { error: '分类名称或 URL 别名 (Slug) 已存在' }); + } + return fail(500, { error: '创建分类失败' }); + } + }, + + delete: async ({ request, platform }) => { + const db = platform?.env?.DB; + if (!db) return fail(500, { error: '数据库未连接' }); + + const formData = await request.formData(); + const id = formData.get('id'); + + if (!id) return fail(400, { error: '缺少分类 ID' }); + + try { + await db.prepare('DELETE FROM categories WHERE id = ?').bind(id).run(); + return { success: true }; + } catch (err) { + console.error('Error deleting category:', err); + return { success: false, error: '删除分类失败' }; + } + } +}; diff --git a/src/routes/admin/categories/+page.svelte b/src/routes/admin/categories/+page.svelte new file mode 100644 index 0000000..896d4d6 --- /dev/null +++ b/src/routes/admin/categories/+page.svelte @@ -0,0 +1,279 @@ + + +
暂无任何分类,在左侧添加一个吧!
+| ID | +分类名称 | +别名 (Slug) | +关联文章数 | +操作 | +
|---|---|---|---|---|
| {category.id} | +{category.name} | +{category.slug} | +{category.post_count} 篇文章 | ++ + | +