refactor: 优化后台管理界面的提示文案和错误处理

This commit is contained in:
seahi committed 2026-09-16 12:51:16 +08:00
1 parent b8b7b823ad
commit 19061047b1
10 files changed
+45 -43

No files matched your search

@@ -75,7 +75,7 @@
if (isDeleting) return; if (isDeleting) return;
const confirmed = await confirmState.show( const confirmed = await confirmState.show(
'确定要彻底删除该附件吗?此操作将从服务器和文章正文中删除此文件。' '确定要彻底删除该附件吗?此操作将从服务器和正文中删除此文件。'
); );
if (!confirmed) return; if (!confirmed) return;
@@ -122,7 +122,7 @@
<div class="article-attachments"> <div class="article-attachments">
{#if attachments.length === 0} {#if attachments.length === 0}
<div class="empty-state">当前文章暂无附件</div> <div class="empty-state">当前暂无附件</div>
{:else} {:else}
<div class="attachment-list"> <div class="attachment-list">
{#each attachments as attachment (attachment.url)} {#each attachments as attachment (attachment.url)}
+3 -3
View File
@@ -5,7 +5,7 @@ export function parseSeriesId(value: FormDataEntryValue | null): number | null {
const id = Number(value); const id = Number(value);
if (!Number.isInteger(id) || id <= 0) { if (!Number.isInteger(id) || id <= 0) {
throw new SeriesValidationError('系列选择无效'); throw new SeriesValidationError('选择项无效');
} }
return id; return id;
@@ -16,7 +16,7 @@ export function parseSeriesWeight(value: FormDataEntryValue | null): number | nu
const weight = Number(value); const weight = Number(value);
if (!Number.isInteger(weight)) { if (!Number.isInteger(weight)) {
throw new SeriesValidationError('系列顺序必须是整数'); throw new SeriesValidationError('顺序必须是整数');
} }
return weight; return weight;
@@ -32,7 +32,7 @@ export async function resolveSeriesWeight(
const series = await db.prepare('SELECT id FROM series WHERE id = ?').bind(seriesId).first(); const series = await db.prepare('SELECT id FROM series WHERE id = ?').bind(seriesId).first();
if (!series) { if (!series) {
throw new SeriesValidationError('所选系列不存在'); throw new SeriesValidationError('所选项不存在');
} }
if (requestedWeight !== null) return requestedWeight; if (requestedWeight !== null) return requestedWeight;
+9 -9
View File
@@ -92,7 +92,7 @@ export const actions: Actions = {
let slug = formData.get('slug')?.toString().trim(); let slug = formData.get('slug')?.toString().trim();
if (!name) { if (!name) {
return fail(400, { error: '分类名称不能为空' }); return fail(400, { error: '名称不能为空' });
} }
if (!slug) { if (!slug) {
@@ -112,14 +112,14 @@ export const actions: Actions = {
.run(); .run();
return { success: true }; return { success: true };
} catch (e: any) { } catch (e: any) {
return fail(500, { error: '创建分类失败: ' + e.message }); return fail(500, { error: '创建失败: ' + e.message });
} }
} }
console.error('Error creating category:', err); console.error('Error creating category:', err);
if ((err as any)?.message?.includes('UNIQUE constraint failed')) { if ((err as any)?.message?.includes('UNIQUE constraint failed')) {
return fail(400, { error: '分类名称或 URL 别名已存在' }); return fail(400, { error: '名称或 URL 别名已存在' });
} }
return fail(500, { error: '创建分类失败' }); return fail(500, { error: '创建失败' });
} }
}, },
@@ -130,14 +130,14 @@ export const actions: Actions = {
const formData = await request.formData(); const formData = await request.formData();
const id = formData.get('id'); const id = formData.get('id');
if (!id) return fail(400, { error: '缺少分类 ID' }); if (!id) return fail(400, { error: '缺少 ID' });
try { try {
await db.prepare('DELETE FROM categories WHERE id = ?').bind(id).run(); await db.prepare('DELETE FROM categories WHERE id = ?').bind(id).run();
return { success: true }; return { success: true };
} catch (err: any) { } catch (err: any) {
console.error('Error deleting category:', err); console.error('Error deleting category:', err);
return { success: false, error: '删除分类失败' }; return { success: false, error: '删除失败' };
} }
}, },
@@ -151,7 +151,7 @@ export const actions: Actions = {
const slug = formData.get('slug')?.toString().trim(); const slug = formData.get('slug')?.toString().trim();
if (!id || !name || !slug) { if (!id || !name || !slug) {
return fail(400, { error: '分类 ID、名称和 URL 别名为必填项' }); return fail(400, { error: 'ID、名称和 URL 别名为必填项' });
} }
try { try {
@@ -163,9 +163,9 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error updating category:', err); console.error('Error updating category:', err);
if ((err as any)?.message?.includes('UNIQUE constraint failed')) { if ((err as any)?.message?.includes('UNIQUE constraint failed')) {
return fail(400, { error: '分类名称或 URL 别名已存在' }); return fail(400, { error: '名称或 URL 别名已存在' });
} }
return fail(500, { error: '更新分类失败' }); return fail(500, { error: '更新失败' });
} }
} }
}; };
+5 -4
View File
@@ -3,9 +3,10 @@
import { error, fail, redirect } from '@sveltejs/kit'; import { error, fail, redirect } from '@sveltejs/kit';
import type { Actions, PageServerLoad } from './$types'; import type { Actions, PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, platform }) => { export const load: PageServerLoad = async ({ params, platform, parent }) => {
const db = platform?.env?.DB; const db = platform?.env?.DB;
const pageId = params.id; const pageId = params.id;
const { aliases } = await parent();
if (!db) { if (!db) {
throw error(500, '数据库未连接'); throw error(500, '数据库未连接');
@@ -18,7 +19,7 @@ export const load: PageServerLoad = async ({ params, platform }) => {
.first<{ id: number; title: string; slug: string; content: string }>(); .first<{ id: number; title: string; slug: string; content: string }>();
if (!page) { if (!page) {
throw error(404, '页面不存在'); throw error(404, `该${aliases?.page || '页面'}不存在`);
} }
return { return {
@@ -27,7 +28,7 @@ export const load: PageServerLoad = async ({ params, platform }) => {
} catch (err: unknown) { } catch (err: unknown) {
if ((err as any)?.status === 404) throw err; if ((err as any)?.status === 404) throw err;
console.error('Error loading page for edit:', err); console.error('Error loading page for edit:', err);
throw error(500, '读取页面详情失败'); throw error(500, '读取详情失败');
} }
}; };
@@ -63,7 +64,7 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error updating page:', err); console.error('Error updating page:', err);
if ((err as any)?.message?.includes('UNIQUE constraint failed')) { if ((err as any)?.message?.includes('UNIQUE constraint failed')) {
return fail(400, { error: 'URL 别名已被其他页面占用' }); return fail(400, { error: 'URL 别名已被占用' });
} }
return fail(500, { error: '保存修改失败' }); return fail(500, { error: '保存修改失败' });
} }
+1 -1
View File
@@ -38,7 +38,7 @@ export const actions: Actions = {
if ((err as any)?.message?.includes('UNIQUE constraint failed')) { if ((err as any)?.message?.includes('UNIQUE constraint failed')) {
return fail(400, { error: 'URL 别名已被占用,请使用其他别名' }); return fail(400, { error: 'URL 别名已被占用,请使用其他别名' });
} }
return fail(500, { error: '保存页面失败' }); return fail(500, { error: '保存失败' });
} }
throw redirect(303, '/admin/pages'); throw redirect(303, '/admin/pages');
+1 -1
View File
@@ -45,7 +45,7 @@ export const load: PageServerLoad = async ({ platform }) => {
ORDER BY p.published_at DESC` ORDER BY p.published_at DESC`
) )
.all<PostListRow>(); .all<PostListRow>();
results = queryRes.results.map((r) => ({ ...r, category: '未分类', series: '' })); results = queryRes.results.map((r) => ({ ...r, category: '', series: '' }));
} }
// Format date for display // Format date for display
+6 -5
View File
@@ -9,9 +9,10 @@ import {
SeriesValidationError SeriesValidationError
} from '$lib/server/series'; } from '$lib/server/series';
export const load: PageServerLoad = async ({ params, platform }) => { export const load: PageServerLoad = async ({ params, platform, parent }) => {
const db = platform?.env?.DB; const db = platform?.env?.DB;
const postId = params.id; const postId = params.id;
const { aliases } = await parent();
if (!db) { if (!db) {
throw error(500, '数据库未连接'); throw error(500, '数据库未连接');
@@ -37,7 +38,7 @@ export const load: PageServerLoad = async ({ params, platform }) => {
}>(); }>();
if (!post) { if (!post) {
throw error(404, '文章不存在'); throw error(404, `该${aliases?.post || '文章'}不存在`);
} }
const { results: allTags } = await db const { results: allTags } = await db
@@ -66,7 +67,7 @@ export const load: PageServerLoad = async ({ params, platform }) => {
} catch (err: unknown) { } catch (err: unknown) {
if (isHttpError(err, 404)) throw err; if (isHttpError(err, 404)) throw err;
console.error('Error loading post for edit:', err); console.error('Error loading post for edit:', err);
throw error(500, '读取文章详情失败'); throw error(500, '读取详情失败');
} }
}; };
@@ -90,7 +91,7 @@ export const actions: Actions = {
const missing: string[] = []; const missing: string[] = [];
if (!title) missing.push('标题'); if (!title) missing.push('标题');
if (!slug) missing.push('URL 别名'); if (!slug) missing.push('URL 别名');
if (!content) missing.push('文章正文'); if (!content) missing.push('正文');
if (missing.length > 0) { if (missing.length > 0) {
return fail(400, { error: `${missing.join('、')}为必填项` }); return fail(400, { error: `${missing.join('、')}为必填项` });
} }
@@ -170,7 +171,7 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error updating post:', err); console.error('Error updating post:', err);
if (err instanceof Error && err.message.includes('UNIQUE constraint failed')) { if (err instanceof Error && err.message.includes('UNIQUE constraint failed')) {
return fail(400, { error: 'URL 别名已被其他文章占用' }); return fail(400, { error: 'URL 别名已被占用' });
} }
return fail(500, { error: '保存修改失败' }); return fail(500, { error: '保存修改失败' });
} }
+2 -2
View File
@@ -55,7 +55,7 @@ export const actions: Actions = {
const missing: string[] = []; const missing: string[] = [];
if (!title) missing.push('标题'); if (!title) missing.push('标题');
if (!slug) missing.push('URL 别名'); if (!slug) missing.push('URL 别名');
if (!content) missing.push('文章正文'); if (!content) missing.push('正文');
if (missing.length > 0) { if (missing.length > 0) {
return fail(400, { error: `${missing.join('、')}为必填项` }); return fail(400, { error: `${missing.join('、')}为必填项` });
} }
@@ -113,7 +113,7 @@ export const actions: Actions = {
if (err instanceof Error && err.message.includes('UNIQUE constraint failed')) { if (err instanceof Error && err.message.includes('UNIQUE constraint failed')) {
return fail(400, { error: 'URL 别名已被占用,请使用其他别名' }); return fail(400, { error: 'URL 别名已被占用,请使用其他别名' });
} }
return fail(500, { error: '保存文章失败' }); return fail(500, { error: '保存失败' });
} }
throw redirect(303, '/admin/posts'); throw redirect(303, '/admin/posts');
+8 -8
View File
@@ -54,7 +54,7 @@ export const actions: Actions = {
const name = formData.get('name')?.toString().trim() || ''; const name = formData.get('name')?.toString().trim() || '';
const slug = makeSlug(formData.get('slug')?.toString() || name); const slug = makeSlug(formData.get('slug')?.toString() || name);
if (!name || !slug) return fail(400, { error: '系列名称和 URL 别名不能为空' }); if (!name || !slug) return fail(400, { error: '名称和 URL 别名不能为空' });
try { try {
const created = await db const created = await db
@@ -65,9 +65,9 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error creating series:', err); console.error('Error creating series:', err);
if (isUniqueConstraintError(err)) { if (isUniqueConstraintError(err)) {
return fail(400, { error: '系列名称或 URL 别名已存在' }); return fail(400, { error: '名称或 URL 别名已存在' });
} }
return fail(500, { error: '创建系列失败' }); return fail(500, { error: '创建失败' });
} }
}, },
@@ -81,7 +81,7 @@ export const actions: Actions = {
const slug = makeSlug(formData.get('slug')?.toString() || ''); const slug = makeSlug(formData.get('slug')?.toString() || '');
if (!Number.isInteger(id) || id <= 0 || !name || !slug) { if (!Number.isInteger(id) || id <= 0 || !name || !slug) {
return fail(400, { error: '系列信息不完整' }); return fail(400, { error: '信息不完整' });
} }
try { try {
@@ -93,9 +93,9 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error updating series:', err); console.error('Error updating series:', err);
if (isUniqueConstraintError(err)) { if (isUniqueConstraintError(err)) {
return fail(400, { error: '系列名称或 URL 别名已存在' }); return fail(400, { error: '名称或 URL 别名已存在' });
} }
return fail(500, { error: '更新系列失败' }); return fail(500, { error: '更新失败' });
} }
}, },
@@ -105,7 +105,7 @@ export const actions: Actions = {
const formData = await request.formData(); const formData = await request.formData();
const id = Number(formData.get('id')); const id = Number(formData.get('id'));
if (!Number.isInteger(id) || id <= 0) return fail(400, { error: '系列 ID 无效' }); if (!Number.isInteger(id) || id <= 0) return fail(400, { error: 'ID 无效' });
try { try {
await db.batch([ await db.batch([
@@ -117,7 +117,7 @@ export const actions: Actions = {
return { success: true }; return { success: true };
} catch (err: any) { } catch (err: any) {
console.error('Error deleting series:', err); console.error('Error deleting series:', err);
return fail(500, { error: '删除系列失败' }); return fail(500, { error: '删除失败' });
} }
} }
}; };
+8 -8
View File
@@ -40,7 +40,7 @@ export const actions: Actions = {
const name = formData.get('name')?.toString().trim(); const name = formData.get('name')?.toString().trim();
if (!name) { if (!name) {
return fail(400, { error: '标签名称不能为空' }); return fail(400, { error: '名称不能为空' });
} }
try { try {
@@ -54,9 +54,9 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error creating tag:', err); console.error('Error creating tag:', err);
if ((err as any)?.message?.includes('UNIQUE constraint failed')) { if ((err as any)?.message?.includes('UNIQUE constraint failed')) {
return fail(400, { error: '标签名称已存在' }); return fail(400, { error: '名称已存在' });
} }
return fail(500, { error: '创建标签失败' }); return fail(500, { error: '创建失败' });
} }
}, },
@@ -67,14 +67,14 @@ export const actions: Actions = {
const formData = await request.formData(); const formData = await request.formData();
const id = formData.get('id'); const id = formData.get('id');
if (!id) return fail(400, { error: '缺少标签 ID' }); if (!id) return fail(400, { error: '缺少 ID' });
try { try {
await db.prepare('DELETE FROM tags WHERE id = ?').bind(id).run(); await db.prepare('DELETE FROM tags WHERE id = ?').bind(id).run();
return { success: true }; return { success: true };
} catch (err: any) { } catch (err: any) {
console.error('Error deleting tag:', err); console.error('Error deleting tag:', err);
return { success: false, error: '删除标签失败' }; return { success: false, error: '删除失败' };
} }
}, },
@@ -87,7 +87,7 @@ export const actions: Actions = {
const name = formData.get('name')?.toString().trim(); const name = formData.get('name')?.toString().trim();
if (!id || !name) { if (!id || !name) {
return fail(400, { error: '标签 ID 和名称为必填项' }); return fail(400, { error: 'ID 和名称为必填项' });
} }
try { try {
@@ -96,9 +96,9 @@ export const actions: Actions = {
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error updating tag:', err); console.error('Error updating tag:', err);
if ((err as any)?.message?.includes('UNIQUE constraint failed')) { if ((err as any)?.message?.includes('UNIQUE constraint failed')) {
return fail(400, { error: '标签名称已存在' }); return fail(400, { error: '名称已存在' });
} }
return fail(500, { error: '更新标签失败' }); return fail(500, { error: '更新失败' });
} }
} }
}; };