feat: 标签管理添加编辑功能,支持修改标签名称

This commit is contained in:
2026-04-13 16:35:09 +08:00
parent 68411813b3
commit ad6d369069
2 changed files with 87 additions and 5 deletions

View File

@@ -132,6 +132,23 @@ def create_tag():
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/tags/<int:tag_id>', 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/<int:tag_id>', methods=['DELETE'])
def delete_tag(tag_id):
"""删除标签"""
@@ -989,14 +1006,28 @@ async function loadTagManagerList() {
}
container.innerHTML = tags.map(tag => `
<div class="d-flex justify-content-between align-items-center p-2 border-bottom">
<div>
<div class="d-flex justify-content-between align-items-center p-2 border-bottom" id="tag-row-${tag.id}">
<div id="tag-display-${tag.id}">
<span class="badge bg-secondary">${tag.name}</span>
<span class="text-muted small ms-2">${tag.item_count || 0} 个条目</span>
</div>
<button class="btn btn-sm btn-outline-danger" onclick="deleteTagManager(${tag.id}, '${tag.name}')">
<i class="bi bi-trash"></i>
</button>
<div id="tag-edit-${tag.id}" style="display:none;">
<input type="text" class="form-control form-control-sm" id="edit-tag-name-${tag.id}" value="${tag.name}" style="width:150px;">
</div>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" id="tag-edit-btn-${tag.id}" onclick="showEditTag(${tag.id})" title="编辑">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-outline-success" id="tag-save-btn-${tag.id}" style="display:none;" onclick="saveEditTag(${tag.id})" title="保存">
<i class="bi bi-check"></i>
</button>
<button class="btn btn-outline-secondary" id="tag-cancel-btn-${tag.id}" style="display:none;" onclick="cancelEditTag(${tag.id}, '${tag.name}')" title="取消">
<i class="bi bi-x"></i>
</button>
<button class="btn btn-outline-danger" onclick="deleteTagManager(${tag.id}, '${tag.name}')" title="删除">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
`).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`);

View File

@@ -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: