From ad6d369069968b4d22f1ed5e9e4cd372d536b732 Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Mon, 13 Apr 2026 16:35:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=A0=87=E7=AD=BE=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BC=96=E8=BE=91=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BF=AE=E6=94=B9=E6=A0=87=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xian_favor/api.py | 80 ++++++++++++++++++++++++++++++++++++++++++++--- xian_favor/db.py | 12 +++++++ 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/xian_favor/api.py b/xian_favor/api.py index e96a060..facaf55 100644 --- a/xian_favor/api.py +++ b/xian_favor/api.py @@ -132,6 +132,23 @@ def create_tag(): return jsonify({'success': False, 'error': str(e)}), 500 +@app.route('/api/tags/', methods=['PUT']) +def update_tag(tag_id): + """更新标签""" + data = request.get_json() + name = data.get('name', '').strip() + + if not name: + return jsonify({'success': False, 'error': '标签名不能为空'}), 400 + + try: + if db.update_tag(tag_id, name): + return jsonify({'success': True, 'data': {'id': tag_id, 'name': name}}) + return jsonify({'success': False, 'error': '标签不存在或名称已存在'}), 404 + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + + @app.route('/api/tags/', methods=['DELETE']) def delete_tag(tag_id): """删除标签""" @@ -989,14 +1006,28 @@ async function loadTagManagerList() { } container.innerHTML = tags.map(tag => ` -
-
+
+
${tag.name} ${tag.item_count || 0} 个条目
- + +
+ + + + +
`).join(''); } @@ -1027,6 +1058,45 @@ async function deleteTagManager(id, name) { loadItems(); } +// 编辑标签 +function showEditTag(id) { + document.getElementById(`tag-display-${id}`).style.display = 'none'; + document.getElementById(`tag-edit-${id}`).style.display = 'block'; + document.getElementById(`tag-edit-btn-${id}`).style.display = 'none'; + document.getElementById(`tag-save-btn-${id}`).style.display = 'inline-block'; + document.getElementById(`tag-cancel-btn-${id}`).style.display = 'inline-block'; + document.getElementById(`edit-tag-name-${id}`).focus(); +} + +function cancelEditTag(id, oldName) { + document.getElementById(`edit-tag-name-${id}`).value = oldName; + document.getElementById(`tag-display-${id}`).style.display = 'block'; + document.getElementById(`tag-edit-${id}`).style.display = 'none'; + document.getElementById(`tag-edit-btn-${id}`).style.display = 'inline-block'; + document.getElementById(`tag-save-btn-${id}`).style.display = 'none'; + document.getElementById(`tag-cancel-btn-${id}`).style.display = 'none'; +} + +async function saveEditTag(id) { + const newName = document.getElementById(`edit-tag-name-${id}`).value.trim(); + if (!newName) return; + + const res = await fetch(`${API_BASE}/tags/${id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: newName }) + }); + + if (res.ok) { + loadTagManagerList(); + loadTags(); + loadItems(); + } else { + const data = await res.json(); + alert(data.error || '更新失败'); + } +} + // 导出数据 async function exportData() { const res = await fetch(`${API_BASE}/items?limit=1000`); diff --git a/xian_favor/db.py b/xian_favor/db.py index 990e3ea..9046e91 100644 --- a/xian_favor/db.py +++ b/xian_favor/db.py @@ -244,6 +244,18 @@ class Database: """) return [dict(row) for row in cursor.fetchall()] + def update_tag(self, tag_id: int, name: str) -> bool: + """更新标签名称""" + with self.get_conn() as conn: + cursor = conn.cursor() + # 检查名称是否已存在(排除自己) + cursor.execute("SELECT id FROM tags WHERE name = ? AND id != ?", (name, tag_id)) + if cursor.fetchone(): + return False # 名称已存在 + cursor.execute("UPDATE tags SET name = ? WHERE id = ?", (name, tag_id)) + conn.commit() + return cursor.rowcount > 0 + def delete_tag(self, tag_id: int = None, name: str = None) -> bool: """删除标签""" with self.get_conn() as conn: