From 3cb85f28b4f1d2df6884061caab6acd3f944e24a Mon Sep 17 00:00:00 2001 From: duxingchen Date: Tue, 11 Aug 2026 17:48:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E5=AE=8F=E8=A7=82=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=89=8D=E7=AB=AFUX=E9=87=8D=E6=9E=84=20=E2=80=94=20?= =?UTF-8?q?=E9=9D=9E=E6=9D=83=E9=99=90=E4=BA=BA=E5=91=98=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E7=AE=AD=E5=A4=B4+=E6=8B=A6=E6=88=AA=E7=82=B9=E5=87=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增 canEditOverallStatus computed: - SUPER_ADMIN 直接放行 - 递归遍历 task_tree,仅 WIP/PENDING 主线任务负责人有权 - 严格对齐后端 update_overall_status 的 main_task 判断 2. handleOverallBarClick 增加权限拦截: 无权限点击 → Toast '仅超级管理员或当前主线负责人可修改状态' 3. overall-arrow 增加 canEditOverallStatus 条件: 无权限用户不显示 ▾ 箭头,视觉上明确不可操作 --- track-uniapp/src/pages/scan/detail.vue | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/track-uniapp/src/pages/scan/detail.vue b/track-uniapp/src/pages/scan/detail.vue index 53580ee..606edd9 100644 --- a/track-uniapp/src/pages/scan/detail.vue +++ b/track-uniapp/src/pages/scan/detail.vue @@ -10,7 +10,7 @@ 宏观状态 {{ product.overall_status || '未激活 — 点击发起首道工序' }} - + @@ -245,6 +245,27 @@ export default { return this.product ? find(this.product.task_tree) : false; }, msgUnreadCount() { if (!this.lastMsgSeenAt) return this.messages.length; return this.messages.filter(m => m.created_at > this.lastMsgSeenAt).length; }, + // 🔒 宏观状态修改权限:对齐后端 update_overall_status 的 main_task 判断标准 + canEditOverallStatus() { + if (!this.currentUser) return false; + if (this.currentUser.role === 'SUPER_ADMIN') return true; + if (!this.product || !this.product.task_tree) return false; + let hasPermission = false; + const checkTask = (tasks) => { + if (!tasks || hasPermission) return; + for (const t of tasks) { + const isMain = !t.parent_task_id || t.task_type === 'TRANSFER' || t.task_type === 'RECOVERY'; + if (isMain && (t.status === 'WIP' || t.status === 'PENDING')) { + if (t.assignee_id == this.currentUserId || t.assignee_id == this.currentUsername) { + hasPermission = true; + } + } + checkTask(t.child_tasks); + } + }; + checkTask(this.product.task_tree); + return hasPermission; + }, }, onLoad(options) { this.loadUsers(); this.loadCurrentUser(); const sn = options.serial || ""; if (sn) { this.doQuery(sn); return; } /* 🚀 兜底: 从 taskId 反查 product */ const tid = options.taskId || ""; if (tid) this.doQueryByTask(tid); }, // 🚀 onShow 生命周期:每次页面显示时刷新留言板(解决从聊天室退回不更新问题) @@ -286,7 +307,7 @@ export default { onTaskNameChange(e) { const idx = e.detail.value; this.firstForm.taskNameIdx = idx; this.firstForm.task_name = TASK_NAME_OPTIONS[idx]; }, onAssigneeChange(e) { const idx = e.detail.value; const u = this.users[idx]; if (u) { this.firstForm.assigneeIdx = idx; this.firstForm.assignee_id = u.username; this.firstForm.assigneeLabel = `${u.full_name} (${u.username})`; } }, openCreateFirstTask() { this.isWarehouseTransfer = false; if (this.currentMode === 'tree') this.currentMode = 'workspace'; this.firstForm = { assignee_id: "", assigneeLabel: "", note: "" }; this.createFirstVisible = true; }, - handleOverallBarClick() { if (!this.product.task_tree || !this.product.task_tree.length) { this.openCreateFirstTask(); } else { this.showStatusPicker = true; } }, + handleOverallBarClick() { if (!this.product.task_tree || !this.product.task_tree.length) { this.openCreateFirstTask(); } else if (this.canEditOverallStatus) { this.showStatusPicker = true; } else { uni.showToast({ title: '仅超级管理员或当前主线负责人可修改状态', icon: 'none', duration: 2500 }); } }, openWarehouseTransfer() { this.isWarehouseTransfer = true; this.openCreateFirstTask(); }, async doCreateFirstTask() { this.firstSaving = true; try { await post("/tasks/", { product_id: this.product.id, task_name: "待确认", assignee_id: this.firstForm.assignee_id, notify_parent_on_complete: false, remark: this.firstForm.note.trim() || undefined }); if (this.product.current_location_id === 'virtual_warehouse') { try { await patch(`/products/${this.product.id}`, { current_location_id: this.firstForm.assignee_id }); } catch {} } uni.showToast({ title: "任务已派发,待接收", icon: "success" }); this.createFirstVisible = false; this.doQuery(this.product.serial_number); } catch {} finally { this.firstSaving = false; } },