Files

82 lines
2.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { draftMode, cookies } from "next/headers";
import { fetchAPI } from "./api-client";
import type { WagtailPageSummary } from "@/types/wagtail";
/**
* Wagtail 预览模式(wagtail_headless_preview + Next.js Draft Mode)。
* 详见 documents/设计方案分析与完善版.md §2.16,后端实现见 apps/api/urls.py
* 的 PagePreviewAPIViewSet(挂载在 /api/v2/page_preview/)。
*/
export const PREVIEW_CONTENT_TYPE_COOKIE = "wagtail_preview_content_type";
export const PREVIEW_TOKEN_COOKIE = "wagtail_preview_token";
/** content_type`app_label.model`,小写)→ 对应前端路由的解析函数 */
const PREVIEW_PATH_RESOLVERS: Record<
string,
(page: WagtailPageSummary) => string
> = {
"home.homepage": () => "/",
"blog.blogpage": (page) => `/blog/${page.meta.slug}`,
"products.productpage": (page) => `/products/${page.meta.slug}`,
"cases.casestudypage": (page) => `/cases/${page.meta.slug}`,
"solutions.solutionpage": (page) => `/solutions/${page.meta.slug}`,
};
/** 根据 content_type 解析预览内容应跳转到的前端路径,未知类型返回 null。 */
export function resolvePreviewPath(
contentType: string,
page: WagtailPageSummary,
): string | null {
const resolver = PREVIEW_PATH_RESOLVERS[contentType];
return resolver ? resolver(page) : null;
}
/**
* 拉取草稿页面数据。`fields` 省略时仅返回 Wagtail API 默认字段(含 meta.slug/meta.type),
* 用于 /preview 路由校验 token 是否有效。
*/
export async function fetchPreviewPage<T extends WagtailPageSummary>(
contentType: string,
token: string,
fields?: string,
): Promise<T | null> {
const query = new URLSearchParams({ content_type: contentType, token });
if (fields) {
query.set("fields", fields);
}
try {
return await fetchAPI<T>(`/api/v2/page_preview/?${query.toString()}`, {
revalidate: 0,
});
} catch {
return null;
}
}
/**
* 在页面组件中调用:若 Draft Mode 已开启且 cookie 中记录的 content_type
* 与当前页面类型一致,返回草稿数据;否则回退到 `fallback()`(正常已发布内容)。
*/
export async function getPreviewOrFallback<T extends WagtailPageSummary>(
expectedContentType: string,
fields: string,
fallback: () => Promise<T | null>,
): Promise<T | null> {
const { isEnabled } = await draftMode();
if (!isEnabled) {
return fallback();
}
const cookieStore = await cookies();
const contentType = cookieStore.get(PREVIEW_CONTENT_TYPE_COOKIE)?.value;
const token = cookieStore.get(PREVIEW_TOKEN_COOKIE)?.value;
if (contentType !== expectedContentType || !token) {
return fallback();
}
const preview = await fetchPreviewPage<T>(expectedContentType, token, fields);
return preview ?? fallback();
}