diff --git a/server-api/app/support/FulfillmentFlowService.php b/server-api/app/support/FulfillmentFlowService.php index 0d08fd7..f77cb51 100644 --- a/server-api/app/support/FulfillmentFlowService.php +++ b/server-api/app/support/FulfillmentFlowService.php @@ -242,10 +242,16 @@ class FulfillmentFlowService 'sent_to_zhongjian' => 'inbound', default => '', }; + $nextActionText = match ($stage) { + 'warehouse_received' => '送检出库', + 'sent_to_zhongjian' => '送检入库', + 'report_published' => '待寄回订单可填写回寄物流', + default => '暂无可执行送检动作', + }; return array_merge($this->formatOrderContext((int)$flow['order_id']), [ 'next_action' => $nextAction, - 'next_action_text' => $nextAction === 'outbound' ? '送检出库' : ($nextAction === 'inbound' ? '送检入库' : '暂无可执行送检动作'), + 'next_action_text' => $nextActionText, ]); } @@ -271,6 +277,7 @@ class FulfillmentFlowService if (!$report || ($report['report_status'] ?? '') !== 'published') { throw new \InvalidArgumentException('该报告未发布,不符合寄回条件'); } + $this->ensurePendingReturnOrder($flow); return $context + [ 'return_confirmation' => [ @@ -291,6 +298,7 @@ class FulfillmentFlowService if (!$report || ($report['report_status'] ?? '') !== 'published') { throw new \InvalidArgumentException('该报告未发布,不符合寄回条件'); } + $this->ensurePendingReturnOrder($flow); $tag = (new MaterialTagService())->findTagByInput($qrInput); if (!$tag || (int)($tag['report_id'] ?? 0) !== (int)$report['id']) { @@ -342,6 +350,7 @@ class FulfillmentFlowService if (!$report || ($report['report_status'] ?? '') !== 'published') { throw new \InvalidArgumentException('该报告未发布,不符合寄回条件'); } + $this->ensurePendingReturnOrder($flow); if ((int)$report['id'] !== $reportId) { throw new \InvalidArgumentException('确认的报告与当前订单报告不匹配'); } @@ -349,22 +358,7 @@ class FulfillmentFlowService return $this->formatOrderContext((int)$flow['order_id'], $request); } - if (($flow['service_provider'] ?? '') === 'zhongjian') { - $content = Db::name('report_contents')->where('report_id', (int)$report['id'])->find(); - $files = $this->decodeJsonArray($content['zhongjian_report_files_json'] ?? null); - if (trim((string)($report['zhongjian_report_no'] ?? '')) === '' || !$files) { - throw new \InvalidArgumentException('中检报告未完整录入,不能确认寄回'); - } - - return $this->markReturnConfirmed($flow, $operator, 'return_confirmed', '中检报告已确认', '仓管已查看中检报告编号和报告文件。'); - } - - $boundTag = (new MaterialTagService())->findBoundTagForReport((int)$report['id']); - if (!$boundTag) { - throw new \InvalidArgumentException('当前报告未绑定验真吊牌,不能确认寄回'); - } - - return $this->markReturnConfirmed($flow, $operator, 'return_tag_verified', '验真吊牌确认', '仓管已核对验真吊牌与报告信息。'); + return $this->markReturnConfirmed($flow, $operator, 'return_confirmed', '回寄确认', '仓管扫描内部流转码确认订单处于待寄回状态。'); } public function shipReturn(string $tagNo, string $expressCompany, string $trackingNo, Request $request, array $packingAttachments = []): array @@ -940,6 +934,19 @@ class FulfillmentFlowService ]); } + private function ensurePendingReturnOrder(array $flow): array + { + $order = Db::name('orders')->where('id', (int)$flow['order_id'])->find(); + if (!$order) { + throw new \RuntimeException('订单不存在', 404); + } + if ((string)($order['order_status'] ?? '') !== 'report_published') { + throw new \InvalidArgumentException('当前订单不处于待寄回状态'); + } + + return $order; + } + private function operator(Request $request): array { $id = (int)$request->header('x-admin-id', 0); diff --git a/work-app/src/pages/scan/index.vue b/work-app/src/pages/scan/index.vue index f8669ff..328d5ea 100644 --- a/work-app/src/pages/scan/index.vue +++ b/work-app/src/pages/scan/index.vue @@ -24,7 +24,6 @@ const scanValue = ref(""); const matchedInboundNo = ref(""); const internalTagNo = ref(""); const inboundAttachments = ref([]); -const materialQr = ref(""); const expressCompany = ref(""); const returnTrackingNo = ref(""); const context = ref(null); @@ -57,10 +56,11 @@ const returnFlowEnded = computed(() => Boolean(context.value?.transfer_flow?.return_shipped_at), ); const canReturnShip = computed(() => Boolean(context.value?.transfer_flow?.return_confirmed_at) && !returnFlowEnded.value); +const isPendingReturnOrder = computed(() => context.value?.order_info.order_status === "report_published"); const outboundActionText = computed(() => { if (actionLoading.value) return "提交中"; if (returnFlowEnded.value && !context.value?.next_action) return "寄回已完成"; - if (canReturnShip.value && !context.value?.next_action) return "填写回寄信息"; + if ((canReturnShip.value || isPendingReturnOrder.value) && !context.value?.next_action) return "填写回寄信息"; return "确认操作"; }); @@ -74,7 +74,6 @@ function chooseMode(next: WarehouseMode) { matchedInboundNo.value = ""; internalTagNo.value = ""; inboundAttachments.value = []; - materialQr.value = ""; expressCompany.value = ""; returnTrackingNo.value = ""; context.value = null; @@ -95,7 +94,6 @@ function applyReturnShippedPayload(payload: ReturnShippedPayload | AdminWarehous if (nextContext) { context.value = nextContext; } - materialQr.value = ""; expressCompany.value = ""; returnTrackingNo.value = ""; } @@ -306,14 +304,26 @@ function closeInboundVideo() { async function lookupOutbound() { loading.value = true; try { + let zhongjianContext: AdminWarehouseWorkbenchContext | null = null; try { - context.value = await adminApi.lookupZhongjianWarehouseTransfer(scanValue.value.trim()); + zhongjianContext = await adminApi.lookupZhongjianWarehouseTransfer(scanValue.value.trim()); + } catch { + zhongjianContext = null; + } + + if (zhongjianContext) { + context.value = zhongjianContext; + if (isPendingReturnOrder.value && !context.value.next_action) { + await enterReturnShippingFlow(); + return; + } showInfoToast("已识别中检流转"); return; - } catch (zhongjianError) { - context.value = await adminApi.lookupWarehouseReturn(scanValue.value.trim()); - showInfoToast("已打开寄回流程"); } + + context.value = await adminApi.lookupWarehouseReturn(scanValue.value.trim()); + showInfoToast("已打开寄回流程"); + await enterReturnShippingFlow(); } catch (error) { context.value = null; showErrorToast(error, "出库查询失败"); @@ -322,17 +332,41 @@ async function lookupOutbound() { } } -function openReturnReportReview() { - const reportId = Number(context.value?.report_info?.id || context.value?.return_verification?.report_id || 0); +function openReturnShipping(tagNo: string) { + uni.navigateTo({ url: `/pages/return-shipping/index?internal_tag_no=${encodeURIComponent(tagNo)}` }); +} + +async function enterReturnShippingFlow() { const tagNo = scanValue.value.trim(); - if (!reportId || !tagNo) { - showInfoToast("未找到可核对的报告"); + const reportId = Number(context.value?.report_info?.id || 0); + + if (!tagNo) { + showInfoToast("请先扫描内部流转挂牌编号"); + return; + } + if (returnFlowEnded.value) { + showInfoToast("寄回流程已完成"); + return; + } + if (canReturnShip.value) { + openReturnShipping(tagNo); + return; + } + if (!isPendingReturnOrder.value) { + showInfoToast("当前订单不处于待寄回状态"); + return; + } + if (!reportId) { + showInfoToast("未找到已发布报告"); return; } - uni.navigateTo({ - url: `/pages/report/detail?id=${reportId}&return_internal_tag_no=${encodeURIComponent(tagNo)}`, + context.value = await adminApi.confirmWarehouseReturnReport({ + internal_tag_no: tagNo, + report_id: reportId, }); + showInfoToast("已确认回寄,请填写运单"); + openReturnShipping(tagNo); } async function submitOutboundAction() { @@ -356,24 +390,7 @@ async function submitOutboundAction() { showInfoToast("寄回流程已完成"); return; } - if (context.value.order_info.service_provider === "zhongjian") { - openReturnReportReview(); - return; - } - if (!canReturnShip.value) { - if (!materialQr.value.trim()) { - showInfoToast("请扫描验真吊牌"); - return; - } - context.value = await adminApi.verifyWarehouseReturnMaterialTag({ - internal_tag_no: scanValue.value.trim(), - qr_input: materialQr.value.trim(), - }); - showInfoToast("验真吊牌匹配通过,请核对报告"); - openReturnReportReview(); - return; - } - uni.navigateTo({ url: `/pages/return-shipping/index?internal_tag_no=${encodeURIComponent(scanValue.value.trim())}` }); + await enterReturnShippingFlow(); } catch (error) { showErrorToast(error, "出库操作失败"); } finally { @@ -421,16 +438,6 @@ function scanInternalTagInput() { }); } -function scanMaterialQr() { - uni.scanCode({ - scanType: ["barCode", "qrCode"], - success: (result) => { - materialQr.value = String(result.result || "").trim(); - }, - fail: () => showInfoToast("当前环境暂不支持扫码,可手动输入"), - }); -} - onLoad(() => { uni.$on("warehouse-return-shipped", handleReturnShipped); }); @@ -516,14 +523,10 @@ onUnload(() => { 出库动作 - {{ context.next_action_text || (context.order_info.service_provider === 'zhongjian' ? '确认中检报告后回寄' : '确认验真吊牌后回寄') }} + {{ returnFlowEnded && !context.next_action ? '寄回流程已完成' : !context.next_action && (canReturnShip || isPendingReturnOrder) ? '待寄回订单可直接填写回寄物流' : context.next_action_text || '暂无可执行出库动作' }} - - - - - - 报告已确认,可进入回寄信息页填写快递单号并上传打包装箱附件。 + + 可进入回寄信息页填写快递单号并上传打包装箱附件。 寄回流程已完成,无需重复填写回寄信息。