feat: v2.6.0 - API安全优化和文档整合

## 核心优化
- 移除详情页自动调用博查API的逻辑,改为按需加载
- 添加基于IP的频率限制(每小时3次)
- 实现验证码防护机制(超过阈值后要求验证)
- 新增频率限制工具类 utils/rate_limiter.py

## 成本控制
- API调用减少约90%+(只在用户点击时调用)
- 防止恶意滥用和攻击
- 可配置的频率限制和验证码策略

## 文档整合
- 创建 docs/ 目录结构
- 归档历史版本文档到 docs/archive/
- 移动部署文档到 docs/deployment/
- 添加文档索引 docs/README.md

## 技术变更
- 新增依赖: Flask-Limiter==3.5.0
- 修改: app.py (移除自动调用,新增API端点)
- 修改: templates/detail_new.html (按需加载UI)
- 新增: utils/rate_limiter.py (频率限制和验证码)
- 新增: docs/archive/DEVELOP_v2.6.0_API_SECURITY.md

## 部署说明
1. pip install Flask-Limiter==3.5.0
2. 重启应用
3. 无需数据库迁移

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jowe
2026-02-06 15:54:13 +08:00
parent c1a06ad684
commit 939717fa57
27 changed files with 1670 additions and 140 deletions

View File

@@ -0,0 +1,594 @@
# ZJPB v2.4.1 开发文档 - 标签功能优化
**版本号**: v2.4.1
**开发日期**: 2026-01-04
**功能主题**: 最新/热门/推荐标签功能
**开发者**: Claude Code
**Git Commit**: 8011e5b
---
## 📋 功能概述
### 用户需求
用户原本要求实现"热门工具排行榜"功能,但在看到初版实现后明确拒绝了顶部独立排行榜的设计,提出了新的需求:
> "这个列表并不好看不用在顶部单独增加模块可以在tag下增加3个tab分别是"最新"、"热门"、"推荐" 这三个,其中"推荐"可以在后台添加网站或者编辑的时候设置"
### 最终实现
-**完全移除**删除顶部热门工具排行榜模块约118行CSS + HTML
-**Tab导航**在分类标签下方添加三个tab最新/热门/推荐)
-**数据库支持**:添加`is_recommended`字段到Site模型
-**后台管理**:支持在后台标记推荐工具
-**状态保持**URL参数保持tab、分类、搜索、分页状态
-**完整测试**:所有功能已本地验证通过
---
## 🏗️ 技术架构
### 1. 数据库层
#### 新增字段
**表名**: `sites`
**字段名**: `is_recommended`
**类型**: `TINYINT(1)`
**默认值**: `0` (False)
**注释**: "是否推荐"
**DDL语句**:
```sql
ALTER TABLE sites ADD COLUMN is_recommended TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否推荐';
```
#### 迁移脚本
**文件**: `migrations/add_is_recommended.py`
**特性**:
- 幂等性检查(避免重复执行)
- 支持upgrade/downgrade
- 自动检测字段是否已存在
- 错误处理和事务回滚
### 2. 后端层
#### 路由修改
**文件**: `app.py`
**函数**: `index()` (Lines 70-148)
**新增参数处理**:
```python
current_tab = request.args.get('tab', 'latest') # 默认为"最新"
```
**三种模式的查询逻辑**:
1. **最新模式** (默认):
```python
if current_tab == 'latest' or not current_tab:
query = query.order_by(Site.created_at.desc(), Site.id.desc())
```
2. **热门模式**:
```python
elif current_tab == 'popular':
query = query.order_by(Site.view_count.desc(), Site.id.desc())
```
3. **推荐模式**:
```python
elif current_tab == 'recommended':
query = query.filter_by(is_recommended=True).order_by(Site.sort_order.desc(), Site.id.desc())
```
**关键特性**:
- 支持与分类筛选tag组合使用
- 支持与搜索q组合使用
- 支持分页
- 所有查询条件可叠加
#### Flask-Admin配置
**文件**: `app.py`
**类**: `SiteAdmin` (Lines 1345-1481)
**修改点**:
```python
# 列表显示添加推荐字段
column_list = ['id', 'code', 'name', 'url', 'slug', 'is_active', 'is_recommended', 'view_count', 'created_at']
# 添加推荐筛选器
column_filters = ['is_active', 'is_recommended', 'tags']
# 表单添加推荐字段
form_columns = ['name', 'url', 'slug', 'logo', 'short_desc', 'description', 'features', 'news_keywords', 'tags', 'is_active', 'is_recommended', 'sort_order']
# 中文标签
column_labels = {
'is_recommended': '是否推荐',
# ... 其他字段
}
```
### 3. 前端层
#### 模板文件
**文件**: `templates/index_new.html`
**删除内容** (约118行):
- `.popular-section` 相关所有CSS
- `.popular-header`, `.popular-title`, `.popular-badge` 样式
- `.popular-grid`, `.popular-item` 样式
- 顶部热门工具HTML结构
**新增内容**:
**Tab导航CSS** (Lines 339-397):
```css
.sort-tabs {
padding: 24px 0 0 0;
border-top: 1px solid var(--border-color);
margin-top: 24px;
}
.sort-tab {
padding: 8px 20px;
border-radius: 50px;
/* ... 完整样式见源码 */
}
.sort-tab.active {
background: var(--primary-blue);
border-color: var(--primary-blue);
color: white;
}
```
**Tab导航HTML** (Lines 443-462):
```html
<div class="sort-tabs">
<div class="sort-tabs-container">
<a href="/?{% if selected_tag %}tag={{ selected_tag.slug }}&{% endif %}tab=latest"
class="sort-tab {% if not current_tab or current_tab == 'latest' %}active{% endif %}">
<span class="icon">🕐</span>
最新
</a>
<a href="/?{% if selected_tag %}tag={{ selected_tag.slug }}&{% endif %}tab=popular"
class="sort-tab {% if current_tab == 'popular' %}active{% endif %}">
<span class="icon">🔥</span>
热门
</a>
<a href="/?{% if selected_tag %}tag={{ selected_tag.slug }}&{% endif %}tab=recommended"
class="sort-tab {% if current_tab == 'recommended' %}active{% endif %}">
<span class="icon"></span>
推荐
</a>
</div>
</div>
```
**分页链接更新** (Lines 505-556):
所有分页链接都更新为保持tab状态
```html
<!-- 示例 -->
<a href="?page={{ page_num }}{% if selected_tag %}&tag={{ selected_tag.slug }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}{% if current_tab and current_tab != 'latest' %}&tab={{ current_tab }}{% endif %}">
```
**关键逻辑**:
- 默认tab为'latest'时不显示在URL中保持URL简洁
- 非默认tab时添加`&tab=xxx`参数
- 保持所有其他状态tag, q, page
---
## 📁 文件变更清单
### 新增文件
1. **migrations/add_is_recommended.py** (73 lines)
- 数据库迁移脚本
- 添加is_recommended字段
### 修改文件
1. **models.py**
- Line 29: 添加`is_recommended`字段定义
- Line 56: `to_dict()`方法添加字段序列化
2. **app.py**
- Lines 95: 添加`current_tab`参数处理
- Lines 130-139: 实现三种tab模式的查询逻辑
- Line 148: 传递`current_tab`到模板
- Lines 1360-1382: Flask-Admin配置更新
3. **templates/index_new.html**
- 删除: ~118行热门section相关代码
- Lines 339-397: 新增tab导航CSS
- Lines 443-462: 新增tab导航HTML
- Lines 505-556: 更新所有分页链接
**统计**: 4个文件修改167行新增181行删除
---
## 🔄 URL参数设计
### 参数说明
| 参数 | 说明 | 默认值 | 示例 |
|------|------|--------|------|
| `tag` | 分类筛选 | 无 | `tag=ai-chat` |
| `tab` | 排序模式 | `latest` | `tab=popular` |
| `q` | 搜索关键词 | 无 | `q=chatgpt` |
| `page` | 页码 | `1` | `page=2` |
### URL组合示例
```
# 只有tab
/?tab=popular
# 分类 + tab
/?tag=ai-chat&tab=popular
# 分类 + tab + 分页
/?tag=ai-chat&tab=recommended&page=2
# 分类 + tab + 搜索 + 分页
/?tag=ai-chat&tab=popular&q=对话&page=2
```
### 设计原则
- **简洁性**: 默认值tab=latest, page=1不出现在URL中
- **状态保持**: 所有操作切换tab、翻页等保持其他参数
- **向后兼容**: 无tab参数时默认为latest模式
- **SEO友好**: URL清晰可读
---
## 🧪 测试验证
### 本地测试(已完成)
**测试环境**:
- Flask Development Server
- 测试时间: 2026-01-04 00:16:41 - 00:54:25
- 数据库: MySQL
**测试用例**:
1.**数据库迁移**
- 执行时间: 00:28:18
- 结果: 成功添加is_recommended字段
- SQL: `ALTER TABLE sites ADD COLUMN is_recommended TINYINT(1) NOT NULL DEFAULT 0`
2.**三种tab模式**
- 最新 (00:38:37): `ORDER BY created_at DESC`
- 热门 (00:38:39): `ORDER BY view_count DESC`
- 推荐 (00:39:10): `WHERE is_recommended = true ORDER BY sort_order DESC`
3.**后台管理**
- 访问admin界面 (00:38:48)
- 编辑Site ID=1 (00:39:02)
- 成功设置is_recommended=1
4.**组合筛选**
- 分类 + tab: `?tag=ai-chat&tab=popular` (00:39:15)
- 所有组合均正常工作
5.**分页状态保持**
- URL参数在翻页时正确保持
### 生产部署(已完成)
**部署时间**: 2026-01-04
**部署方式**: Git pull + 数据库迁移 + 应用重启
**部署状态**: ✅ 成功
---
## 💡 核心技术要点
### 1. SQLAlchemy查询链式调用
```python
# 基础查询
query = Site.query.filter_by(is_active=True)
# 条件叠加
if tag_slug:
query = query.filter(Site.tags.contains(selected_tag))
# 排序方式
query = query.order_by(Site.created_at.desc(), Site.id.desc())
# 分页
pagination = query.paginate(page=page, per_page=100, error_out=False)
```
### 2. Jinja2条件CSS类
```html
<a class="sort-tab {% if current_tab == 'popular' %}active{% endif %}">
```
### 3. URL参数拼接
```html
href="/?{% if selected_tag %}tag={{ selected_tag.slug }}&{% endif %}tab=latest"
```
**技巧**: 使用`{% if %}`控制参数是否出现,避免空参数
### 4. Flask请求参数处理
```python
# 获取参数,提供默认值
current_tab = request.args.get('tab', 'latest')
# 安全获取整数
page = request.args.get('page', 1, type=int)
# 字符串处理
search_query = request.args.get('q', '').strip()
```
---
## 🎨 UI/UX设计
### 视觉设计
**Tab样式**:
- 未激活: 白色背景,灰色边框,灰色文字
- 悬停: 蓝色边框,浅蓝背景,蓝色文字
- 激活: 蓝色背景,白色文字
- 圆角: 50px胶囊形状
- 图标: Unicode emoji🕐🔥⭐
**位置**:
- 在分类标签下方
- 顶部有1px灰色分隔线
- 24px上边距
### 交互设计
**用户流程**:
1. 用户访问首页,默认显示"最新"工具
2. 点击分类标签,查看特定分类
3. 切换tab改变排序方式
4. 所有状态通过URL保持支持刷新和分享
**状态反馈**:
- 当前激活的tab高亮显示
- URL参数实时更新
- 页面内容即时切换
---
## 🔒 数据完整性
### 默认值处理
- 所有现有记录的`is_recommended`默认为`0` (False)
- 新创建的Site默认`is_recommended=False`
- 不影响现有数据
### 查询优化
```python
# 推荐模式只查询is_recommended=True的记录
query.filter_by(is_recommended=True)
# 使用索引字段排序
order_by(Site.sort_order.desc(), Site.id.desc())
```
### 数据库索引建议
```sql
-- 可选:如果推荐工具数量很多,建议添加索引
CREATE INDEX idx_is_recommended ON sites(is_recommended);
```
---
## 📊 性能影响评估
### 查询性能
- **Latest模式**: 使用created_at索引性能无影响
- **Popular模式**: 使用view_count字段建议添加索引
- **Recommended模式**: 数据量少(推荐工具有限),性能影响可忽略
### 数据库存储
- 新增1个TINYINT字段1 byte/record
- 假设1000个工具1 KB额外存储
- 影响可忽略
### 页面加载
- 无额外HTTP请求
- CSS/HTML增加约2KBgzip后<1KB
- 渲染时间 <5ms
---
## 🐛 已知问题和解决方案
### 问题1: 推荐tab显示为空
**原因**: 没有标记任何工具为推荐
**解决**: 在后台至少标记几个优质工具为推荐
### 问题2: 数据库迁移重复执行
**原因**: 迁移脚本被多次运行
**解决**: 脚本有幂等性检查,会自动跳过已存在的字段
### 问题3: URL过长
**原因**: 同时使用tag, tab, q, page参数
**解决**:
- 默认值不出现在URLtab=latest, page=1
- 这是正常行为,利于状态保持
---
## 🚀 未来优化建议
### 短期优化 (1-2周)
1. **添加数据库索引**
```sql
CREATE INDEX idx_view_count ON sites(view_count DESC);
CREATE INDEX idx_is_recommended ON sites(is_recommended);
```
2. **优化推荐工具管理**
- 在后台网站列表添加"快速推荐"按钮
- 批量操作:批量设置/取消推荐
3. **用户行为分析**
- 添加Google Analytics事件追踪
- 统计哪个tab使用最频繁
### 中期优化 (1个月)
1. **Tab切换动画**
- 添加淡入淡出效果
- 优化用户体验
2. **推荐算法**
- 根据浏览量、评分自动建议推荐
- 定期更新推荐列表
3. **A/B测试**
- 测试不同的默认tablatest vs popular
- 测试tab位置上方 vs 下方)
### 长期优化 (3个月+)
1. **个性化推荐**
- 基于用户浏览历史
- 机器学习推荐算法
2. **多维度筛选**
- 添加更多tab如"最受欢迎"、"编辑精选"
- 组合筛选器
3. **缓存优化**
- Redis缓存热门查询
- 减少数据库压力
---
## 📚 相关文档
### 项目文档
- `DEPLOY_v2.4.0.md` - SEO功能部署文档
- `DEPLOY_CHECKLIST_v2.3.md` - 部署检查清单
- `README.md` - 项目总体说明
### 代码文件
- `app.py` - Flask应用主文件
- `models.py` - 数据库模型定义
- `templates/index_new.html` - 首页模板
- `migrations/add_is_recommended.py` - 本次迁移脚本
### Git提交
- **Commit ID**: `8011e5b`
- **Commit Message**: "feat: 实现最新/热门/推荐标签功能"
- **上一个版本**: `da30394` (热门工具排行榜 - 已废弃)
---
## 🔧 开发环境设置
### 本地开发
```bash
# 1. 克隆项目
git clone http://server.zjpb.net:3000/jowelin/zjpb.git
cd zjpb
# 2. 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
# 或
venv\Scripts\activate # Windows
# 3. 安装依赖
pip install -r requirements.txt
# 4. 配置环境变量
cp .env.example .env
# 编辑.env文件配置数据库等信息
# 5. 运行数据库迁移
python migrations/add_is_recommended.py
# 6. 启动开发服务器
python app.py
# 访问 http://localhost:5000
```
### 数据库配置
```python
# .env文件示例
FLASK_ENV=development
DATABASE_URL=mysql+pymysql://root:password@localhost/zjpb
SECRET_KEY=your-secret-key
BOCHA_API_KEY=your-api-key
```
---
## 📞 技术支持
### 问题反馈
- **Git仓库**: http://server.zjpb.net:3000/jowelin/zjpb
- **Issues**: 在Git仓库创建Issue
### 开发者联系
- **开发者**: Claude Code
- **开发日期**: 2026-01-04
- **版本**: v2.4.1
---
## ✅ 二次开发快速启动清单
下次重新开启开发时,参考以下清单:
- [ ] 阅读本文档,了解最新功能
- [ ] 查看Git log了解最近提交
- [ ] 拉取最新代码:`git pull origin master`
- [ ] 激活虚拟环境
- [ ] 运行`python app.py`启动开发服务器
- [ ] 访问`http://localhost:5000`验证功能
- [ ] 登录后台`/admin`检查数据
- [ ] 查看`logs/error.log`确认无错误
---
## 📈 功能使用统计(建议追踪)
### 关键指标
- Tab点击率latest vs popular vs recommended
- 推荐工具数量
- 用户停留时间
- 分类+tab组合使用频率
### 数据查询示例
```sql
-- 查看推荐工具数量
SELECT COUNT(*) FROM sites WHERE is_recommended = 1 AND is_active = 1;
-- 查看各分类的推荐工具分布
SELECT t.name, COUNT(st.site_id) as recommended_count
FROM tags t
LEFT JOIN site_tags st ON t.id = st.tag_id
LEFT JOIN sites s ON st.site_id = s.id
WHERE s.is_recommended = 1 AND s.is_active = 1
GROUP BY t.id, t.name
ORDER BY recommended_count DESC;
-- 查看热门工具TOP 10
SELECT id, name, view_count
FROM sites
WHERE is_active = 1
ORDER BY view_count DESC
LIMIT 10;
```
---
**文档版本**: v1.0
**最后更新**: 2026-01-04
**下次更新**: 根据需要
---
祝二次开发顺利!🎉