import { eq, desc } from 'drizzle-orm' import { useDB, schema } from '../utils/db.js' export default defineEventHandler((event) => { const db = useDB() const today = new Date().toISOString().split('T')[0] const base = 'https://1814.love' // ── 静态页面 ── const staticPages = [ { url: '/', priority: '1.0', changefreq: 'weekly', images: [{ loc: '/images/team/hero-grassland.jpg', title: '呼伦贝尔草原风光 - 呼籁旅行' }] }, { url: '/products', priority: '0.9', changefreq: 'weekly', images: [{ loc: '/images/mascot/xiaomengma.png', title: '小蒙马亲子游学营IP形象' }] }, { url: '/faq', priority: '0.95', changefreq: 'weekly', images: [] }, { url: '/reviews', priority: '0.8', changefreq: 'weekly', images: [] }, { url: '/about', priority: '0.85', changefreq: 'monthly', images: [{ loc: '/images/team/hero-family.jpg', title: '呼伦贝尔家庭游合影' }, { loc: '/images/team/guide-group.jpg', title: '呼籁旅行领队团队合影' }] }, { url: '/contact', priority: '0.8', changefreq: 'monthly', images: [{ loc: '/images/contact/qrcode-wechat.jpg', title: '呼籁旅行微信客服二维码' }] }, { url: '/guides', priority: '0.8', changefreq: 'monthly', images: [] }, { url: '/guide-custom', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/summer-camp', priority: '0.85', changefreq: 'monthly', images: [{ loc: '/images/summer-camp/river-banner.jpg', title: '小蒙马亲子游学营河畔活动' }] }, { url: '/winter-camp', priority: '0.8', changefreq: 'monthly', images: [] }, { url: '/courses', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/blog', priority: '0.9', changefreq: 'weekly', images: [] }, { url: '/news', priority: '0.7', changefreq: 'weekly', images: [] }, { url: '/gallery', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/stories', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/destinations', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/calendar', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/pricing', priority: '0.8', changefreq: 'monthly', images: [] }, { url: '/selector', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/customize', priority: '0.8', changefreq: 'monthly', images: [] }, { url: '/brand', priority: '0.7', changefreq: 'monthly', images: [] }, { url: '/company', priority: '0.6', changefreq: 'monthly', images: [] }, { url: '/qualifications', priority: '0.6', changefreq: 'monthly', images: [] }, { url: '/partners', priority: '0.5', changefreq: 'monthly', images: [] }, { url: '/xiaohongshu', priority: '0.7', changefreq: 'weekly', images: [] }, { url: '/youji', priority: '0.7', changefreq: 'weekly', images: [] }, // 产品详情页 { url: '/products/v9-5d4n-forest', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/products/v9-5d4n-prairie', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/products/v9-6d5n-family', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/products/v9-6d5n-explore', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/products/v9-7d6n-family', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/products/v9-7d6n-wild', priority: '0.85', changefreq: 'monthly', images: [] }, { url: '/products/autumn', priority: '0.8', changefreq: 'monthly', images: [] }, { url: '/products/winter', priority: '0.8', changefreq: 'monthly', images: [] }, // 目的地详情页 { url: '/destinations/moriguole', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/eergunashire', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/baihualin', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/enhe-shiwei', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/heishantou', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/manzhouli', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/hulunhu', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/aershan', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/daxinganling', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/aoluguya', priority: '0.75', changefreq: 'monthly', images: [] }, { url: '/destinations/genhe', priority: '0.75', changefreq: 'monthly', images: [] }, ] // ── 动态页面:从数据库读取已发布的博客文章 ── const blogArticles = db.select().from(schema.articles) .where(eq(schema.articles.published, true)) .orderBy(desc(schema.articles.id)) .all() .filter(a => a.type === 'blog') const blogPages = blogArticles.map(a => ({ url: `/blog/${a.slug}`, priority: '0.8', changefreq: 'monthly', lastmod: a.updatedAt ? a.updatedAt.split('T')[0] : (a.createdAt ? a.createdAt.split('T')[0] : today), images: a.coverImage ? [{ loc: a.coverImage, title: a.title }] : [], })) // ── 动态页面:从数据库读取已发布的客户故事 ── const stories = db.select().from(schema.stories) .where(eq(schema.stories.published, true)) .all() const storyPages = stories.map(s => ({ url: `/stories/${s.slug}`, priority: '0.7', changefreq: 'monthly', lastmod: s.createdAt ? s.createdAt.split('T')[0] : today, images: s.coverImage ? [{ loc: s.coverImage, title: s.title }] : [], })) const allPages = [...staticPages, ...blogPages, ...storyPages] const xml = ` ${allPages .map( (p) => ` ${base}${p.url} ${p.lastmod || today} ${p.changefreq} ${p.priority}${(p.images || []).map(img => ` ${img.loc.startsWith('http') ? img.loc : base + img.loc} ${escapeXml(img.title)} `).join('')} ` ) .join('\n')} ` setResponseHeader(event, 'content-type', 'application/xml') setHeader(event, 'Cache-Control', 'public, max-age=3600') return xml }) function escapeXml(str) { if (!str) return '' return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''') }