feat: optimize warehouse return scan flow
This commit is contained in:
@@ -242,10 +242,16 @@ class FulfillmentFlowService
|
|||||||
'sent_to_zhongjian' => 'inbound',
|
'sent_to_zhongjian' => 'inbound',
|
||||||
default => '',
|
default => '',
|
||||||
};
|
};
|
||||||
|
$nextActionText = match ($stage) {
|
||||||
|
'warehouse_received' => '送检出库',
|
||||||
|
'sent_to_zhongjian' => '送检入库',
|
||||||
|
'report_published' => '待寄回订单可填写回寄物流',
|
||||||
|
default => '暂无可执行送检动作',
|
||||||
|
};
|
||||||
|
|
||||||
return array_merge($this->formatOrderContext((int)$flow['order_id']), [
|
return array_merge($this->formatOrderContext((int)$flow['order_id']), [
|
||||||
'next_action' => $nextAction,
|
'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') {
|
if (!$report || ($report['report_status'] ?? '') !== 'published') {
|
||||||
throw new \InvalidArgumentException('该报告未发布,不符合寄回条件');
|
throw new \InvalidArgumentException('该报告未发布,不符合寄回条件');
|
||||||
}
|
}
|
||||||
|
$this->ensurePendingReturnOrder($flow);
|
||||||
|
|
||||||
return $context + [
|
return $context + [
|
||||||
'return_confirmation' => [
|
'return_confirmation' => [
|
||||||
@@ -291,6 +298,7 @@ class FulfillmentFlowService
|
|||||||
if (!$report || ($report['report_status'] ?? '') !== 'published') {
|
if (!$report || ($report['report_status'] ?? '') !== 'published') {
|
||||||
throw new \InvalidArgumentException('该报告未发布,不符合寄回条件');
|
throw new \InvalidArgumentException('该报告未发布,不符合寄回条件');
|
||||||
}
|
}
|
||||||
|
$this->ensurePendingReturnOrder($flow);
|
||||||
|
|
||||||
$tag = (new MaterialTagService())->findTagByInput($qrInput);
|
$tag = (new MaterialTagService())->findTagByInput($qrInput);
|
||||||
if (!$tag || (int)($tag['report_id'] ?? 0) !== (int)$report['id']) {
|
if (!$tag || (int)($tag['report_id'] ?? 0) !== (int)$report['id']) {
|
||||||
@@ -342,6 +350,7 @@ class FulfillmentFlowService
|
|||||||
if (!$report || ($report['report_status'] ?? '') !== 'published') {
|
if (!$report || ($report['report_status'] ?? '') !== 'published') {
|
||||||
throw new \InvalidArgumentException('该报告未发布,不符合寄回条件');
|
throw new \InvalidArgumentException('该报告未发布,不符合寄回条件');
|
||||||
}
|
}
|
||||||
|
$this->ensurePendingReturnOrder($flow);
|
||||||
if ((int)$report['id'] !== $reportId) {
|
if ((int)$report['id'] !== $reportId) {
|
||||||
throw new \InvalidArgumentException('确认的报告与当前订单报告不匹配');
|
throw new \InvalidArgumentException('确认的报告与当前订单报告不匹配');
|
||||||
}
|
}
|
||||||
@@ -349,22 +358,7 @@ class FulfillmentFlowService
|
|||||||
return $this->formatOrderContext((int)$flow['order_id'], $request);
|
return $this->formatOrderContext((int)$flow['order_id'], $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($flow['service_provider'] ?? '') === 'zhongjian') {
|
return $this->markReturnConfirmed($flow, $operator, 'return_confirmed', '回寄确认', '仓管扫描内部流转码确认订单处于待寄回状态。');
|
||||||
$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', '验真吊牌确认', '仓管已核对验真吊牌与报告信息。');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shipReturn(string $tagNo, string $expressCompany, string $trackingNo, Request $request, array $packingAttachments = []): array
|
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
|
private function operator(Request $request): array
|
||||||
{
|
{
|
||||||
$id = (int)$request->header('x-admin-id', 0);
|
$id = (int)$request->header('x-admin-id', 0);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ const scanValue = ref("");
|
|||||||
const matchedInboundNo = ref("");
|
const matchedInboundNo = ref("");
|
||||||
const internalTagNo = ref("");
|
const internalTagNo = ref("");
|
||||||
const inboundAttachments = ref<AdminFileAsset[]>([]);
|
const inboundAttachments = ref<AdminFileAsset[]>([]);
|
||||||
const materialQr = ref("");
|
|
||||||
const expressCompany = ref("");
|
const expressCompany = ref("");
|
||||||
const returnTrackingNo = ref("");
|
const returnTrackingNo = ref("");
|
||||||
const context = ref<AdminWarehouseWorkbenchContext | null>(null);
|
const context = ref<AdminWarehouseWorkbenchContext | null>(null);
|
||||||
@@ -57,10 +56,11 @@ const returnFlowEnded = computed(() =>
|
|||||||
Boolean(context.value?.transfer_flow?.return_shipped_at),
|
Boolean(context.value?.transfer_flow?.return_shipped_at),
|
||||||
);
|
);
|
||||||
const canReturnShip = computed(() => Boolean(context.value?.transfer_flow?.return_confirmed_at) && !returnFlowEnded.value);
|
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(() => {
|
const outboundActionText = computed(() => {
|
||||||
if (actionLoading.value) return "提交中";
|
if (actionLoading.value) return "提交中";
|
||||||
if (returnFlowEnded.value && !context.value?.next_action) 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 "确认操作";
|
return "确认操作";
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -74,7 +74,6 @@ function chooseMode(next: WarehouseMode) {
|
|||||||
matchedInboundNo.value = "";
|
matchedInboundNo.value = "";
|
||||||
internalTagNo.value = "";
|
internalTagNo.value = "";
|
||||||
inboundAttachments.value = [];
|
inboundAttachments.value = [];
|
||||||
materialQr.value = "";
|
|
||||||
expressCompany.value = "";
|
expressCompany.value = "";
|
||||||
returnTrackingNo.value = "";
|
returnTrackingNo.value = "";
|
||||||
context.value = null;
|
context.value = null;
|
||||||
@@ -95,7 +94,6 @@ function applyReturnShippedPayload(payload: ReturnShippedPayload | AdminWarehous
|
|||||||
if (nextContext) {
|
if (nextContext) {
|
||||||
context.value = nextContext;
|
context.value = nextContext;
|
||||||
}
|
}
|
||||||
materialQr.value = "";
|
|
||||||
expressCompany.value = "";
|
expressCompany.value = "";
|
||||||
returnTrackingNo.value = "";
|
returnTrackingNo.value = "";
|
||||||
}
|
}
|
||||||
@@ -306,14 +304,26 @@ function closeInboundVideo() {
|
|||||||
async function lookupOutbound() {
|
async function lookupOutbound() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
|
let zhongjianContext: AdminWarehouseWorkbenchContext | null = null;
|
||||||
try {
|
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("已识别中检流转");
|
showInfoToast("已识别中检流转");
|
||||||
return;
|
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) {
|
} catch (error) {
|
||||||
context.value = null;
|
context.value = null;
|
||||||
showErrorToast(error, "出库查询失败");
|
showErrorToast(error, "出库查询失败");
|
||||||
@@ -322,17 +332,41 @@ async function lookupOutbound() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openReturnReportReview() {
|
function openReturnShipping(tagNo: string) {
|
||||||
const reportId = Number(context.value?.report_info?.id || context.value?.return_verification?.report_id || 0);
|
uni.navigateTo({ url: `/pages/return-shipping/index?internal_tag_no=${encodeURIComponent(tagNo)}` });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enterReturnShippingFlow() {
|
||||||
const tagNo = scanValue.value.trim();
|
const tagNo = scanValue.value.trim();
|
||||||
if (!reportId || !tagNo) {
|
const reportId = Number(context.value?.report_info?.id || 0);
|
||||||
showInfoToast("未找到可核对的报告");
|
|
||||||
|
if (!tagNo) {
|
||||||
|
showInfoToast("请先扫描内部流转挂牌编号");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (returnFlowEnded.value) {
|
||||||
|
showInfoToast("寄回流程已完成");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (canReturnShip.value) {
|
||||||
|
openReturnShipping(tagNo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isPendingReturnOrder.value) {
|
||||||
|
showInfoToast("当前订单不处于待寄回状态");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!reportId) {
|
||||||
|
showInfoToast("未找到已发布报告");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uni.navigateTo({
|
context.value = await adminApi.confirmWarehouseReturnReport({
|
||||||
url: `/pages/report/detail?id=${reportId}&return_internal_tag_no=${encodeURIComponent(tagNo)}`,
|
internal_tag_no: tagNo,
|
||||||
|
report_id: reportId,
|
||||||
});
|
});
|
||||||
|
showInfoToast("已确认回寄,请填写运单");
|
||||||
|
openReturnShipping(tagNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitOutboundAction() {
|
async function submitOutboundAction() {
|
||||||
@@ -356,24 +390,7 @@ async function submitOutboundAction() {
|
|||||||
showInfoToast("寄回流程已完成");
|
showInfoToast("寄回流程已完成");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (context.value.order_info.service_provider === "zhongjian") {
|
await enterReturnShippingFlow();
|
||||||
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())}` });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(error, "出库操作失败");
|
showErrorToast(error, "出库操作失败");
|
||||||
} finally {
|
} 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(() => {
|
onLoad(() => {
|
||||||
uni.$on("warehouse-return-shipped", handleReturnShipped);
|
uni.$on("warehouse-return-shipped", handleReturnShipped);
|
||||||
});
|
});
|
||||||
@@ -516,14 +523,10 @@ onUnload(() => {
|
|||||||
<view v-if="mode === 'outbound' && context" class="card">
|
<view v-if="mode === 'outbound' && context" class="card">
|
||||||
<view class="card-title">出库动作</view>
|
<view class="card-title">出库动作</view>
|
||||||
<view class="card-desc">
|
<view class="card-desc">
|
||||||
{{ context.next_action_text || (context.order_info.service_provider === 'zhongjian' ? '确认中检报告后回寄' : '确认验真吊牌后回寄') }}
|
{{ returnFlowEnded && !context.next_action ? '寄回流程已完成' : !context.next_action && (canReturnShip || isPendingReturnOrder) ? '待寄回订单可直接填写回寄物流' : context.next_action_text || '暂无可执行出库动作' }}
|
||||||
</view>
|
</view>
|
||||||
<view v-if="context.order_info.service_provider !== 'zhongjian' && !canReturnShip && !returnFlowEnded && !context.next_action" class="scan-control">
|
<view v-if="(canReturnShip || isPendingReturnOrder) && !returnFlowEnded && !context.next_action" class="ship-fields">
|
||||||
<input v-model="materialQr" class="field scan-input" placeholder="验真吊牌二维码" />
|
<view class="card-desc">可进入回寄信息页填写快递单号并上传打包装箱附件。</view>
|
||||||
<button class="btn scan-button" @click="scanMaterialQr">扫码</button>
|
|
||||||
</view>
|
|
||||||
<view v-if="canReturnShip && !context.next_action" class="ship-fields">
|
|
||||||
<view class="card-desc">报告已确认,可进入回寄信息页填写快递单号并上传打包装箱附件。</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view v-if="returnFlowEnded && !context.next_action" class="ship-fields">
|
<view v-if="returnFlowEnded && !context.next_action" class="ship-fields">
|
||||||
<view class="card-desc">寄回流程已完成,无需重复填写回寄信息。</view>
|
<view class="card-desc">寄回流程已完成,无需重复填写回寄信息。</view>
|
||||||
|
|||||||
Reference in New Issue
Block a user