|
|
@@ -0,0 +1,755 @@
|
|
|
+<template>
|
|
|
+ <div class="transfer-container">
|
|
|
+ <van-nav-bar title="移库" left-arrow fixed placeholder @click-left="goBack" @click-right="onConfirm">
|
|
|
+ <template #left>
|
|
|
+ <van-icon name="arrow-left" size="25" />
|
|
|
+ <div style="color: #fff">返回</div>
|
|
|
+ </template>
|
|
|
+ <template #right>
|
|
|
+ <span style="color: #fff">确认移库</span>
|
|
|
+ </template>
|
|
|
+ </van-nav-bar>
|
|
|
+ <!-- 搜索表单 -->
|
|
|
+ <div class="top" ref="topRef">
|
|
|
+ <van-notice-bar :text="tips" speed="50" class="tip-notice" />
|
|
|
+ <div class="search-section">
|
|
|
+ <van-cell-group>
|
|
|
+ <van-field
|
|
|
+ v-model.lazy="sourceLocation"
|
|
|
+ label="来源库位"
|
|
|
+ placeholder="请输入来源库位"
|
|
|
+ clearable
|
|
|
+ :class="{ 'field-focused': scanType === 1 }"
|
|
|
+ @focus="scanType = 1"
|
|
|
+ @keyup.enter="_handlerScan(sourceLocation)"
|
|
|
+ ref="sourceLocationRef"
|
|
|
+ autocomplete="off"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ v-model.lazy="productBarcode"
|
|
|
+ label="商品条码"
|
|
|
+ placeholder="请输入商品条码"
|
|
|
+ clearable
|
|
|
+ :class="{ 'field-focused': scanType === 2 }"
|
|
|
+ @focus="scanType = 2"
|
|
|
+ @keyup.enter="_handlerScan(productBarcode)"
|
|
|
+ @input="onAsnCancel"
|
|
|
+ ref="productBarcodeRef"
|
|
|
+ autocomplete="off"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ v-model="transferQuantity"
|
|
|
+ label="移库数量"
|
|
|
+ placeholder="请输入移库数量"
|
|
|
+ ref="countRef"
|
|
|
+ type="number"
|
|
|
+ clearable
|
|
|
+ :class="{ 'field-focused': scanType === 3,'active-color': scanType != 3}"
|
|
|
+ @focus="scanType = 3"
|
|
|
+ @keyup.enter="_handlerScan(transferQuantity)"
|
|
|
+ autocomplete="off"
|
|
|
+ >
|
|
|
+ <template #right-icon v-if="selectedProducts['id']">
|
|
|
+ <div class="quantity-display">
|
|
|
+ <span class="quantity-label">库存</span>
|
|
|
+ <span class="quantity-value">{{ selectedProducts.quantityAvailable }}</span>
|
|
|
+ <span class="quantity-label">件</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ <van-field
|
|
|
+ v-model="targetLocation"
|
|
|
+ label="目标库位"
|
|
|
+ placeholder="请输入目标库位"
|
|
|
+ clearable
|
|
|
+ :class="{ 'field-focused': scanType === 4 }"
|
|
|
+ @focus="scanType = 4"
|
|
|
+ autocomplete="off"
|
|
|
+ ref="targetLocationRef"
|
|
|
+ @keyup.enter="_handlerScan(targetLocation)"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+ </div>
|
|
|
+ <!-- 已选择商品展示 -->
|
|
|
+ <div v-if="selectedProducts['id']" class="selected-section">
|
|
|
+ <van-cell-group>
|
|
|
+ <van-cell class="selected-product-cell">
|
|
|
+ <template #title>
|
|
|
+ <div class="selected-product-header">
|
|
|
+ <div class="location-info">
|
|
|
+ <span class="location-label">跟踪号</span>
|
|
|
+ <span class="location-value">{{ selectedProducts.traceId }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #label>
|
|
|
+ <div class="selected-product-details">
|
|
|
+ <div class="detail-auto-grid">
|
|
|
+ <span class="detail-text" v-if="selectedProducts.lotAtt01">生产日期: {{ selectedProducts.lotAtt01 }}</span>
|
|
|
+ <span class="detail-text" v-if="selectedProducts.lotAtt02">失效日期: {{ selectedProducts.lotAtt02 }}</span>
|
|
|
+ <span class="detail-text" v-if="selectedProducts.lotAtt02">属性仓:{{ selectedProducts.lotAtt05 }}</span>
|
|
|
+ <span class="detail-text" v-if="selectedProducts.lotAtt08">质量状态: {{ selectedProducts.lotAtt08}}</span>
|
|
|
+ <span class="detail-text" v-if="selectedProducts.lotNumber">批次号: {{ selectedProducts.lotNumber }}</span>
|
|
|
+ <span class="detail-text" v-if="selectedProducts.lotAtt04">生产批号: {{ selectedProducts.lotAtt04 }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ </van-cell-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 查询结果表格 -->
|
|
|
+ <div class="table-section">
|
|
|
+ <div class="table-container">
|
|
|
+ <div class="table-title" v-if="productList.length==0">库位商品明细</div>
|
|
|
+ <div class="table-wrapper" :style="'height:'+tableHeight+'px'">
|
|
|
+ <div class="table-header-fixed">
|
|
|
+ <table class="product-table header-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th style="width: 40px">货主</th>
|
|
|
+ <th>库位</th>
|
|
|
+ <th>条码</th>
|
|
|
+ <th>余量</th>
|
|
|
+ <th>分配</th>
|
|
|
+ <th>可用</th>
|
|
|
+ <th style="width: 30px">操作</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ <div class="table-body-wrapper">
|
|
|
+ <table class="product-table body-table">
|
|
|
+ <tbody>
|
|
|
+ <tr v-if="productList.length>0"
|
|
|
+ v-for="(product, index) in productList"
|
|
|
+ :key="product.id"
|
|
|
+ :class="{ selected: isSelected(product) }"
|
|
|
+ @click="onProductSelect(product)"
|
|
|
+ class="clickable-row"
|
|
|
+ >
|
|
|
+ <td
|
|
|
+ v-if="isFirstInOwnerGroup(product, index)"
|
|
|
+ :rowspan="getOwnerRowspan(product, index)"
|
|
|
+ class="owner-cell"
|
|
|
+ style="width: 40px"
|
|
|
+ >
|
|
|
+ {{ product.owner }}
|
|
|
+ </td>
|
|
|
+ <td class="location-cell">{{ product.location }}</td>
|
|
|
+ <td class="barcode-cell">{{ product.barcode }}</td>
|
|
|
+ <td class="quantity-cell">{{ product.quantity }}</td>
|
|
|
+ <td class="quantity-cell">{{ product.qtyPreAllocated }}</td>
|
|
|
+ <td class="quantity-cell">{{ product.quantityAvailable }}</td>
|
|
|
+ <td class="checkbox-cell">
|
|
|
+ <van-checkbox
|
|
|
+ :model-value="isSelected(product)"
|
|
|
+ @update:model-value="onProductSelect(product)"
|
|
|
+ />
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr v-else>
|
|
|
+ <td colspan="7">
|
|
|
+ <van-empty :image="<string>nodataUrl" image-size="140"></van-empty>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, onMounted, onUnmounted, computed, nextTick } from 'vue'
|
|
|
+import { showConfirmDialog, showNotify, showToast } from 'vant'
|
|
|
+import nodataUrl from '@/assets/nodata.png'
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
+import { useStore } from '@/store/modules/user'
|
|
|
+import { androidFocus, getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
|
|
|
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
|
|
|
+import { getInventory, inventoryMovement } from '@/api/inventory'
|
|
|
+import { closeLoading, showLoading } from '@/utils/loading'
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const store = useStore()
|
|
|
+try {
|
|
|
+ getHeader()
|
|
|
+ androidFocus()
|
|
|
+} catch (error) {
|
|
|
+ router.push('/login')
|
|
|
+}
|
|
|
+const warehouse = store.warehouse
|
|
|
+// 页面初始化
|
|
|
+onMounted(() => {
|
|
|
+ openListener()
|
|
|
+ scanInit(_handlerScan)
|
|
|
+ // 初始化表格高度
|
|
|
+ setTimeout(() => {
|
|
|
+ calculateTableHeight()
|
|
|
+ }, 100)
|
|
|
+
|
|
|
+ // 监听视窗变化(键盘弹起/收回)
|
|
|
+ if (window.visualViewport) {
|
|
|
+ window.visualViewport.addEventListener('resize', calculateTableHeight)
|
|
|
+ }
|
|
|
+ // 兼容方案:监听窗口大小变化
|
|
|
+ window.addEventListener('resize', calculateTableHeight)
|
|
|
+})
|
|
|
+const sourceLocation = ref('')
|
|
|
+const productBarcode = ref('')
|
|
|
+const transferQuantity = ref('')
|
|
|
+const targetLocation = ref('')
|
|
|
+const productList = ref([])
|
|
|
+const selectedProducts = ref({})
|
|
|
+const oldProductBarcode = ref('')
|
|
|
+const countRef=ref(null)
|
|
|
+const targetLocationRef=ref(null)
|
|
|
+const productBarcodeRef=ref(null)
|
|
|
+const sourceLocationRef=ref(null)
|
|
|
+// 扫描类型控制焦点高亮
|
|
|
+const scanType = ref(2) // 1: 来源库位, 2: 商品条码, 3: 移库数量, 4: 目标库位
|
|
|
+const tips = ref('请扫描商品条码/来源库位')
|
|
|
+
|
|
|
+// 扫描条码监听
|
|
|
+const _handlerScan = (code) => {
|
|
|
+ if(!code) return
|
|
|
+ if (scanType.value == 2 || scanType.value == 1) {
|
|
|
+ if (scanType.value == 2) {
|
|
|
+ productBarcode.value = code
|
|
|
+ oldProductBarcode.value=code
|
|
|
+ } else if (scanType.value == 1) {
|
|
|
+ sourceLocation.value = code
|
|
|
+ }
|
|
|
+ const params = {
|
|
|
+ warehouse,
|
|
|
+ barcode: productBarcode.value,
|
|
|
+ location: sourceLocation.value,
|
|
|
+ locationRegexp: '^(?!STAGE_|SORTATION_).*$',
|
|
|
+ }
|
|
|
+ showLoading()
|
|
|
+ getInventory(params).then(res => {
|
|
|
+ if (res.data.length > 0) {
|
|
|
+ res.data.forEach((item, i) => {
|
|
|
+ item.id = i + 1
|
|
|
+ })
|
|
|
+ // 按照locationUsage排序:PC、CS、EA、RS、ST、SS,其他的放最后
|
|
|
+ const sortOrder = {
|
|
|
+ 'PC': 1,
|
|
|
+ 'CS': 2,
|
|
|
+ 'EA': 3,
|
|
|
+ 'RS': 4,
|
|
|
+ 'ST': 5,
|
|
|
+ 'SS': 6,
|
|
|
+ }
|
|
|
+ res.data.sort((a, b) => {
|
|
|
+ const orderA = sortOrder[a.locationUsage] || 999
|
|
|
+ const orderB = sortOrder[b.locationUsage] || 999
|
|
|
+ // 先按locationUsage排序
|
|
|
+ if (orderA !== orderB) {
|
|
|
+ return orderA - orderB
|
|
|
+ }
|
|
|
+ // locationUsage相同时,再按location排序
|
|
|
+ return b.location.localeCompare(a.location)
|
|
|
+ })
|
|
|
+ productList.value = res.data
|
|
|
+ onProductSelect(productList.value[0])
|
|
|
+ // 数据加载完成后重新计算表格高度
|
|
|
+ setTimeout(() => {
|
|
|
+ calculateTableHeight()
|
|
|
+ }, 100)
|
|
|
+ closeLoading()
|
|
|
+ scanSuccess()
|
|
|
+ tips.value = '请扫描目标库位/修改移库数量'
|
|
|
+ scanType.value = 4
|
|
|
+ } else {
|
|
|
+ scanError()
|
|
|
+ closeLoading()
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `暂未查询到《${code}》库存数据` })
|
|
|
+ tips.value = `暂未查询到《${code}》库存数据`
|
|
|
+ productBarcode.value = ''
|
|
|
+ reset()
|
|
|
+ }
|
|
|
+ }).catch((err) => {
|
|
|
+ scanError()
|
|
|
+ closeLoading()
|
|
|
+ tips.value = err.message || '系统异常,请联系技术支持'
|
|
|
+ reset()
|
|
|
+ })
|
|
|
+ }else if (scanType.value == 3) {
|
|
|
+ countRef.value?.blur()
|
|
|
+ scanSuccess()
|
|
|
+ if(targetLocation.value){
|
|
|
+ tips.value = '请手动进行移库操作'
|
|
|
+ }else {
|
|
|
+ tips.value = '请扫描目标库位'
|
|
|
+ scanType.value = 4
|
|
|
+ }
|
|
|
+ }else if (scanType.value == 4) {
|
|
|
+ scanSuccess()
|
|
|
+ targetLocation.value = code
|
|
|
+ tips.value = '请手动进行移库操作'
|
|
|
+ }
|
|
|
+ targetLocationRef.value?.blur()
|
|
|
+ productBarcodeRef.value?.blur()
|
|
|
+ sourceLocationRef.value?.blur()
|
|
|
+}
|
|
|
+const onConfirm=()=>{
|
|
|
+ if(!selectedProducts.value.id){
|
|
|
+ tips.value = '请先查询库存信息'
|
|
|
+ scanType.value=2
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `请先查询库存信息` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!productBarcode.value){
|
|
|
+ scanError()
|
|
|
+ tips.value = '请先扫描商品条码'
|
|
|
+ scanType.value=2
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `请先扫描商品条码` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!transferQuantity.value){
|
|
|
+ scanError()
|
|
|
+ tips.value = '请先输入移库数量'
|
|
|
+ countRef.value?.focus()
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `请先输入移库数量` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(transferQuantity.value<=0 || transferQuantity.value>selectedProducts.value.quantityAvailable){
|
|
|
+ scanError()
|
|
|
+ countRef.value?.focus()
|
|
|
+ tips.value = '请先输入正确的移库数量'
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `请先输入正确的移库数量` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!targetLocation.value){
|
|
|
+ scanError()
|
|
|
+ tips.value = '请先扫描目标库位'
|
|
|
+ scanType.value=4
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `请先扫描目标库位` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '移库确认',
|
|
|
+ message:
|
|
|
+ `${productBarcode.value}从"${sourceLocation.value}"移动至"${targetLocation.value}"-${transferQuantity.value}件`
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ const {fmContainer,lotNumber,ownerCode,sku,location}=selectedProducts.value
|
|
|
+ const data={
|
|
|
+ fmLocation:sourceLocation.value,
|
|
|
+ fmContainer,
|
|
|
+ owner:ownerCode,
|
|
|
+ sku,
|
|
|
+ lotNum:lotNumber,
|
|
|
+ warehouse,
|
|
|
+ quantity:transferQuantity.value,
|
|
|
+ toLocation:targetLocation.value
|
|
|
+ }
|
|
|
+ showLoading()
|
|
|
+ inventoryMovement(data).then(res=>{
|
|
|
+ closeLoading()
|
|
|
+ scanSuccess()
|
|
|
+ showNotify({ type: 'success', duration: 3000, message: `操作成功,请继续扫描商品条码` })
|
|
|
+ tips.value = '操作成功,请继续扫描商品条码'
|
|
|
+ scanType.value = 2
|
|
|
+ productBarcode.value=''
|
|
|
+ reset()
|
|
|
+ }).catch(err=>{
|
|
|
+ scanError()
|
|
|
+ closeLoading()
|
|
|
+ tips.value = err.message || '系统异常,请联系技术支持'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .catch(() => {});
|
|
|
+}
|
|
|
+const onAsnCancel = () => {
|
|
|
+ if (productBarcode.value === '' || (oldProductBarcode.value.length != productBarcode.value.length && oldProductBarcode.value != '')) {
|
|
|
+ productList.value = []
|
|
|
+ transferQuantity.value = ''
|
|
|
+ selectedProducts.value = {}
|
|
|
+ scanType.value=2
|
|
|
+ }
|
|
|
+}
|
|
|
+const reset = () => {
|
|
|
+ productList.value = []
|
|
|
+ sourceLocation.value = ''
|
|
|
+ targetLocation.value = ''
|
|
|
+ transferQuantity.value = ''
|
|
|
+ oldProductBarcode.value=''
|
|
|
+ selectedProducts.value = {}
|
|
|
+}
|
|
|
+const topRef = ref(null)
|
|
|
+const tableHeight = ref(261)
|
|
|
+
|
|
|
+// 计算表格高度
|
|
|
+const calculateTableHeight = () => {
|
|
|
+ if (topRef.value) {
|
|
|
+ // 使用 nextTick 确保DOM更新完成后再计算
|
|
|
+ nextTick(() => {
|
|
|
+ // 获取键盘高度
|
|
|
+ const keyboardHeight = window.innerHeight - window.visualViewport?.height || 0
|
|
|
+ // 视图高度 - topRef高度 - 导航栏高度(约46px) - 键盘高度
|
|
|
+ const newHeight = window.innerHeight - topRef.value.offsetHeight - 46 - keyboardHeight
|
|
|
+ tableHeight.value = Math.max(newHeight, 200) // 最小高度200px
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onProductSelect = (product) => {
|
|
|
+ selectedProducts.value = product
|
|
|
+ // 选择商品时自动赋值移库数量
|
|
|
+ transferQuantity.value = product.quantityAvailable
|
|
|
+ sourceLocation.value = product.location
|
|
|
+ scanType.value=4
|
|
|
+ // 重新计算表格高度
|
|
|
+ calculateTableHeight()
|
|
|
+}
|
|
|
+
|
|
|
+const isSelected = (product) => {
|
|
|
+ return selectedProducts.value?.id === product.id
|
|
|
+}
|
|
|
+
|
|
|
+// 检查是否为同一货主的第一行
|
|
|
+const isFirstInOwnerGroup = (product, index: number) => {
|
|
|
+ if (index === 0) return true
|
|
|
+ return productList.value[index - 1].owner !== product.owner
|
|
|
+}
|
|
|
+
|
|
|
+// 计算相同货主的行跨度
|
|
|
+const getOwnerRowspan = (product, index: number) => {
|
|
|
+ let rowspan = 1
|
|
|
+ for (let i = index + 1; i < productList.value.length; i++) {
|
|
|
+ if (productList.value[i].owner === product.owner) {
|
|
|
+ rowspan++
|
|
|
+ } else {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rowspan
|
|
|
+}
|
|
|
+// 数据刷新
|
|
|
+const loadData = () => {
|
|
|
+}
|
|
|
+onUnmounted(() => {
|
|
|
+ closeListener()
|
|
|
+ // 移除键盘事件监听器
|
|
|
+ if (window.visualViewport) {
|
|
|
+ window.visualViewport.removeEventListener('resize', calculateTableHeight)
|
|
|
+ }
|
|
|
+ window.removeEventListener('resize', calculateTableHeight)
|
|
|
+})
|
|
|
+window.onRefresh = loadData
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.transfer-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+/* 搜索表单美化样式 */
|
|
|
+.search-section {
|
|
|
+ margin: 0;
|
|
|
+ background: white;
|
|
|
+ border-radius: 0;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.search-section ::v-deep(.van-cell-group) {
|
|
|
+ background: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.search-section ::v-deep(.van-field) {
|
|
|
+ position: relative;
|
|
|
+ background: white;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ border-radius: 0;
|
|
|
+ padding: 0 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-section ::v-deep(.van-field:last-child) {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.search-section ::v-deep(.van-field__label) {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #323233;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 38px;
|
|
|
+ width: 65px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 基于scanType的动态高亮效果 */
|
|
|
+.search-section ::v-deep(.van-field__body) {
|
|
|
+ border-bottom: 2px solid #e7eaf3;
|
|
|
+ height: 36px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-section ::v-deep(.van-field__control) {
|
|
|
+ font-size: 15px;
|
|
|
+ color: #323233;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.search-section ::v-deep(.van-field__control::placeholder) {
|
|
|
+ color: #c8c9cc;
|
|
|
+ font-weight: 400;
|
|
|
+}
|
|
|
+
|
|
|
+/* 基于scanType的动态高亮效果 */
|
|
|
+.field-focused ::v-deep(.van-field__body) {
|
|
|
+ border-bottom: 2px solid #1989fa;
|
|
|
+ background: linear-gradient(to right, rgba(25, 137, 250, 0.02), rgba(25, 137, 250, 0.05));
|
|
|
+ position: relative;
|
|
|
+ height: 36px;
|
|
|
+}
|
|
|
+
|
|
|
+.field-focused ::v-deep(.van-field::after) {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ height: 2px;
|
|
|
+ background: #1989fa;
|
|
|
+ z-index: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.field-focused ::v-deep(.van-field__label) {
|
|
|
+ color: #1989fa !important;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+
|
|
|
+.field-focused ::v-deep(.van-field__control) {
|
|
|
+ color: #1989fa !important;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.active-color ::v-deep(.van-field__control) {
|
|
|
+ color: orangered !important;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+/* 移除原有的焦点样式 */
|
|
|
+.search-section ::v-deep(.van-field--focused .van-cell) {
|
|
|
+ border-color: transparent !important;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-section {
|
|
|
+ margin: 5px 0;
|
|
|
+ padding: 0 8px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 库存数量展示样式 */
|
|
|
+.quantity-display {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 2px;
|
|
|
+ margin-right: 10px;
|
|
|
+ padding: 4px 8px;
|
|
|
+ background: rgba(25, 137, 250, 0.1);
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 1px solid rgba(25, 137, 250, 0.2);
|
|
|
+}
|
|
|
+
|
|
|
+.quantity-label {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #666;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.quantity-value {
|
|
|
+ font-size: 14px;
|
|
|
+ color: orangered;
|
|
|
+ align-items: center;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+
|
|
|
+/* 已选商品美化展示 - 蓝色主题直角卡片 */
|
|
|
+.selected-product-cell {
|
|
|
+ background: linear-gradient(135deg, #1989fa 0%, #0570d8 100%);
|
|
|
+ color: white;
|
|
|
+ border-radius: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 4px 12px rgba(25, 137, 250, 0.3);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep(.selected-product-cell.van-cell) {
|
|
|
+ padding: 8px;
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-product-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.location-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ line-height: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.location-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #fff;
|
|
|
+ font-weight: 400;
|
|
|
+}
|
|
|
+
|
|
|
+.location-value {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #fff;
|
|
|
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.selected-product-details {
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
+ padding: 5px 0;
|
|
|
+ border-radius: 0;
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.15);
|
|
|
+}
|
|
|
+
|
|
|
+.detail-auto-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 8px 12px;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgba(255, 255, 255, 0.95);
|
|
|
+ font-weight: 500;
|
|
|
+ flex: 1;
|
|
|
+ text-align: center;
|
|
|
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
|
|
|
+ line-height: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.table-section {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.table-container {
|
|
|
+ background: white;
|
|
|
+ border-radius: 6px;
|
|
|
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.table-wrapper {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.table-header-fixed {
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 10;
|
|
|
+ background: white;
|
|
|
+ border-bottom: 2px solid #ebedf0;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.table-body-wrapper {
|
|
|
+ overflow-y: auto;
|
|
|
+ overflow-x: hidden;
|
|
|
+ max-height: calc(100% - 40px); /* 减去表头高度 */
|
|
|
+}
|
|
|
+
|
|
|
+.header-table,
|
|
|
+.body-table {
|
|
|
+ table-layout: fixed;
|
|
|
+}
|
|
|
+
|
|
|
+.header-table th:nth-child(1),
|
|
|
+.body-table td:nth-child(1) {
|
|
|
+ width: 40px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-table th:nth-child(2),
|
|
|
+.body-table td:nth-child(2) {
|
|
|
+ width: 15%;
|
|
|
+}
|
|
|
+
|
|
|
+.header-table th:nth-child(3),
|
|
|
+.body-table td:nth-child(3) {
|
|
|
+ width: 20%;
|
|
|
+}
|
|
|
+
|
|
|
+.header-table th:nth-child(4),
|
|
|
+.body-table td:nth-child(4) {
|
|
|
+ width: 12%;
|
|
|
+}
|
|
|
+
|
|
|
+.header-table th:nth-child(5),
|
|
|
+.body-table td:nth-child(5) {
|
|
|
+ width: 12%;
|
|
|
+}
|
|
|
+
|
|
|
+.header-table th:nth-child(6),
|
|
|
+.body-table td:nth-child(6) {
|
|
|
+ width: 12%;
|
|
|
+}
|
|
|
+.table-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #323233;
|
|
|
+ padding: 4px 16px 4px;
|
|
|
+ border-bottom: 1px solid #ebedf0;
|
|
|
+ background: #f7f8fa;
|
|
|
+}
|
|
|
+
|
|
|
+.product-table {
|
|
|
+ width: 100%;
|
|
|
+ border-collapse: collapse;
|
|
|
+}
|
|
|
+
|
|
|
+.product-table th,
|
|
|
+.product-table td {
|
|
|
+ padding: 8px 4px;
|
|
|
+ text-align: center;
|
|
|
+ border-bottom: 1px solid #ebedf0;
|
|
|
+ font-size: 12px;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.product-table th {
|
|
|
+ background-color: #f7f8fa;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #323233;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+
|
|
|
+.product-table td {
|
|
|
+ color: #646566;
|
|
|
+}
|
|
|
+
|
|
|
+.product-table tr.selected {
|
|
|
+ background-color: #e8f4ff;
|
|
|
+}
|
|
|
+
|
|
|
+.product-table tr.selected td {
|
|
|
+ color: #1989fa;
|
|
|
+}
|
|
|
+
|
|
|
+.clickable-row {
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.checkbox-cell {
|
|
|
+ width: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+</style>
|