feat(assets): 更新 Logo 与图片资源,添加数据层服务模块

- 更新 logo.svg/logo-light.svg/logo-white.svg 品牌标识
- 新增 logo-calligraphy.svg 书法体 Logo 变体
- 新增新闻、二维码、微信业务等图片资源
- 删除旧版 JPEG 测试图片
- 新增 CMS 数据层服务模块 (admin-api, auth, cms, crypto, db)
- 新增 cases/cross-references/methodology/team 常量数据
- 新增 site-config 站点配置
This commit is contained in:
张翔
2026-07-07 06:54:47 +08:00
parent 636bc4ecde
commit 49dbced0cb
32 changed files with 4219 additions and 23 deletions
+174
View File
@@ -0,0 +1,174 @@
/**
* CMS 服务端数据访问层
* 从 Prisma 数据库直接读取已发布内容,供页面组件使用
*/
import { prisma } from '@/lib/db';
import { cache } from 'react';
import type { ContentItem, ContentStatus } from './types';
// ============ 类型转换 ============
function toContentItem(item: Record<string, unknown>): ContentItem {
return {
id: item.id as string,
modelId: item.modelId as string,
modelCode: item.modelCode as string,
title: item.title as string,
slug: (item.slug as string | null) ?? undefined,
status: item.status as ContentStatus,
data: JSON.parse(item.data as string),
version: item.version as number,
sortOrder: (item.sortOrder as number | null) ?? undefined,
publishedAt: (item.publishedAt as Date | null)?.toISOString(),
createdBy: item.createdBy as string,
updatedBy: item.updatedBy as string,
createdAt: (item.createdAt as Date).toISOString(),
updatedAt: (item.updatedAt as Date).toISOString(),
};
}
// ============ 内容条目查询 ============
/**
* 获取指定模型的已发布内容列表
*/
export const getPublishedItems = cache(async (modelCode: string): Promise<ContentItem[]> => {
const items = await prisma.contentItem.findMany({
where: { modelCode, status: 'published' },
orderBy: { sortOrder: 'asc' },
});
return items.map((item) => toContentItem(item as unknown as Record<string, unknown>));
});
/**
* 根据 slug 获取单条已发布内容
*/
export const getPublishedItemBySlug = cache(async (modelCode: string, slug: string): Promise<ContentItem | null> => {
const item = await prisma.contentItem.findFirst({
where: { modelCode, slug, status: 'published' },
});
if (!item) return null;
return toContentItem(item as unknown as Record<string, unknown>);
});
/**
* 根据 ID 获取单条内容(不限状态)
*/
export const getItemById = cache(async (id: string): Promise<ContentItem | null> => {
const item = await prisma.contentItem.findUnique({ where: { id } });
if (!item) return null;
return toContentItem(item as unknown as Record<string, unknown>);
});
// ============ 内容区域查询 ============
/**
* 获取指定页面的内容区域配置
*/
export const getPageZones = cache(async (pageCode: string) => {
const zones = await prisma.contentZone.findMany({
where: { pageCode },
});
return zones.map((z) => ({
...z,
allowedModels: JSON.parse(z.allowedModels),
items: JSON.parse(z.items),
settings: JSON.parse(z.settings),
}));
});
/**
* 获取单个内容区域
*/
export const getZone = cache(async (code: string) => {
const zone = await prisma.contentZone.findUnique({ where: { code } });
if (!zone) return null;
return {
...zone,
allowedModels: JSON.parse(zone.allowedModels),
items: JSON.parse(zone.items),
settings: JSON.parse(zone.settings),
};
});
// ============ 内容模型查询 ============
/**
* 获取所有内容模型
*/
export const getContentModels = cache(async () => {
const models = await prisma.contentModel.findMany({
orderBy: { sortOrder: 'asc' },
});
return models.map((m) => ({
...m,
fields: JSON.parse(m.fields),
}));
});
// ============ 便捷函数:按业务类型获取 ============
export async function getCases() {
return getPublishedItems('case-study');
}
export async function getNews() {
return getPublishedItems('news');
}
export async function getServices() {
return getPublishedItems('service');
}
export async function getProducts() {
return getPublishedItems('product');
}
export async function getSolutions() {
return getPublishedItems('solution');
}
export async function getStats() {
return getPublishedItems('stat-item');
}
export async function getHeroBanners() {
return getPublishedItems('hero-banner');
}
export async function getCaseBySlug(slug: string) {
return getPublishedItemBySlug('case-study', slug);
}
export async function getNewsBySlug(slug: string) {
return getPublishedItemBySlug('news', slug);
}
export async function getServiceBySlug(slug: string) {
return getPublishedItemBySlug('service', slug);
}
export async function getProductBySlug(slug: string) {
return getPublishedItemBySlug('product', slug);
}
export async function getSolutionBySlug(slug: string) {
return getPublishedItemBySlug('solution', slug);
}
export async function getHomePageZones() {
return getPageZones('home');
}
// ============ 静态生成辅助 ============
/**
* 获取所有已发布内容的 slug 列表(用于 generateStaticParams)
*/
export async function getAllPublishedSlugs(modelCode: string) {
const items = await prisma.contentItem.findMany({
where: { modelCode, status: 'published' },
select: { slug: true },
});
return items.filter((i) => i.slug).map((i) => ({ slug: i.slug }));
}