diff --git a/server/api/content/[key].get.js b/server/api/content/[key].get.js index 9cb87ac..857864d 100644 --- a/server/api/content/[key].get.js +++ b/server/api/content/[key].get.js @@ -1,22 +1,168 @@ -import { eq } from 'drizzle-orm' +import { eq, desc, asc } from 'drizzle-orm' import { useDB, schema } from '../../utils/db.js' +/** + * 实体表数据构建器 + * 当 key 对应独立实体表时,从实体表动态读取数据, + * 同时合并 site_content 中的元数据(summary/seo 等) + */ +function buildFromEntityTable(db, key, siteData) { + switch (key) { + case 'reviews': { + const items = db.select().from(schema.reviews) + .where(eq(schema.reviews.published, true)) + .orderBy(asc(schema.reviews.sortOrder), desc(schema.reviews.id)) + .all() + .map(r => ({ + id: r.id, + nickname: r.author, + travelDate: r.date, + productVersion: r.title, + screenshot: '', + content: r.content, + rating: r.rating, + scenes: [], + concerns: [], + })) + // 合并 site_content 的 summary(如果有/ + const summary = siteData?.summary || { + totalCount: items.length, + approvalRate: '98%', + } + // 用实体表 items 覆盖 site_content 的 items + return { summary, items } + } + + case 'faq': { + const items = db.select().from(schema.faqs) + .where(eq(schema.faqs.published, true)) + .orderBy(asc(schema.faqs.sortOrder), asc(schema.faqs.id)) + .all() + // site_content 有分类结构则保留,把实体表的问答作为「全部」 + if (siteData?.categories) return siteData + return { + categories: [{ + id: 'all', + name: '常见问题', + questions: items.map(f => ({ + question: f.question, + answer: f.answer, + })), + }], + } + } + + case 'gallery': { + const items = db.select().from(schema.galleryItems) + .where(eq(schema.galleryItems.published, true)) + .orderBy(asc(schema.galleryItems.sortOrder), asc(schema.galleryItems.id)) + .all() + const works = items.map(g => ({ + id: g.id, + title: g.title, + category: g.category, + location: g.location, + description: g.description, + image: g.image, + orientation: g.orientation, + })) + const categories = siteData?.categories || [{key:"all",label:"全部作品"}] + return { + seo: siteData?.seo || {}, + intro: siteData?.intro || {}, + categories, + works, + } + } + + case 'stories': { + const items = db.select().from(schema.stories) + .where(eq(schema.stories.published, true)) + .orderBy(asc(schema.stories.sortOrder), desc(schema.stories.id)) + .all() + .map(s => ({ + ...s, + sections: s.sections ? JSON.parse(s.sections) : [], + keyMoments: s.keyMoments ? JSON.parse(s.keyMoments) : [], + })) + return { stories: items } + } + + case 'news': { + const items = db.select().from(schema.articles) + .where(eq(schema.articles.published, true)) + .orderBy(desc(schema.articles.id)) + .all() + .filter(a => a.type === 'news') + .map(a => ({ + id: a.slug, + title: a.title, + summary: a.summary, + content: a.content, + category: a.category, + coverImage: a.coverImage, + author: a.author, + tags: a.tags ? JSON.parse(a.tags) : [], + date: a.createdAt, + })) + return { articles: items } + } + + case 'blog': { + const items = db.select().from(schema.articles) + .where(eq(schema.articles.published, true)) + .orderBy(desc(schema.articles.id)) + .all() + .filter(a => a.type === 'blog') + .map(a => ({ + id: a.slug, + title: a.title, + summary: a.summary, + content: a.content, + category: a.category, + coverImage: a.coverImage, + author: a.author, + tags: a.tags ? JSON.parse(a.tags) : [], + seoTitle: a.seoTitle, + seoDescription: a.seoDesc, + seoKeywords: a.seoKeywords, + date: a.createdAt, + })) + return { articles: items } + } + + default: + return null + } +} + +// 有entity表的 key 列表 +const ENTITY_KEYS = ['reviews', 'faq', 'gallery', 'stories', 'news', 'blog'] + export default defineEventHandler(async (event) => { const key = getRouterParam(event, 'key') - const db = useDB() - const item = db - .select() - .from(schema.siteContent) + // 读site_content(作为元数据或兜底) + const item = db.select().from(schema.siteContent) .where(eq(schema.siteContent.key, key)) .get() + const siteData = item ? JSON.parse(item.data) : null - if (!item) { + // 如果是实体表key,优先从实体表构建 + if (ENTITY_KEYS.includes(key)) { + const result = buildFromEntityTable(db, key, siteData) + if (result) { + setHeader(event, 'Cache-Control', 'public, max-age=60') + return result + } + } + + // 普通 site_content key + if (!siteData) { throw createError({ statusCode: 404, message: `未找到配置项: ${key}` }) } setHeader(event, 'Cache-Control', 'public, max-age=60') - - return JSON.parse(item.data) + return siteData })