Compare commits

...

3 Commits

Author SHA1 Message Date
6f20e5978d fix: 分页正确显示当前筛选的总数
- API返回 total 字段(筛选后的实际总数)
- 新增 count_items 函数计算筛选条件下的总数
- 分页使用API返回的total而不是全局统计
- 解决筛选后分页显示不正确的问题
2026-04-16 14:08:12 +08:00
56ff1e8163 fix: 搜索输入实时响应修复
- 改用直接 setTimeout 方式,不用 debounce 函数
- 避免函数绑定问题导致搜索不触发
2026-04-16 14:03:05 +08:00
9ec479415a docs: 更新版本历史 v2.4.0 2026-04-16 13:55:07 +08:00
3 changed files with 60 additions and 6 deletions

View File

@@ -141,6 +141,13 @@ xian-favor/
## 版本历史
- **v2.4.0** (2026-04-16): 数据库备份机制
- 自动备份:每天 04:00 执行
- 手动备份:页面一键操作
- 备份清理规则保留30天 + 每月第一天永久保留
- 手动备份最多保留10个
- 支持恢复备份和删除备份
- 备份管理页面入口在侧边栏
- **v2.3.2** (2026-04-16): 搜索功能修复
- 修复 debounce 函数定义顺序问题
- 搜索框输入后可正常过滤列表

View File

@@ -25,7 +25,16 @@ def list_items():
limit=int(request.args.get('limit', 50)),
offset=int(request.args.get('offset', 0))
)
return jsonify({'success': True, 'data': items})
# 获取符合条件的总数(用于分页)
total = db.count_items(
type=request.args.get('type'),
status=request.args.get('status'),
tag=request.args.get('tag'),
keyword=request.args.get('keyword')
)
return jsonify({'success': True, 'data': items, 'total': total})
@app.route('/api/items', methods=['POST'])
@@ -1201,8 +1210,12 @@ document.addEventListener('DOMContentLoaded', async () => {
updateEditFieldsByType(e.target.value);
});
// 搜索
document.getElementById('searchInput').addEventListener('input', debounce(loadItems, 300));
// 搜索 - 直接绑定,不用 debounce
let searchTimer;
document.getElementById('searchInput').addEventListener('input', (e) => {
clearTimeout(searchTimer);
searchTimer = setTimeout(() => loadItems(), 300);
});
// 类型过滤
document.getElementById('typeFilter').addEventListener('change', (e) => {
@@ -1244,7 +1257,7 @@ async function loadItems(page = 1) {
if (data.success) {
renderItems(data.data);
renderPagination(data.data.length, page);
renderPagination(data.total, page); // 使用API返回的total
}
}
@@ -1289,9 +1302,8 @@ function renderItems(items) {
}
// 渲染分页
function renderPagination(itemCount, page) {
function renderPagination(total, page) {
const container = document.getElementById('pagination');
const total = parseInt(document.getElementById('statTotal').textContent);
const totalPages = Math.ceil(total / pageSize);
if (totalPages <= 1) {

View File

@@ -204,6 +204,41 @@ class Database:
return items
def count_items(self, type: str = None, status: str = None, tag: str = None,
keyword: str = None) -> int:
"""计算符合条件的条目总数"""
with self.get_conn() as conn:
cursor = conn.cursor()
query = "SELECT COUNT(DISTINCT i.id) as count FROM items i"
params = []
conditions = []
# 标签过滤需要JOIN
if tag:
query += " JOIN item_tags it ON i.id = it.item_id JOIN tags t ON it.tag_id = t.id"
conditions.append("t.name = ?")
params.append(tag)
if type:
conditions.append("i.type = ?")
params.append(type)
if status:
conditions.append("i.status = ?")
params.append(status)
if keyword:
conditions.append("(i.title LIKE ? OR i.content LIKE ? OR i.note LIKE ?)")
keyword_pattern = f"%{keyword}%"
params.extend([keyword_pattern, keyword_pattern, keyword_pattern])
if conditions:
query += " WHERE " + " AND ".join(conditions)
cursor.execute(query, params)
return cursor.fetchone()['count']
def update_item(self, item_id: int, **kwargs) -> bool:
"""更新条目"""
allowed_fields = ['type', 'title', 'content', 'url', 'source', 'status', 'priority', 'due_date', 'note']