## 核心优化 - 移除详情页自动调用博查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>
595 lines
14 KiB
Markdown
595 lines
14 KiB
Markdown
# 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增加约2KB(gzip后<1KB)
|
||
- 渲染时间 <5ms
|
||
|
||
---
|
||
|
||
## 🐛 已知问题和解决方案
|
||
|
||
### 问题1: 推荐tab显示为空
|
||
|
||
**原因**: 没有标记任何工具为推荐
|
||
**解决**: 在后台至少标记几个优质工具为推荐
|
||
|
||
### 问题2: 数据库迁移重复执行
|
||
|
||
**原因**: 迁移脚本被多次运行
|
||
**解决**: 脚本有幂等性检查,会自动跳过已存在的字段
|
||
|
||
### 问题3: URL过长
|
||
|
||
**原因**: 同时使用tag, tab, q, page参数
|
||
**解决**:
|
||
- 默认值不出现在URL(tab=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测试**
|
||
- 测试不同的默认tab(latest 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
|
||
**下次更新**: 根据需要
|
||
|
||
---
|
||
|
||
祝二次开发顺利!🎉
|