feat: v2.4.0 - SEO全面优化

新增功能:
1. 自动化SEO基础设施
   - Sitemap.xml 动态生成 (/sitemap.xml)
   - Robots.txt 动态配置 (/robots.txt)

2. Schema.org 结构化数据
   - 工具详情页添加 SoftwareApplication 结构化数据
   - 面包屑导航添加 BreadcrumbList 结构化数据
   - Open Graph 标签支持社交媒体分享

3. 智能内链系统
   - 自动识别工具名称并添加内部链接
   - auto_link 过滤器支持内容互联

4. 标签专题页SEO优化
   - Tag模型新增字段: seo_title, seo_description, seo_keywords
   - 支持自定义标签页SEO信息
   - 提供迁移脚本: migrate_tag_seo_fields.py

5. 面包屑导航
   - 可视化导航: 首页 > 标签 > 工具名
   - 支持Schema.org和视觉显示

6. 页面级SEO改进
   - 工具详情页: canonical链接, 动态meta标签
   - 标签页: 专属SEO信息支持
   - 首页: 完整meta标签配置

技术改进:
- 迁移脚本支持幂等性检查
- Windows控制台编码兼容性优化
- 数据库字段注释标注版本

部署文档: DEPLOY_v2.4.0.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jowe
2026-01-03 16:32:13 +08:00
parent 495c3b8025
commit 7da0bb6e54
7 changed files with 703 additions and 5 deletions

102
app.py
View File

@@ -29,6 +29,33 @@ def create_app(config_name='default'):
return ''
return markdown.markdown(text, extensions=['nl2br', 'fenced_code'])
# v2.4新增: 自动内链过滤器
@app.template_filter('auto_link')
def auto_link_filter(text, current_site_id=None):
"""自动为内容中的工具名称添加链接"""
if not text:
return ''
# 获取所有启用的网站(排除当前网站)
sites = Site.query.filter_by(is_active=True).all()
if current_site_id:
sites = [s for s in sites if s.id != current_site_id]
# 按名称长度降序排序,优先匹配长名称
sites = sorted(sites, key=lambda s: len(s.name), reverse=True)
# 记录已经添加链接的位置,避免重复
linked_sites = set()
for site in sites:
if site.name in text and site.name not in linked_sites:
# 只链接第一次出现的位置
link = f'<a href="/site/{site.code}" title="{site.short_desc or site.name}" style="color: var(--primary-blue); text-decoration: underline; text-decoration-style: dotted;">{site.name}</a>'
text = text.replace(site.name, link, 1)
linked_sites.add(site.name)
return text
# 初始化登录管理
login_manager = LoginManager()
login_manager.init_app(app)
@@ -709,6 +736,76 @@ def create_app(config_name='default'):
'message': f'批量获取失败: {str(e)}'
}), 500
# ========== SEO路由 (v2.4新增) ==========
@app.route('/sitemap.xml')
def sitemap():
"""动态生成sitemap.xml"""
from flask import make_response
# 获取所有启用的网站
sites = Site.query.filter_by(is_active=True).order_by(Site.updated_at.desc()).all()
# 获取所有标签
tags = Tag.query.all()
# 构建XML内容
xml_content = '''<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'''
# 首页
xml_content += '''
<url>
<loc>{}</loc>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>'''.format(request.url_root.rstrip('/'))
# 工具详情页
for site in sites:
xml_content += '''
<url>
<loc>{}</loc>
<lastmod>{}</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>'''.format(
request.url_root.rstrip('/') + url_for('site_detail', code=site.code),
site.updated_at.strftime('%Y-%m-%d') if site.updated_at else datetime.now().strftime('%Y-%m-%d')
)
# 标签页
for tag in tags:
xml_content += '''
<url>
<loc>{}</loc>
<changefreq>weekly</changefreq>
<priority>0.6</priority>
</url>'''.format(request.url_root.rstrip('/') + '/?tag=' + tag.slug)
xml_content += '''
</urlset>'''
response = make_response(xml_content)
response.headers['Content-Type'] = 'application/xml; charset=utf-8'
return response
@app.route('/robots.txt')
def robots():
"""动态生成robots.txt"""
from flask import make_response
robots_content = '''User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Sitemap: {}sitemap.xml
'''.format(request.url_root)
response = make_response(robots_content)
response.headers['Content-Type'] = 'text/plain; charset=utf-8'
return response
@app.route('/api/refresh-site-news/<site_code>', methods=['POST'])
def refresh_site_news(site_code):
"""手动刷新指定网站的新闻(前台用户可访问)- v2.3新增"""
@@ -1211,11 +1308,14 @@ def create_app(config_name='default'):
'name': '标签名称',
'slug': 'URL别名',
'description': '标签描述',
'seo_title': 'SEO标题 (v2.4)',
'seo_description': 'SEO描述 (v2.4)',
'seo_keywords': 'SEO关键词 (v2.4)',
'icon': '图标',
'sort_order': '排序权重',
'created_at': '创建时间'
}
form_columns = ['name', 'slug', 'description', 'icon', 'sort_order']
form_columns = ['name', 'slug', 'description', 'seo_title', 'seo_description', 'seo_keywords', 'icon', 'sort_order']
# 管理员视图
class AdminAdmin(SecureModelView):