feat: 初始化慧遇书院官网一期
This commit is contained in:
205
server/utils/site-schema.ts
Normal file
205
server/utils/site-schema.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
const localOrHttpUrl = z.string().max(300).refine(value => !value || value.startsWith('/') || /^https?:\/\//i.test(value), '请输入站内路径或以 http(s) 开头的完整链接')
|
||||
const httpUrl = z.string().max(300).refine(value => !value || /^https?:\/\//i.test(value), '请输入以 http(s) 开头的完整链接')
|
||||
|
||||
const metricSchema = z.object({
|
||||
value: z.string().max(20),
|
||||
label: z.string().max(30),
|
||||
description: z.string().max(80),
|
||||
})
|
||||
|
||||
const productSchema = z.object({
|
||||
slug: z.string().regex(/^[a-z0-9-]+$/).max(80),
|
||||
title: z.string().max(60),
|
||||
subtitle: z.string().max(80),
|
||||
type: z.enum(['course', 'service', 'tool']).default('course'),
|
||||
summary: z.string().max(300).default(''),
|
||||
content: z.string().max(6000).default(''),
|
||||
image: localOrHttpUrl,
|
||||
href: localOrHttpUrl,
|
||||
status: z.enum(['draft', 'published', 'offline']).default('draft'),
|
||||
})
|
||||
|
||||
const articleSchema = z.object({
|
||||
slug: z.string().regex(/^[a-z0-9-]+$/).max(100),
|
||||
type: z.enum(['news', 'statement', 'media']),
|
||||
title: z.string().min(1).max(120),
|
||||
summary: z.string().max(300),
|
||||
content: z.string().max(12000),
|
||||
cover: localOrHttpUrl,
|
||||
publishedAt: z.string().max(40),
|
||||
status: z.enum(['draft', 'published', 'offline']),
|
||||
statementNo: z.string().max(60).default(''),
|
||||
sourceName: z.string().max(80).default(''),
|
||||
sourceUrl: httpUrl.default(''),
|
||||
})
|
||||
|
||||
const teamMemberSchema = z.object({
|
||||
slug: z.string().regex(/^[a-z0-9-]+$/).max(80),
|
||||
name: z.string().min(1).max(40),
|
||||
role: z.string().max(80),
|
||||
summary: z.string().max(300),
|
||||
avatar: localOrHttpUrl,
|
||||
specialties: z.array(z.string().max(30)).max(8),
|
||||
status: z.enum(['draft', 'published', 'offline']),
|
||||
})
|
||||
|
||||
const channelSchema = z.object({
|
||||
name: z.string().min(1).max(40),
|
||||
account: z.string().max(80),
|
||||
url: httpUrl,
|
||||
qrCode: localOrHttpUrl,
|
||||
})
|
||||
|
||||
const siteDocumentBaseSchema = z.object({
|
||||
brand: z.object({
|
||||
name: z.string().min(1).max(40),
|
||||
englishName: z.string().max(80),
|
||||
logo: localOrHttpUrl,
|
||||
slogan: z.string().min(1).max(40),
|
||||
subSlogan: z.string().max(80),
|
||||
companyName: z.string().max(100).default('待后台配置'),
|
||||
creditCode: z.string().max(40).default('待后台配置'),
|
||||
introduction: z.string().max(500).default(''),
|
||||
copyright: z.string().max(100).default('© 2026 慧遇书院 版权所有'),
|
||||
icp: z.string().max(80).default('备案信息待配置'),
|
||||
policeRecord: z.string().max(80).default(''),
|
||||
}),
|
||||
hero: z.object({
|
||||
titleLine1: z.string().min(1).max(20),
|
||||
titleLine2: z.string().min(1).max(20),
|
||||
subtitle: z.string().max(80),
|
||||
cta: z.string().max(20),
|
||||
backgroundImage: localOrHttpUrl,
|
||||
}),
|
||||
about: z.object({
|
||||
title: z.string().max(40),
|
||||
summary: z.string().max(300),
|
||||
metrics: z.array(metricSchema).min(1).max(4),
|
||||
}),
|
||||
teacher: z.object({
|
||||
name: z.string().max(30),
|
||||
title: z.string().max(80),
|
||||
summary: z.string().max(400),
|
||||
portrait: localOrHttpUrl,
|
||||
tags: z.array(z.string().max(20)).max(6),
|
||||
fullBio: z.string().max(8000).default(''),
|
||||
experiences: z.array(z.object({ year: z.string().max(20), title: z.string().max(100), description: z.string().max(300) })).max(20).default([]),
|
||||
achievements: z.array(z.string().max(120)).max(12).default([]),
|
||||
externalLinks: z.array(z.object({ label: z.string().max(40), url: httpUrl })).max(10).default([]),
|
||||
}),
|
||||
products: z.array(productSchema).max(8),
|
||||
articles: z.array(articleSchema).max(60).default([]),
|
||||
team: z.array(teamMemberSchema).max(30).default([]),
|
||||
channels: z.array(channelSchema).max(12).default([]),
|
||||
contact: z.object({
|
||||
phone: z.string().max(30),
|
||||
email: z.string().max(100),
|
||||
address: z.string().max(160),
|
||||
}),
|
||||
seo: z.object({
|
||||
title: z.string().max(70),
|
||||
description: z.string().max(180),
|
||||
}),
|
||||
legal: z.object({
|
||||
privacyTitle: z.string().max(80).default('隐私政策'),
|
||||
privacyContent: z.string().max(12000).default(''),
|
||||
termsTitle: z.string().max(80).default('服务条款'),
|
||||
termsContent: z.string().max(12000).default(''),
|
||||
}).default({ privacyTitle: '隐私政策', privacyContent: '', termsTitle: '服务条款', termsContent: '' }),
|
||||
})
|
||||
|
||||
export const siteDocumentSchema = siteDocumentBaseSchema.superRefine((document, context) => {
|
||||
const ensureUnique = (items: Array<{ slug: string }>, field: 'products' | 'articles' | 'team') => {
|
||||
const seen = new Set<string>()
|
||||
items.forEach((item, index) => {
|
||||
if (seen.has(item.slug)) context.addIssue({ code: 'custom', path: [field, index, 'slug'], message: `英文标识“${item.slug}”重复` })
|
||||
seen.add(item.slug)
|
||||
})
|
||||
}
|
||||
ensureUnique(document.products, 'products')
|
||||
ensureUnique(document.articles, 'articles')
|
||||
ensureUnique(document.team, 'team')
|
||||
})
|
||||
|
||||
export type SiteDocument = z.infer<typeof siteDocumentSchema>
|
||||
|
||||
export const defaultSiteDocument: SiteDocument = {
|
||||
brand: {
|
||||
name: '慧遇书院',
|
||||
englishName: 'HUIYU ACADEMY',
|
||||
logo: '/images/brand-mark-v2.png',
|
||||
slogan: '身心疗愈 · 科技赋能',
|
||||
subSlogan: '用科技与专业,陪伴每一次心灵的成长',
|
||||
companyName: '慧遇书院',
|
||||
creditCode: '待后台配置',
|
||||
introduction: '慧遇书院专注于家庭教育、心理成长与长期成长实践。当前公司主体信息为演示内容,正式上线前需完成核验与替换。',
|
||||
copyright: '© 2026 慧遇书院 版权所有',
|
||||
icp: 'ICP备案信息待配置',
|
||||
policeRecord: '',
|
||||
},
|
||||
hero: {
|
||||
titleLine1: '身心疗愈',
|
||||
titleLine2: '科技赋能',
|
||||
subtitle: '用科技与专业,陪伴每一次心灵的成长',
|
||||
cta: '了解慧遇书院',
|
||||
backgroundImage: '/images/hero-bg-v3.webp',
|
||||
},
|
||||
about: {
|
||||
title: '关于慧遇书院',
|
||||
summary: '慧遇书院专注于身心疗愈与成长领域,以专业内容与长期实践陪伴心灵成长。',
|
||||
metrics: [
|
||||
{ value: '身心', label: '专注领域', description: '疗愈与成长' },
|
||||
{ value: '10万+', label: '陪伴学员', description: '持续连接与支持' },
|
||||
{ value: '2018', label: '成立时间', description: '长期主义实践' },
|
||||
],
|
||||
},
|
||||
teacher: {
|
||||
name: '卢慧老师',
|
||||
title: '家庭教育与心理学研究者|慧遇书院创始人',
|
||||
summary: '长期从事家庭教育与心理成长实践,探索东方智慧与现代心理学在家庭场景中的融合应用。',
|
||||
portrait: '/images/lu-hui-portrait.jpg',
|
||||
tags: ['家庭教育', '心理成长', '关系支持', '东方智慧'],
|
||||
fullBio: '卢慧老师长期从事家庭教育与心理成长实践,关注个体在家庭关系、亲密关系与自我成长中的真实需要。\n\n她持续探索东方智慧与现代心理学在日常生活中的融合应用,并通过课程、陪伴与内容分享,帮助更多人建立稳定、清晰、可持续的成长路径。\n\n以上为官网演示介绍,正式发布前应以经本人确认的资料为准。',
|
||||
experiences: [
|
||||
{ year: '2024', title: '持续完善身心整合实践体系', description: '结合真实家庭场景,形成结构化的陪伴与成长方法。' },
|
||||
{ year: '2021', title: '出版与内容传播', description: '围绕家庭教育、关系与自我成长开展内容分享。' },
|
||||
{ year: '2018', title: '创立慧遇书院', description: '持续开展家庭教育与心理成长实践。' },
|
||||
],
|
||||
achievements: ['长期开展家庭教育与心理成长实践', '持续研发结构化陪伴与成长课程', '推动东方智慧与现代心理学融合应用'],
|
||||
externalLinks: [{ label: '百度百科', url: 'https://baike.baidu.com/item/%E5%8D%A2%E6%85%A7/65761247' }],
|
||||
},
|
||||
products: [
|
||||
{ slug: 'family-relationship', title: '家庭关系训练营', subtitle: '关注关系与代际议题', type: 'course', summary: '从真实家庭场景出发,理解关系互动背后的需要与模式。', content: '课程内容为演示信息,正式上线前需由运营人员在后台核验与替换。\n\n课程将围绕觉察、沟通和关系实践展开,帮助参与者把理解转化为日常行动。', image: '/images/hero-bg-v3.webp', href: '/products/family-relationship', status: 'published' },
|
||||
{ slug: 'human-wisdom', title: '人本智慧学', subtitle: '从觉知走向实践', type: 'course', summary: '以长期主义的方式理解自我、关系与成长。', content: '本页面为产品结构演示,具体课程体系、适用人群和服务安排待后台补充。', image: '/images/hero-bg-v3.webp', href: '/products/human-wisdom', status: 'published' },
|
||||
{ slug: 'companion-assistant', title: '智能陪伴助手', subtitle: '科技赋能日常练习', type: 'tool', summary: '让日常觉察和练习更清晰、更容易坚持。', content: '该产品当前处于演示阶段,正式能力与使用入口以后台发布信息为准。', image: '/images/hero-bg-v3.webp', href: '/products/companion-assistant', status: 'published' },
|
||||
],
|
||||
articles: [
|
||||
{ slug: 'official-information-notice', type: 'statement', title: '慧遇书院官方信息说明(演示)', summary: '用于说明官网、官方账号与对外信息的统一发布原则。', content: '本页面为官方声明结构演示。正式上线前,需要由运营人员替换为经审核的真实声明内容。', cover: '/images/hero-bg-v3.webp', publishedAt: '2026-08-10', status: 'published', statementNo: 'HUIYU-DEMO-001', sourceName: '', sourceUrl: '' },
|
||||
{ slug: 'website-phase-one', type: 'news', title: '慧遇书院官网一期建设启动', summary: '官网将成为品牌、人物、课程与官方信息的统一可信入口。', content: '慧遇书院官网一期建设已经启动。首阶段将完成品牌信息、卢慧老师资料、课程产品、官方声明与团队介绍的结构化呈现。\n\n当前内容包含演示数据,生产发布前将通过后台统一核验。', cover: '/images/hero-bg-v3.webp', publishedAt: '2026-08-10', status: 'published', statementNo: '', sourceName: '', sourceUrl: '' },
|
||||
],
|
||||
team: [
|
||||
{ slug: 'course-consultant', name: '课程顾问', role: '成长路径与课程支持', summary: '为来访者提供清晰、克制的课程信息说明。演示成员,待后台替换。', avatar: '/images/lu-hui-portrait.jpg', specialties: ['课程咨询', '成长支持'], status: 'published' },
|
||||
{ slug: 'content-editor', name: '内容老师', role: '品牌内容与知识整理', summary: '负责把专业内容整理成可信、易理解的表达。演示成员,待后台替换。', avatar: '/images/lu-hui-portrait.jpg', specialties: ['内容整理', '知识传播'], status: 'published' },
|
||||
],
|
||||
channels: [
|
||||
{ name: '微信公众号', account: '账号待后台配置', url: '', qrCode: '' },
|
||||
{ name: '视频号', account: '账号待后台配置', url: '', qrCode: '' },
|
||||
],
|
||||
contact: {
|
||||
phone: '待后台配置',
|
||||
email: '待后台配置',
|
||||
address: '待后台配置',
|
||||
},
|
||||
seo: {
|
||||
title: '慧遇书院|身心疗愈 专业陪伴',
|
||||
description: '慧遇书院官方网站,关注家庭教育、心理成长与长期成长实践。',
|
||||
},
|
||||
legal: {
|
||||
privacyTitle: '隐私政策',
|
||||
privacyContent: '更新日期:2026年8月10日\n\n本网站一期不提供用户注册、支付或在线咨询信息收集功能。访问过程中产生的必要技术日志仅用于保障网站安全与稳定。\n\n如后续增加表单、统计或第三方服务,本政策将同步更新并在收集前说明用途、范围与保存期限。',
|
||||
termsTitle: '服务条款',
|
||||
termsContent: '本网站内容用于介绍慧遇书院、卢慧老师、课程产品与官方信息。\n\n演示或待替换内容不构成正式服务承诺,正式课程与服务以经审核发布的页面及双方确认的协议为准。\n\n未经授权,不得以误导方式转载、改编或冒用本网站品牌与人物资料。',
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user