feat: connect plan-level preload confirmation
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { RefreshCw, Save, Check, Play, Camera, Eye, Plus, Pencil, Trash2 } from '@lucide/vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { ApiResponseError, getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
@@ -15,8 +16,6 @@ import { sanitizePreloadItem, validatePreloadItem, validatePreloadItems } from '
|
||||
import {
|
||||
completeLoading,
|
||||
completePicking,
|
||||
confirmingPreload,
|
||||
confirmPreload,
|
||||
downloadEvidenceFile,
|
||||
getEvidence,
|
||||
getOutboundDispatch,
|
||||
@@ -52,6 +51,7 @@ const props = withDefaults(defineProps<{
|
||||
|
||||
const emit = defineEmits<{ updated: [] }>()
|
||||
const access = useAccessPreviewStore()
|
||||
const router = useRouter()
|
||||
const preload = ref<PreloadPlan | null>(null)
|
||||
const preloadItems = ref<PreloadItem[]>([])
|
||||
const picking = ref<PickingTask | null>(null)
|
||||
@@ -87,8 +87,8 @@ const preloadVersion = computed(() => preload.value?.version ?? 0)
|
||||
const pickingExpectedVersion = computed(() => picking.value?.version ?? props.pickingVersion ?? null)
|
||||
const inboundExpectedVersion = computed(() => props.inboundVersion)
|
||||
const canSplit = computed(() => !props.readOnly && access.can('firstleg:inbound:split'))
|
||||
const canPreload = computed(() => !props.readOnly && access.can('firstleg:inbound:preload'))
|
||||
const canPreloadView = computed(() => access.can('firstleg:inbound:preload-view'))
|
||||
const canViewLoadingPlans = computed(() => access.can('platform:firstleg:preload:list'))
|
||||
const canPicking = computed(() => !props.readOnly && access.can('platform:firstleg:inbound:picking:edit'))
|
||||
const canPickingView = computed(() => access.can('platform:firstleg:inbound:picking:view'))
|
||||
// 操作员、理货员由 IAM 授予 loading:edit;拣货员仅能在 PDA 现场采集,不授予该权限。
|
||||
@@ -292,18 +292,8 @@ async function runSmartSplit() {
|
||||
}
|
||||
}
|
||||
|
||||
async function startPreloadConfirmation() {
|
||||
const result = await run('preload-confirming', () => confirmingPreload(props.tenantId, props.inboundId, {
|
||||
expectedVersion: preloadVersion.value,
|
||||
}), '预装清单已进入确认中')
|
||||
if (result?.preloadPlan) preload.value = result.preloadPlan
|
||||
}
|
||||
|
||||
async function finishPreloadConfirmation() {
|
||||
const result = await run('preload-confirm', () => confirmPreload(props.tenantId, props.inboundId, {
|
||||
expectedVersion: preloadVersion.value,
|
||||
}), '预装清单已确认,订单进入装柜中')
|
||||
if (result?.preloadPlan) preload.value = result.preloadPlan
|
||||
function openPreloadPlans() {
|
||||
void router.push({ name: 'loading-plans' })
|
||||
}
|
||||
|
||||
function pickingRequest(): { expectedVersion: number; expectedCount: number; pickedCount: number; remark?: string } | null {
|
||||
@@ -465,8 +455,11 @@ onMounted(() => { void refresh() })
|
||||
</template>
|
||||
<div class="workflow-actions">
|
||||
<el-button :disabled="!canSplit || Boolean(busy) || Boolean(preloadLoadError)" :loading="busy === 'smart-split'" @click="runSmartSplit"><Save :size="15" />保存分柜清单</el-button>
|
||||
<el-button :disabled="!canPreload || !preload || preload.status !== 'PENDING' || Boolean(busy)" :loading="busy === 'preload-confirming'" @click="startPreloadConfirmation"><Play :size="15" />提交确认</el-button>
|
||||
<el-button type="primary" :disabled="!canPreload || !preload || preload?.status !== 'CONFIRMING' || Boolean(busy)" :loading="busy === 'preload-confirm'" @click="finishPreloadConfirmation"><Check :size="15" />确认预装清单</el-button>
|
||||
</div>
|
||||
<div class="preload-confirmation-guide">
|
||||
<div><strong>计划级预装确认</strong><span>当前单票状态:{{ preloadStatusLabel(preload?.status) }}。请前往预装清单,从实际预装计划详情确认整份计划。</span></div>
|
||||
<el-button v-if="canViewLoadingPlans" type="primary" plain @click="openPreloadPlans"><Eye :size="15" />前往预装清单</el-button>
|
||||
<span v-else class="workflow-hint">当前账号无预装清单列表权限。</span>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
@@ -573,6 +566,11 @@ onMounted(() => { void refresh() })
|
||||
.preload-dialog-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
|
||||
.workflow-actions { margin-top: 14px; }
|
||||
.workflow-remark { margin-top: 10px; }
|
||||
.preload-confirmation-guide { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 12px; padding: 12px 14px; border: 1px solid var(--cc-border); border-radius: 6px; background: #f8fafc; }
|
||||
.preload-confirmation-guide > div { display: grid; min-width: 0; gap: 4px; }
|
||||
.preload-confirmation-guide strong { color: var(--cc-text, #1f2937); font-size: 13px; }
|
||||
.preload-confirmation-guide span { color: var(--cc-text-secondary, #64748b); font-size: 12px; line-height: 1.5; }
|
||||
.preload-confirmation-guide > .el-button { flex: 0 0 auto; }
|
||||
.evidence-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
||||
.evidence-item { display: grid; min-width: 0; gap: 8px; align-content: start; padding: 12px; border: 1px solid var(--cc-border); border-radius: 6px; }
|
||||
.evidence-item strong { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
|
||||
@@ -592,6 +590,7 @@ onMounted(() => { void refresh() })
|
||||
@media (max-width: 640px) {
|
||||
.preload-dialog-grid, .evidence-grid { grid-template-columns: 1fr; }
|
||||
.preload-dialog-grid { gap: 0; }
|
||||
.preload-confirmation-guide { align-items: stretch; flex-direction: column; }
|
||||
.evidence-item, .gate-grid { grid-template-columns: 1fr; }
|
||||
.workflow-actions > .el-button { flex: 1 1 150px; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user