From 3a7e52360c653a991ea4ad3fd8cac4c613a4ead6 Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Fri, 10 Apr 2026 20:53:22 +0000 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E8=AE=B0=E5=BD=95=E6=9D=83=E9=99=90=E5=8F=98?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改用户权限时记录旧角色→新角色(中文)和用户名 - 日志显示"查看者 → 高级编辑"格式 - 商业认证日志显示商户名 Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/main.py | 14 ++++++++++++-- frontend/src/views/AuditLog.vue | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/backend/main.py b/backend/main.py index 18a7bea..b469c36 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1094,6 +1094,9 @@ def delete_user(user_id: int, user=Depends(require_role("admin"))): @app.put("/api/users/{user_id}") def update_user(user_id: int, body: UserUpdate, user=Depends(require_role("admin"))): conn = get_db() + target = conn.execute("SELECT role, display_name, username FROM users WHERE id = ?", (user_id,)).fetchone() + old_role = target["role"] if target else "unknown" + target_name = (target["display_name"] or target["username"]) if target else "unknown" if body.role is not None: if body.role == "admin": conn.close() @@ -1101,8 +1104,15 @@ def update_user(user_id: int, body: UserUpdate, user=Depends(require_role("admin conn.execute("UPDATE users SET role = ?, role_changed_at = datetime('now') WHERE id = ?", (body.role, user_id)) if body.display_name is not None: conn.execute("UPDATE users SET display_name = ? WHERE id = ?", (body.display_name, user_id)) - log_audit(conn, user["id"], "update_user", "user", user_id, None, - json.dumps({"role": body.role, "display_name": body.display_name})) + role_labels = {"admin": "管理员", "senior_editor": "高级编辑", "editor": "编辑", "viewer": "查看者"} + detail = {} + if body.role is not None and body.role != old_role: + detail["from_role"] = role_labels.get(old_role, old_role) + detail["to_role"] = role_labels.get(body.role, body.role) + if body.display_name is not None: + detail["display_name"] = body.display_name + log_audit(conn, user["id"], "update_user", "user", user_id, target_name, + json.dumps(detail, ensure_ascii=False)) conn.commit() conn.close() return {"ok": True} diff --git a/frontend/src/views/AuditLog.vue b/frontend/src/views/AuditLog.vue index 0d98051..71a9034 100644 --- a/frontend/src/views/AuditLog.vue +++ b/frontend/src/views/AuditLog.vue @@ -153,9 +153,10 @@ function parsedDetail(log) { try { const d = JSON.parse(log.detail) const parts = [] + if (d.from_role && d.to_role) parts.push(`${d.from_role} → ${d.to_role}`) if (d.from_user) parts.push(`来自: ${d.from_user}`) if (d.reason) parts.push(`原因: ${d.reason}`) - if (d.role) parts.push(`角色: ${d.role}`) + if (d.business_name) parts.push(`商户: ${d.business_name}`) if (d.display_name) parts.push(`显示名: ${d.display_name}`) if (d.original_log_id) parts.push(`恢复自 #${d.original_log_id}`) if (parts.length) return parts.join(' · ') -- 2.49.1 From ac3abc3c84704f268e926742c3c3e8c44c9ac724 Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Fri, 10 Apr 2026 20:55:32 +0000 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=E6=89=B9=E9=87=8F=E6=94=B9=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E5=8F=AA=E5=8F=91=E9=80=81tags=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=8F=91=E9=80=81=E6=95=B4=E4=B8=AArecipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复因ingredients格式不匹配(oil vs oil_name)导致PUT请求失败 标签修改实际未保存到数据库的问题 Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/views/RecipeManager.vue | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 16beca7..cd5f6f7 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -601,15 +601,22 @@ async function applyBatchTags() { for (const id of pubIds) { const recipe = recipeStore.recipes.find(r => r._id === id) if (!recipe) continue + let newTags = [...recipe.tags] let changed = false for (const t of tagsToAdd) { - if (!recipe.tags.includes(t)) { recipe.tags.push(t); changed = true } + if (!newTags.includes(t)) { newTags.push(t); changed = true } } for (const t of tagsToRemove) { - const idx = recipe.tags.indexOf(t) - if (idx >= 0) { recipe.tags.splice(idx, 1); changed = true } + const idx = newTags.indexOf(t) + if (idx >= 0) { newTags.splice(idx, 1); changed = true } + } + if (changed) { + await api(`/api/recipes/${recipe._id}`, { + method: 'PUT', + body: JSON.stringify({ tags: newTags }), + }) + recipe.tags = newTags } - if (changed) await recipeStore.saveRecipe(recipe) } for (const id of diaryIds) { const d = diaryStore.userDiary.find(r => r.id === id) -- 2.49.1 From f2c95985cf207bb93950d4e89004bf269e3ad7b3 Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Fri, 10 Apr 2026 20:59:58 +0000 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20=E6=A0=87=E7=AD=BE=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E6=97=B6=E8=87=AA=E5=8A=A8=E5=B1=95=E5=BC=80=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/views/RecipeManager.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index cd5f6f7..1f26ce7 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -109,7 +109,7 @@ 已贡献 {{ sharedCount.adopted }}/{{ sharedCount.total }} 条 {{ showMyRecipes ? '▾' : '▸' }} -