chore: prepare project for server deployment

This commit is contained in:
amb
2026-09-09 17:43:07 +08:00
commit d0bcff2311
83 changed files with 24163 additions and 0 deletions
+251
View File
@@ -0,0 +1,251 @@
import { Entity, DirectedRelationship, Content, Page, Article, Case, FAQ, Capability, Service, PaginatedResponse } from '@/types';
const API_BASE_URL = process.env.API_URL || 'http://localhost:3000';
// 通用请求函数
async function fetchApi<T>(endpoint: string, options?: RequestInit): Promise<T> {
const url = `${API_BASE_URL}${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
});
if (!response.ok) {
throw new Error(`API请求失败: ${response.status} ${response.statusText}`);
}
return response.json();
}
// 实体相关API
export const entityApi = {
// 获取实体列表
getList: (params?: { page?: number; pageSize?: number; orderBy?: string }) => {
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
if (params?.orderBy) searchParams.set('orderBy', params.orderBy);
return fetchApi<PaginatedResponse<Entity>>(`/api/entities?${searchParams.toString()}`);
},
// 获取实体详情
getById: (id: string) => fetchApi<Entity>(`/api/entities/${id}`),
// 公开接口:获取实体列表
getPublicList: (params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<Entity[]>(`/api/public/entities?${searchParams.toString()}`);
},
// 公开接口:获取实体详情
getPublicById: (id: string) => fetchApi<Entity>(`/api/public/entities/${id}`),
// 公开接口:获取实体的关系
getPublicRelationships: (id: string) => fetchApi<{ source: DirectedRelationship[]; target: DirectedRelationship[] }>(`/api/public/entities/${id}/relationships`),
// 公开接口:获取实体的内容
getPublicContents: (id: string) => fetchApi<Content[]>(`/api/public/entities/${id}/contents`),
};
// 关系相关API
export const relationshipApi = {
// 获取关系列表
getList: (params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<PaginatedResponse<DirectedRelationship>>(`/api/relationships?${searchParams.toString()}`);
},
// 获取关系详情
getById: (id: string) => fetchApi<DirectedRelationship>(`/api/relationships/${id}`),
// 获取实体的出向关系
getBySourceEntity: (entityId: string) => fetchApi<DirectedRelationship[]>(`/api/relationships/source/${entityId}`),
// 获取实体的入向关系
getByTargetEntity: (entityId: string) => fetchApi<DirectedRelationship[]>(`/api/relationships/target/${entityId}`),
};
// 内容相关API
export const contentApi = {
// 获取内容列表
getList: (type: string, params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<PaginatedResponse<Content>>(`/api/contents/${type}?${searchParams.toString()}`);
},
// 获取内容详情
getById: (type: string, id: string) => fetchApi<Content>(`/api/contents/${type}/${id}`),
// 公开接口:获取内容列表
getPublicList: (type?: string, params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams();
if (type) searchParams.set('type', type);
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<Content[]>(`/api/public/contents?${searchParams.toString()}`);
},
// 公开接口:获取内容详情
getPublicById: (id: string) => fetchApi<Content>(`/api/public/contents/${id}`),
// 公开接口:获取内容的实体关联
getPublicEntities: (id: string) => fetchApi<Entity[]>(`/api/public/contents/${id}/entities`),
};
// 页面相关API
export const pageApi = {
// 获取页面列表
getList: (params?: { page?: number; pageSize?: number }) => contentApi.getList('page', params),
// 获取页面详情
getById: (id: string) => contentApi.getById('page', id),
// 公开接口:获取页面列表
getPublicList: (params?: { page?: number; pageSize?: number }) => contentApi.getPublicList('page', params),
// 公开接口:获取页面详情
getPublicById: (id: string) => contentApi.getPublicById(id),
};
// 文章相关API
export const articleApi = {
// 获取文章列表
getList: (params?: { page?: number; pageSize?: number }) => contentApi.getList('article', params),
// 获取文章详情
getById: (id: string) => contentApi.getById('article', id),
// 公开接口:获取文章列表
getPublicList: (params?: { page?: number; pageSize?: number }) => contentApi.getPublicList('article', params),
// 公开接口:获取文章详情
getPublicById: (id: string) => contentApi.getPublicById(id),
};
// 案例相关API
export const caseApi = {
// 获取案例列表
getList: (params?: { page?: number; pageSize?: number }) => contentApi.getList('case', params),
// 获取案例详情
getById: (id: string) => contentApi.getById('case', id),
// 公开接口:获取案例列表
getPublicList: (params?: { page?: number; pageSize?: number }) => contentApi.getPublicList('case', params),
// 公开接口:获取案例详情
getPublicById: (id: string) => contentApi.getPublicById(id),
};
// FAQ相关API
export const faqApi = {
// 获取FAQ列表
getList: (params?: { page?: number; pageSize?: number }) => contentApi.getList('faq', params),
// 获取FAQ详情
getById: (id: string) => contentApi.getById('faq', id),
// 公开接口:获取FAQ列表
getPublicList: (params?: { page?: number; pageSize?: number }) => contentApi.getPublicList('faq', params),
// 公开接口:获取FAQ详情
getPublicById: (id: string) => contentApi.getPublicById(id),
};
// 能力相关API
export const capabilityApi = {
// 获取能力列表
getList: (params?: { page?: number; pageSize?: number }) => contentApi.getList('capability', params),
// 获取能力详情
getById: (id: string) => contentApi.getById('capability', id),
// 公开接口:获取能力列表
getPublicList: (params?: { page?: number; pageSize?: number }) => contentApi.getPublicList('capability', params),
// 公开接口:获取能力详情
getPublicById: (id: string) => contentApi.getPublicById(id),
};
// 服务相关API
export const serviceApi = {
// 获取服务列表
getList: (params?: { page?: number; pageSize?: number }) => contentApi.getList('service', params),
// 获取服务详情
getById: (id: string) => contentApi.getById('service', id),
// 公开接口:获取服务列表
getPublicList: (params?: { page?: number; pageSize?: number }) => contentApi.getPublicList('service', params),
// 公开接口:获取服务详情
getPublicById: (id: string) => contentApi.getPublicById(id),
};
// 关联相关API
export const joinApi = {
// 获取关联列表
getList: (params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<PaginatedResponse<{ join_id: string; entity_id: string; content_id: string; join_note?: string; created_at: string }>>(`/api/joins?${searchParams.toString()}`);
},
// 获取实体的所有关联
getByEntityId: (entityId: string) => fetchApi<{ join_id: string; entity_id: string; content_id: string; join_note?: string; created_at: string }[]>(`/api/joins/entity/${entityId}`),
// 获取内容的所有关联
getByContentId: (contentId: string) => fetchApi<{ join_id: string; entity_id: string; content_id: string; join_note?: string; created_at: string }[]>(`/api/joins/content/${contentId}`),
};
// 搜索相关API
export const searchApi = {
// 搜索实体
entities: (keyword: string, params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams({ keyword });
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<Entity[]>(`/api/public/search/entities?${searchParams.toString()}`);
},
// 搜索内容
contents: (keyword: string, type?: string, params?: { page?: number; pageSize?: number }) => {
const searchParams = new URLSearchParams({ keyword });
if (type) searchParams.set('type', type);
if (params?.page) searchParams.set('page', params.page.toString());
if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString());
return fetchApi<Content[]>(`/api/public/search/contents?${searchParams.toString()}`);
},
};
// JSON-LD相关API
export const jsonLdApi = {
// 获取实体的JSON-LD
getEntityJsonLd: (id: string) => fetchApi<Record<string, any>>(`/api/jsonld/entities/${id}`),
// 获取内容的JSON-LD
getContentJsonLd: (id: string) => fetchApi<Record<string, any>>(`/api/jsonld/contents/${id}`),
// 获取所有实体的JSON-LD列表
getAllEntitiesJsonLd: () => fetchApi<Record<string, any>[]>('/api/jsonld/entities'),
// 获取所有内容的JSON-LD列表
getAllContentsJsonLd: (type?: string) => {
const searchParams = new URLSearchParams();
if (type) searchParams.set('type', type);
return fetchApi<Record<string, any>[]>(`/api/jsonld/contents?${searchParams.toString()}`);
},
// 获取站点地图的JSON-LD
getSitemapJsonLd: () => fetchApi<Record<string, any>>('/api/jsonld/sitemap'),
};
+160
View File
@@ -0,0 +1,160 @@
import { SEOData, Breadcrumb, JsonLdData } from '@/types';
const SITE_NAME = '阿美巴AI官网';
const SITE_DESCRIPTION = '阿美巴AI - AI时代企业进化平台';
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://ameiba.com';
// 生成SEO数据
export function generateSEO(data: SEOData): Record<string, string> {
const title = data.title ? `${data.title} - ${SITE_NAME}` : SITE_NAME;
const description = data.description || SITE_DESCRIPTION;
const canonical = data.canonical ? `${SITE_URL}${data.canonical}` : SITE_URL;
return {
title,
description,
canonical,
'og:title': data.ogTitle || title,
'og:description': data.ogDescription || description,
'og:image': data.ogImage || `${SITE_URL}/og-default.jpg`,
'og:type': 'website',
'og:url': canonical,
'twitter:card': 'summary_large_image',
'twitter:title': data.ogTitle || title,
'twitter:description': data.ogDescription || description,
'twitter:image': data.ogImage || `${SITE_URL}/og-default.jpg`,
};
}
// 生成面包屑Schema
export function generateBreadcrumbSchema(breadcrumbs: Breadcrumb[]): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: breadcrumbs.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: `${SITE_URL}${item.url}`,
})),
};
}
// 生成组织Schema
export function generateOrganizationSchema(): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'Organization',
name: '阿美巴AI',
description: 'AI时代企业进化平台',
url: SITE_URL,
logo: `${SITE_URL}/logo.png`,
sameAs: [],
};
}
// 生成文章Schema
export function generateArticleSchema(data: {
title: string;
description: string;
url: string;
image?: string;
author?: string;
datePublished?: string;
dateModified?: string;
}): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'Article',
headline: data.title,
description: data.description,
image: data.image || `${SITE_URL}/og-default.jpg`,
url: `${SITE_URL}${data.url}`,
author: data.author ? {
'@type': 'Person',
name: data.author,
} : undefined,
publisher: {
'@type': 'Organization',
name: SITE_NAME,
logo: {
'@type': 'ImageObject',
url: `${SITE_URL}/logo.png`,
},
},
datePublished: data.datePublished,
dateModified: data.dateModified,
};
}
// 生成FAQ Schema
export function generateFAQSchema(faqs: Array<{ question: string; answer: string }>): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqs.map(faq => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
};
}
// 生成服务Schema
export function generateServiceSchema(data: {
name: string;
description: string;
url: string;
provider?: string;
}): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'Service',
name: data.name,
description: data.description,
url: `${SITE_URL}${data.url}`,
provider: data.provider ? {
'@type': 'Organization',
name: data.provider,
} : undefined,
};
}
// 生成案例Schema
export function generateCaseSchema(data: {
title: string;
description: string;
url: string;
image?: string;
}): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'Article',
headline: data.title,
description: data.description,
image: data.image || `${SITE_URL}/og-default.jpg`,
url: `${SITE_URL}${data.url}`,
articleSection: '案例',
};
}
// 生成网站搜索Schema
export function generateWebSiteSearchAction(): JsonLdData {
return {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: SITE_NAME,
url: SITE_URL,
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: `${SITE_URL}/search?q={search_term_string}`,
},
'query-input': 'required name=search_term_string',
},
};
}
+13
View File
@@ -0,0 +1,13 @@
const API_URL = process.env.API_URL || 'http://localhost:24731';
export type SiteSettings = Record<string, string>;
export async function getSiteSettings(): Promise<SiteSettings> {
try {
const response = await fetch(`${API_URL}/api/public/settings`, { cache: 'no-store' });
if (!response.ok) return {};
return response.json();
} catch {
return {};
}
}