重构: PENDING恢复驳回按钮 + 转交弹窗升级多分支裂变(无限加分支)
This commit is contained in:
@ -103,6 +103,10 @@
|
||||
@tap="handleTaskAction({ task: activeTask, type: 'receive' })">
|
||||
✅ 接收任务
|
||||
</button>
|
||||
<button v-if="activeTask.status === 'PENDING'" class="footer-btn footer-reject"
|
||||
@tap="handleTaskAction({ task: activeTask, type: 'reject' })">
|
||||
❌ 驳回任务
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -235,50 +239,69 @@
|
||||
<button class="btn-danger" :disabled="actionLoading || !rejectReason.trim()" @tap="doReject">确认驳回</button>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 转交 -->
|
||||
<!-- 转交(支持多分支裂变) -->
|
||||
<template v-if="actionPopup.type === 'transfer'">
|
||||
<text class="popup-title">完工转交</text>
|
||||
<text class="popup-title">完工转交 · 裂变派发</text>
|
||||
|
||||
<!-- 工序选择 (Picker) -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">下一道工序 <text class="required">*</text></text>
|
||||
<picker mode="selector" :range="processOptions" @change="onProcessChange">
|
||||
<view class="picker-value">
|
||||
<text :class="transferForm.next_task_name ? '' : 'picker-placeholder'">
|
||||
{{ transferForm.next_task_name || '请选择下一道工序' }}
|
||||
</text>
|
||||
<text class="picker-arrow">▾</text>
|
||||
</view>
|
||||
</picker>
|
||||
<!-- 分支列表 -->
|
||||
<view v-for="(branch, idx) in transferForm.branches" :key="idx" class="branch-item">
|
||||
<view class="branch-header">
|
||||
<text class="branch-label">分支 {{ idx + 1 }}</text>
|
||||
<text v-if="transferForm.branches.length > 1" class="branch-del"
|
||||
@tap="removeBranch(idx)">🗑️ 删除</text>
|
||||
</view>
|
||||
|
||||
<!-- 工序选择 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">工序 <text class="required">*</text></text>
|
||||
<picker mode="selector" :range="processOptions" @change="(e) => onBranchProcessChange(idx, e)">
|
||||
<view class="picker-value">
|
||||
<text :class="branch.task_name ? '' : 'picker-placeholder'">
|
||||
{{ branch.task_name || '请选择工序' }}
|
||||
</text>
|
||||
<text class="picker-arrow">▾</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 接收人(入库分支不需要) -->
|
||||
<view v-if="!isBranchWarehouse(idx)" class="form-item">
|
||||
<text class="form-label">接收人 <text class="required">*</text></text>
|
||||
<picker mode="selector" :range="userOptions" range-key="name" @change="(e) => onBranchUserChange(idx, e)">
|
||||
<view class="picker-value">
|
||||
<text :class="branchUserName(idx) ? '' : 'picker-placeholder'">
|
||||
{{ branchUserName(idx) || '请选择接收人' }}
|
||||
</text>
|
||||
<text class="picker-arrow">▾</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view v-if="isBranchWarehouse(idx)" class="warehouse-hint">
|
||||
📦 入库分支 — 直接归档,无需指定接收人
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 接收人选择(仅非入库时显示) -->
|
||||
<view v-if="!isWarehouse" class="form-item">
|
||||
<text class="form-label">接收人 <text class="required">*</text></text>
|
||||
<picker mode="selector" :range="userOptions" range-key="name" @change="onUserChange">
|
||||
<view class="picker-value">
|
||||
<text :class="selectedUserName ? '' : 'picker-placeholder'">
|
||||
{{ selectedUserName || '请选择接收人' }}
|
||||
</text>
|
||||
<text class="picker-arrow">▾</text>
|
||||
</view>
|
||||
</picker>
|
||||
<!-- ➕ 添加分支 -->
|
||||
<button class="btn-add-branch" @tap="addBranch">➕ 添加并行分支</button>
|
||||
|
||||
<!-- 备注 -->
|
||||
<input v-model="transferForm.note" class="popup-input" placeholder="交接备注(选填)" style="margin-top:12px;" />
|
||||
|
||||
<!-- 预览 -->
|
||||
<view v-if="transferForm.branches.some(b => b.task_name)" class="preview-hint">
|
||||
将创建 {{ transferForm.branches.length }} 个并行任务:
|
||||
<text v-for="(b, i) in transferForm.branches" :key="i" style="display:block;margin-top:2px;">
|
||||
{{ i + 1 }}. {{ b.task_name || '—' }} → {{ branchUserName(i) || (isBranchWarehouse(i) ? '仓库' : '未选') }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 入库提示 -->
|
||||
<view v-if="isWarehouse" class="warehouse-hint">
|
||||
📦 该任务将直接入库,任务状态变为「已入库」
|
||||
</view>
|
||||
|
||||
<input v-model="transferForm.note" class="popup-input" placeholder="交接备注(选填)" />
|
||||
|
||||
<view v-if="transferForm.next_task_name" class="preview-hint">
|
||||
{{ isWarehouse ? '产品将入库并从个人待办中移除' : '将创建 1 个「' + transferForm.next_task_name + '」任务指派给 ' + (selectedUserName || '—') }}
|
||||
</view>
|
||||
<view class="popup-btns">
|
||||
<button class="btn-cancel" @tap="closeActionPopup">取消</button>
|
||||
<button class="btn-primary" :disabled="actionLoading || !transferForm.next_task_name || (!isWarehouse && !transferForm.assignees.length)" @tap="doTransfer">
|
||||
{{ isWarehouse ? '📦 确认入库' : '确认转交' }}
|
||||
<button class="btn-primary"
|
||||
:disabled="actionLoading || !transferForm.branches.some(b => b.task_name) || !canSubmitTransfer"
|
||||
@tap="doTransfer">
|
||||
{{ actionLoading ? '提交中...' : '确认转交 (' + transferForm.branches.length + '分支)' }}
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user