import { locales, defaultLocale } from './i18n'; import { getSitemapStats, generateSitemap } from './sitemap-generator'; /** * 站点地图验证工具 */ export class SitemapValidator { private baseUrl: string; constructor(baseUrl: string) { this.baseUrl = baseUrl; } /** * 验证所有 URL 是否可访问 */ async validateUrls(): Promise<{ valid: string[]; invalid: string[]; errors: Array<{ url: string; error: string }>; }> { const sitemap = generateSitemap(this.baseUrl); const valid: string[] = []; const invalid: string[] = []; const errors: Array<{ url: string; error: string }> = []; for (const entry of sitemap) { try { const response = await fetch(entry.url, { method: 'HEAD' }); if (response.ok) { valid.push(entry.url); } else { invalid.push(entry.url); errors.push({ url: entry.url, error: `HTTP ${response.status}: ${response.statusText}`, }); } } catch (error) { invalid.push(entry.url); errors.push({ url: entry.url, error: error instanceof Error ? error.message : 'Unknown error', }); } } return { valid, invalid, errors }; } /** * 检查重复的 URL */ checkDuplicates(): string[] { const sitemap = generateSitemap(this.baseUrl); const urls = sitemap.map((entry) => entry.url); const duplicates: string[] = []; const seen = new Set(); for (const url of urls) { if (seen.has(url)) { duplicates.push(url); } else { seen.add(url); } } return duplicates; } /** * 生成站点地图报告 */ generateReport(): { stats: ReturnType; duplicates: string[]; recommendations: string[]; } { const stats = getSitemapStats(this.baseUrl); const duplicates = this.checkDuplicates(); const recommendations: string[] = []; // 生成建议 if (duplicates.length > 0) { recommendations.push(`发现 ${duplicates.length} 个重复的 URL,请检查站点地图生成逻辑`); } if (stats.urlCount > 50000) { recommendations.push('站点地图包含超过 50,000 个 URL,建议分割为多个站点地图文件'); } if (stats.blogPages === 0) { recommendations.push('未发现博客页面,请确认博客内容是否正确配置'); } return { stats, duplicates, recommendations, }; } } /** * 站点地图提交工具 */ export class SitemapSubmitter { private baseUrl: string; constructor(baseUrl: string) { this.baseUrl = baseUrl; } /** * 生成搜索引擎提交 URL */ getSubmissionUrls(): Record { const sitemapUrl = `${this.baseUrl}/sitemap.xml`; return { google: `https://www.google.com/ping?sitemap=${encodeURIComponent(sitemapUrl)}`, bing: `https://www.bing.com/ping?sitemap=${encodeURIComponent(sitemapUrl)}`, yandex: `https://webmaster.yandex.com/ping?sitemap=${encodeURIComponent(sitemapUrl)}`, baidu: `https://ping.baidu.com/ping/RPC2?sitemap=${encodeURIComponent(sitemapUrl)}`, }; } /** * 自动提交站点地图到搜索引擎 */ async submitToSearchEngines(): Promise<{ success: string[]; failed: Array<{ engine: string; error: string }>; }> { const urls = this.getSubmissionUrls(); const success: string[] = []; const failed: Array<{ engine: string; error: string }> = []; for (const [engine, url] of Object.entries(urls)) { try { const response = await fetch(url, { method: 'GET' }); if (response.ok) { success.push(engine); } else { failed.push({ engine, error: `HTTP ${response.status}: ${response.statusText}`, }); } } catch (error) { failed.push({ engine, error: error instanceof Error ? error.message : 'Unknown error', }); } } return { success, failed }; } } /** * 生成站点地图索引文件 */ export function generateSitemapIndex(baseUrl: string): string { const lastmod = new Date().toISOString(); return ` ${baseUrl}/sitemap.xml ${lastmod} `; } /** * 生成人类可读的站点地图 HTML */ export function generateHtmlSitemap(baseUrl: string): string { const sitemap = generateSitemap(baseUrl); const stats = getSitemapStats(baseUrl); // 按页面类型分组 const groupedPages = sitemap.reduce( (acc, entry) => { let category = 'other'; if (entry.url.includes('/blog/') && !entry.url.endsWith('/blog')) { category = 'blog-posts'; } else if (entry.url.endsWith('/blog')) { category = 'blog'; } else if (entry.url.endsWith('/contact')) { category = 'contact'; } else if (entry.url.endsWith('/products')) { category = 'products'; } else if (entry.url === baseUrl || entry.url.match(/\/[a-z-]+$/)) { category = 'main'; } if (!acc[category]) acc[category] = []; acc[category].push(entry); return acc; }, {} as Record, ); const categoryNames = { main: '主要页面', blog: '博客', 'blog-posts': '博客文章', contact: '联系我们', products: '产品', other: '其他页面', }; let html = ` 站点地图 - Eco Life

站点地图

生成时间: ${new Date().toLocaleString('zh-CN')}

统计信息

总页面数: ${stats.urlCount}

静态页面: ${stats.staticPages}

博客文章: ${stats.blogPages}

支持语言: ${stats.languages} (${locales.join(', ')})

`; Object.entries(groupedPages).forEach(([category, pages]) => { html += `

${categoryNames[category as keyof typeof categoryNames] || category}

    `; pages.forEach((page) => { const priorityClass = page.priority >= 0.8 ? 'priority-high' : page.priority >= 0.6 ? 'priority-medium' : 'priority-low'; html += `
  • ${page.url}
    优先级: ${page.priority} 更新频率: ${page.changeFrequency} 最后修改: ${page.lastModified.toLocaleDateString('zh-CN')}
  • `; }); html += `
`; }); html += ` `; return html; }