You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
976 lines
44 KiB
Vue
976 lines
44 KiB
Vue
<template>
|
|
<view class="page-container">
|
|
<NavBar :title="t('productInbound.createTitle')" />
|
|
|
|
<scroll-view scroll-y class="detail-scroll">
|
|
<view class="content-section">
|
|
<view class="section-card">
|
|
<view class="section-header">
|
|
<view class="section-icon">
|
|
<uni-icons type="paperplane" size="24" color="#1f7cff"></uni-icons>
|
|
</view>
|
|
<text class="section-title">{{ t('productInbound.taskInfo') }}</text>
|
|
</view>
|
|
|
|
<view class="form-field">
|
|
<text class="form-label">{{ t('productInbound.relatedTask') }}<text class="required-star">*</text></text>
|
|
<view class="segment-control">
|
|
<view :class="['segment-item', relateTask ? 'active' : '']" @click="setRelateTask(true)">{{ t('productInbound.yes') }}</view>
|
|
<view :class="['segment-item', !relateTask ? 'active' : '']" @click="setRelateTask(false)">{{ t('productInbound.no') }}</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="relateTask" class="form-field">
|
|
<text class="form-label">{{ t('productInbound.taskOrder') }}<text class="required-star">*</text></text>
|
|
<view :class="['select-field', taskCode ? 'selected' : '']" @click="goSelectTask">
|
|
<view class="select-content">
|
|
<text :class="taskCode ? 'select-value' : 'select-placeholder'">{{ taskCode || t('productInbound.selectTask') }}</text>
|
|
</view>
|
|
<uni-icons type="right" size="18" color="#9ca3af"></uni-icons>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="relateTask && taskId" class="form-field">
|
|
<text class="form-label">{{ t('productInbound.product') }}<text class="required-star">*</text></text>
|
|
<view class="task-product-search-row">
|
|
<view class="scan-input-wrap">
|
|
<input
|
|
id="product-inbound-task-product-scan-input"
|
|
v-model="taskProductScanInput"
|
|
class="task-product-scan-input"
|
|
type="text"
|
|
:placeholder="t('productInbound.selectProduct')"
|
|
confirm-type="done"
|
|
@input="onTaskProductScanInput"
|
|
@confirm="onTaskProductScanConfirm"
|
|
/>
|
|
<view class="scan-input-icon">
|
|
<uni-icons type="scan" size="20" color="#9ca3af"></uni-icons>
|
|
</view>
|
|
</view>
|
|
<view class="task-product-select-field" @click="goSelectTaskProduct">
|
|
<text class="task-product-select-text">{{ t('productInbound.selectProductTitle') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="!relateTask" class="form-field">
|
|
<text class="form-label">{{ t('productInbound.product') }}<text class="required-star">*</text></text>
|
|
<view class="task-product-search-row">
|
|
<view class="scan-input-wrap">
|
|
<input
|
|
id="product-inbound-product-scan-input"
|
|
v-model="productScanInput"
|
|
class="task-product-scan-input"
|
|
type="text"
|
|
:placeholder="t('productInbound.selectProduct')"
|
|
confirm-type="done"
|
|
@input="onProductScanInput"
|
|
@confirm="onProductScanConfirm"
|
|
/>
|
|
<view class="scan-input-icon">
|
|
<uni-icons type="scan" size="20" color="#9ca3af"></uni-icons>
|
|
</view>
|
|
</view>
|
|
<view class="task-product-select-field" @click="goSelectProduct">
|
|
<text class="task-product-select-text">{{ t('productInbound.selectProductTitle') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="productId" class="info-panel">
|
|
<view class="info-grid">
|
|
<view v-if="relateTask" class="info-item">
|
|
<text class="info-label">{{ t('productInbound.workOrderNo') }}</text>
|
|
<text class="info-value">{{ textValue(taskCode) }}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">{{ t('productInbound.product') }}</text>
|
|
<text class="info-value">{{ textValue(productName) }}</text>
|
|
</view>
|
|
<view v-if="!relateTask" class="info-item">
|
|
<text class="info-label">{{ t('productInbound.code') }}</text>
|
|
<text class="info-value">{{ textValue(productBarCode) }}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">{{ t('productInbound.packagingScheme') }}</text>
|
|
<text class="info-value">{{ textValue(packagingSchemeName) }}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">{{ t('productInbound.palletPackageQuantity') }}</text>
|
|
<text class="info-value">{{ t('productInbound.packageUnit', { count: textValue(palletPackageQuantity) }) }}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">{{ t('productInbound.packageQuantity') }}</text>
|
|
<text class="info-value">{{ t('productInbound.pieceUnit', { count: textValue(packageQuantity) }) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="section-card">
|
|
<view class="section-header">
|
|
<view class="section-icon">
|
|
<uni-icons type="list" size="24" color="#1f7cff"></uni-icons>
|
|
</view>
|
|
<text class="section-title">{{ t('productInbound.pallet') }}</text>
|
|
</view>
|
|
|
|
<view class="form-field">
|
|
<view class="form-label-row">
|
|
<text class="form-label">{{ t('productInbound.palletCode') }}<text class="required-star">*</text></text>
|
|
<text v-if="selectedPallets.length" class="label-tip">{{ t('productInbound.selectedPalletCount', { count: selectedPallets.length }) }}</text>
|
|
</view>
|
|
<view class="task-product-search-row">
|
|
<view class="scan-input-wrap">
|
|
<input
|
|
id="product-inbound-pallet-scan-input"
|
|
v-model="palletScanInput"
|
|
class="task-product-scan-input"
|
|
type="text"
|
|
:placeholder="palletCode || t('productInbound.selectPallet')"
|
|
confirm-type="done"
|
|
@input="onPalletScanInput"
|
|
@confirm="onPalletScanConfirm"
|
|
/>
|
|
<view class="scan-input-icon">
|
|
<uni-icons type="scan" size="20" color="#9ca3af"></uni-icons>
|
|
</view>
|
|
</view>
|
|
<view class="task-product-select-field" @click="goSelectPallet">
|
|
<text class="task-product-select-text">{{ t('productInbound.selectPalletTitle') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="selectedPallets.length" class="pallet-list">
|
|
<view v-for="(pallet, index) in selectedPallets" :key="pallet.id || index" class="pallet-card">
|
|
<view class="pallet-main">
|
|
<view class="pallet-top">
|
|
<text class="pallet-code">{{ textValue(getPalletCode(pallet)) }}</text>
|
|
<view class="remove-btn" @click="removePallet(index)">
|
|
<uni-icons type="closeempty" size="18" color="#ef4444"></uni-icons>
|
|
</view>
|
|
</view>
|
|
<view class="pallet-field-list">
|
|
<view class="loc-cell">
|
|
<text class="loc-label">{{ t('productInbound.warehouse') }}</text>
|
|
<picker mode="selector" :range="warehouseOptions" range-key="label" :value="getWarehouseIndex(pallet.warehouseId)" @change="onPalletWarehouseChange($event, index)">
|
|
<view class="loc-picker pallet-field-control">
|
|
<text :class="pallet.warehouseId ? 'loc-value' : 'loc-placeholder'">{{ pallet.warehouseId ? getWarehouseName(pallet.warehouseId) : t('productInbound.choose') }}</text>
|
|
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
|
|
</view>
|
|
</picker>
|
|
</view>
|
|
<view class="loc-cell">
|
|
<text class="loc-label">{{ t('productInbound.area') }}</text>
|
|
<view class="task-product-search-row area-select-row">
|
|
<view class="scan-input-wrap">
|
|
<input
|
|
v-model="pallet._areaScanInput"
|
|
class="task-product-scan-input"
|
|
type="text"
|
|
:placeholder="getPalletAreaDisplayName(pallet) || t('productInbound.selectArea')"
|
|
confirm-type="done"
|
|
@input="onPalletAreaScanInput($event, index)"
|
|
@confirm="onPalletAreaScanConfirm(index)"
|
|
/>
|
|
<view class="scan-input-icon">
|
|
<uni-icons type="scan" size="20" color="#9ca3af"></uni-icons>
|
|
</view>
|
|
</view>
|
|
<view v-if="pallet.warehouseId && getAreaOptions(pallet.warehouseId).length" class="area-select-picker">
|
|
<picker mode="selector" :range="getAreaOptions(pallet.warehouseId)" range-key="label" :value="getAreaIndex(pallet.warehouseId, pallet.areaId)" @change="onPalletAreaChange($event, index)">
|
|
<view class="task-product-select-field area-select-button">
|
|
<text class="task-product-select-text">{{ t('productInbound.selectAreaTitle') }}</text>
|
|
</view>
|
|
</picker>
|
|
</view>
|
|
<view v-else class="task-product-select-field area-select-button disabled" @click="onAreaPickerUnavailable(index)">
|
|
<text class="task-product-select-text">{{ t('productInbound.selectAreaTitle') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="loc-cell">
|
|
<text class="count-label">{{ t('productInbound.packageCount') }}</text>
|
|
<input class="count-input pallet-field-control" type="number" :value="pallet.packageCount" @input="onPalletCountInput($event, index)" placeholder="0" />
|
|
</view>
|
|
<view class="pallet-piece-row">
|
|
<text class="count-label">{{ t('productInbound.pieceCount') }}</text>
|
|
<text class="pallet-piece-value">{{ getPalletItemCount(pallet) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="quantity-summary">
|
|
<view class="quantity-item">
|
|
<text class="quantity-value">{{ inputCount }}</text>
|
|
<text class="quantity-label">{{ t('productInbound.packageCount') }}</text>
|
|
</view>
|
|
<view class="quantity-item">
|
|
<text class="quantity-value">{{ count }}</text>
|
|
<text class="quantity-label">{{ t('productInbound.pieceCount') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view v-else class="empty-card" @click="goSelectPallet">{{ t('productInbound.selectPalletFirst') }}</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<view class="action-bar">
|
|
<view class="action-btn back-btn" @click="handleCancel">{{ t('productInbound.cancel') }}</view>
|
|
<view class="action-btn submit-btn" @click="handleConfirm">{{ t('productInbound.confirm') }}</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, ref } from 'vue'
|
|
import { onLoad, onShow } from '@dcloudio/uni-app'
|
|
import { useI18n } from 'vue-i18n'
|
|
import NavBar from '@/components/common/NavBar.vue'
|
|
import { getPallet, getTaskDefaultPackagingSchemes } from '@/api/mes/productInbound'
|
|
import { getProduct } from '@/api/erp/productInfo'
|
|
import { getWarehouseArea, getWarehouseAreaSimpleList, getWarehouseSimpleList } from '@/api/mes/moldget'
|
|
|
|
const { t } = useI18n()
|
|
const product = ref({})
|
|
const relateTask = ref(true)
|
|
const taskId = ref(null)
|
|
const taskCode = ref('')
|
|
const selectedTaskData = ref(null)
|
|
const selectedTaskProduct = ref(null)
|
|
const selectedPallets = ref([])
|
|
const editingIndex = ref(null)
|
|
const taskProductScanInput = ref('')
|
|
const productScanInput = ref('')
|
|
const palletScanInput = ref('')
|
|
|
|
const warehouseOptions = ref([])
|
|
const warehouseAreaMap = ref({})
|
|
|
|
const taskProductList = ref([])
|
|
const PRODUCT_CATEGORY_TYPE = 1
|
|
const WAREHOUSE_CATEGORY_TYPE = 1
|
|
const SCAN_AUTO_SEARCH_DELAY = 300
|
|
let taskProductScanTimer = null
|
|
let productScanTimer = null
|
|
let palletScanTimer = null
|
|
const palletAreaScanTimers = {}
|
|
|
|
const productName = computed(() => selectedTaskProduct.value?.productName || product.value.name || '')
|
|
const productId = computed(() => selectedTaskProduct.value?.productId || product.value.id)
|
|
const productBarCode = computed(() => selectedTaskProduct.value?.productCode || product.value.barCode || product.value.code || '')
|
|
const currentScheme = computed(() => selectedTaskProduct.value ? getDefaultScheme(selectedTaskProduct.value) : getDefaultScheme(product.value))
|
|
const packagingSchemeName = computed(() => currentScheme.value?.packagingSchemeName || '')
|
|
const packageQuantity = computed(() => Number(currentScheme.value?.packageQuantity) || 0)
|
|
const palletPackageQuantity = computed(() => Number(currentScheme.value?.palletPackageQuantity) || 0)
|
|
const palletTotalQuantity = computed(() => Number(currentScheme.value?.palletTotalQuantity) || packageQuantity.value * palletPackageQuantity.value)
|
|
const inputCount = computed(() => {
|
|
if (!selectedPallets.value.length) return 0
|
|
return selectedPallets.value.reduce((sum, pallet) => sum + (Number(pallet.packageCount) || 0), 0)
|
|
})
|
|
const count = computed(() => {
|
|
return selectedPallets.value.reduce((sum, pallet) => {
|
|
const packageCount = Number(pallet.packageCount) || 0
|
|
return sum + packageCount * (packageQuantity.value || 1)
|
|
}, 0)
|
|
})
|
|
const palletCode = computed(() => selectedPallets.value.map((item) => getPalletCode(item)).filter(Boolean).join(', '))
|
|
|
|
function cloneData(value) {
|
|
if (value === null || value === undefined) return value
|
|
return JSON.parse(JSON.stringify(value))
|
|
}
|
|
function buildSchemeFromItem(item) {
|
|
return {
|
|
id: item?.packagingSchemeRelationId,
|
|
packagingSchemeId: item?.packagingSchemeId,
|
|
packagingSchemeName: item?.packagingSchemeName,
|
|
packageQuantity: item?.packageQuantity,
|
|
palletPackageQuantity: item?.palletPackageQuantity,
|
|
palletTotalQuantity: item?.palletTotalQuantity,
|
|
defaultStatus: 1
|
|
}
|
|
}
|
|
function normalizeEditPallets(item) {
|
|
return (Array.isArray(item?.pallets) ? item.pallets : []).map((pallet) => ({
|
|
...pallet,
|
|
id: pallet.id || pallet.palletId,
|
|
code: pallet.code || pallet.palletCode,
|
|
palletCode: pallet.palletCode || pallet.code,
|
|
packageCount: Number(pallet.packageCount) || 0,
|
|
warehouseId: pallet.warehouseId,
|
|
areaId: pallet.areaId
|
|
}))
|
|
}
|
|
async function hydrateEditItem(item) {
|
|
if (!item) return
|
|
const scheme = buildSchemeFromItem(item)
|
|
relateTask.value = item.relateTask === true || item.relateTask === 1 || item.relateTask === '1'
|
|
taskId.value = relateTask.value ? item.taskId : null
|
|
taskCode.value = relateTask.value ? (item.taskCode || '') : ''
|
|
selectedTaskData.value = item._selectedTaskData ? cloneData(item._selectedTaskData) : null
|
|
product.value = item._product
|
|
? cloneData(item._product)
|
|
: {
|
|
id: item.productId,
|
|
name: item.productName,
|
|
barCode: item.productBarCode,
|
|
code: item.productBarCode,
|
|
unitName: item.productUnitName,
|
|
images: item.images,
|
|
packagingSchemes: [scheme]
|
|
}
|
|
if (relateTask.value) {
|
|
selectedTaskProduct.value = item._selectedTaskProduct
|
|
? cloneData(item._selectedTaskProduct)
|
|
: {
|
|
productId: item.productId,
|
|
productName: item.productName,
|
|
productCode: item.productBarCode,
|
|
taskDetailIds: item.taskDetailIds,
|
|
packagingSchemes: [scheme]
|
|
}
|
|
if (taskId.value) {
|
|
try {
|
|
const res = await getTaskDefaultPackagingSchemes(taskId.value)
|
|
selectedTaskData.value = res?.data || res || selectedTaskData.value || {}
|
|
taskProductList.value = Array.isArray(selectedTaskData.value?.products) ? selectedTaskData.value.products : []
|
|
} catch (e) {
|
|
taskProductList.value = Array.isArray(selectedTaskData.value?.products) ? selectedTaskData.value.products : []
|
|
}
|
|
}
|
|
} else {
|
|
selectedTaskProduct.value = null
|
|
selectedTaskData.value = null
|
|
taskProductList.value = []
|
|
}
|
|
selectedPallets.value = normalizeEditPallets(item)
|
|
await loadAreasForPallets(selectedPallets.value)
|
|
}
|
|
function textValue(v) {
|
|
if (v === 0) return '0'
|
|
if (v == null) return '-'
|
|
const s = String(v).trim()
|
|
return s || '-'
|
|
}
|
|
function getDefaultScheme(item) {
|
|
const schemes = Array.isArray(item?.packagingSchemes) ? item.packagingSchemes : []
|
|
return schemes.find((scheme) => Number(scheme?.defaultStatus) === 1) || schemes[0] || {}
|
|
}
|
|
function getPalletCode(pallet) {
|
|
return pallet?.code || pallet?.palletCode || ''
|
|
}
|
|
function getWarehouseName(id) {
|
|
return warehouseOptions.value.find((item) => String(item.value) === String(id))?.label || ''
|
|
}
|
|
function getAreaName(warehouseId, areaId) {
|
|
const areas = warehouseAreaMap.value[String(warehouseId)] || []
|
|
return areas.find((item) => String(item.value) === String(areaId))?.label || ''
|
|
}
|
|
function getAreaOptions(warehouseId) {
|
|
return warehouseAreaMap.value[String(warehouseId)] || []
|
|
}
|
|
function getWarehouseAreaLabel(area) {
|
|
return area?.areaName || area?.name || area?.areaCode || String(area?.id || '')
|
|
}
|
|
function getPalletAreaDisplayName(pallet) {
|
|
return getAreaName(pallet?.warehouseId, pallet?.areaId) || pallet?.areaName || pallet?.warehouseAreaName || ''
|
|
}
|
|
function getWarehouseIndex(id) {
|
|
const i = warehouseOptions.value.findIndex((item) => String(item.value) === String(id))
|
|
return i >= 0 ? i : 0
|
|
}
|
|
function getAreaIndex(warehouseId, areaId) {
|
|
const areas = getAreaOptions(warehouseId)
|
|
const i = areas.findIndex((item) => String(item.value) === String(areaId))
|
|
return i >= 0 ? i : 0
|
|
}
|
|
function getPalletItemCount(pallet) {
|
|
const c = Number(pallet?.packageCount) || 0
|
|
return c * (packageQuantity.value || 1)
|
|
}
|
|
async function onPalletWarehouseChange(e, index) {
|
|
const opt = warehouseOptions.value[Number(e.detail.value)]
|
|
if (!opt) return
|
|
selectedPallets.value[index].warehouseId = opt.value
|
|
selectedPallets.value[index].areaId = null
|
|
selectedPallets.value[index].areaName = ''
|
|
selectedPallets.value[index].warehouseAreaName = ''
|
|
selectedPallets.value[index]._areaScanInput = ''
|
|
await loadAreasForWarehouse(opt.value)
|
|
}
|
|
function applySelectedArea(index, opt) {
|
|
if (!opt || !selectedPallets.value[index]) return
|
|
selectedPallets.value[index].areaId = opt.value
|
|
selectedPallets.value[index].areaName = opt.label
|
|
selectedPallets.value[index]._areaScanInput = ''
|
|
}
|
|
function onPalletAreaChange(e, index) {
|
|
const areas = getAreaOptions(selectedPallets.value[index].warehouseId)
|
|
applySelectedArea(index, areas[Number(e.detail.value)])
|
|
}
|
|
function onAreaPickerUnavailable(index) {
|
|
const pallet = selectedPallets.value[index]
|
|
if (!pallet?.warehouseId) {
|
|
uni.showToast({ title: '\u8bf7\u5148\u9009\u62e9\u4ed3\u5e93', icon: 'none' })
|
|
return
|
|
}
|
|
uni.showToast({ title: t('productInbound.emptyArea'), icon: 'none' })
|
|
}
|
|
function onSelectAreaWithoutWarehouse() {
|
|
uni.showToast({ title: '\u8bf7\u5148\u9009\u62e9\u4ed3\u5e93', icon: 'none' })
|
|
}
|
|
function onPalletCountInput(e, index) {
|
|
const v = Number(e.detail.value)
|
|
selectedPallets.value[index].packageCount = Number.isFinite(v) ? v : 0
|
|
}
|
|
function setRelateTask(value) {
|
|
if (relateTask.value === value) return
|
|
relateTask.value = value
|
|
product.value = {}
|
|
selectedTaskProduct.value = null
|
|
taskProductScanInput.value = ''
|
|
productScanInput.value = ''
|
|
palletScanInput.value = ''
|
|
taskId.value = null
|
|
taskCode.value = ''
|
|
selectedTaskData.value = null
|
|
selectedPallets.value = []
|
|
}
|
|
function goSelectTask() {
|
|
const suffix = taskId.value ? `?selectedId=${taskId.value}` : ''
|
|
uni.navigateTo({ url: `/pages_function/pages/productInbound/taskSelect${suffix}` })
|
|
}
|
|
function goSelectProduct() {
|
|
const suffix = product.value?.id ? `?selectedId=${product.value.id}` : ''
|
|
uni.navigateTo({ url: `/pages_function/pages/productInbound/productSelect${suffix}` })
|
|
}
|
|
function goSelectTaskProduct() {
|
|
if (!taskId.value) {
|
|
uni.showToast({ title: t('productInbound.selectTaskFirst'), icon: 'none' })
|
|
return
|
|
}
|
|
const suffix = selectedTaskProduct.value?.productId ? `?selectedId=${selectedTaskProduct.value.productId}` : ''
|
|
uni.navigateTo({ url: `/pages_function/pages/productInbound/productSelect${suffix}` })
|
|
}
|
|
function normalizeScanValue(value) {
|
|
return String(value || '').trim().toLowerCase()
|
|
}
|
|
function getProductMaterialScanCode(value) {
|
|
const text = String(value || '').trim()
|
|
const match = text.match(/^PRODUCTMATERIAL[-:]?\s*(.+)$/i)
|
|
return match ? match[1].trim() : ''
|
|
}
|
|
function getPalletScanCode(value) {
|
|
const text = String(value || '').trim()
|
|
const match = text.match(/^PALLET[-:]?\s*(.+)$/i)
|
|
return match ? match[1].trim() : ''
|
|
}
|
|
function getWarehouseAreaScanCode(value) {
|
|
const text = String(value || '').trim()
|
|
const match = text.match(/^WAREHOUSE_AREA[-:]?\s*(.+)$/i)
|
|
return match ? match[1].trim() : ''
|
|
}
|
|
function getProductIdValue(item) {
|
|
return item?.id || item?.productId
|
|
}
|
|
function getProductNameValue(item) {
|
|
return item?.name || item?.productName || ''
|
|
}
|
|
function getProductCodeValue(item) {
|
|
return item?.barCode || item?.code || item?.productCode || item?.productBarCode || ''
|
|
}
|
|
function getTaskProductScanValues(item) {
|
|
return [
|
|
item?.productId,
|
|
item?.productCode,
|
|
item?.productBarCode,
|
|
item?.barCode,
|
|
item?.code,
|
|
item?.productName,
|
|
item?.name
|
|
].map(normalizeScanValue).filter(Boolean)
|
|
}
|
|
async function findProductByScanCode(scanCode) {
|
|
const id = String(scanCode || '').trim()
|
|
if (!/^\d+$/.test(id)) return null
|
|
const res = await getProduct(id)
|
|
const detail = res?.data || res
|
|
if (!detail?.id) return null
|
|
if (detail.categoryType && Number(detail.categoryType) !== PRODUCT_CATEGORY_TYPE) return null
|
|
return detail
|
|
}
|
|
function getTaskProductByProduct(productItem) {
|
|
const productValues = [getProductIdValue(productItem), getProductCodeValue(productItem), getProductNameValue(productItem)].map(normalizeScanValue).filter(Boolean)
|
|
return taskProductList.value.find((item) => {
|
|
const values = getTaskProductScanValues(item)
|
|
return productValues.some((value) => values.includes(value))
|
|
})
|
|
}
|
|
function buildTaskProductSelection(productItem) {
|
|
const taskProduct = getTaskProductByProduct(productItem)
|
|
return {
|
|
...productItem,
|
|
...(taskProduct || {}),
|
|
productId: getProductIdValue(productItem),
|
|
productName: getProductNameValue(productItem),
|
|
productCode: getProductCodeValue(productItem),
|
|
packagingSchemes: taskProduct?.packagingSchemes || productItem?.packagingSchemes || []
|
|
}
|
|
}
|
|
function scheduleTaskProductScanSearch(value) {
|
|
if (!getProductMaterialScanCode(value)) return
|
|
if (taskProductScanTimer) clearTimeout(taskProductScanTimer)
|
|
taskProductScanTimer = setTimeout(() => {
|
|
taskProductScanTimer = null
|
|
onTaskProductScanConfirm()
|
|
}, SCAN_AUTO_SEARCH_DELAY)
|
|
}
|
|
function scheduleProductScanSearch(value) {
|
|
if (!getProductMaterialScanCode(value)) return
|
|
if (productScanTimer) clearTimeout(productScanTimer)
|
|
productScanTimer = setTimeout(() => {
|
|
productScanTimer = null
|
|
onProductScanConfirm()
|
|
}, SCAN_AUTO_SEARCH_DELAY)
|
|
}
|
|
function onTaskProductScanInput(e) {
|
|
scheduleTaskProductScanSearch(e?.detail?.value ?? taskProductScanInput.value)
|
|
}
|
|
function onProductScanInput(e) {
|
|
scheduleProductScanSearch(e?.detail?.value ?? productScanInput.value)
|
|
}
|
|
async function onTaskProductScanConfirm() {
|
|
if (taskProductScanTimer) {
|
|
clearTimeout(taskProductScanTimer)
|
|
taskProductScanTimer = null
|
|
}
|
|
const scanCode = getProductMaterialScanCode(taskProductScanInput.value)
|
|
if (!scanCode) return
|
|
if (!taskId.value) {
|
|
uni.showToast({ title: t('productInbound.selectTaskFirst'), icon: 'none' })
|
|
return
|
|
}
|
|
try {
|
|
uni.showLoading({ title: t('productInbound.loading'), mask: true })
|
|
const matched = await findProductByScanCode(scanCode)
|
|
uni.hideLoading()
|
|
if (!matched?.id) {
|
|
uni.showToast({ title: '\u6ca1\u6709\u8fd9\u4e2a\u4ea7\u54c1', icon: 'none' })
|
|
return
|
|
}
|
|
selectedTaskProduct.value = buildTaskProductSelection(matched)
|
|
selectedPallets.value = []
|
|
palletScanInput.value = ''
|
|
taskProductScanInput.value = ''
|
|
} catch (e) {
|
|
uni.hideLoading()
|
|
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
|
|
}
|
|
}
|
|
async function onProductScanConfirm() {
|
|
if (productScanTimer) {
|
|
clearTimeout(productScanTimer)
|
|
productScanTimer = null
|
|
}
|
|
const scanCode = getProductMaterialScanCode(productScanInput.value)
|
|
if (!scanCode) return
|
|
try {
|
|
uni.showLoading({ title: t('productInbound.loading'), mask: true })
|
|
const matched = await findProductByScanCode(scanCode)
|
|
uni.hideLoading()
|
|
if (!matched?.id) {
|
|
uni.showToast({ title: '\u6ca1\u6709\u8fd9\u4e2a\u4ea7\u54c1', icon: 'none' })
|
|
return
|
|
}
|
|
product.value = matched
|
|
selectedTaskProduct.value = null
|
|
selectedPallets.value = []
|
|
palletScanInput.value = ''
|
|
productScanInput.value = ''
|
|
} catch (e) {
|
|
uni.hideLoading()
|
|
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
|
|
}
|
|
}
|
|
function schedulePalletScanSearch(value) {
|
|
if (!getPalletScanCode(value)) return
|
|
if (palletScanTimer) clearTimeout(palletScanTimer)
|
|
palletScanTimer = setTimeout(() => {
|
|
palletScanTimer = null
|
|
onPalletScanConfirm()
|
|
}, SCAN_AUTO_SEARCH_DELAY)
|
|
}
|
|
function onPalletScanInput(e) {
|
|
schedulePalletScanSearch(e?.detail?.value ?? palletScanInput.value)
|
|
}
|
|
|
|
function addScannedPallet(pallet) {
|
|
if (!pallet?.id) return
|
|
const exists = selectedPallets.value.some((item) => String(item.id) === String(pallet.id))
|
|
if (exists) return
|
|
selectedPallets.value.push({
|
|
...pallet,
|
|
packageCount: pallet.productCount || pallet.packageCount || palletPackageQuantity.value || 1
|
|
})
|
|
}
|
|
async function findPalletByScanCode(scanCode) {
|
|
const id = String(scanCode || '').trim()
|
|
if (!/^\d+$/.test(id)) return null
|
|
const res = await getPallet(id)
|
|
const detail = res?.data || res
|
|
if (!detail?.id) return null
|
|
if (detail.productId && productId.value && String(detail.productId) !== String(productId.value)) return null
|
|
return detail
|
|
}
|
|
async function onPalletScanConfirm() {
|
|
if (palletScanTimer) {
|
|
clearTimeout(palletScanTimer)
|
|
palletScanTimer = null
|
|
}
|
|
const scanCode = getPalletScanCode(palletScanInput.value)
|
|
if (!scanCode) return
|
|
if (!productId.value) {
|
|
uni.showToast({ title: t('productInbound.selectProductFirst'), icon: 'none' })
|
|
return
|
|
}
|
|
try {
|
|
uni.showLoading({ title: t('productInbound.loading'), mask: true })
|
|
const matched = await findPalletByScanCode(scanCode)
|
|
uni.hideLoading()
|
|
if (!matched?.id) {
|
|
uni.showToast({ title: '\u6ca1\u6709\u8fd9\u4e2a\u6258\u76d8', icon: 'none' })
|
|
return
|
|
}
|
|
addScannedPallet(matched)
|
|
await loadAreasForPallets([matched])
|
|
palletScanInput.value = ''
|
|
} catch (e) {
|
|
uni.hideLoading()
|
|
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
|
|
}
|
|
}
|
|
function getPalletAreaTimerKey(index) {
|
|
const pallet = selectedPallets.value[index]
|
|
return String(pallet?.id || index)
|
|
}
|
|
function schedulePalletAreaScanSearch(value, index) {
|
|
if (!getWarehouseAreaScanCode(value)) return
|
|
const key = getPalletAreaTimerKey(index)
|
|
if (palletAreaScanTimers[key]) clearTimeout(palletAreaScanTimers[key])
|
|
palletAreaScanTimers[key] = setTimeout(() => {
|
|
palletAreaScanTimers[key] = null
|
|
onPalletAreaScanConfirm(index)
|
|
}, SCAN_AUTO_SEARCH_DELAY)
|
|
}
|
|
function onPalletAreaScanInput(e, index) {
|
|
const pallet = selectedPallets.value[index]
|
|
if (!pallet) return
|
|
const value = e?.detail?.value ?? pallet._areaScanInput ?? ''
|
|
pallet._areaScanInput = value
|
|
schedulePalletAreaScanSearch(value, index)
|
|
}
|
|
async function findWarehouseAreaByScanCode(scanCode) {
|
|
const id = String(scanCode || '').trim()
|
|
if (!/^\d+$/.test(id)) return null
|
|
const res = await getWarehouseArea(id)
|
|
const detail = res?.data || res
|
|
return detail?.id ? detail : null
|
|
}
|
|
function cacheWarehouseArea(area) {
|
|
if (!area?.id || !area?.warehouseId) return
|
|
const key = String(area.warehouseId)
|
|
const current = warehouseAreaMap.value[key] || []
|
|
const nextItem = { value: area.id, label: getWarehouseAreaLabel(area) }
|
|
const exists = current.some((item) => String(item.value) === String(area.id))
|
|
warehouseAreaMap.value = {
|
|
...warehouseAreaMap.value,
|
|
[key]: exists ? current.map((item) => String(item.value) === String(area.id) ? nextItem : item) : [...current, nextItem]
|
|
}
|
|
}
|
|
function isWarehouseAreaMatched(pallet, area) {
|
|
return Boolean(pallet?.warehouseId && area?.warehouseId && String(pallet.warehouseId) === String(area.warehouseId))
|
|
}
|
|
function applyScannedWarehouseArea(index, area) {
|
|
const pallet = selectedPallets.value[index]
|
|
if (!pallet || !area?.id) return
|
|
cacheWarehouseArea(area)
|
|
pallet.areaId = area.id
|
|
pallet.areaName = getWarehouseAreaLabel(area)
|
|
pallet._areaScanInput = ''
|
|
}
|
|
async function onPalletAreaScanConfirm(index) {
|
|
const key = getPalletAreaTimerKey(index)
|
|
if (palletAreaScanTimers[key]) {
|
|
clearTimeout(palletAreaScanTimers[key])
|
|
palletAreaScanTimers[key] = null
|
|
}
|
|
const pallet = selectedPallets.value[index]
|
|
if (!pallet) return
|
|
const scanCode = getWarehouseAreaScanCode(pallet._areaScanInput)
|
|
if (!scanCode) return
|
|
try {
|
|
uni.showLoading({ title: t('productInbound.loading'), mask: true })
|
|
const matched = await findWarehouseAreaByScanCode(scanCode)
|
|
uni.hideLoading()
|
|
if (!matched?.id) {
|
|
uni.showToast({ title: '\u6ca1\u6709\u8fd9\u4e2a\u5e93\u533a', icon: 'none' })
|
|
return
|
|
}
|
|
if (!pallet.warehouseId) {
|
|
uni.showToast({ title: '\u8bf7\u5148\u9009\u62e9\u4ed3\u5e93', icon: 'none' })
|
|
return
|
|
}
|
|
if (!isWarehouseAreaMatched(pallet, matched)) {
|
|
pallet._areaScanInput = ''
|
|
uni.showToast({ title: '\u5e93\u533a\u4e0d\u5c5e\u4e8e\u5f53\u524d\u4ed3\u5e93', icon: 'none' })
|
|
return
|
|
}
|
|
applyScannedWarehouseArea(index, matched)
|
|
} catch (e) {
|
|
uni.hideLoading()
|
|
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
|
|
}
|
|
}
|
|
function goSelectPallet() {
|
|
if (!productId.value) {
|
|
uni.showToast({ title: t('productInbound.selectProductFirst'), icon: 'none' })
|
|
return
|
|
}
|
|
getApp().globalData._productInboundSelectedPallets = [...selectedPallets.value]
|
|
const query = `productId=${productId.value}&packageCount=${palletPackageQuantity.value || 1}`
|
|
uni.navigateTo({ url: `/pages_function/pages/productInbound/palletSelect?${query}` })
|
|
}
|
|
function removePallet(index) {
|
|
selectedPallets.value.splice(index, 1)
|
|
}
|
|
async function loadWarehouses() {
|
|
try {
|
|
const res = await getWarehouseSimpleList({ categoryType: WAREHOUSE_CATEGORY_TYPE })
|
|
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
|
|
warehouseOptions.value = data.map((w) => ({ value: w.id, label: w.name || String(w.id || '') }))
|
|
} catch (e) {}
|
|
}
|
|
async function loadAreasForWarehouse(warehouseId) {
|
|
if (!warehouseId || warehouseAreaMap.value[String(warehouseId)]) return
|
|
try {
|
|
const res = await getWarehouseAreaSimpleList(warehouseId)
|
|
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
|
|
warehouseAreaMap.value = {
|
|
...warehouseAreaMap.value,
|
|
[String(warehouseId)]: data.map((a) => ({ value: a.id, label: a.name || a.areaName || String(a.id || '') }))
|
|
}
|
|
} catch (e) {
|
|
warehouseAreaMap.value = { ...warehouseAreaMap.value, [String(warehouseId)]: [] }
|
|
}
|
|
}
|
|
async function loadAreasForPallets(pallets) {
|
|
const warehouseIds = Array.from(new Set((pallets || []).map((p) => p.warehouseId).filter(Boolean)))
|
|
await Promise.all(warehouseIds.map((id) => loadAreasForWarehouse(id)))
|
|
}
|
|
function handleCancel() {
|
|
const gd = getApp().globalData
|
|
gd._productInboundEditIndex = null
|
|
gd._productInboundEditItem = null
|
|
uni.navigateBack()
|
|
}
|
|
function handleConfirm() {
|
|
if (relateTask.value && !taskId.value) {
|
|
uni.showToast({ title: t('productInbound.selectTask'), icon: 'none' })
|
|
return
|
|
}
|
|
if (relateTask.value && !selectedTaskProduct.value) {
|
|
uni.showToast({ title: t('productInbound.selectTaskProduct'), icon: 'none' })
|
|
return
|
|
}
|
|
if (!productId.value) {
|
|
uni.showToast({ title: t('productInbound.selectProduct'), icon: 'none' })
|
|
return
|
|
}
|
|
if (!selectedPallets.value.length) {
|
|
uni.showToast({ title: t('productInbound.selectPallet'), icon: 'none' })
|
|
return
|
|
}
|
|
const invalid = selectedPallets.value.find((p) => !p.warehouseId || !p.areaId || !Number(p.packageCount))
|
|
if (invalid) {
|
|
uni.showToast({ title: t('productInbound.completePalletInfo'), icon: 'none' })
|
|
return
|
|
}
|
|
const firstPallet = selectedPallets.value[0]
|
|
const item = {
|
|
productId: productId.value,
|
|
productName: productName.value,
|
|
productBarCode: productBarCode.value,
|
|
productUnitName: product.value.unitName || product.value.minStockUnitName || '个',
|
|
inputUnitType: '个',
|
|
inputCount: inputCount.value,
|
|
count: count.value,
|
|
relateTask: relateTask.value,
|
|
taskId: relateTask.value ? taskId.value : null,
|
|
taskCode: taskCode.value,
|
|
taskDetailIds: selectedTaskProduct.value?.taskDetailIds,
|
|
packagingSchemeRelationId: currentScheme.value?.id,
|
|
packagingSchemeId: currentScheme.value?.packagingSchemeId,
|
|
packagingSchemeName: packagingSchemeName.value,
|
|
packageQuantity: packageQuantity.value,
|
|
palletPackageQuantity: palletPackageQuantity.value,
|
|
palletTotalQuantity: palletTotalQuantity.value,
|
|
warehouseId: firstPallet?.warehouseId || null,
|
|
warehouseName: getWarehouseName(firstPallet?.warehouseId),
|
|
areaId: firstPallet?.areaId || null,
|
|
areaName: getAreaName(firstPallet?.warehouseId, firstPallet?.areaId),
|
|
palletCode: palletCode.value,
|
|
pallets: selectedPallets.value.map((pallet) => ({
|
|
palletId: pallet.id,
|
|
palletCode: getPalletCode(pallet),
|
|
packageCount: Number(pallet.packageCount) || 0,
|
|
warehouseId: pallet.warehouseId,
|
|
areaId: pallet.areaId,
|
|
count: (Number(pallet.packageCount) || 0) * (packageQuantity.value || 1)
|
|
})),
|
|
images: product.value.images,
|
|
_product: { ...product.value },
|
|
_selectedTaskProduct: selectedTaskProduct.value ? { ...selectedTaskProduct.value } : null,
|
|
_selectedTaskData: selectedTaskData.value ? { ...selectedTaskData.value } : null
|
|
}
|
|
const gd = getApp().globalData
|
|
if (!gd._productInboundItems) gd._productInboundItems = []
|
|
const index = Number(editingIndex.value)
|
|
if (Number.isInteger(index) && index >= 0 && index < gd._productInboundItems.length) {
|
|
gd._productInboundItems.splice(index, 1, item)
|
|
} else {
|
|
gd._productInboundItems.push(item)
|
|
}
|
|
gd._productInboundEditIndex = null
|
|
gd._productInboundEditItem = null
|
|
uni.showToast({ title: t('productInbound.productAdded'), icon: 'success', duration: 1000 })
|
|
setTimeout(() => uni.navigateBack(), 700)
|
|
}
|
|
|
|
onLoad(async () => {
|
|
const gd = getApp().globalData
|
|
const index = gd?._productInboundEditIndex
|
|
const item = gd?._productInboundEditItem
|
|
if (item && index !== null && index !== undefined) {
|
|
editingIndex.value = Number(index)
|
|
gd._productInboundEditIndex = null
|
|
gd._productInboundEditItem = null
|
|
await hydrateEditItem(item)
|
|
}
|
|
})
|
|
onShow(async () => {
|
|
const gd = getApp().globalData
|
|
const taskResult = gd?._productInboundTaskSelectResult
|
|
if (taskResult) {
|
|
taskId.value = taskResult.id
|
|
taskCode.value = taskResult.code || taskResult.taskName || ''
|
|
selectedTaskProduct.value = null
|
|
taskProductScanInput.value = ''
|
|
selectedPallets.value = []
|
|
palletScanInput.value = ''
|
|
gd._productInboundTaskSelectResult = null
|
|
try {
|
|
uni.showLoading({ title: t('productInbound.loading'), mask: true })
|
|
const res = await getTaskDefaultPackagingSchemes(taskResult.id)
|
|
uni.hideLoading()
|
|
selectedTaskData.value = res?.data || res || {}
|
|
taskProductList.value = Array.isArray(selectedTaskData.value?.products) ? selectedTaskData.value.products : []
|
|
} catch (e) {
|
|
uni.hideLoading()
|
|
uni.showToast({ title: t('productInbound.taskProductLoadFailed'), icon: 'none' })
|
|
}
|
|
}
|
|
const productResult = gd?._productInboundProductSelectResult
|
|
if (productResult) {
|
|
product.value = productResult
|
|
if (relateTask.value) {
|
|
selectedTaskProduct.value = buildTaskProductSelection(productResult)
|
|
taskProductScanInput.value = ''
|
|
} else {
|
|
selectedTaskProduct.value = null
|
|
productScanInput.value = ''
|
|
}
|
|
selectedPallets.value = []
|
|
palletScanInput.value = ''
|
|
gd._productInboundProductSelectResult = null
|
|
}
|
|
const palletResult = gd?._productInboundPalletSelectResult
|
|
if (Array.isArray(palletResult)) {
|
|
selectedPallets.value = palletResult
|
|
await loadAreasForPallets(selectedPallets.value)
|
|
gd._productInboundPalletSelectResult = null
|
|
}
|
|
await loadWarehouses()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page-container { min-height: 100vh; background: #f5f7fb; }
|
|
.detail-scroll { height: calc(100vh - 172rpx); }
|
|
.content-section { padding: 20rpx 24rpx 28rpx; }
|
|
.section-card { background: #ffffff; border-radius: 20rpx; padding: 24rpx; margin-bottom: 20rpx; border: 1rpx solid #eef2f7; box-shadow: 0 6rpx 18rpx rgba(15, 23, 42, 0.04); }
|
|
.section-header { display: flex; align-items: center; gap: 12rpx; margin-bottom: 22rpx; padding-bottom: 18rpx; border-bottom: 1rpx solid #f1f5f9; }
|
|
.section-icon { width: 40rpx; height: 40rpx; border-radius: 10rpx; background: #eff6ff; display: flex; align-items: center; justify-content: center; }
|
|
.section-title { font-size: 32rpx; font-weight: 600; color: #1f2937; }
|
|
.form-field { display: flex; flex-direction: column; gap: 12rpx; }
|
|
.form-field + .form-field { margin-top: 24rpx; }
|
|
.form-label-row { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; }
|
|
.form-label { font-size: 26rpx; color: #4b5563; font-weight: 500; }
|
|
.label-tip { flex-shrink: 0; font-size: 24rpx; color: #6b7280; }
|
|
.required-star { color: #ef4444; font-size: 28rpx; margin-left: 4rpx; }
|
|
.segment-control { display: grid; grid-template-columns: 1fr 1fr; gap: 12rpx; padding: 6rpx; background: #f3f4f6; border-radius: 16rpx; }
|
|
.segment-item { height: 72rpx; border-radius: 12rpx; display: flex; align-items: center; justify-content: center; color: #6b7280; font-size: 28rpx; font-weight: 600; }
|
|
.segment-item.active { background: #ffffff; color: #1f7cff; box-shadow: 0 4rpx 12rpx rgba(15, 23, 42, 0.08); }
|
|
.select-field { min-height: 70rpx; padding: 16rpx 22rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 14rpx; box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: 12rpx; }
|
|
.select-field.selected { background: #f9fbff; border-color: #bfdbfe; box-shadow: 0 4rpx 12rpx rgba(31, 124, 255, 0.08); }
|
|
.select-content { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6rpx; }
|
|
.select-value { font-size: 28rpx; font-weight: 600; color: #1f2937; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.select-placeholder { font-size: 28rpx; color: #9ca3af; }
|
|
.select-subtext { font-size: 24rpx; color: #6b7280; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.task-product-search-row { display: flex; align-items: center; gap: 16rpx; }
|
|
.scan-input-wrap { position: relative; flex: 1; min-width: 0; }
|
|
.task-product-scan-input { width: 100%; height: 70rpx; padding: 0 64rpx 0 22rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 14rpx; box-sizing: border-box; font-size: 28rpx; color: #1f2937; }
|
|
.scan-input-icon { position: absolute; right: 20rpx; top: 0; bottom: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; }
|
|
.task-product-select-field { flex-shrink: 0; width: 160rpx; min-height: 70rpx; padding: 0 18rpx; background: #1f4b79; border-radius: 14rpx; box-sizing: border-box; display: flex; align-items: center; justify-content: center; }
|
|
.task-product-select-text { flex: 1; min-width: 0; font-size: 26rpx; font-weight: 600; color: #ffffff; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.info-panel { margin-top: 22rpx; padding: 20rpx; background: #f8fafc; border: 1rpx solid #e8eef6; border-radius: 16rpx; }
|
|
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; background: #ffffff; border: 1rpx solid #eef2f7; border-radius: 14rpx; overflow: hidden; }
|
|
.info-item { min-width: 0; display: flex; flex-direction: column; gap: 8rpx; padding: 18rpx 20rpx; border-right: 1rpx solid #f1f5f9; border-bottom: 1rpx solid #f1f5f9; }
|
|
.info-item:nth-child(2n) { border-right: 0; }
|
|
.info-label { font-size: 23rpx; color: #8a94a6; }
|
|
.info-value { font-size: 27rpx; color: #334155; line-height: 1.35; word-break: break-all; }
|
|
.pallet-list { margin-top: 20rpx; display: flex; flex-direction: column; gap: 14rpx; }
|
|
.pallet-card { padding: 18rpx 20rpx; border: 1rpx solid #eef2f7; border-radius: 16rpx; background: #ffffff; }
|
|
.pallet-main { display: flex; flex-direction: column; gap: 14rpx; }
|
|
.pallet-top { display: flex; align-items: center; justify-content: space-between; gap: 12rpx; }
|
|
.pallet-code { flex: 1; min-width: 0; font-size: 28rpx; color: #1f2937; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.remove-btn { width: 48rpx; height: 48rpx; border-radius: 24rpx; background: #fef2f2; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
|
.pallet-field-list { display: flex; flex-direction: column; gap: 14rpx; }
|
|
.loc-cell { min-width: 0; display: flex; flex-direction: column; gap: 8rpx; }
|
|
.loc-label { font-size: 22rpx; color: #9ca3af; }
|
|
.loc-picker { min-height: 68rpx; padding: 0 18rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 12rpx; display: flex; align-items: center; justify-content: space-between; gap: 8rpx; box-sizing: border-box; }
|
|
.pallet-field-control { width: 100%; }
|
|
.loc-value { flex: 1; min-width: 0; font-size: 26rpx; color: #1f2937; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.loc-placeholder { flex: 1; font-size: 26rpx; color: #9ca3af; }
|
|
.area-select-row { width: 100%; }
|
|
.area-select-picker { flex-shrink: 0; width: 160rpx; display: block; }
|
|
.area-select-button { width: 160rpx; }
|
|
.area-select-button.disabled { background: #94a3b8; }
|
|
.count-label { font-size: 22rpx; color: #9ca3af; }
|
|
.count-input { height: 68rpx; padding: 0 18rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 12rpx; font-size: 26rpx; color: #1f2937; box-sizing: border-box; }
|
|
.pallet-piece-row { min-height: 44rpx; display: flex; align-items: center; justify-content: space-between; gap: 16rpx; }
|
|
.pallet-piece-value { flex: 1; min-width: 0; font-size: 28rpx; font-weight: 600; color: #475569; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.quantity-summary { display: grid; grid-template-columns: 1fr 1fr; gap: 14rpx; }
|
|
.quantity-item { padding: 18rpx; background: #eff6ff; border-radius: 14rpx; display: flex; flex-direction: column; align-items: center; gap: 6rpx; }
|
|
.quantity-value { font-size: 34rpx; color: #1f4b79; font-weight: 700; }
|
|
.quantity-label { font-size: 23rpx; color: #64748b; }
|
|
.empty-card { height: 96rpx; border-radius: 14rpx; background: #f8fafc; color: #94a3b8; font-size: 27rpx; display: flex; align-items: center; justify-content: center;margin-top: 20rpx; }
|
|
.action-bar { position: fixed; left: 0; right: 0; bottom: 0; display: flex; gap: 18rpx; padding: 18rpx 24rpx calc(18rpx + env(safe-area-inset-bottom)); background: #ffffff; box-shadow: 0 -8rpx 24rpx rgba(15, 23, 42, 0.06); z-index: 99; }
|
|
.action-btn { flex: 1; height: 84rpx; border-radius: 16rpx; display: flex; align-items: center; justify-content: center; font-size: 30rpx; font-weight: 600; }
|
|
.back-btn { background: #eef2f7; color: #475569; }
|
|
.submit-btn { background: #1f4b79; color: #ffffff; }
|
|
</style>
|