316 lines
15 KiB
JavaScript
316 lines
15 KiB
JavaScript
const { getDb, closeDb } = require('../config/database');
|
||
|
||
const createTables = () => {
|
||
const db = getDb();
|
||
|
||
// Entity表 - 知识实体表(P1-01增加entity_type,P1-02增加status/public_flag)
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS entities (
|
||
entity_id VARCHAR(36) PRIMARY KEY,
|
||
entity_type VARCHAR(64) DEFAULT 'concept',
|
||
name TEXT NOT NULL,
|
||
definition TEXT,
|
||
description TEXT,
|
||
status VARCHAR(32) DEFAULT 'active',
|
||
public_flag BOOLEAN DEFAULT 1,
|
||
authority_level INTEGER DEFAULT 1,
|
||
metadata TEXT,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
)
|
||
`);
|
||
|
||
// DirectedRelationship表 - 有向实体关系表
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS directed_relationships (
|
||
rel_id VARCHAR(36) PRIMARY KEY,
|
||
source_entity_id VARCHAR(36) NOT NULL,
|
||
relation_type VARCHAR(255) NOT NULL,
|
||
target_entity_id VARCHAR(36) NOT NULL,
|
||
rel_status VARCHAR(32) DEFAULT 'active',
|
||
authority_level INTEGER DEFAULT 1,
|
||
is_public BOOLEAN DEFAULT 0,
|
||
effective_at DATETIME,
|
||
expire_at DATETIME,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (source_entity_id) REFERENCES entities(entity_id),
|
||
FOREIGN KEY (target_entity_id) REFERENCES entities(entity_id)
|
||
)
|
||
`);
|
||
|
||
// Content基础表 - 内容基础模型
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS contents (
|
||
content_id VARCHAR(36) PRIMARY KEY,
|
||
title TEXT NOT NULL,
|
||
body TEXT,
|
||
content_type VARCHAR(32) NOT NULL,
|
||
publish_status VARCHAR(32) DEFAULT 'draft',
|
||
authority_level INTEGER DEFAULT 1,
|
||
version_no INTEGER DEFAULT 1,
|
||
version_note TEXT,
|
||
metadata TEXT,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
archived_at DATETIME
|
||
)
|
||
`);
|
||
|
||
// Page表 - 页面扩展(P1-03增加summary)
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS pages (
|
||
page_id VARCHAR(36) PRIMARY KEY,
|
||
slug VARCHAR(255) UNIQUE,
|
||
template VARCHAR(255),
|
||
summary TEXT,
|
||
seo_title TEXT,
|
||
seo_description TEXT,
|
||
seo_keywords TEXT,
|
||
FOREIGN KEY (page_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// Article表 - 文章扩展(P1-04增加published_at)
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS articles (
|
||
article_id VARCHAR(36) PRIMARY KEY,
|
||
category VARCHAR(255),
|
||
tags TEXT,
|
||
cover_image VARCHAR(1024),
|
||
author VARCHAR(255),
|
||
published_at DATETIME,
|
||
FOREIGN KEY (article_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// Case表 - 案例扩展(P0-01扩展完整案例字段)
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS cases (
|
||
case_id VARCHAR(36) PRIMARY KEY,
|
||
client_name TEXT,
|
||
industry TEXT,
|
||
challenge TEXT,
|
||
solution TEXT,
|
||
result TEXT,
|
||
background TEXT,
|
||
enterprise_stage TEXT,
|
||
original_goal TEXT,
|
||
current_state TEXT,
|
||
surface_problem TEXT,
|
||
amb_judgment TEXT,
|
||
key_obstacle TEXT,
|
||
root_cause TEXT,
|
||
evolution_path TEXT,
|
||
implementation TEXT,
|
||
case_significance TEXT,
|
||
FOREIGN KEY (case_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// FAQ表 - 常见问题扩展
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS faqs (
|
||
faq_id VARCHAR(36) PRIMARY KEY,
|
||
question TEXT,
|
||
answer TEXT,
|
||
sort_order INTEGER DEFAULT 0,
|
||
FOREIGN KEY (faq_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// Capability表 - 能力扩展
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS capabilities (
|
||
capability_id VARCHAR(36) PRIMARY KEY,
|
||
capability_type TEXT,
|
||
features TEXT,
|
||
use_cases TEXT,
|
||
FOREIGN KEY (capability_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// Service表 - 服务扩展
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS services (
|
||
service_id VARCHAR(36) PRIMARY KEY,
|
||
service_type TEXT,
|
||
pricing_model TEXT,
|
||
delivery_method TEXT,
|
||
FOREIGN KEY (service_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// EntityContentJoin表 - 实体-内容多对多关联中间表
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS entity_content_joins (
|
||
join_id VARCHAR(36) PRIMARY KEY,
|
||
entity_id VARCHAR(36) NOT NULL,
|
||
content_id VARCHAR(36) NOT NULL,
|
||
join_note TEXT,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (entity_id) REFERENCES entities(entity_id),
|
||
FOREIGN KEY (content_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
// 管理员账号表
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS admin_users (
|
||
user_id VARCHAR(36) PRIMARY KEY,
|
||
username VARCHAR(64) NOT NULL UNIQUE,
|
||
password_hash VARCHAR(255) NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
)
|
||
`);
|
||
|
||
// 前台可编辑站点配置
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS site_settings (
|
||
setting_key VARCHAR(128) PRIMARY KEY,
|
||
setting_value TEXT,
|
||
setting_group VARCHAR(64) DEFAULT 'general',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
)
|
||
`);
|
||
|
||
// 内容判断引擎发布映射:复用既有 contents/articles,而非建立第二套文章系统。
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS integration_publications (
|
||
publication_id VARCHAR(36) PRIMARY KEY,
|
||
content_id VARCHAR(36) NOT NULL UNIQUE,
|
||
source_system VARCHAR(64) NOT NULL,
|
||
source_task_id VARCHAR(128) NOT NULL,
|
||
source_version_id VARCHAR(128) NOT NULL,
|
||
source_version_number INTEGER NOT NULL,
|
||
site_profile VARCHAR(16) NOT NULL,
|
||
idempotency_key VARCHAR(255) NOT NULL UNIQUE,
|
||
content_hash VARCHAR(128) NOT NULL,
|
||
revision INTEGER NOT NULL DEFAULT 1,
|
||
slug VARCHAR(180) UNIQUE,
|
||
summary TEXT,
|
||
primary_keyword VARCHAR(255),
|
||
keywords_json TEXT,
|
||
source_content_type VARCHAR(64),
|
||
direction VARCHAR(255),
|
||
target_audience VARCHAR(255),
|
||
canonical_url VARCHAR(2048),
|
||
human_confirmed BOOLEAN NOT NULL DEFAULT 0,
|
||
confirmed_at DATETIME,
|
||
knowledge_refs_json TEXT,
|
||
entities_json TEXT,
|
||
questions_json TEXT,
|
||
facts_json TEXT,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
published_at DATETIME,
|
||
UNIQUE KEY uq_integration_source_task (source_system, source_task_id, site_profile),
|
||
FOREIGN KEY (content_id) REFERENCES contents(content_id)
|
||
)
|
||
`);
|
||
|
||
console.log('数据库表创建完成');
|
||
};
|
||
|
||
const migrate = () => {
|
||
try {
|
||
createTables();
|
||
seedAdminAndSettings();
|
||
console.log('数据库迁移完成');
|
||
} catch (error) {
|
||
console.error('数据库迁移失败:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
const seedAdminAndSettings = () => {
|
||
const db = getDb();
|
||
const crypto = require('crypto');
|
||
const user = db.prepare('SELECT user_id FROM admin_users WHERE username = ?').get('admin');
|
||
if (!user) {
|
||
const initialAdminPassword = process.env.ADMIN_INITIAL_PASSWORD;
|
||
if (!initialAdminPassword) {
|
||
throw new Error('首次初始化管理员账号需要配置 ADMIN_INITIAL_PASSWORD');
|
||
}
|
||
const salt = crypto.randomBytes(16).toString('hex');
|
||
const hash = crypto.scryptSync(initialAdminPassword, salt, 64).toString('hex');
|
||
db.prepare(`
|
||
INSERT INTO admin_users (user_id, username, password_hash)
|
||
VALUES (?, ?, ?)
|
||
`).run(require('uuid').v4(), 'admin', `${salt}:${hash}`);
|
||
console.log('默认管理员账号已创建: admin');
|
||
}
|
||
|
||
const defaults = {
|
||
'site.name': ['阿美巴AI', 'general'],
|
||
'site.footerCopyright': ['© 2026 阿美巴AI. All rights reserved.', 'general'],
|
||
'site.footerEmail': ['ameiba0258@gmail.com', 'general'],
|
||
'site.footerPhone': ['4009080258', 'general'],
|
||
'site.footerAddress': ['四川省成都市双流区正兴街道湖畔路北段366号1栋3楼1号', 'general'],
|
||
'site.icp': ['蜀ICP备2025143754号-7', 'general'],
|
||
'home.heroTitle': ['阿美巴(Ameiba)', 'home'],
|
||
'home.heroSubtitle': ['AI时代企业进化平台', 'home'],
|
||
'home.heroDescription': ['我们帮助企业在AI时代实现系统化进化,从战略顶层设计到组织重塑,从经营增长到AI部署,提供完整的企业进化能力与服务。', 'home'],
|
||
'contact.title': ['联系我们', 'contact'],
|
||
'contact.contactTitle': ['联系方式', 'contact'],
|
||
'contact.email': ['contact@ameiba.com', 'contact'],
|
||
'contact.phone': ['待填充', 'contact'],
|
||
'contact.address': ['待填充', 'contact'],
|
||
'contact.serviceHoursTitle': ['服务时间', 'contact'],
|
||
'contact.serviceHours': ['周一至周五:9:00 - 18:00', 'contact'],
|
||
'contact.consultationTitle': ['咨询服务', 'contact'],
|
||
'contact.consultationIntro': ['我们提供以下咨询服务:', 'contact'],
|
||
'contact.consultationItems': ['企业进化诊断\n进化路径规划\n战略咨询\n组织变革咨询\nAI部署咨询', 'contact'],
|
||
'contact.cooperationTitle': ['合作方式', 'contact'],
|
||
'contact.cooperationItems': ['顾问服务\n咨询服务\n企业陪跑\n定制化服务', 'contact'],
|
||
'contact.faqTitle': ['常见问题', 'contact'],
|
||
'contact.faqText': ['如有其他问题,请查看', 'contact'],
|
||
'contact.relatedTitle': ['相关知识', 'contact'],
|
||
};
|
||
const pageDefaults = {
|
||
about: ['阿美巴是谁', '阿美巴(Ameiba)是AI时代企业进化平台,专注于帮助企业实现系统化进化。'],
|
||
evolution: ['企业进化', '企业进化是企业围绕长期发展目标持续调整、重构与升级的过程。'],
|
||
value: ['四大价值', '价值创造、价值传递、价值交付、价值支持共同构成企业经营的价值体系。'],
|
||
amb: ['A/M/B三态模型:AI时代企业进化状态识别框架', 'A/M/B模型用于帮助企业识别自身所处的进化状态,并明确下一步行动。'],
|
||
capabilities: ['企业进化能力地图', '从战略、经营、组织到AI部署,构建企业持续进化所需要的能力地图。'],
|
||
cases: ['企业进化案例', '通过真实案例,展示企业在经营环境中的目标、障碍、进化路径与实施过程。'],
|
||
knowledge: ['知识中心', '集中展示企业进化相关的知识、方法和实践内容。'],
|
||
faq: ['常见问题', '以下是关于企业进化的常见问题解答。'],
|
||
};
|
||
Object.entries(pageDefaults).forEach(([page, [title, intro]]) => {
|
||
defaults[`${page}.title`] = [title, page];
|
||
defaults[`${page}.intro`] = [intro, page];
|
||
});
|
||
const extraDefaults = {
|
||
'amb.whatTitle': ['什么是A/M/B', 'amb'], 'amb.whatNote': ['A/M/B不是产品套餐,不是收费等级,不是强制线性路径,不是所有企业必须经历的三个固定阶段。', 'amb'], 'amb.whatPurpose': ['A/M/B的作用,是帮助企业识别自身所处状态,并进一步判断当前需要完成的关键进化动作。', 'amb'], 'amb.statesTitle': ['三种状态', 'amb'], 'amb.stateA': ['A态·入态|企业开始进入AI时代企业进化的一种状态', 'amb'], 'amb.stateM': ['M态·优态|企业进一步围绕现有经营与管理体系进行优化的一种状态', 'amb'], 'amb.stateB': ['B态·越态|企业突破原有运行边界、形成新的企业运行能力的一种状态', 'amb'], 'amb.recognitionTitle': ['状态识别', 'amb'], 'amb.recognitionText': ['企业可以根据自身情况处于不同状态,也不意味着所有企业必须从A到M再到B。\n企业需要根据自身发展阶段和实际情况,判断当前所处的状态,并确定需要完成的关键进化动作。', 'amb'],
|
||
'evolution.definitionTitle': ['什么是企业进化', 'evolution'], 'evolution.definitionMore': ['增长更多体现结果层变化。进化更强调底层能力、系统与企业状态的持续调整和升级。AI是时代变量和重要赋能工具,不是企业进化本身的终点。', 'evolution'], 'evolution.whyTitle': ['为什么需要企业进化', 'evolution'], 'evolution.whyIntro': ['在AI时代,企业面临着前所未有的挑战:', 'evolution'], 'evolution.whyItems': ['技术快速迭代,传统业务模式面临冲击\n客户需求变化,个性化、智能化要求提高\n竞争环境加剧,需要更高效的运营模式\n人才结构变化,需要新的组织能力', 'evolution'],
|
||
'value.overviewTitle': ['价值体系概述', 'value'], 'value.valuesTitle': ['四大价值', 'value'], 'value.relationTitle': ['价值体系的关系', 'value'], 'value.relationText': ['四大价值相互关联、相互支撑。价值创造是基础,价值传递是桥梁,价值交付是结果,价值支持是保障。企业需要在这四个维度上协调发展,才能实现持续增长。', 'value'],
|
||
'about.positionTitle': ['定位', 'about'], 'about.positionText': ['阿美巴(Ameiba)是AI时代企业进化平台,专注于帮助企业实现系统化进化,从战略顶层设计到组织重塑,从经营增长到AI部署,提供完整的企业进化能力与服务。', 'about'], 'about.existTitle': ['为什么存在', 'about'], 'about.existText': ['在AI时代,企业面临着前所未有的挑战与机遇。传统的企业管理方法已无法适应快速变化的环境,企业需要一套系统化的进化方法,实现从传统模式向AI时代模式的转型。\n阿美巴的存在,就是为了帮助企业完成这一进化过程,实现可持续增长与发展。', 'about'], 'about.audienceTitle': ['服务对象', 'about'], 'about.audienceText': ['我们服务的对象是那些希望在AI时代实现转型与增长的企业,无论企业当前处于哪个发展阶段,我们都能提供适合的进化路径与能力支持。', 'about'], 'about.historyTitle': ['发展历程', 'about'], 'about.historyText': ['待填充', 'about'],
|
||
'capabilities.overviewTitle': ['能力概述', 'capabilities'], 'capabilities.categoryTitle': ['能力分类', 'capabilities'], 'cases.overviewTitle': ['案例概述', 'cases'], 'cases.listTitle': ['案例列表', 'cases'], 'knowledge.systemTitle': ['知识体系', 'knowledge'], 'knowledge.categoryTitle': ['知识分类', 'knowledge'], 'knowledge.articleTitle': ['最新文章', 'knowledge'], 'faq.overviewTitle': ['FAQ概述', 'faq'], 'faq.listTitle': ['问题列表', 'faq'],
|
||
};
|
||
Object.entries(extraDefaults).forEach(([key, [value, group]]) => {
|
||
defaults[key] = [value, group];
|
||
});
|
||
Object.entries(defaults).forEach(([key, [value, group]]) => {
|
||
const existing = db.prepare('SELECT setting_key FROM site_settings WHERE setting_key = ?').get(key);
|
||
if (!existing) {
|
||
db.prepare('INSERT INTO site_settings (setting_key, setting_value, setting_group) VALUES (?, ?, ?)').run(key, value, group);
|
||
}
|
||
});
|
||
|
||
// 修正早期版本中误写的 A/M-B 文案;保留管理员已编辑的其他内容。
|
||
db.prepare(`
|
||
UPDATE site_settings
|
||
SET setting_value = REPLACE(setting_value, 'A/M-B', 'A/M/B'),
|
||
updated_at = CURRENT_TIMESTAMP
|
||
WHERE setting_value LIKE '%A/M-B%'
|
||
`).run();
|
||
};
|
||
|
||
if (require.main === module) {
|
||
migrate();
|
||
}
|
||
|
||
module.exports = { migrate, createTables, seedAdminAndSettings };
|