From 5affda0889fe73af01a0caaf547d350a2c428817 Mon Sep 17 00:00:00 2001 From: seaHi Date: Sat, 15 Aug 2026 14:35:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=88=86=E7=B1=BB?= =?UTF-8?q?=E7=9A=84=E8=A1=8C=E5=86=85=E7=BC=96=E8=BE=91=E5=92=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/admin/categories/+page.server.ts | 28 +++++ src/routes/admin/categories/+page.svelte | 125 ++++++++++++++++---- 2 files changed, 127 insertions(+), 26 deletions(-) diff --git a/src/routes/admin/categories/+page.server.ts b/src/routes/admin/categories/+page.server.ts index aa8f05c..e7ce52b 100644 --- a/src/routes/admin/categories/+page.server.ts +++ b/src/routes/admin/categories/+page.server.ts @@ -139,5 +139,33 @@ export const actions: Actions = { console.error('Error deleting category:', err); return { success: false, error: '删除分类失败' }; } + }, + + update: async ({ request, platform }) => { + const db = platform?.env?.DB as any; + if (!db) return fail(500, { error: '数据库未连接' }); + + const formData = await request.formData(); + const id = formData.get('id'); + const name = formData.get('name')?.toString().trim(); + const slug = formData.get('slug')?.toString().trim(); + + if (!id || !name || !slug) { + return fail(400, { error: '分类 ID、名称和 URL 别名为必填项' }); + } + + try { + await db + .prepare('UPDATE categories SET name = ?, slug = ? WHERE id = ?') + .bind(name, slug, id) + .run(); + return { success: true }; + } catch (err: unknown) { + console.error('Error updating category:', err); + if ((err as any)?.message?.includes('UNIQUE constraint failed')) { + return fail(400, { error: '分类名称或 URL 别名已存在' }); + } + return fail(500, { error: '更新分类失败' }); + } } }; diff --git a/src/routes/admin/categories/+page.svelte b/src/routes/admin/categories/+page.svelte index a3393f4..cf93f35 100644 --- a/src/routes/admin/categories/+page.svelte +++ b/src/routes/admin/categories/+page.svelte @@ -11,6 +11,8 @@ let isSlugUserModified = $state(false); let isGenerating = $state(false); + let editingId = $state(null); + const slugHandler = createSlugAutoHandler({ getSlug: () => slug, setSlug: (val) => (slug = val), @@ -104,34 +106,88 @@ {#each data.categories as category (category.id || category)} {category.id} - {category.name} - {category.slug} + + {#if editingId === category.id} + + {:else} + {category.name} + {/if} + + + {#if editingId === category.id} + + {:else} + {category.slug} + {/if} + {category.post_count} 篇文章 -
{ - if ((e.target as HTMLFormElement).dataset.confirmed === 'true') { - (e.target as HTMLFormElement).removeAttribute('data-confirmed'); - return; - } - e.preventDefault(); - const form = e.target as HTMLFormElement; - const submitter = e.submitter; - const confirmed = await confirmState.show( - `确定要删除${$page.data.aliases?.category || '分类'} "${category.name}" 吗?删除后相关文章将归为未${$page.data.aliases?.category || '分类'}。` - ); - if (confirmed) { - form.dataset.confirmed = 'true'; - form.requestSubmit(submitter); - } - }} - > - - -
+ {#if editingId === category.id} +
{ + // will submit naturally, just reset editingId + setTimeout(() => { + editingId = null; + }, 0); + }} + > + + +
+ + {:else} + +
{ + if ((e.target as HTMLFormElement).dataset.confirmed === 'true') { + (e.target as HTMLFormElement).removeAttribute('data-confirmed'); + return; + } + e.preventDefault(); + const form = e.target as HTMLFormElement; + const submitter = e.submitter; + const confirmed = await confirmState.show( + `确定要删除${$page.data.aliases?.category || '分类'} "${category.name}" 吗?删除后相关文章将归为未${$page.data.aliases?.category || '分类'}。` + ); + if (confirmed) { + form.dataset.confirmed = 'true'; + form.requestSubmit(submitter); + } + }} + > + + +
+ {/if} {/each} @@ -322,4 +378,21 @@ text-align: center; color: var(--text-muted, rgba(0, 0, 0, 0.6)); } + + .edit-input { + width: 100%; + padding: 6px 8px; + border: 1px solid rgba(0, 0, 0, 0.2); + background: transparent; + font-family: inherit; + font-size: 0.95rem; + color: var(--text-color); + box-sizing: border-box; + border-radius: 4px; + } + + .edit-input:focus { + outline: none; + border-color: var(--accent-color, #419b38); + }