Files
novalon-website/prisma/seed.ts
T
张翔 10404dbb36 chore: sync marketing pages, CMS extensions, tests and project docs
同步工作区剩余变更,主要包括:
- 营销页面组件与布局持续优化(about/news/services/solutions/team 等)
- 详情页四层叙事组件、布局组件、UI 组件调整
- CMS 数据模型、API 路由、权限、工作流、站内通知、媒体管理扩展
- 新增/补充单元测试与 E2E 测试(cms-workflow.spec.ts 等)
- ESLint 9 迁移、jest/tsconfig 配置更新、依赖调整
- 新增 ADR、CMS 评估文档、Release Review / Acceptance 报告
- 移除水墨装饰组件与大体积未使用字体文件
2026-07-25 08:04:01 +08:00

891 lines
35 KiB
TypeScript
Raw 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 'dotenv/config';
import { PrismaClient } from '../src/generated/prisma/client';
import { hashPassword } from '../src/lib/auth';
import { CONTENT_TYPE_CONFIGS } from '../src/lib/cms/content-types';
import { PRIVACY_POLICY_HTML, TERMS_OF_SERVICE_HTML } from './seeds/legal-pages';
import { CASE_STUDIES } from './seeds/case-studies';
import { NEWS } from '../src/lib/constants/news';
import { SERVICES } from './seeds/services';
import { PRODUCTS } from './seeds/products';
import { STANDALONE_PRODUCTS } from './seeds/standalone-products';
import { SOLUTIONS } from './seeds/solutions';
import { STATS } from '../src/lib/constants/stats';
import { COMPANY_INFO } from '../src/lib/constants/company';
import { NAVIGATION_V2, MEGA_DROPDOWN_DATA } from '../src/lib/constants/navigation';
const prisma = new PrismaClient();
async function getModelId(code: string): Promise<string> {
const model = await prisma.contentModel.findUnique({ where: { code } });
if (!model) throw new Error(`模型 ${code} 未找到`);
return model.id;
}
async function seedItems(
modelCode: string,
items: Record<string, unknown>[],
options: { slugField?: string; titleField?: string } = {},
) {
const modelId = await getModelId(modelCode);
const slugField = options.slugField || 'slug';
const titleField = options.titleField || 'title';
for (let i = 0; i < items.length; i++) {
const item = items[i]!;
const slug = String(item[slugField] || item.id || `${modelCode}-${i}`);
const title = String(item[titleField] || `未命名 ${i + 1}`);
const data = item as Record<string, unknown>;
await prisma.contentItem.upsert({
where: { modelCode_slug_locale: { modelCode, slug, locale: 'zh-CN' } },
update: {
title,
data: JSON.stringify(data),
sortOrder: i,
status: 'published',
publishedAt: new Date(),
},
create: {
modelId,
modelCode,
title,
slug,
data: JSON.stringify(data),
sortOrder: i,
status: 'published',
publishedAt: new Date(),
createdBy: 'system',
updatedBy: 'system',
},
});
}
}
async function seedHomeZones() {
const heroItem = await prisma.contentItem.findFirst({
where: { modelCode: 'hero-banner', status: 'published' },
orderBy: { sortOrder: 'asc' },
});
const statItems = await prisma.contentItem.findMany({
where: { modelCode: 'stat-item', status: 'published' },
orderBy: { sortOrder: 'asc' },
take: 4,
});
const serviceItems = await prisma.contentItem.findMany({
where: { modelCode: 'service', status: 'published' },
orderBy: { sortOrder: 'asc' },
take: 6,
});
const solutionItems = await prisma.contentItem.findMany({
where: { modelCode: 'solution', status: 'published' },
orderBy: { sortOrder: 'asc' },
take: 6,
});
const caseItems = await prisma.contentItem.findMany({
where: { modelCode: 'case-study', status: 'published' },
orderBy: { sortOrder: 'asc' },
});
const featuredCaseItems = caseItems
.filter((item) => {
try {
const data = JSON.parse(item.data) as Record<string, unknown>;
return data.featured === true;
} catch {
return false;
}
})
.slice(0, 3);
const newsItems = await prisma.contentItem.findMany({
where: { modelCode: 'news', status: 'published' },
orderBy: { sortOrder: 'asc' },
take: 3,
});
const zones = [
{
code: 'home-hero',
name: '首页 - Hero Banner',
pageCode: 'home',
zoneKey: 'hero',
allowedModels: ['hero-banner'],
items: heroItem ? [{ itemId: heroItem.id, sortOrder: 0, variant: 'default' }] : [],
},
{
code: 'home-stats',
name: '首页 - 数据指标',
pageCode: 'home',
zoneKey: 'stats',
allowedModels: ['stat-item'],
items: statItems.map((item, i) => ({ itemId: item.id, sortOrder: i, variant: 'default' })),
},
{
code: 'home-services',
name: '首页 - 服务展示',
pageCode: 'home',
zoneKey: 'services',
allowedModels: ['service'],
items: serviceItems.map((item, i) => ({ itemId: item.id, sortOrder: i, variant: 'default' })),
},
{
code: 'home-solutions',
name: '首页 - 解决方案',
pageCode: 'home',
zoneKey: 'solutions',
allowedModels: ['solution'],
items: solutionItems.map((item, i) => ({ itemId: item.id, sortOrder: i, variant: 'default' })),
},
{
code: 'home-cases',
name: '首页 - 精选案例',
pageCode: 'home',
zoneKey: 'cases',
allowedModels: ['case-study'],
items: featuredCaseItems.map((item, i) => ({ itemId: item.id, sortOrder: i, variant: 'default' })),
},
{
code: 'home-news',
name: '首页 - 新闻动态',
pageCode: 'home',
zoneKey: 'news',
allowedModels: ['news'],
items: newsItems.map((item, i) => ({ itemId: item.id, sortOrder: i, variant: 'default' })),
},
];
for (const zone of zones) {
await prisma.contentZone.upsert({
where: { code: zone.code },
update: {
name: zone.name,
pageCode: zone.pageCode,
zoneKey: zone.zoneKey,
allowedModels: JSON.stringify(zone.allowedModels),
items: JSON.stringify(zone.items),
},
create: {
code: zone.code,
name: zone.name,
pageCode: zone.pageCode,
zoneKey: zone.zoneKey,
allowedModels: JSON.stringify(zone.allowedModels),
items: JSON.stringify(zone.items),
},
});
console.log(` ✅ 区域: ${zone.name}`);
}
}
async function main() {
console.log('🌱 开始数据库初始化...');
// ============ 1. 创建管理员用户 ============
console.log('📝 创建管理员用户...');
const adminPassword = await hashPassword('admin123');
const adminUser = await prisma.user.upsert({
where: { username: 'admin' },
update: {},
create: {
username: 'admin',
password: adminPassword,
nickname: '管理员',
role: 'admin',
status: 1,
},
});
console.log(' ✅ 管理员: admin / admin123');
// ============ 1.5 创建 RBAC 角色与权限 ============
console.log('📝 创建 RBAC 角色与权限...');
const roleCodes = ['super_admin', 'content_admin', 'content_editor', 'reviewer', 'readonly'];
for (const code of roleCodes) {
const nameMap: Record<string, string> = {
super_admin: '超级管理员',
content_admin: '内容管理员',
content_editor: '内容编辑',
reviewer: '审核员',
readonly: '只读用户',
};
await prisma.role.upsert({
where: { code },
update: {},
create: { code, name: nameMap[code] || code },
});
}
const contentModels = [
'news',
'product',
'solution',
'service',
'case-study',
'team',
'legal',
'about-page',
'hero-banner',
'stat-item',
'standalone-product',
'media',
];
// 为 super_admin 之外的角色创建权限
const permissionMatrix: Array<{ roleCode: string; actions: string[]; models?: string[] }> = [
{
roleCode: 'content_admin',
actions: ['create', 'read', 'update', 'delete', 'publish'],
models: contentModels,
},
{
roleCode: 'content_editor',
actions: ['create', 'read', 'update'],
models: contentModels,
},
{
roleCode: 'reviewer',
actions: ['read', 'publish'],
models: contentModels,
},
{
roleCode: 'readonly',
actions: ['read'],
models: contentModels,
},
];
for (const { roleCode, actions, models } of permissionMatrix) {
if (!models) continue;
for (const modelCode of models) {
for (const action of actions) {
await prisma.permission.upsert({
where: {
roleCode_modelCode_action: {
roleCode,
modelCode,
action,
},
},
update: {},
create: {
roleCode,
modelCode,
action,
},
});
}
}
}
// 为 admin 用户分配 super_admin 角色
await prisma.userRole.upsert({
where: {
userId_roleCode: {
userId: adminUser.id,
roleCode: 'super_admin',
},
},
update: {},
create: {
userId: adminUser.id,
roleCode: 'super_admin',
},
});
// 为 E2E 测试创建固定角色账号
console.log('📝 创建 E2E 测试用户...');
const editorPassword = await hashPassword('editor123');
const reviewerPassword = await hashPassword('reviewer123');
const e2eEditor = await prisma.user.upsert({
where: { username: 'e2e_editor' },
update: {},
create: {
username: 'e2e_editor',
password: editorPassword,
nickname: 'E2E 编辑',
role: 'content_editor',
status: 1,
},
});
const e2eReviewer = await prisma.user.upsert({
where: { username: 'e2e_reviewer' },
update: {},
create: {
username: 'e2e_reviewer',
password: reviewerPassword,
nickname: 'E2E 审核',
role: 'reviewer',
status: 1,
},
});
await prisma.userRole.upsert({
where: { userId_roleCode: { userId: e2eEditor.id, roleCode: 'content_editor' } },
update: {},
create: { userId: e2eEditor.id, roleCode: 'content_editor' },
});
await prisma.userRole.upsert({
where: { userId_roleCode: { userId: e2eReviewer.id, roleCode: 'reviewer' } },
update: {},
create: { userId: e2eReviewer.id, roleCode: 'reviewer' },
});
console.log(' ✅ E2E 测试用户: e2e_editor / editor123, e2e_reviewer / reviewer123');
console.log(' ✅ RBAC 角色与权限初始化完成');
// ============ 2. 创建内容模型 ============
console.log('📝 创建内容模型...');
const modelConfigs = [
...Object.values(CONTENT_TYPE_CONFIGS),
// === about-page ===
{
model: {
code: 'about-page',
name: '关于我们',
description: '公司介绍、核心价值、发展历程与资质认证信息',
isPageType: true,
urlPattern: '/about',
hasVersions: true,
hasDraft: true,
icon: 'building2',
fields: [
{ name: 'heroSubtitle', type: 'text', label: 'Hero 标签', required: true },
{ name: 'heroTitle', type: 'text', label: 'Hero 主标题', required: true },
{ name: 'heroDescription', type: 'textarea', label: 'Hero 描述', required: true },
{ name: 'whoWeAreTitle', type: 'text', label: '"我们是谁"标题' },
{ name: 'whoWeAreDescription', type: 'textarea', label: '"我们是谁"描述' },
{ name: 'promise', type: 'textarea', label: '承诺标语', required: true },
{ name: 'coreValues', type: 'array', label: '核心价值观', fields: [
{ name: 'number', type: 'text', label: '编号' },
{ name: 'title', type: 'text', label: '标题' },
{ name: 'description', type: 'textarea', label: '描述' },
]},
{ name: 'milestones', type: 'array', label: '发展历程', fields: [
{ name: 'year', type: 'text', label: '年份' },
{ name: 'title', type: 'text', label: '标题' },
{ name: 'description', type: 'textarea', label: '描述' },
{ name: 'highlight', type: 'text', label: '亮点' },
]},
{ name: 'keyMetrics', type: 'array', label: '关键指标', fields: [
{ name: 'value', type: 'text', label: '数值' },
{ name: 'label', type: 'text', label: '标签' },
{ name: 'sub', type: 'text', label: '副文本' },
]},
{ name: 'certifications', type: 'array', label: '资质认证', fields: [
{ name: 'name', type: 'text', label: '名称' },
{ name: 'desc', type: 'text', label: '描述' },
{ name: 'icon', type: 'text', label: '图标名称' },
]},
{ name: 'partners', type: 'array', label: '合作伙伴', fields: [
{ name: 'name', type: 'text', label: '名称' },
]},
{ name: 'ctaTitle', type: 'text', label: 'CTA 标题' },
{ name: 'ctaDescription', type: 'textarea', label: 'CTA 描述' },
],
},
},
// === team-page ===
{
model: {
code: 'team-page',
name: '团队介绍',
description: '团队实力、文化氛围、数据指标',
isPageType: true,
urlPattern: '/team',
hasVersions: true,
hasDraft: true,
icon: 'users',
fields: [
{ name: 'heroSubtitle', type: 'text', label: 'Hero 标签', required: true },
{ name: 'heroTitle', type: 'textarea', label: 'Hero 主标题', required: true },
{ name: 'heroDescription', type: 'textarea', label: 'Hero 描述', required: true },
{ name: 'stats', type: 'array', label: '统计指标', fields: [
{ name: 'value', type: 'number', label: '数值' },
{ name: 'suffix', type: 'text', label: '后缀' },
{ name: 'label', type: 'text', label: '标签' },
]},
{ name: 'strengths', type: 'array', label: '团队优势', fields: [
{ name: 'icon', type: 'text', label: '图标名称' },
{ name: 'number', type: 'text', label: '编号' },
{ name: 'title', type: 'text', label: '标题' },
{ name: 'description', type: 'textarea', label: '描述' },
]},
{ name: 'culture', type: 'array', label: '团队文化', fields: [
{ name: 'icon', type: 'text', label: '图标名称' },
{ name: 'number', type: 'text', label: '编号' },
{ name: 'title', type: 'text', label: '标题' },
{ name: 'description', type: 'textarea', label: '描述' },
]},
{ name: 'teamAboutTitle', type: 'text', label: '团队介绍标题' },
{ name: 'ctaTitle', type: 'text', label: 'CTA 标题' },
{ name: 'ctaDescription', type: 'textarea', label: 'CTA 描述' },
],
},
},
// === contact-page ===
{
model: {
code: 'contact-page',
name: '联系我们',
description: '联系信息、工作时间与服务承诺',
isPageType: true,
urlPattern: '/contact',
hasVersions: true,
hasDraft: true,
icon: 'phone',
fields: [
{ name: 'heroSubtitle', type: 'text', label: 'Hero 标签', required: true },
{ name: 'heroTitle', type: 'textarea', label: 'Hero 主标题', required: true },
{ name: 'heroDescription', type: 'textarea', label: 'Hero 描述', required: true },
{ name: 'companyName', type: 'text', label: '公司名称', required: true },
{ name: 'companyEmail', type: 'text', label: '联系邮箱', required: true },
{ name: 'companyAddress', type: 'text', label: '公司地址', required: true },
{ name: 'workHoursWeekday', type: 'text', label: '工作日描述' },
{ name: 'workHoursTime', type: 'text', label: '工作时间段' },
{ name: 'promises', type: 'array', label: '服务承诺', fields: [
{ name: 'text', type: 'textarea', label: '承诺内容' },
]},
{ name: 'ctaTitle', type: 'text', label: 'CTA 标题' },
{ name: 'ctaDescription', type: 'textarea', label: 'CTA 描述' },
],
},
},
// === site-config ===
{
model: {
code: 'site-config',
name: '站点配置',
description: '公司基本信息、SEO 元数据等全局配置',
isPageType: false,
urlPattern: '',
hasVersions: false,
hasDraft: true,
icon: 'settings',
fields: [
{ name: 'name', type: 'text', label: '公司全称', required: true },
{ name: 'shortName', type: 'text', label: '公司简称', required: true },
{ name: 'displayName', type: 'text', label: '展示名称', required: true },
{ name: 'slogan', type: 'text', label: '品牌标语', required: true },
{ name: 'description', type: 'textarea', label: '公司简介', required: true },
{ name: 'founded', type: 'text', label: '成立年份' },
{ name: 'location', type: 'text', label: '所在地' },
{ name: 'email', type: 'text', label: '联系邮箱', required: true },
{ name: 'address', type: 'text', label: '办公地址', required: true },
{ name: 'icp', type: 'text', label: 'ICP 备案号' },
{ name: 'police', type: 'text', label: '公安备案号' },
],
},
},
// === navigation ===
{
model: {
code: 'navigation',
name: '导航菜单',
description: '主导航项和下拉菜单内容',
isPageType: false,
urlPattern: '',
hasVersions: false,
hasDraft: true,
icon: 'menu',
fields: [
{ name: 'mainNav', type: 'json', label: '主导航项', required: true },
{ name: 'megaDropdown', type: 'json', label: '下拉菜单数据', required: true },
],
},
},
// === legal-page ===
{
model: {
code: 'legal-page',
name: '法律页面',
description: '隐私政策/服务条款页面内容配置',
isPageType: false,
urlPattern: '',
hasVersions: false,
hasDraft: true,
icon: 'file-text',
fields: [
{ name: 'pageType', type: 'text', label: '页面类型', required: true, options: [
{ label: '隐私政策', value: 'privacy' },
{ label: '服务条款', value: 'terms' },
]},
{ name: 'heroTitle', type: 'text', label: '页面标题', required: true },
{ name: 'heroDescription', type: 'textarea', label: '页面描述' },
{ name: 'lastUpdated', type: 'text', label: '最后更新日期', required: true },
{ name: 'content', type: 'richtext', label: '页面正文(HTML', required: true, description: '隐私政策/服务条款完整正文,支持 HTML 标签' },
],
},
},
];
for (let i = 0; i < modelConfigs.length; i++) {
const config = modelConfigs[i]!;
await prisma.contentModel.upsert({
where: { code: config.model.code },
update: {
name: config.model.name,
description: config.model.description,
fields: JSON.stringify(config.model.fields),
isPageType: config.model.isPageType,
urlPattern: config.model.urlPattern || '',
hasVersions: config.model.hasVersions,
hasDraft: config.model.hasDraft,
icon: config.model.icon || '',
sortOrder: i,
},
create: {
code: config.model.code,
name: config.model.name,
description: config.model.description,
fields: JSON.stringify(config.model.fields),
isPageType: config.model.isPageType,
urlPattern: config.model.urlPattern || '',
hasVersions: config.model.hasVersions,
hasDraft: config.model.hasDraft,
icon: config.model.icon || '',
sortOrder: i,
},
});
console.log(` ✅ 模型: ${config.model.name} (${config.model.code})`);
}
// ============ 3. 导入内容数据 ============
console.log('📝 导入首页 Hero Banner...');
await seedItems('hero-banner', [
{
slug: 'home',
title: '首页 Hero Banner',
eyebrow: '企业数字化转型',
heading: '让每一家企业都拥有数据驱动的决策能力',
subheading: '12 年深耕,从战略规划到系统落地,陪伴制造、零售、医疗、金融、教育、物流六大行业客户实现可衡量的业务改善。',
headingTop: '四川睿新致远科技有限公司',
headingBottom: '让技术成为业务增长引擎',
ctaLabel: '预约咨询',
ctaHref: '/contact',
secondaryCtaLabel: '了解我们的方法论',
secondaryCtaHref: '/services/consulting',
statValue: '500+',
statSubtext: '企业数字化转型实践',
ctaTitleLine1: '每一次合作,',
ctaTitleLine2: '真正转化为业务增长',
},
]);
console.log(' ✅ 首页 Hero Banner');
console.log('📝 导入案例研究...');
await seedItems('case-study', CASE_STUDIES as unknown as Record<string, unknown>[]);
console.log(`${CASE_STUDIES.length} 个案例`);
console.log('📝 导入新闻...');
await seedItems('news', NEWS as unknown as Record<string, unknown>[]);
console.log(`${NEWS.length} 条新闻`);
console.log('📝 导入服务...');
const homeServiceFields: Record<string, { subtitle: string; desc: string; highlights: string[]; metrics: { value: string; label: string }[]; href: string }> = {
consulting: {
subtitle: '战略咨询',
desc: '数字化转型战略规划与落地路径设计,让技术投资真正驱动业务增长。从愿景制定到执行落地,陪伴企业穿越转型周期。',
highlights: ['数字化成熟度评估', '转型路线图设计', '技术选型评估', '组织变革管理'],
metrics: [
{ value: '50+', label: '咨询项目' },
{ value: '90%+', label: '方案落地率' },
],
href: '/services/consulting',
},
software: {
subtitle: '企业软件',
desc: 'ERP、CRM、BI 等核心系统的评估、实施与定制化开发,基于行业最佳实践打造适配企业实际的数字化底座。',
highlights: ['ERP 实施优化', 'CRM 客户管理', 'BI 商业智能', '系统集成'],
metrics: [
{ value: '95%+', label: '准时交付率' },
{ value: '<4h', label: '平均响应' },
],
href: '/services/software',
},
data: {
subtitle: '技术服务',
desc: '系统集成、数据中台、云原生架构设计与技术外包服务,以工程化能力保障系统的稳定性、可扩展性与持续迭代。',
highlights: ['数据中台建设', '云原生迁移', '研发效能提升', '7x24 运维'],
metrics: [
{ value: '20+', label: '数据源对接' },
{ value: '99.9%', label: '系统可用率' },
],
href: '/services/data',
},
solutions: {
subtitle: 'AI 赋能',
desc: 'AI 成熟度评估、场景落地与大模型应用开发,帮助企业找到 AI 与业务的最佳结合点,实现智能化升级。',
highlights: ['AI 战略规划', '大模型应用开发', '智能流程自动化', 'AI 模型训练'],
metrics: [
{ value: '30+', label: 'AI 场景落地' },
{ value: '85%', label: '平均效率提升' },
],
href: '/services/solutions',
},
};
const servicesForSeed = SERVICES.map((s) => ({
...s,
...homeServiceFields[s.id],
}));
await seedItems('service', servicesForSeed as unknown as Record<string, unknown>[]);
console.log(`${SERVICES.length} 个服务`);
console.log('📝 导入产品...');
await seedItems('product', PRODUCTS as unknown as Record<string, unknown>[]);
console.log(`${PRODUCTS.length} 个产品`);
console.log('📝 导入独立产品...');
await seedItems('standalone-product', STANDALONE_PRODUCTS as unknown as Record<string, unknown>[]);
console.log(`${STANDALONE_PRODUCTS.length} 个独立产品`);
console.log('📝 导入解决方案...');
await seedItems('solution', SOLUTIONS as unknown as Record<string, unknown>[]);
console.log(`${SOLUTIONS.length} 个解决方案`);
// 数据指标需要特殊处理
console.log('📝 导入数据指标...');
const statList = Array.isArray(STATS) ? STATS : (STATS as { stats?: unknown[] }).stats || [];
const statModelId = await getModelId('stat-item');
for (let i = 0; i < statList.length; i++) {
const s = statList[i] as Record<string, unknown>;
const slug = `stat-${i}`;
const title = String(s.label || `指标 ${i + 1}`);
const { id: _id, ...data } = s;
await prisma.contentItem.upsert({
where: { modelCode_slug_locale: { modelCode: 'stat-item', slug, locale: 'zh-CN' } },
update: {
title,
data: JSON.stringify({ ...data, accentColor: s.color }),
sortOrder: i,
status: 'published',
publishedAt: new Date(),
},
create: {
modelId: statModelId,
modelCode: 'stat-item',
title,
slug,
data: JSON.stringify({ ...data, accentColor: s.color }),
sortOrder: i,
status: 'published',
publishedAt: new Date(),
createdBy: 'system',
updatedBy: 'system',
},
});
}
console.log(`${statList.length} 个数据指标`);
// ============ 4. 导入页面内容 ============
console.log('📝 导入关于页面...');
await seedItems('about-page', [
{
slug: 'default',
title: '关于我们',
heroSubtitle: '关于我们',
heroTitle: '12 年深耕\n500+ 企业\n的转型伙伴',
heroDescription: '我们不把项目完成当作终点。您的业务增长了吗?您的团队能力提升了吗?\n这才是我们真正在意的事。',
heroCtaText: '预约咨询',
heroCtaLink: '/contact',
heroSecondaryCtaText: '了解服务',
heroSecondaryCtaLink: '/services',
whoWeAreTitle: '我们是谁',
whoWeAreDescription: '我们坚持对行业趋势的深度研究,不追逐昙花一现的概念。每一次方案,都源于对您业务场景的洞察;每一次连接,都为了让技术真正服务于您的未来。',
promise: '不卖您用不上的技术,不说不懂业务的术语,不做路过就忘的一锤子买卖。',
coreValues: [
{ number: '01', title: '结果导向', description: '不以「项目上线」为终点,以「客户业务是否真正改善」为衡量标准。每一次交付,都追求可量化的价值。' },
{ number: '02', title: '长期主义', description: '不追逐风口,只做真正为客户创造价值的事。您的下一次难题,还愿意第一个想到我们——这才是我们追求的成功。' },
{ number: '03', title: '技术驱动', description: '用扎实的工程能力和行业经验赢得信任。技术不是炫技的工具,而是解决真实问题的手段。' },
],
milestones: [
{ year: '2014', title: '团队启航', description: '核心团队始于大型企业数字化转型项目,深耕 ERP、CRM 实施与定制开发。', highlight: '服务首批 20+ 企业客户' },
{ year: '2018', title: '业务扩展', description: '从单一实施服务向全链路咨询转型,建立战略咨询 + 技术落地的双轮驱动模式。', highlight: '客户突破 100 家' },
{ year: '2021', title: '产品化起步', description: '开始自研产品矩阵,从项目制向「产品+服务」双模式升级。', highlight: '3 款自研产品上线' },
{ year: '2023', title: '行业深耕', description: '聚焦制造、零售、医疗三大核心行业,建立行业解决方案库与最佳实践沉淀。', highlight: '客户续约率 95%+' },
{ year: '2026', title: '睿新致远成立', description: '四川睿新致远科技有限公司在成都正式成立,以全新品牌开启下一段征程。', highlight: '全新启航,步履不停' },
],
keyMetrics: [
{ value: '500+', label: '服务企业', sub: '六大行业覆盖' },
{ value: '200+', label: '专业顾问', sub: '平均行业经验 8 年' },
{ value: '98%', label: '客户满意度', sub: '97% 续约率' },
{ value: '12年', label: '行业深耕', sub: 'since 2014' },
],
certifications: [
{ name: 'ISO 27001', description: '信息安全管理体系认证', icon: 'Shield' },
{ name: 'ISO 9001', description: '质量管理体系认证', icon: 'Award' },
{ name: 'CMMI 3级', description: '软件能力成熟度认证', icon: 'Zap' },
{ name: '高新技术企业', description: '国家高新技术企业认定', icon: 'Trophy' },
],
partners: [
'SAP', 'Oracle', 'Salesforce', 'Microsoft',
'阿里云', '腾讯云', '华为云', '金蝶',
],
ctaTitle: '准备好开始了吗?',
ctaDescription: '无论您是想了解合作机会,还是希望深入探讨具体方案,都欢迎随时联系。',
},
]);
console.log(' ✅ 关于页面');
console.log('📝 导入团队页面...');
await seedItems('team-page', [
{
slug: 'default',
title: '团队介绍',
heroSubtitle: '核心团队',
heroTitle: '既懂技术又懂业务的\n复合型团队',
heroDescription: '我们的成员不只是写代码的工程师——我们是能理解您业务场景、能和您一起想清楚问题的合作伙伴。',
heroPrimaryCtaLabel: '加入我们',
heroPrimaryCtaHref: '/contact',
heroSecondaryCtaLabel: '了解公司',
heroSecondaryCtaHref: '/about',
stats: [
{ value: 12, suffix: '+', label: '年行业经验' },
{ value: 10, suffix: '+', label: '核心成员' },
{ value: 5, suffix: '+', label: '行业覆盖' },
],
strengths: [
{ iconName: 'Shield', number: '01', title: '12 年+ 行业深耕', description: '核心团队长期从事技术咨询、企业数字化等领域,服务覆盖金融、制造、零售、政务、农业等多个行业。' },
{ iconName: 'Building2', number: '02', title: '大型 IT 企业背景', description: '开发团队成员来自多个大型传统 IT 企业,具备扎实的工程能力、规范化的交付流程和严格的质量意识。' },
{ iconName: 'Users', number: '03', title: '复合型技术团队', description: '既懂技术又懂业务,能够深入理解客户的真实场景和痛点,提供真正可落地的解决方案。' },
{ iconName: 'Code', number: '04', title: '全栈技术能力', description: '从前端到后端、从云原生到数据智能、从移动端到物联网——应对各种复杂技术挑战。' },
{ iconName: 'Target', number: '05', title: '结果导向交付', description: '不以"项目上线"为终点,以"客户业务是否真正改善"为衡量标准。每一个交付成果都追求可量化的业务价值。' },
],
culture: [
{ iconName: 'Layers', number: '01', title: '扁平化协作', description: '没有冗长的汇报链条,每个人都有机会直接参与决策。信息透明,沟通高效。' },
{ iconName: 'BookOpen', number: '02', title: '持续学习', description: '技术日新月异,我们保持对新技术的好奇。内部分享、技术沙龙、外部培训——学习是日常的一部分。' },
{ iconName: 'Sparkles', number: '03', title: '客户成功', description: '我们的成就感来自客户的成功。客户的业务增长,就是我们最好的成绩单。' },
],
aboutTitle: '关于我们的团队',
aboutParagraphs: [
{ text: '我们的核心团队长期从事技术咨询、企业数字化等行业,拥有 12 年以上的深厚积累。' },
{ text: '开发团队成员来自于多个大型传统 IT 企业,具备扎实的工程能力和规范化的交付经验。' },
{ text: '我们相信,优秀的技术咨询不仅需要过硬的技术能力,更需要深入理解客户的业务场景和真实需求。每一位成员都是既懂技术又懂业务的复合型人才。' },
],
ctaTitle: '想成为我们的一员?',
ctaDescription: '我们始终在寻找既懂技术又热爱业务的伙伴。如果您认同我们的理念,欢迎聊聊。',
ctaPrimaryLabel: '联系我们',
ctaPrimaryHref: '/contact',
ctaSecondaryLabel: '了解公司',
ctaSecondaryHref: '/about',
},
]);
console.log(' ✅ 团队页面');
console.log('📝 导入联系页面...');
await seedItems('contact-page', [
{
slug: 'default',
title: '联系我们',
heroSubtitle: '联系我们',
heroTitle: '随时欢迎\n聊一聊',
heroDescription: '工作日 2 小时内快速响应,首次咨询免费。\n没有销售压力,只是坐下来把问题理清楚。',
email: 'contact@novalon.cn',
address: '中国四川省成都市龙泉驿区幸福路12号',
commitmentItems: [
'工作日 2 小时内快速响应您的咨询',
'提供免费的业务咨询和方案评估服务',
'根据您的需求量身定制最优解决方案',
],
contactTitle: '联系方式',
emailLabel: '邮箱',
addressLabel: '地址',
workHoursTitle: '工作时间',
dayLabel: '周一至周五',
hours: '9:00 - 18:00',
commitmentTitle: '服务承诺',
formTitle: '发送消息',
submitLabel: '发送消息',
submittingLabel: '发送中…',
successTitle: '消息已发送',
successMessage: '感谢您的留言,我们会尽快与您联系。',
ctaSubtitle: '更直接的方式',
ctaTitle: '还是想直接聊?',
ctaDescription: '表单填起来太麻烦?直接发邮件到 contact@novalon.cn,我们同样会快速回复。',
ctaPrimaryLabel: '发送邮件',
ctaPrimaryHref: 'mailto:contact@novalon.cn',
ctaSecondaryLabel: '返回首页',
ctaSecondaryHref: '/',
},
]);
console.log(' ✅ 联系页面');
console.log('📝 导入法律页面...');
await seedItems('legal-page', [
{
slug: 'privacy',
title: '隐私政策',
pageType: 'privacy',
heroTitle: '隐私政策',
heroDescription: '我们重视您的隐私,致力于保护您的个人信息安全',
lastUpdated: '2026-02-26',
content: PRIVACY_POLICY_HTML,
},
{
slug: 'terms',
title: '服务条款',
pageType: 'terms',
heroTitle: '服务条款',
heroDescription: '请仔细阅读以下服务条款,使用我们的服务即表示您同意这些条款',
lastUpdated: '2026-02-26',
content: TERMS_OF_SERVICE_HTML,
},
]);
console.log(' ✅ 法律页面');
console.log('📝 导入站点配置...');
await seedItems('site-config', [
{
slug: 'default',
title: '站点配置',
name: COMPANY_INFO.name,
shortName: COMPANY_INFO.shortName,
displayName: COMPANY_INFO.displayName,
slogan: COMPANY_INFO.slogan,
description: COMPANY_INFO.description,
founded: COMPANY_INFO.founded,
location: COMPANY_INFO.location,
email: COMPANY_INFO.email,
address: COMPANY_INFO.address,
icp: COMPANY_INFO.icp,
police: COMPANY_INFO.police,
},
]);
console.log(' ✅ 站点配置');
console.log('📝 导入导航菜单...');
await seedItems('navigation', [
{
slug: 'default',
title: '导航菜单',
mainNav: NAVIGATION_V2,
megaDropdown: MEGA_DROPDOWN_DATA,
},
]);
console.log(' ✅ 导航菜单');
// ============ 5. 创建默认内容区域 ============
console.log('📝 创建默认内容区域...');
await seedHomeZones();
console.log(' ✅ 首页内容区域创建完成');
// ============ 统计 ============
const itemCount = await prisma.contentItem.count();
const modelCount = await prisma.contentModel.count();
const zoneCount = await prisma.contentZone.count();
console.log('\n🎉 数据库初始化完成!');
console.log(` 📊 内容模型: ${modelCount}`);
console.log(` 📄 内容条目: ${itemCount}`);
console.log(` 🗂️ 内容区域: ${zoneCount}`);
console.log(` 👤 管理员: admin / admin123`);
}
main()
.catch((e) => {
console.error('❌ 种子数据初始化失败:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});