优化
This commit is contained in:
@@ -4,7 +4,12 @@ import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { MapPin, Plus, Send, Trash2 } from '@lucide/vue'
|
||||
import { useAuthStore } from '@/modules/auth/store/auth'
|
||||
import { getMerchantPricingChannels, type MerchantPricingChannel } from '@/modules/first-leg/api/firstLeg'
|
||||
import {
|
||||
getMerchantInboundCodePolicy,
|
||||
getMerchantPricingChannels,
|
||||
type InboundCodePolicy,
|
||||
type MerchantPricingChannel,
|
||||
} from '@/modules/first-leg/api/firstLeg'
|
||||
import { useFirstLegOrdersStore } from '@/modules/first-leg/store/firstLegOrders'
|
||||
import type { FirstLegOrderDraft } from '@/modules/first-leg/types/firstLegOrder'
|
||||
import { createEmptyCargoItem } from '@/modules/first-leg/utils/firstLegOrder'
|
||||
@@ -19,6 +24,7 @@ interface QuickOrderProduct {
|
||||
|
||||
interface QuickOrderRow {
|
||||
id: string
|
||||
inboundCode: string
|
||||
channelKey: string
|
||||
destinationType: DestinationType
|
||||
destinationWarehouseId: string
|
||||
@@ -52,6 +58,7 @@ const store = useFirstLegOrdersStore()
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const loadError = ref('')
|
||||
const inboundCodePolicy = ref<InboundCodePolicy | null>(null)
|
||||
const channelOptions = ref<QuickChannelOption[]>([])
|
||||
const destinationDialogOpen = ref(false)
|
||||
const destinationLoading = ref(false)
|
||||
@@ -85,6 +92,7 @@ function createProduct(): QuickOrderProduct {
|
||||
function createRow(): QuickOrderRow {
|
||||
return reactive({
|
||||
id: `quick-order-${++rowSequence}`,
|
||||
inboundCode: '',
|
||||
channelKey: '',
|
||||
destinationType: 'FBA',
|
||||
destinationWarehouseId: '',
|
||||
@@ -102,6 +110,7 @@ function createRow(): QuickOrderRow {
|
||||
|
||||
const rows = reactive<QuickOrderRow[]>([createRow()])
|
||||
const hasChannels = computed(() => channelOptions.value.length > 0)
|
||||
const manualInboundCodeRequired = computed(() => inboundCodePolicy.value?.mode === 'LEGACY_MANUAL')
|
||||
const availableDestinationWarehouses = computed(() => destinationForm.type === 'PRIVATE'
|
||||
? []
|
||||
: store.warehouses.filter((warehouse) => warehouse.warehouseType === destinationForm.type))
|
||||
@@ -163,6 +172,7 @@ function hasCompletePrivateContact(row: QuickOrderRow) {
|
||||
function buildOrderDraft(row: QuickOrderRow, channel: QuickChannelOption): FirstLegOrderDraft {
|
||||
const pricingTaxMode = channel.pricingTaxModes[0] ?? 'TAX_INCLUDED'
|
||||
return {
|
||||
inboundCode: row.inboundCode.trim() || undefined,
|
||||
referenceNo: '',
|
||||
transportMode: 'FCL',
|
||||
businessType: 'EXPORT',
|
||||
@@ -288,7 +298,11 @@ async function loadChannels() {
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
try {
|
||||
await store.loadWarehouseType('DOMESTIC', true)
|
||||
const [, policy] = await Promise.all([
|
||||
store.loadWarehouseType('DOMESTIC', true),
|
||||
getMerchantInboundCodePolicy(),
|
||||
])
|
||||
inboundCodePolicy.value = policy
|
||||
const results = await Promise.allSettled(store.warehouses
|
||||
.filter((warehouse) => warehouse.warehouseType === 'DOMESTIC')
|
||||
.map(async (warehouse) => {
|
||||
@@ -305,6 +319,17 @@ async function loadChannels() {
|
||||
}
|
||||
|
||||
async function submitQuickOrder() {
|
||||
if (!inboundCodePolicy.value) {
|
||||
ElMessage.warning('入仓码规则尚未加载,请刷新页面后重试')
|
||||
return
|
||||
}
|
||||
const missingInboundCodeIndex = manualInboundCodeRequired.value
|
||||
? rows.findIndex((row) => !row.inboundCode.trim())
|
||||
: -1
|
||||
if (missingInboundCodeIndex >= 0) {
|
||||
ElMessage.warning(`请填写第 ${missingInboundCodeIndex + 1} 行的旧系统入仓码`)
|
||||
return
|
||||
}
|
||||
const incompleteIndex = rows.findIndex((row) => !row.channelKey || !row.destinationWarehouseName
|
||||
|| row.products.some((product) => !product.sku.trim() || product.packageCount < 1))
|
||||
if (incompleteIndex >= 0) {
|
||||
@@ -330,7 +355,7 @@ async function submitQuickOrder() {
|
||||
if (!activeBatchKey.value) activeBatchKey.value = createBatchKey()
|
||||
const response = await store.saveDraftBatch(drafts, customerName, activeBatchKey.value)
|
||||
const successes = response.items.flatMap((item): QuickDraftResult[] => {
|
||||
if (!item.success || item.orderId == null || !item.inboundCode?.trim()) return []
|
||||
if (!item.success || item.orderId == null) return []
|
||||
const row = rows.find((candidate) => candidate.id === item.clientRowId)
|
||||
if (!row) return []
|
||||
return [{
|
||||
@@ -338,10 +363,10 @@ async function submitQuickOrder() {
|
||||
sku: row.products.map((product) => product.sku.trim()).join('、'),
|
||||
draftId: String(item.orderId),
|
||||
orderNo: item.orderNo ?? '',
|
||||
inboundCode: item.inboundCode.trim(),
|
||||
inboundCode: item.inboundCode?.trim() ?? '',
|
||||
}]
|
||||
})
|
||||
const failures = response.items.filter((item) => !item.success || item.orderId == null || !item.inboundCode?.trim())
|
||||
const failures = response.items.filter((item) => !item.success || item.orderId == null)
|
||||
draftResults.splice(0, draftResults.length, ...successes)
|
||||
const successfulIds = new Set(successes.map((item) => item.rowId))
|
||||
for (let index = rows.length - 1; index >= 0; index -= 1) {
|
||||
@@ -374,6 +399,7 @@ onMounted(loadChannels)
|
||||
<header class="quick-order-intro">
|
||||
<h2 id="quick-order-heading">客户下单</h2>
|
||||
<p>只需输入渠道、目的仓、产品 SKU 和箱数,即可快速填写订单。</p>
|
||||
<small v-if="manualInboundCodeRequired">当前全局使用旧系统入仓码,每张草稿都需要填写旧系统生成的入仓码。</small>
|
||||
<small>每一行会直接生成一张独立草稿单,其他明细可进入草稿后继续编辑并提交。</small>
|
||||
</header>
|
||||
|
||||
@@ -385,14 +411,23 @@ onMounted(loadChannels)
|
||||
<table class="quick-order-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>选择渠道</th>
|
||||
<th>目的仓</th>
|
||||
<th>操作</th>
|
||||
<th v-if="manualInboundCodeRequired" class="inbound-code-heading">旧系统入仓码</th>
|
||||
<th class="channel-heading">选择渠道</th>
|
||||
<th class="destination-heading">目的仓</th>
|
||||
<th class="operation-heading">操作</th>
|
||||
<th>产品信息:产品 SKU / 箱数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="row.id">
|
||||
<td v-if="manualInboundCodeRequired" class="inbound-code-cell">
|
||||
<el-input
|
||||
v-model="row.inboundCode"
|
||||
maxlength="40"
|
||||
placeholder="请输入旧系统入仓码"
|
||||
@input="row.inboundCode = String($event).trim().toUpperCase()"
|
||||
/>
|
||||
</td>
|
||||
<td class="channel-cell">
|
||||
<el-select v-model="row.channelKey" :disabled="!hasChannels" placeholder="请选择">
|
||||
<el-option
|
||||
@@ -476,7 +511,7 @@ onMounted(loadChannels)
|
||||
<el-dialog v-model="resultDialogOpen" class="quick-result-dialog" title="草稿单生成结果" width="min(700px, 94vw)">
|
||||
<div class="quick-draft-results">
|
||||
<article v-for="result in draftResults" :key="result.rowId">
|
||||
<div><strong>{{ result.orderNo || `草稿 ${result.draftId}` }}</strong><span>SKU {{ result.sku }}</span><span>入仓码 {{ result.inboundCode }}</span></div>
|
||||
<div><strong>{{ result.orderNo || `草稿 ${result.draftId}` }}</strong><span>SKU {{ result.sku }}</span><span>{{ result.inboundCode ? `入仓码 ${result.inboundCode}` : '入仓码将在提交订单时生成' }}</span></div>
|
||||
<el-button type="primary" plain @click="editDraft(result)">编辑明细</el-button>
|
||||
</article>
|
||||
</div>
|
||||
@@ -494,11 +529,12 @@ onMounted(loadChannels)
|
||||
.quick-order-table-wrap { min-height: 126px; overflow-x: auto; border: 1px solid #e5eaf2; border-radius: 8px; }
|
||||
.quick-order-table { width: 100%; min-width: 900px; border-collapse: collapse; table-layout: fixed; }
|
||||
.quick-order-table th { height: 42px; padding: 0 14px; background: #f4f5fb; color: #637fec; font-size: 12px; font-weight: 650; text-align: left; }
|
||||
.quick-order-table th:nth-child(1) { width: 220px; }
|
||||
.quick-order-table th:nth-child(2) { width: 145px; }
|
||||
.quick-order-table th:nth-child(3) { width: 210px; }
|
||||
.quick-order-table .inbound-code-heading, .quick-order-table .channel-heading { width: 220px; }
|
||||
.quick-order-table .destination-heading { width: 145px; }
|
||||
.quick-order-table .operation-heading { width: 210px; }
|
||||
.quick-order-table td { padding: 12px 14px; border-top: 1px solid #edf0f5; vertical-align: middle; }
|
||||
.channel-cell :deep(.el-select) { width: 100%; }
|
||||
.inbound-code-cell :deep(.el-input) { width: 100%; }
|
||||
.destination-options { display: flex; align-items: flex-start; flex-direction: column; gap: 4px; }
|
||||
.destination-options :deep(.el-radio) { height: 20px; margin-right: 0; }
|
||||
.destination-binding { display: flex; width: 100%; min-width: 0; align-items: center; gap: 5px; margin-top: 7px; padding: 0; border: 0; background: transparent; color: #637fec; cursor: pointer; font-size: 11px; text-align: left; }
|
||||
|
||||
Reference in New Issue
Block a user