feat: 官网代码全量更新 (2026-04-18)
这个提交包含在:
@@ -24,12 +24,30 @@ function buildFromEntityTable(db, key, siteData) {
|
||||
scenes: r.scenes ? JSON.parse(r.scenes) : [],
|
||||
concerns: r.concerns ? JSON.parse(r.concerns) : [],
|
||||
}))
|
||||
// 合并 site_content 的 summary(如果有/��
|
||||
const summary = siteData?.summary || {
|
||||
totalCount: items.length,
|
||||
approvalRate: '98%',
|
||||
// 高频关键词:从评价正文中按预设词表统计出现频次
|
||||
const KEYWORD_DICT = [
|
||||
'领队', '服务', '贴心', '耐心', '细心', '专业',
|
||||
'摄影', '拍照', '旅拍', '骑马', '越野车', '滑草',
|
||||
'营地', '烧烤', '住宿', '行程', '错峰', '不排队',
|
||||
'亲子', '小朋友', '孩子', '家人', '老人',
|
||||
'草原', '风景', '美', '惊艳', '难忘', '舒适',
|
||||
'安排', '推荐', '值得', '良心', '安心', '用心',
|
||||
]
|
||||
const freq = {}
|
||||
for (const it of items) {
|
||||
const c = it.content || ''
|
||||
for (const kw of KEYWORD_DICT) if (c.includes(kw)) freq[kw] = (freq[kw] || 0) + 1
|
||||
}
|
||||
const keywords = Object.entries(freq)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, 12)
|
||||
.map(([w]) => w)
|
||||
|
||||
const summary = {
|
||||
totalCount: siteData?.summary?.totalCount || items.length,
|
||||
approvalRate: siteData?.summary?.approvalRate || '98%',
|
||||
keywords: siteData?.summary?.keywords?.length ? siteData.summary.keywords : keywords,
|
||||
}
|
||||
// 用实体表 items 覆盖 site_content 的 items
|
||||
return { summary, items }
|
||||
}
|
||||
|
||||
@@ -82,6 +100,7 @@ function buildFromEntityTable(db, key, siteData) {
|
||||
.all()
|
||||
.map(s => ({
|
||||
...s,
|
||||
tags: s.tags ? (() => { try { return JSON.parse(s.tags) } catch { return [] } })() : [],
|
||||
sections: s.sections ? JSON.parse(s.sections) : [],
|
||||
keyMoments: s.keyMoments ? JSON.parse(s.keyMoments) : [],
|
||||
}))
|
||||
@@ -91,7 +110,7 @@ function buildFromEntityTable(db, key, siteData) {
|
||||
case 'news': {
|
||||
const items = db.select().from(schema.articles)
|
||||
.where(eq(schema.articles.published, true))
|
||||
.orderBy(desc(schema.articles.id))
|
||||
.orderBy(desc(schema.articles.createdAt), desc(schema.articles.id))
|
||||
.all()
|
||||
.filter(a => a.type === 'news')
|
||||
.map(a => ({
|
||||
@@ -153,7 +172,7 @@ export default defineEventHandler(async (event) => {
|
||||
if (ENTITY_KEYS.includes(key)) {
|
||||
const result = buildFromEntityTable(db, key, siteData)
|
||||
if (result) {
|
||||
setHeader(event, 'Cache-Control', 'public, max-age=60')
|
||||
setHeader(event, 'Cache-Control', 'no-store, must-revalidate')
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -165,7 +184,7 @@ export default defineEventHandler(async (event) => {
|
||||
.get()
|
||||
const productsData = productsItem ? JSON.parse(productsItem.data) : null
|
||||
if (productsData?.summerCamp) {
|
||||
setHeader(event, 'Cache-Control', 'public, max-age=60')
|
||||
setHeader(event, 'Cache-Control', 'no-store, must-revalidate')
|
||||
return productsData.summerCamp
|
||||
}
|
||||
}
|
||||
@@ -175,6 +194,6 @@ export default defineEventHandler(async (event) => {
|
||||
throw createError({ statusCode: 404, message: `未找到配置项: ${key}` })
|
||||
}
|
||||
|
||||
setHeader(event, 'Cache-Control', 'public, max-age=60')
|
||||
setHeader(event, 'Cache-Control', 'no-store, must-revalidate')
|
||||
return siteData
|
||||
})
|
||||
|
||||
在新工单中引用
屏蔽一个用户