diff --git a/track-uniapp/src/pages/scan/detail.vue b/track-uniapp/src/pages/scan/detail.vue index 4640b66..c7087f9 100644 --- a/track-uniapp/src/pages/scan/detail.vue +++ b/track-uniapp/src/pages/scan/detail.vue @@ -103,6 +103,10 @@ @tap="handleTaskAction({ task: activeTask, type: 'receive' })"> ✅ 接收任务 + @@ -235,50 +239,69 @@ - + @@ -334,7 +357,7 @@ export default { actionPopup: { visible: false, type: "", task: null }, actionLoading: false, rejectReason: "", - transferForm: { next_task_name: "", assignees: [], selectedUserId: "", warehouse: false, note: "" }, + transferForm: { branches: [{ task_name: "", assignee_id: "" }], note: "" }, }; }, computed: { @@ -346,12 +369,12 @@ export default { if (!this.currentUser) return true; return this.currentUser.username === this.recordPopup.task.assignee_id; }, - selectedUserName() { - const u = this.userOptions.find(u => u.id === this.transferForm.selectedUserId); - return u ? u.name : ""; - }, - isWarehouse() { - return this.transferForm.next_task_name === "🏭 入库 (virtual_warehouse)"; + canSubmitTransfer() { + return this.transferForm.branches.every(b => { + if (!b.task_name) return false; + if (b.task_name === "🏭 入库 (virtual_warehouse)") return true; + return !!b.assignee_id; + }); }, activeTask() { // 查找树中第一个 WIP 或 PENDING 任务作为底部 Footer 的操作目标 @@ -658,7 +681,7 @@ export default { this.actionPopup = { visible: true, type, task }; this.rejectReason = ""; - this.transferForm = { next_task_name: "", assignees: [], selectedUserId: "", warehouse: false, note: "" }; + this.transferForm = { branches: [{ task_name: "", assignee_id: "" }], note: "" }; }, handleViewRecords(task) { uni.navigateTo({ url: `/pages/scan/records?taskId=${task.id}` }); @@ -683,28 +706,46 @@ export default { this.doQuery(this.product.serial_number); } catch {} finally { this.actionLoading = false; } }, - onProcessChange(e) { - this.transferForm.next_task_name = this.processOptions[e.detail.value]; - }, - onUserChange(e) { - const user = this.userOptions[e.detail.value]; - if (user) { - this.transferForm.selectedUserId = user.id; - this.transferForm.assignees = [user.id]; + // ---- 多分支操作 ---- + addBranch() { + if (this.transferForm.branches.length >= 5) { + uni.showToast({ title: "最多 5 个并行分支", icon: "none" }); return; } + this.transferForm.branches.push({ task_name: "", assignee_id: "" }); + }, + removeBranch(idx) { + if (this.transferForm.branches.length <= 1) return; + this.transferForm.branches.splice(idx, 1); + }, + onBranchProcessChange(idx, e) { + this.transferForm.branches[idx].task_name = this.processOptions[e.detail.value]; + // 切换工序时清空接收人 + this.transferForm.branches[idx].assignee_id = ""; + }, + onBranchUserChange(idx, e) { + const user = this.userOptions[e.detail.value]; + if (user) this.transferForm.branches[idx].assignee_id = user.id; + }, + isBranchWarehouse(idx) { + return this.transferForm.branches[idx].task_name === "🏭 入库 (virtual_warehouse)"; + }, + branchUserName(idx) { + const u = this.userOptions.find(u => u.id === this.transferForm.branches[idx].assignee_id); + return u ? u.name : ""; }, async doTransfer() { this.actionLoading = true; - const finalAssignees = this.isWarehouse - ? ["virtual_warehouse"] - : [...this.transferForm.assignees]; + const branches = this.transferForm.branches.filter(b => b.task_name); try { await post(`/tasks/${this.actionPopup.task.id}/transfer`, { - next_assignees: finalAssignees, - next_task_name: this.transferForm.next_task_name.trim(), + next_tasks: branches.map(b => ({ + task_name: b.task_name, + assignees: b.task_name === "🏭 入库 (virtual_warehouse)" + ? ["virtual_warehouse"] : [b.assignee_id], + })), note: this.transferForm.note.trim() || undefined, }); - uni.showToast({ title: this.isWarehouse ? "已入库" : "转交成功", icon: "success" }); + uni.showToast({ title: `已派发 ${branches.length} 个分支`, icon: "success" }); this.closeActionPopup(); this.doQuery(this.product.serial_number); } catch {} finally { this.actionLoading = false; } @@ -793,6 +834,14 @@ export default { .warehouse-hint { font-size: 13px; background: #ede9fe; color: #7c3aed; padding: 10px 14px; border-radius: 10px; margin: 8px 0; text-align: center; } .preview-hint { font-size: 12px; background: #f0fdf4; color: #16a34a; padding: 8px 10px; border-radius: 8px; margin: 6px 0; } +/* 多分支裂变 */ +.branch-item { background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 10px; padding: 12px; margin-bottom: 10px; } +.branch-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; } +.branch-label { font-size: 13px; font-weight: 700; color: #374151; } +.branch-del { font-size: 12px; color: #ef4444; font-weight: 600; padding: 2px 8px; } +.btn-add-branch { width: 100%; height: 40px; border: 2px dashed #93c5fd; border-radius: 10px; background: #eff6ff; color: #2563eb; font-size: 14px; font-weight: 700; line-height: 40px; margin: 4px 0; } +.btn-add-branch::after { border: none; } + /* Picker & 表单 */ .field-label { font-size: 14px; font-weight: 600; color: #374151; margin-top: 10px; margin-bottom: 4px; } .required { color: #ef4444; } @@ -826,6 +875,7 @@ export default { .footer-transfer { background: #dcfce7; color: #16a34a; } .footer-record { background: #eff6ff; color: #2563eb; } .footer-receive { background: #dbeafe; color: #1d4ed8; } +.footer-reject { background: #fce4ec; color: #dc2626; } /* Picker 选择器 */ .form-item { margin: 10px 0; }