feat: 增加系列相关服务端逻辑与 Hugo 元数据解析支持

This commit is contained in:
seahi committed 2026-08-06 12:14:13 +08:00
1 parent fe37e26e5f
commit 592d4e1f6d
2 files changed
+59 -1

No files matched your search

+11 -1
View File
@@ -10,6 +10,8 @@ export interface HugoPostData {
updated_at: string; updated_at: string;
categories: string[]; categories: string[];
tags: string[]; tags: string[];
series: string[];
series_weight: number | null;
} }
/** /**
@@ -41,6 +43,12 @@ function parseArrayField(val: unknown): string[] {
return []; return [];
} }
function parseIntegerField(val: unknown): number | null {
if (val === null || val === undefined || val === '') return null;
const parsed = typeof val === 'number' ? val : Number(String(val).trim());
return Number.isInteger(parsed) ? parsed : null;
}
/** /**
* 去掉文件名结尾的格式拓展名,提供纯文件名基础 * 去掉文件名结尾的格式拓展名,提供纯文件名基础
*/ */
@@ -120,6 +128,8 @@ export function parseHugoMarkdown(rawContent: string, fileName = ''): HugoPostDa
published_at, published_at,
updated_at, updated_at,
categories: parseArrayField(meta.categories || meta.category), categories: parseArrayField(meta.categories || meta.category),
tags: parseArrayField(meta.tags || meta.tag) tags: parseArrayField(meta.tags || meta.tag),
series: parseArrayField(meta.series),
series_weight: parseIntegerField(meta.series_weight)
}; };
} }
+48
View File
@@ -0,0 +1,48 @@
export class SeriesValidationError extends Error {}
export function parseSeriesId(value: FormDataEntryValue | null): number | null {
if (value === null || value.toString().trim() === '') return null;
const id = Number(value);
if (!Number.isInteger(id) || id <= 0) {
throw new SeriesValidationError('系列选择无效');
}
return id;
}
export function parseSeriesWeight(value: FormDataEntryValue | null): number | null {
if (value === null || value.toString().trim() === '') return null;
const weight = Number(value);
if (!Number.isInteger(weight)) {
throw new SeriesValidationError('系列顺序必须是整数');
}
return weight;
}
export async function resolveSeriesWeight(
db: D1Database,
seriesId: number | null,
requestedWeight: number | null,
excludePostId?: string
): Promise<number | null> {
if (seriesId === null) return null;
const series = await db.prepare('SELECT id FROM series WHERE id = ?').bind(seriesId).first();
if (!series) {
throw new SeriesValidationError('所选系列不存在');
}
if (requestedWeight !== null) return requestedWeight;
const query = excludePostId
? 'SELECT COALESCE(MAX(series_weight), 0) + 1 AS next_weight FROM posts WHERE series_id = ? AND id != ?'
: 'SELECT COALESCE(MAX(series_weight), 0) + 1 AS next_weight FROM posts WHERE series_id = ?';
const result = excludePostId
? await db.prepare(query).bind(seriesId, excludePostId).first<{ next_weight: number }>()
: await db.prepare(query).bind(seriesId).first<{ next_weight: number }>();
return result?.next_weight ?? 1;
}