fix: 高级编辑直接添加公共库+编辑者权限精确控制
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 4s
Test / build-check (push) Successful in 3s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 17s
Test / e2e-test (push) Failing after 56s
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 4s
Test / build-check (push) Successful in 3s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 17s
Test / e2e-test (push) Failing after 56s
公共库添加: - 高级编辑直接添加到公共库时owner_id设为admin,所有人可见 - 高级编辑添加不触发审核通知 精油价目权限: - 编辑精油改为canManage(senior_editor+admin) - editor只能编辑配方,不能编辑精油价目 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -781,8 +781,14 @@ def create_recipe(recipe: RecipeIn, user=Depends(get_current_user)):
|
|||||||
raise HTTPException(401, "请先登录")
|
raise HTTPException(401, "请先登录")
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
# Senior editors adding directly to public library: set owner to admin so everyone can see
|
||||||
|
owner_id = user["id"]
|
||||||
|
if user["role"] in ("senior_editor",):
|
||||||
|
admin = c.execute("SELECT id FROM users WHERE role = 'admin' LIMIT 1").fetchone()
|
||||||
|
if admin:
|
||||||
|
owner_id = admin["id"]
|
||||||
c.execute("INSERT INTO recipes (name, note, owner_id) VALUES (?, ?, ?)",
|
c.execute("INSERT INTO recipes (name, note, owner_id) VALUES (?, ?, ?)",
|
||||||
(recipe.name, recipe.note, user["id"]))
|
(recipe.name, recipe.note, owner_id))
|
||||||
rid = c.lastrowid
|
rid = c.lastrowid
|
||||||
for ing in recipe.ingredients:
|
for ing in recipe.ingredients:
|
||||||
c.execute(
|
c.execute(
|
||||||
@@ -793,8 +799,8 @@ def create_recipe(recipe: RecipeIn, user=Depends(get_current_user)):
|
|||||||
c.execute("INSERT OR IGNORE INTO tags (name) VALUES (?)", (tag,))
|
c.execute("INSERT OR IGNORE INTO tags (name) VALUES (?)", (tag,))
|
||||||
c.execute("INSERT OR IGNORE INTO recipe_tags (recipe_id, tag_name) VALUES (?, ?)", (rid, tag))
|
c.execute("INSERT OR IGNORE INTO recipe_tags (recipe_id, tag_name) VALUES (?, ?)", (rid, tag))
|
||||||
log_audit(conn, user["id"], "create_recipe", "recipe", rid, recipe.name)
|
log_audit(conn, user["id"], "create_recipe", "recipe", rid, recipe.name)
|
||||||
# Notify admin only when non-admin creates a recipe
|
# Notify admin when non-admin/non-senior_editor creates a recipe (needs review)
|
||||||
if user["role"] != "admin":
|
if user["role"] not in ("admin", "senior_editor"):
|
||||||
who = user.get("display_name") or user["username"]
|
who = user.get("display_name") or user["username"]
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO notifications (target_role, title, body) VALUES (?, ?, ?)",
|
"INSERT INTO notifications (target_role, title, body) VALUES (?, ?, ?)",
|
||||||
|
|||||||
@@ -98,15 +98,15 @@
|
|||||||
<button @click="viewMode = 'drop'" :style="viewMode === 'drop' ? 'background:var(--sage);color:white' : 'background:white;color:var(--text-mid)'" style="border:none;border-radius:0;font-size:12px;padding:6px 12px;cursor:pointer">每滴价</button>
|
<button @click="viewMode = 'drop'" :style="viewMode === 'drop' ? 'background:var(--sage);color:white' : 'background:white;color:var(--text-mid)'" style="border:none;border-radius:0;font-size:12px;padding:6px 12px;cursor:pointer">每滴价</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Desktop: text buttons -->
|
<!-- Desktop: text buttons -->
|
||||||
<button v-if="auth.canEdit" class="toolbar-btn-text" @click="showAddForm = !showAddForm">{{ showAddForm ? '收起' : '+ 新增' }}</button>
|
<button v-if="auth.canManage" class="toolbar-btn-text" @click="showAddForm = !showAddForm">{{ showAddForm ? '收起' : '+ 新增' }}</button>
|
||||||
<button v-if="auth.isAdmin" class="toolbar-btn-text" @click="exportPDF">📥 导出PDF</button>
|
<button v-if="auth.isAdmin" class="toolbar-btn-text" @click="exportPDF">📥 导出PDF</button>
|
||||||
<!-- Mobile: emoji-only buttons -->
|
<!-- Mobile: emoji-only buttons -->
|
||||||
<button v-if="auth.canEdit" class="toolbar-btn-icon" @click="showAddForm = !showAddForm" title="新增精油">➕</button>
|
<button v-if="auth.canManage" class="toolbar-btn-icon" @click="showAddForm = !showAddForm" title="新增精油">➕</button>
|
||||||
<button v-if="auth.isAdmin" class="toolbar-btn-icon" @click="exportPDF" title="导出PDF">📄</button>
|
<button v-if="auth.isAdmin" class="toolbar-btn-icon" @click="exportPDF" title="导出PDF">📄</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Add Oil Form (toggleable) -->
|
<!-- Add Oil Form (toggleable) -->
|
||||||
<div v-if="showAddForm && auth.canEdit" class="add-oil-form">
|
<div v-if="showAddForm && auth.canManage" class="add-oil-form">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input v-model="newOilName" style="flex:1;min-width:120px" placeholder="精油名称" class="form-input-sm" />
|
<input v-model="newOilName" style="flex:1;min-width:120px" placeholder="精油名称" class="form-input-sm" />
|
||||||
<input v-model="newOilEnName" style="flex:1;min-width:100px" placeholder="英文名" class="form-input-sm" />
|
<input v-model="newOilEnName" style="flex:1;min-width:100px" placeholder="英文名" class="form-input-sm" />
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="auth.canEdit" class="oil-chip-actions" @click.stop>
|
<div v-if="auth.canManage" class="oil-chip-actions" @click.stop>
|
||||||
<button @click="editOil(name)" title="编辑">✏️</button>
|
<button @click="editOil(name)" title="编辑">✏️</button>
|
||||||
<button @click="removeOil(name)" title="删除">🗑</button>
|
<button @click="removeOil(name)" title="删除">🗑</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user