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:
@@ -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 }));
|
||||
}
|
||||
Reference in New Issue
Block a user