feat: 增加系列相关服务端逻辑与 Hugo 元数据解析支持
This commit is contained in:
1 parent
fe37e26e5f
commit
592d4e1f6d
2 files changed
+59
-1
No files matched your search
+11
-1
@@ -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)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user