feat(plugins): 4 个业务插件代码 + 前台公开页面改造

plugins/navManager:导航 CRUD + 导航分类 CRUD(独立 blueprint)
plugins/friendManager:友情链接 CRUD
plugins/aboutManager:关于本站 CRUD
plugins/siteStats:访问统计主页 + JSON 接口 + /site/* GET 埋点 + nav 卡片点击埋点

applications/view/public/nav.py:导航聚合页 / 分类详情 / JSON 接口,支持 visit_count 注入
applications/view/public/about.py:关于本站公开页
applications/view/public/friend.py:友情链接公开页

templates/public/base.html:响应式首页(搜索框 / 分类抽屉 / 5 主题切换 / footer 隐私小字)
templates/public/index.html / category.html:卡片右下角访问次数
templates/public/about.html / friend.html:关于 + 友链前台页

docs/plugins-development.md:插件开发完整指南(生命周期 + 4 个示例 + FAQ + framework 迁移)

scripts/:探针与端到端验证脚本(probe_*/verify_*/test_*)
This commit is contained in:
bwstudio
2026-09-06 18:18:06 +08:00
parent 1ea69c2c34
commit 0ffc103e46
53 changed files with 4705 additions and 89 deletions
+41
View File
@@ -0,0 +1,41 @@
"""
前台友情链接页视图(无需登录)。
URL
- GET /site/friend 按分组聚合展示所有启用友情链接
注:不是 /site/friends(避免与系统内部 hyperlink 对齐)
"""
from collections import OrderedDict
from flask import Blueprint, render_template
from applications.models import Friend
bp = Blueprint('public_friend', __name__, url_prefix='/site')
@bp.get('/friend')
def friend_index():
"""
公开友情链接页:按 category 分组聚合展示
"""
items = (
Friend.query
.filter(Friend.enable == 1)
.order_by(Friend.category.asc(), Friend.sort.asc(), Friend.id.asc())
.all()
)
groups = OrderedDict()
for item in items:
if not item.url:
continue
groups.setdefault(item.category or '推荐友链', []).append(item.to_dict())
total = sum(len(g) for g in groups.values())
return render_template(
'public/friend.html',
groups=groups,
total=total,
site_name='旺珂 · 导航',
)