新增 IDE 官网静态资源与 D3 分区域地图布局,构建时复制至 dist/site;同步应收应付、代发打包、订单详情等页面优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
218 lines
7.0 KiB
TypeScript
218 lines
7.0 KiB
TypeScript
import { ref, reactive, computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { $baseMessage } from '@/utils'
|
|
import { resolveOmsAssetUrl } from '@/api/oms/common'
|
|
import {
|
|
printLabelLookup,
|
|
type PrintLabelBindItem,
|
|
type PrintLabelLookupCandidate,
|
|
type PrintLabelLookupResult,
|
|
} from '@/api/operation'
|
|
import { useOperationScanFocus } from '@/composables/useOperationScanFocus'
|
|
|
|
export function normalizeFulfillBindLookup(raw: any): PrintLabelLookupResult {
|
|
return {
|
|
matched: raw?.matched ?? raw?.Matched,
|
|
matchedNumberType: raw?.matchedNumberType ?? raw?.MatchedNumberType,
|
|
warnings: raw?.warnings ?? raw?.Warnings ?? [],
|
|
orderId: raw?.orderId ?? raw?.OrderId,
|
|
serviceNo: raw?.serviceNo ?? raw?.ServiceNo,
|
|
clientNo: raw?.clientNo ?? raw?.ClientNo,
|
|
trackNo: raw?.trackNo ?? raw?.TrackNo,
|
|
productCode: raw?.productCode ?? raw?.ProductCode,
|
|
salesProductName: raw?.salesProductName ?? raw?.SalesProductName,
|
|
destinationCountry: raw?.destinationCountry ?? raw?.DestinationCountry,
|
|
destinationCountryName: raw?.destinationCountryName ?? raw?.DestinationCountryName,
|
|
orderStatus: raw?.orderStatus ?? raw?.OrderStatus,
|
|
orderStatusName: raw?.orderStatusName ?? raw?.OrderStatusName,
|
|
warehouseId: raw?.warehouseId ?? raw?.WarehouseId,
|
|
warehouseName: raw?.warehouseName ?? raw?.WarehouseName,
|
|
bindStatus: raw?.bindStatus ?? raw?.BindStatus ?? 'none',
|
|
bindQtyTotal: raw?.bindQtyTotal ?? raw?.BindQtyTotal ?? 0,
|
|
bindLineCount: raw?.bindLineCount ?? raw?.BindLineCount ?? 0,
|
|
bindItems: (raw?.bindItems ?? raw?.BindItems ?? []).map((item: any) => ({
|
|
bindType: item.bindType ?? item.BindType,
|
|
skuCode: item.skuCode ?? item.SkuCode,
|
|
skuName: item.skuName ?? item.SkuName,
|
|
trackingNo: item.trackingNo ?? item.TrackingNo,
|
|
productName: item.productName ?? item.ProductName,
|
|
attributeText: item.attributeText ?? item.AttributeText,
|
|
imageUrl: item.imageUrl ?? item.ImageUrl,
|
|
binCode: item.binCode ?? item.BinCode,
|
|
bindQty: item.bindQty ?? item.BindQty,
|
|
status: item.status ?? item.Status,
|
|
})),
|
|
candidates: (raw?.candidates ?? raw?.Candidates ?? []).map((c: any) => ({
|
|
orderId: c.orderId ?? c.OrderId,
|
|
serviceNo: c.serviceNo ?? c.ServiceNo,
|
|
clientNo: c.clientNo ?? c.ClientNo,
|
|
trackNo: c.trackNo ?? c.TrackNo,
|
|
orderStatusName: c.orderStatusName ?? c.OrderStatusName,
|
|
bindQtyTotal: c.bindQtyTotal ?? c.BindQtyTotal,
|
|
matchedHint: c.matchedHint ?? c.MatchedHint,
|
|
})),
|
|
}
|
|
}
|
|
|
|
export function useFulfillBindLookup(pageKey: string, defaultNumberType = 'auto') {
|
|
const { t } = useI18n()
|
|
const scanInputRef = ref<{ focus?: () => void } | null>(null)
|
|
const { keepScanFocus, maybeRefocusScan } = useOperationScanFocus(pageKey, scanInputRef)
|
|
|
|
const formData = reactive({
|
|
scanNumber: '',
|
|
numberType: defaultNumberType,
|
|
})
|
|
|
|
const lookingUp = ref(false)
|
|
const lookup = ref<PrintLabelLookupResult | null>(null)
|
|
const candidates = ref<PrintLabelLookupCandidate[]>([])
|
|
|
|
const bindItems = computed(() => lookup.value?.bindItems || [])
|
|
const hasNoneBindWarning = computed(() => (lookup.value?.warnings || []).includes('noneBind'))
|
|
const canConfirmPick = computed(
|
|
() => Boolean(lookup.value?.matched && lookup.value?.bindStatus === 'bound'),
|
|
)
|
|
|
|
const matchedTypeLabel = computed(() => {
|
|
const type = lookup.value?.matchedNumberType || ''
|
|
const key = `operation.printLabel.numberType.${type === 'customerorder' ? 'customerOrder' : type}`
|
|
const text = t(key)
|
|
return text === key ? type : text
|
|
})
|
|
|
|
const bindStatusLabel = computed(() => {
|
|
const code = lookup.value?.bindStatus || 'none'
|
|
const key = `order.myOrders.stockBind.status.${code}`
|
|
const text = t(key)
|
|
return text === key ? code : text
|
|
})
|
|
|
|
const bindStatusColor = computed(() => {
|
|
const code = lookup.value?.bindStatus
|
|
if (code === 'deducted') return 'red'
|
|
if (code === 'bound') return 'green'
|
|
return 'gray'
|
|
})
|
|
|
|
function itemImage(item: PrintLabelBindItem) {
|
|
return resolveOmsAssetUrl(item.imageUrl || '') || ''
|
|
}
|
|
|
|
function bindPrimaryName(item: PrintLabelBindItem) {
|
|
if (item.bindType === 'parcelItem') {
|
|
return item.productName || item.skuName || item.trackingNo || '-'
|
|
}
|
|
return item.skuName || item.skuCode || '-'
|
|
}
|
|
|
|
function bindCode(item: PrintLabelBindItem) {
|
|
return item.skuCode || ''
|
|
}
|
|
|
|
async function handleLookup(silent = false) {
|
|
const number = formData.scanNumber.trim()
|
|
if (!number) {
|
|
if (!silent) {
|
|
$baseMessage(t('operation.fulfillPack.message.numberRequired'), 'warning')
|
|
}
|
|
maybeRefocusScan()
|
|
return false
|
|
}
|
|
lookingUp.value = true
|
|
lookup.value = null
|
|
candidates.value = []
|
|
try {
|
|
const raw = await printLabelLookup({
|
|
number,
|
|
numberType: formData.numberType || 'auto',
|
|
})
|
|
const data = normalizeFulfillBindLookup(raw)
|
|
if (data.candidates?.length && !data.matched) {
|
|
candidates.value = data.candidates
|
|
lookup.value = null
|
|
if (!silent) {
|
|
$baseMessage(t('operation.printLabel.preview.multiMatch'), 'warning')
|
|
}
|
|
return false
|
|
}
|
|
lookup.value = data
|
|
candidates.value = []
|
|
if (formData.numberType === 'auto' && data.matchedNumberType) {
|
|
const mt = data.matchedNumberType
|
|
formData.numberType =
|
|
mt === 'customerorder' ? 'customerOrder' : mt === 'auto' ? 'auto' : mt
|
|
}
|
|
if (!silent) {
|
|
$baseMessage(t('operation.fulfillPack.message.lookupSuccess'), 'success')
|
|
}
|
|
return true
|
|
} catch (e: any) {
|
|
lookup.value = null
|
|
candidates.value = []
|
|
if (!silent) {
|
|
$baseMessage(e?.message || t('operation.fulfillPack.message.lookupFailed'), 'error')
|
|
}
|
|
return false
|
|
} finally {
|
|
lookingUp.value = false
|
|
maybeRefocusScan()
|
|
}
|
|
}
|
|
|
|
async function selectCandidate(c: PrintLabelLookupCandidate) {
|
|
formData.scanNumber = c.serviceNo || c.clientNo || String(c.orderId)
|
|
formData.numberType = c.serviceNo ? 'waybill' : 'customerOrder'
|
|
candidates.value = []
|
|
await handleLookup()
|
|
}
|
|
|
|
async function lookupByWaybill(serviceNo: string) {
|
|
formData.scanNumber = serviceNo
|
|
formData.numberType = 'waybill'
|
|
return handleLookup(true)
|
|
}
|
|
|
|
async function lookupByDomesticTracking(trackingNo: string) {
|
|
formData.scanNumber = trackingNo
|
|
formData.numberType = 'parcel'
|
|
return handleLookup(true)
|
|
}
|
|
|
|
function handleReset() {
|
|
formData.scanNumber = ''
|
|
formData.numberType = defaultNumberType
|
|
lookup.value = null
|
|
candidates.value = []
|
|
maybeRefocusScan()
|
|
}
|
|
|
|
async function onScanEnter() {
|
|
await handleLookup()
|
|
}
|
|
|
|
return {
|
|
scanInputRef,
|
|
keepScanFocus,
|
|
formData,
|
|
lookingUp,
|
|
lookup,
|
|
candidates,
|
|
bindItems,
|
|
hasNoneBindWarning,
|
|
canConfirmPick,
|
|
matchedTypeLabel,
|
|
bindStatusLabel,
|
|
bindStatusColor,
|
|
itemImage,
|
|
bindPrimaryName,
|
|
bindCode,
|
|
handleLookup,
|
|
selectCandidate,
|
|
lookupByWaybill,
|
|
lookupByDomesticTracking,
|
|
handleReset,
|
|
onScanEnter,
|
|
}
|
|
}
|