Files
Zhengen 4bbd6947da feat: 补全剩余 6 个 StreamField Block 前端渲染 (ProductCard/Pricing/Timeline/Team/TechStack/Video)
- types/wagtail.ts 新增对应 6 个 Block 值类型接口及 StreamFieldBlock 联合类型分支
- 新建 6 个渲染组件:ProductCardGrid/Pricing/Timeline/Team/TechStack/Video,风格与既有 Block 一致
- BlockRenderer.tsx 映射表接入新组件,key 与后端 COMMON_BLOCKS 保持一致
- lint/build 均验证通过
2026-08-07 15:59:08 +08:00

283 lines
6.3 KiB
TypeScript

/**
* Wagtail API v2 通用类型定义。
* 对应后端 apps/core/blocks.py 中的 StreamField Block 结构,
* 前后端字段需保持一致(详见 documents/设计方案分析与完善版.md §2.6)。
*/
export interface WagtailMeta {
type: string;
detail_url: string;
html_url: string | null;
slug: string;
first_published_at: string | null;
}
export interface WagtailPageSummary {
id: number;
meta: WagtailMeta;
title: string;
}
export interface WagtailListResponse<T> {
meta: { total_count: number };
items: T[];
}
export interface CTAButtonValue {
text: string;
link: string;
}
export interface StatItemValue {
value: string;
label: string;
}
export interface FeatureItemValue {
icon?: string;
title: string;
description: string;
}
export interface FAQItemValue {
question: string;
answer: string; // richtext HTML
}
export interface HeroBlockValue {
title: string;
subtitle?: string;
background_image?: { url: string; title: string } | null;
buttons: CTAButtonValue[];
}
export interface StatsBlockValue {
items: StatItemValue[];
}
export interface FeatureGridBlockValue {
heading?: string;
items: FeatureItemValue[];
}
export interface FAQBlockValue {
items: FAQItemValue[];
}
export interface CTABlockValue {
heading: string;
description?: string;
button: CTAButtonValue;
}
export interface LogoCloudBlockValue {
heading?: string;
logos: { url: string; title: string }[];
}
export interface CaseStudyBlockValue {
case_page: WagtailPageSummary | null;
summary?: string;
}
/** 与后端 apps/forms/models.py FIELD_TYPE_CHOICES 保持一致 */
export type FormFieldType = "text" | "textarea" | "email" | "tel" | "select";
export interface FormFieldDef {
label: string;
field_key: string;
field_type: FormFieldType;
required: boolean;
choices: string[];
}
export interface FormDefinitionValue {
id: number;
name: string;
submit_button_text: string;
success_message: string;
fields: FormFieldDef[];
}
export interface FormBlockValue {
form: FormDefinitionValue | null;
}
export interface ProductCardItemValue {
title: string;
description?: string;
image?: { url: string; title: string } | null;
link?: string;
}
export interface ProductCardBlockValue {
heading?: string;
items: ProductCardItemValue[];
}
export interface PricingPlanValue {
name: string;
price: string;
features: string[];
highlighted?: boolean;
button?: CTAButtonValue | null;
}
export interface PricingBlockValue {
heading?: string;
plans: PricingPlanValue[];
}
export interface TimelineItemValue {
year: string;
event: string;
}
export interface TimelineBlockValue {
heading?: string;
items: TimelineItemValue[];
}
export interface TeamMemberBlockValue {
id: number;
name: string;
role: string;
bio: string;
photo: { url: string; title: string } | null;
}
export interface TeamBlockValue {
heading?: string;
members: TeamMemberBlockValue[];
}
export interface TechStackItemValue {
icon?: string;
label: string;
}
export interface TechStackBlockValue {
heading?: string;
items: TechStackItemValue[];
}
export interface VideoBlockValue {
heading?: string;
video_url: string;
poster?: { url: string; title: string } | null;
}
export type StreamFieldBlock =
| { id: string; type: "hero"; value: HeroBlockValue }
| { id: string; type: "stats"; value: StatsBlockValue }
| { id: string; type: "feature_grid"; value: FeatureGridBlockValue }
| { id: string; type: "faq"; value: FAQBlockValue }
| { id: string; type: "cta"; value: CTABlockValue }
| { id: string; type: "logo_cloud"; value: LogoCloudBlockValue }
| { id: string; type: "case_study"; value: CaseStudyBlockValue }
| { id: string; type: "form"; value: FormBlockValue }
| { id: string; type: "product_card"; value: ProductCardBlockValue }
| { id: string; type: "pricing"; value: PricingBlockValue }
| { id: string; type: "timeline"; value: TimelineBlockValue }
| { id: string; type: "team"; value: TeamBlockValue }
| { id: string; type: "tech_stack"; value: TechStackBlockValue }
| { id: string; type: "video"; value: VideoBlockValue }
| { id: string; type: "richtext"; value: string };
export interface HomePageDetail extends WagtailPageSummary {
body: StreamFieldBlock[];
seo_title_override?: string;
seo_description_override?: string;
}
export interface BlogPageSummary extends WagtailPageSummary {
intro?: string;
published_at?: string;
}
export interface BlogPageDetail extends BlogPageSummary {
body: StreamFieldBlock[];
}
export interface ProductPageSummary extends WagtailPageSummary {
summary?: string;
}
export interface ProductPageDetail extends ProductPageSummary {
body: StreamFieldBlock[];
}
export interface CaseStudyPageSummary extends WagtailPageSummary {
client_name: string;
industry?: string;
published_at?: string;
summary?: string;
}
export interface CaseStudyPageDetail extends CaseStudyPageSummary {
body: StreamFieldBlock[];
}
export interface SolutionPageSummary extends WagtailPageSummary {
industry?: string;
summary?: string;
}
export interface SolutionPageDetail extends SolutionPageSummary {
body: StreamFieldBlock[];
}
export interface SimpleContentPageDetail extends WagtailPageSummary {
body: string; // richtext HTML
}
/**
* 全局 Snippet 类型(apps/core/models.py)。
* 通过 /api/v1/custom/core/... 只读接口获取,非 Wagtail Page API。
*/
export interface TeamMemberValue {
id: number;
name: string;
role: string;
bio: string;
photo: { url: string; title: string } | null;
}
export interface TestimonialValue {
id: number;
quote: string;
author_name: string;
author_title: string;
author_photo: { url: string; title: string } | null;
}
export interface PartnerValue {
id: number;
name: string;
website_url: string;
logo: { url: string; title: string } | null;
}
export interface NavigationMenuItemValue {
label: string;
url: string;
open_in_new_tab: boolean;
}
export interface NavigationMenuValue {
name: string;
items: NavigationMenuItemValue[];
}
export interface SiteSettingsValue {
company_name: string;
contact_phone: string;
contact_email: string;
address: string;
icp_number: string;
icp_url: string;
wechat_account: string;
weibo_url: string;
wechat_qrcode: { url: string; title: string } | null;
}