fix: 修复后台文章计数为0 + 分类编辑补全描述字段 + CSP放行外部图片 + 更新关于页描述

- 文章管理:计数请求补 page=1 参数,命中分页接口返回正确的 total
- 分类管理:编辑模式新增描述输入框,保存时一并提交 description
- CSP:img-src 加入 https: 允许加载外部图片
- 关于页:数据存储描述从 JSON 文件更正为 SQLite 数据库
- Footer:添加 ICP 备案号
This commit is contained in:
胡旭
2026-06-24 13:51:48 +08:00
parent 3707eddfd4
commit 18e915bcbb
69 changed files with 6818 additions and 1422 deletions
+40
View File
@@ -0,0 +1,40 @@
import { NextResponse } from "next/server";
import { ZodError } from "zod";
import { checkAuth } from "./auth";
/** 统一的未授权响应。 */
export function unauthorized() {
return NextResponse.json({ error: "未授权" }, { status: 401 });
}
/** 解析并校验请求体,失败时返回 422 响应(由调用方 return)。 */
export async function parseBody<T>(
request: Request,
schema: { parse: (d: unknown) => T }
): Promise<{ ok: true; data: T } | { ok: false; response: NextResponse }> {
try {
const json = await request.json();
const data = schema.parse(json);
return { ok: true, data };
} catch (err) {
if (err instanceof ZodError) {
return {
ok: false,
response: NextResponse.json(
{ error: "输入校验失败", issues: err.issues.map((i) => i.message) },
{ status: 422 }
),
};
}
return {
ok: false,
response: NextResponse.json({ error: "请求格式错误" }, { status: 400 }),
};
}
}
/** 在受保护路由开头做鉴权,未通过则返回 401 响应。 */
export async function requireAuth(): Promise<NextResponse | null> {
if (!(await checkAuth())) return unauthorized();
return null;
}