refactor: 优化后台管理界面的提示文案和错误处理
This commit is contained in:
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)}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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: '更新失败' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -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: '保存修改失败' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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: '保存修改失败' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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: '删除失败' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -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: '更新失败' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Reference in new issue
Block a user