feat: 新功能改进 #20

Merged
hera merged 57 commits from feat/next-improvements into main 2026-04-10 20:30:37 +00:00
2 changed files with 29 additions and 18 deletions
Showing only changes of commit f3e4329d1f - Show all commits

View File

@@ -1497,19 +1497,27 @@ def list_recipe_reviews(user=Depends(require_role("admin"))):
@app.get("/api/me/contribution")
def my_contribution(user=Depends(get_current_user)):
if not user.get("id"):
return {"adopted_count": 0, "shared_count": 0}
return {"adopted_count": 0, "shared_count": 0, "adopted_names": [], "pending_names": []}
conn = get_db()
# adopted_count: recipes adopted from this user (owner changed to admin)
adopted = conn.execute(
"SELECT COUNT(*) FROM audit_log WHERE action = 'adopt_recipe' AND detail LIKE ?",
(f'%"from_user": "{user.get("display_name") or user.get("username")}"%',)
).fetchone()[0]
# pending: recipes still owned by user in public library (not yet adopted)
pending = conn.execute(
"SELECT COUNT(*) FROM recipes WHERE owner_id = ?", (user["id"],)
).fetchone()[0]
display = user.get("display_name") or user.get("username")
# adopted: recipes adopted from this user
adopted_rows = conn.execute(
"SELECT target_name FROM audit_log WHERE action = 'adopt_recipe' AND detail LIKE ?",
(f'%"from_user": "{display}"%',)
).fetchall()
adopted_names = [r["target_name"] for r in adopted_rows if r["target_name"]]
# pending: recipes still owned by user in public library
pending_rows = conn.execute(
"SELECT name FROM recipes WHERE owner_id = ?", (user["id"],)
).fetchall()
pending_names = [r["name"] for r in pending_rows]
conn.close()
return {"adopted_count": adopted, "shared_count": adopted + pending}
return {
"adopted_count": len(adopted_names),
"shared_count": len(adopted_names) + len(pending_names),
"adopted_names": adopted_names,
"pending_names": pending_names,
}
# ── Notifications ──────────────────────────────────────

View File

@@ -1028,14 +1028,19 @@ async function saveAllParsed() {
closeOverlay()
}
const sharedCount = ref({ adopted: 0, total: 0 })
const sharedCount = ref({ adopted: 0, total: 0, adoptedNames: [], pendingNames: [] })
async function loadContribution() {
try {
const res = await api('/api/me/contribution')
if (res.ok) {
const data = await res.json()
sharedCount.value = { adopted: data.adopted_count || 0, total: data.shared_count || 0 }
sharedCount.value = {
adopted: data.adopted_count || 0,
total: data.shared_count || 0,
adoptedNames: data.adopted_names || [],
pendingNames: data.pending_names || [],
}
}
} catch {}
}
@@ -1136,11 +1141,9 @@ function openRecipeDetail(recipe) {
}
function getDiaryShareStatus(d) {
// Check if a public recipe with same name exists, owned by current user or adopted by admin
const pub = recipeStore.recipes.find(r => r.name === d.name)
if (!pub) return null
if (pub._owner_id === auth.user?.id) return 'pending'
return 'shared'
if (sharedCount.value.adoptedNames.includes(d.name)) return 'shared'
if (sharedCount.value.pendingNames.includes(d.name)) return 'pending'
return null
}
async function shareDiaryToPublic(diary) {