|
|
<template>
|
|
|
<view class="page-container">
|
|
|
<NavBar :title="t('sparepartInbound.createTitle')" />
|
|
|
|
|
|
<!-- 操作按钮区 -->
|
|
|
<view class="action-row">
|
|
|
<view class="action-btn scan-btn" @click="handleScan">
|
|
|
<view class="btn-icon-wrap">
|
|
|
<text class="iconfont icon-scan btn-icon"></text>
|
|
|
</view>
|
|
|
<text class="btn-text">{{ t('sparepartInbound.scanSparepart') }}</text>
|
|
|
</view>
|
|
|
<view class="action-btn select-btn" @click="handleSelectSparepart">
|
|
|
<view class="btn-icon-wrap">
|
|
|
<text class="iconfont icon-device btn-icon"></text>
|
|
|
</view>
|
|
|
<text class="btn-text">{{ t('sparepartInbound.selectSparepart') }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 已选备件 -->
|
|
|
<view v-if="selectedSparepart.id" class="sparepart-section">
|
|
|
<view class="section-title-bar">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">{{ t('sparepartInbound.selectedSpareparts') }}</text>
|
|
|
</view>
|
|
|
<view class="sparepart-card">
|
|
|
<!-- 上半部分:左侧图片 + 右侧基本信息 -->
|
|
|
<view class="card-top">
|
|
|
<!-- 左侧图片区 -->
|
|
|
<view class="card-image-wrap">
|
|
|
<image
|
|
|
v-if="sparepartImage"
|
|
|
:src="sparepartImage"
|
|
|
class="card-image"
|
|
|
mode="aspectFill"
|
|
|
/>
|
|
|
<view v-else class="card-image-empty">
|
|
|
<text class="empty-img-icon">📦</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<!-- 右侧基本信息 -->
|
|
|
<view class="card-info-right">
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">备件名称:</text>
|
|
|
<text class="info-name">{{ textValue(selectedSparepart.name) }}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">规格:</text>
|
|
|
<text class="info-value">{{ textValue(selectedSparepart.standard || selectedSparepart.deviceSpec) }}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">当前库存:</text>
|
|
|
<text class="info-value stock-highlight">{{ textValue(selectedSparepart.stock) }}{{ textUnit(selectedSparepart.minStockUnitName) }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 下半部分:详细信息 -->
|
|
|
<view class="card-bottom">
|
|
|
<view class="detail-row two-col">
|
|
|
<view class="detail-col">
|
|
|
<text class="detail-label">采购单位:</text>
|
|
|
<text class="detail-value">{{ textValue(selectedSparepart.purchaseUnitName) }}</text>
|
|
|
</view>
|
|
|
<view class="detail-col">
|
|
|
<text class="detail-label">库存单位:</text>
|
|
|
<text class="detail-value">{{ textValue(selectedSparepart.unitName || selectedSparepart.minStockUnitName) }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="detail-row">
|
|
|
<text class="detail-label">换算关系:</text>
|
|
|
<text class="detail-value">1{{ textValue(selectedSparepart.purchaseUnitName) }}={{ textValue(selectedSparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(selectedSparepart) }}</text>
|
|
|
</view>
|
|
|
<view class="detail-row">
|
|
|
<text class="detail-label">默认仓库</text>
|
|
|
<text class="detail-value" style="margin-left: 8rpx;">{{ selectedSparepart.warehouseName ? textValue(selectedSparepart.warehouseName) : '库区/备件仓' }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 入库数量 -->
|
|
|
<view class="inbound-qty-section">
|
|
|
<view class="section-title-bar">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">入库数量</text>
|
|
|
</view>
|
|
|
<view class="qty-input-card">
|
|
|
<view class="form-field">
|
|
|
<text class="form-label">入库数量</text>
|
|
|
<input
|
|
|
v-model="inboundQty"
|
|
|
class="form-input"
|
|
|
placeholder="请输入"
|
|
|
confirm-type="done"
|
|
|
/>
|
|
|
<text class="form-suffix-text">单位:{{ textValue(selectedSparepart.purchaseUnitName) }}</text>
|
|
|
</view>
|
|
|
<!-- 折算后库存数量 -->
|
|
|
<view class="convert-row">
|
|
|
<text class="convert-label-inline">折算后库存数量:</text>
|
|
|
<text class="convert-value-inline">{{ calculatedStock }}</text>
|
|
|
<text class="convert-unit-inline">{{ stockUnitLabel(selectedSparepart) }}</text>
|
|
|
</view>
|
|
|
<view class="convert-formula-inline">
|
|
|
{{ inboundQty || 0 }}{{ textValue(selectedSparepart.purchaseUnitName) }} × {{ textValue(selectedSparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(selectedSparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(selectedSparepart) }}
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 供应商(取备件默认供应商) -->
|
|
|
<view class="section-title-bar" style="padding-top: 24rpx;">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">供应商</text>
|
|
|
</view>
|
|
|
<view class="select-row-card">
|
|
|
<view class="full-dropdown">
|
|
|
<text :class="{ placeholder: !defaultSupplierName }">
|
|
|
{{ defaultSupplierName || '未配置默认供应商' }}
|
|
|
</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 经办人 -->
|
|
|
<view class="section-title-bar" style="padding-top: 24rpx;">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">经办人</text>
|
|
|
</view>
|
|
|
<view class="select-row-card" @click="toggleOperatorDropdown">
|
|
|
<view class="full-dropdown">
|
|
|
<text :class="{ placeholder: !selectedOperator }">
|
|
|
{{ selectedOperator ? selectedOperator.label : '请选择经办人' }}
|
|
|
</text>
|
|
|
<text class="dropdown-arrow">▼</text>
|
|
|
</view>
|
|
|
<view v-if="showOperatorDropdown" class="dropdown-panel">
|
|
|
<scroll-view scroll-y class="dropdown-scroll">
|
|
|
<view
|
|
|
v-for="item in operatorOptions"
|
|
|
:key="item.value"
|
|
|
class="dropdown-item"
|
|
|
:class="{ active: selectedOperator?.value === item.value }"
|
|
|
@click.stop="handleSelectOperator(item)"
|
|
|
>
|
|
|
<text class="dropdown-item-text">{{ item.label }}</text>
|
|
|
<text v-if="selectedOperator?.value === item.value" class="dropdown-check">✓</text>
|
|
|
</view>
|
|
|
<view v-if="!operatorOptions.length" class="dropdown-empty">暂无数据</view>
|
|
|
</scroll-view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 仓库 / 库区 -->
|
|
|
<view class="section-title-bar" style="padding-top: 24rpx;">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">仓库/库区</text>
|
|
|
</view>
|
|
|
<view class="select-row-card warehouse-area-card">
|
|
|
<view class="warehouse-area-rows">
|
|
|
<!-- 仓库行 -->
|
|
|
<view class="warehouse-area-row">
|
|
|
<text class="warehouse-area-label">仓库</text>
|
|
|
<view class="warehouse-area-dropdown" @click="toggleWarehouseDropdown">
|
|
|
<view class="dropdown-input">
|
|
|
<text :class="['dropdown-value', { placeholder: !selectedWarehouse }]">
|
|
|
{{ selectedWarehouse ? selectedWarehouse.label : '请选择' }}
|
|
|
</text>
|
|
|
<text class="dropdown-arrow">▼</text>
|
|
|
</view>
|
|
|
<view v-if="showWarehouseDropdown" class="dropdown-panel">
|
|
|
<scroll-view scroll-y class="dropdown-scroll">
|
|
|
<view
|
|
|
v-for="item in warehouseOptions"
|
|
|
:key="item.value"
|
|
|
class="dropdown-item"
|
|
|
:class="{ active: selectedWarehouse?.value === item.value }"
|
|
|
@click.stop="handleSelectWarehouse(item)"
|
|
|
>
|
|
|
<text class="dropdown-item-text">{{ item.label }}</text>
|
|
|
<text v-if="selectedWarehouse?.value === item.value" class="dropdown-check">✓</text>
|
|
|
</view>
|
|
|
<view v-if="!warehouseOptions.length" class="dropdown-empty">暂无数据</view>
|
|
|
</scroll-view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<!-- 库区行 -->
|
|
|
<view class="warehouse-area-row">
|
|
|
<text class="warehouse-area-label">库区</text>
|
|
|
<view class="warehouse-area-dropdown" @click="toggleAreaDropdown">
|
|
|
<view class="dropdown-input">
|
|
|
<text :class="['dropdown-value', { placeholder: !selectedArea }]">
|
|
|
{{ selectedArea ? selectedArea.label : (loadingAreas ? '加载中...' : '请选择') }}
|
|
|
</text>
|
|
|
<text class="dropdown-arrow">▼</text>
|
|
|
</view>
|
|
|
<view v-if="showAreaDropdown" class="dropdown-panel">
|
|
|
<scroll-view scroll-y class="dropdown-scroll">
|
|
|
<view
|
|
|
v-for="item in areaOptions"
|
|
|
:key="item.value"
|
|
|
class="dropdown-item"
|
|
|
:class="{ active: selectedArea?.value === item.value }"
|
|
|
@click.stop="handleSelectArea(item)"
|
|
|
>
|
|
|
<text class="dropdown-item-text">{{ item.label }}</text>
|
|
|
<text v-if="selectedArea?.value === item.value" class="dropdown-check">✓</text>
|
|
|
</view>
|
|
|
<view v-if="!areaOptions.length" class="dropdown-empty">暂无数据</view>
|
|
|
</scroll-view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 空状态 -->
|
|
|
<view v-else class="empty-wrap">
|
|
|
<text class="empty-text">{{ t('sparepartInbound.noSelectedSparepart') }}</text>
|
|
|
</view>
|
|
|
|
|
|
<!-- 底部操作栏 -->
|
|
|
<view class="bottom-actions">
|
|
|
<view class="bottom-btn cancel-btn" @click="handleCancel">取消</view>
|
|
|
<view class="bottom-btn confirm-btn" @click="handleSubmit">确认入库</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, computed } from 'vue'
|
|
|
import { onShow, onHide } from '@dcloudio/uni-app'
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
import NavBar from '@/components/common/NavBar.vue'
|
|
|
import { getSimpleUserList, getWarehouseSimpleList, getWarehouseAreaSimpleList } from '@/api/mes/moldget'
|
|
|
import { createSparepartInbound } from '@/api/mes/sparepartInbound'
|
|
|
import { getSparepartDetail } from '@/api/mes/sparepart'
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
|
const selectedSparepart = ref({})
|
|
|
const inboundQty = ref(null)
|
|
|
|
|
|
// 备件默认供应商(从备件数据中取)
|
|
|
const defaultSupplierName = computed(() => {
|
|
|
const suppliers = selectedSparepart.value.suppliers
|
|
|
const defaultId = selectedSparepart.value.defaultSupplierId
|
|
|
if (!suppliers || !suppliers.length) return ''
|
|
|
if (defaultId) {
|
|
|
const found = suppliers.find(s => s.supplierId === defaultId || s.id === defaultId)
|
|
|
if (found) return found.supplierName || ''
|
|
|
}
|
|
|
// 没配默认供应商,取第一个标记为默认的
|
|
|
const firstDefault = suppliers.find(s => s.defaultStatus === 1)
|
|
|
return firstDefault?.supplierName || ''
|
|
|
})
|
|
|
const defaultSupplierId = computed(() => {
|
|
|
const suppliers = selectedSparepart.value.suppliers
|
|
|
const defaultId = selectedSparepart.value.defaultSupplierId
|
|
|
if (!suppliers || !suppliers.length) return undefined
|
|
|
if (defaultId) {
|
|
|
const found = suppliers.find(s => s.supplierId === defaultId || s.id === defaultId)
|
|
|
if (found) return found.supplierId || found.id
|
|
|
}
|
|
|
const firstDefault = suppliers.find(s => s.defaultStatus === 1)
|
|
|
return firstDefault?.supplierId || firstDefault?.id
|
|
|
})
|
|
|
|
|
|
// 经办人下拉
|
|
|
const operatorOptions = ref([])
|
|
|
const selectedOperator = ref(null)
|
|
|
const showOperatorDropdown = ref(false)
|
|
|
|
|
|
// 仓库下拉
|
|
|
const warehouseOptions = ref([])
|
|
|
const selectedWarehouse = ref(null)
|
|
|
const showWarehouseDropdown = ref(false)
|
|
|
|
|
|
// 库区下拉
|
|
|
const areaOptions = ref([])
|
|
|
const selectedArea = ref(null)
|
|
|
const showAreaDropdown = ref(false)
|
|
|
const loadingAreas = ref(false)
|
|
|
|
|
|
// 备件图片(后端返回 images 字段,逗号分隔多图 URL,取第一张)
|
|
|
const sparepartImage = computed(() => {
|
|
|
const images = selectedSparepart.value.images
|
|
|
if (!images) return ''
|
|
|
if (Array.isArray(images)) return String(images[0] || '')
|
|
|
return String(images).split(',')[0]?.trim() || ''
|
|
|
})
|
|
|
|
|
|
// 折算后库存数量
|
|
|
const calculatedStock = computed(() => {
|
|
|
const qty = Number(inboundQty.value) || 0
|
|
|
const ratio = Number(selectedSparepart.value.purchaseUnitConvertQuantity) || 0
|
|
|
return qty * ratio
|
|
|
})
|
|
|
|
|
|
function textValue(v) {
|
|
|
if (v === 0) return '0'
|
|
|
if (v == null) return '-'
|
|
|
const s = String(v).trim()
|
|
|
return s || '-'
|
|
|
}
|
|
|
|
|
|
function textUnit(v) {
|
|
|
if (v === 0) return '0'
|
|
|
if (v == null) return ''
|
|
|
return String(v).trim()
|
|
|
}
|
|
|
|
|
|
function stockUnitLabel(item) {
|
|
|
return item.unitName || item.minStockUnitName || '个'
|
|
|
}
|
|
|
|
|
|
function handleScan() {
|
|
|
uni.scanCode({
|
|
|
onlyFromCamera: true,
|
|
|
scanType: ['barCode', 'qrCode'],
|
|
|
success: (res) => {
|
|
|
console.log('扫码结果:', res.result)
|
|
|
// TODO: 根据扫码结果查询备件信息并添加到列表
|
|
|
uni.showToast({ title: '扫码成功: ' + res.result, icon: 'none' })
|
|
|
},
|
|
|
fail: () => {
|
|
|
uni.showToast({ title: t('functionCommon.scanFailed'), icon: 'none' })
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
|
|
|
function handleCancel() {
|
|
|
uni.navigateBack()
|
|
|
}
|
|
|
|
|
|
function handleSelectSparepart() {
|
|
|
uni.navigateTo({
|
|
|
url: '/pages_function/pages/sparepartInbound/sparepartSelect'
|
|
|
})
|
|
|
}
|
|
|
|
|
|
function toggleOperatorDropdown() {
|
|
|
showOperatorDropdown.value = !showOperatorDropdown.value
|
|
|
}
|
|
|
|
|
|
function handleSelectOperator(item) {
|
|
|
selectedOperator.value = item
|
|
|
showOperatorDropdown.value = false
|
|
|
}
|
|
|
|
|
|
async function loadOperators() {
|
|
|
try {
|
|
|
const res = await getSimpleUserList()
|
|
|
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
|
|
|
operatorOptions.value = data.map((u) => ({
|
|
|
value: u.id || u.userId,
|
|
|
label: u.nickname || u.userName || u.name || String(u.id || '')
|
|
|
}))
|
|
|
} catch (e) {
|
|
|
console.error('loadOperators error', e)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function toggleWarehouseDropdown() {
|
|
|
showWarehouseDropdown.value = !showWarehouseDropdown.value
|
|
|
}
|
|
|
|
|
|
function handleSelectWarehouse(item) {
|
|
|
selectedWarehouse.value = item
|
|
|
showWarehouseDropdown.value = false
|
|
|
// 清空之前选择的库区
|
|
|
selectedArea.value = null
|
|
|
areaOptions.value = []
|
|
|
// 自动加载该仓库的库区列表
|
|
|
loadAreas(item.value)
|
|
|
}
|
|
|
|
|
|
function toggleAreaDropdown() {
|
|
|
if (!selectedWarehouse.value) {
|
|
|
uni.showToast({ title: '请先选择仓库', icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
showAreaDropdown.value = !showAreaDropdown.value
|
|
|
}
|
|
|
|
|
|
function handleSelectArea(item) {
|
|
|
selectedArea.value = item
|
|
|
showAreaDropdown.value = false
|
|
|
}
|
|
|
|
|
|
async function loadAreas(warehouseId) {
|
|
|
if (!warehouseId) return
|
|
|
loadingAreas.value = true
|
|
|
areaOptions.value = []
|
|
|
try {
|
|
|
const res = await getWarehouseAreaSimpleList(warehouseId)
|
|
|
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
|
|
|
areaOptions.value = data.map((a) => ({
|
|
|
value: a.id,
|
|
|
label: a.name || a.areaName || String(a.id || '')
|
|
|
}))
|
|
|
} catch (e) {
|
|
|
console.error('loadAreas error', e)
|
|
|
} finally {
|
|
|
loadingAreas.value = false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async function loadWarehouses() {
|
|
|
try {
|
|
|
const res = await getWarehouseSimpleList()
|
|
|
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) {
|
|
|
console.error('loadWarehouses error', e)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async function handleSubmit() {
|
|
|
if (!selectedSparepart.value.id) {
|
|
|
uni.showToast({ title: '请先选择备件', icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
if (!inboundQty.value || Number(inboundQty.value) <= 0) {
|
|
|
uni.showToast({ title: '请输入入库数量', icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
if (!selectedOperator.value) {
|
|
|
uni.showToast({ title: '请选择经办人', icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
if (!selectedWarehouse.value) {
|
|
|
uni.showToast({ title: '请选择仓库', icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
if (!selectedArea.value) {
|
|
|
uni.showToast({ title: '请选择库区', icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
|
|
|
const inputCount = Number(inboundQty.value)
|
|
|
const convertRatio = Number(selectedSparepart.value.purchaseUnitConvertQuantity) || 1
|
|
|
const count = inputCount * convertRatio
|
|
|
|
|
|
const submitData = {
|
|
|
isCode: true,
|
|
|
inTime: Date.now(),
|
|
|
stockUserId: String(selectedOperator.value.value),
|
|
|
supplierId: defaultSupplierId.value,
|
|
|
status: 0,
|
|
|
totalCount: count,
|
|
|
totalPrice: 0,
|
|
|
items: [{
|
|
|
warehouseId: selectedWarehouse.value.value,
|
|
|
areaId: selectedArea.value.value,
|
|
|
productId: selectedSparepart.value.id,
|
|
|
productName: selectedSparepart.value.name || '',
|
|
|
productBarCode: selectedSparepart.value.barCode || '',
|
|
|
productUnitName: selectedSparepart.value.unitName || selectedSparepart.value.minStockUnitName || '',
|
|
|
purchaseUnitName: selectedSparepart.value.purchaseUnitName || '',
|
|
|
purchaseUnitConvertQuantity: convertRatio,
|
|
|
inputCount: inputCount,
|
|
|
count: count
|
|
|
}]
|
|
|
}
|
|
|
console.log('提交数据:', JSON.stringify(submitData))
|
|
|
|
|
|
uni.showLoading({ title: '提交中...', mask: true })
|
|
|
try {
|
|
|
await createSparepartInbound(submitData)
|
|
|
uni.hideLoading()
|
|
|
uni.showToast({ title: '入库成功', icon: 'success' })
|
|
|
setTimeout(() => {
|
|
|
uni.navigateBack()
|
|
|
}, 1500)
|
|
|
} catch (e) {
|
|
|
uni.hideLoading()
|
|
|
const msg = e?.message || e?.data?.msg || e?.response?.data?.msg || t('functionCommon.saveFailed')
|
|
|
console.error('入库提交失败:', e)
|
|
|
uni.showToast({ title: String(msg).substring(0, 50), icon: 'none' })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
onShow(async () => {
|
|
|
const selectResult = getApp().globalData?._sparepartSelectResult
|
|
|
if (selectResult) {
|
|
|
selectedSparepart.value = selectResult
|
|
|
console.log('[sparepartInbound] 已选备件 suppliers:', JSON.stringify(selectResult.suppliers))
|
|
|
console.log('[sparepartInbound] 已选备件 defaultSupplierId:', selectResult.defaultSupplierId)
|
|
|
// 补充获取备件详情(含供应商、图片等)
|
|
|
if (selectResult.id) {
|
|
|
try {
|
|
|
const res = await getSparepartDetail(selectResult.id)
|
|
|
const detail = res?.data || res
|
|
|
if (detail && detail.suppliers) {
|
|
|
console.log('[sparepartInbound] 详情接口 suppliers:', JSON.stringify(detail.suppliers))
|
|
|
selectedSparepart.value = { ...selectedSparepart.value, ...detail }
|
|
|
}
|
|
|
} catch (e) {
|
|
|
console.error('获取备件详情失败:', e)
|
|
|
}
|
|
|
}
|
|
|
inboundQty.value = null
|
|
|
getApp().globalData._sparepartSelectResult = null
|
|
|
}
|
|
|
loadOperators()
|
|
|
loadWarehouses()
|
|
|
})
|
|
|
|
|
|
onHide(() => {
|
|
|
showOperatorDropdown.value = false
|
|
|
showWarehouseDropdown.value = false
|
|
|
showAreaDropdown.value = false
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.page-container {
|
|
|
min-height: 100vh;
|
|
|
background: #f5f6f8;
|
|
|
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
|
|
|
}
|
|
|
|
|
|
/* ====== 操作按钮区 ====== */
|
|
|
.action-row {
|
|
|
display: flex;
|
|
|
gap: 20rpx;
|
|
|
padding: 20rpx 24rpx;
|
|
|
}
|
|
|
|
|
|
.action-btn {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
gap: 12rpx;
|
|
|
height: 96rpx;
|
|
|
border-radius: 12rpx;
|
|
|
background: #1f4b79;
|
|
|
color: #fff;
|
|
|
font-size: 28rpx;
|
|
|
font-weight: 600;
|
|
|
|
|
|
.btn-icon-wrap {
|
|
|
width: 44rpx;
|
|
|
height: 44rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
.btn-icon {
|
|
|
font-size: 36rpx;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.btn-text {
|
|
|
font-size: 28rpx;
|
|
|
font-weight: 600;
|
|
|
color: #fff;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* ====== 已选备件区域 ====== */
|
|
|
.sparepart-section {
|
|
|
padding: 0;
|
|
|
}
|
|
|
|
|
|
.section-title-bar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 10rpx;
|
|
|
padding: 24rpx 24rpx 18rpx;
|
|
|
}
|
|
|
|
|
|
.section-bar-line {
|
|
|
width: 6rpx;
|
|
|
height: 32rpx;
|
|
|
border-radius: 3rpx;
|
|
|
background: #2563eb;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.section-title {
|
|
|
font-size: 30rpx;
|
|
|
font-weight: 700;
|
|
|
color: #1a1a1a;
|
|
|
}
|
|
|
|
|
|
.sparepart-card {
|
|
|
background: #fff;
|
|
|
border-radius: 16rpx;
|
|
|
padding: 24rpx;
|
|
|
margin: 0 24rpx 20rpx;
|
|
|
box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.04);
|
|
|
}
|
|
|
|
|
|
/* ====== 卡片上半部分:图片 + 信息 + 删除 ====== */
|
|
|
.card-top {
|
|
|
display: flex;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.card-image-wrap {
|
|
|
width: 160rpx;
|
|
|
height: 160rpx;
|
|
|
border-radius: 12rpx;
|
|
|
overflow: hidden;
|
|
|
background: #f8fafc;
|
|
|
border: 1rpx solid #f0f0f0;
|
|
|
flex-shrink: 0;
|
|
|
margin-right: 20rpx;
|
|
|
}
|
|
|
|
|
|
.card-image {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
.card-image-empty {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
background: #f8fafc;
|
|
|
}
|
|
|
|
|
|
.empty-img-icon {
|
|
|
font-size: 56rpx;
|
|
|
opacity: 0.3;
|
|
|
}
|
|
|
|
|
|
/* 右侧信息区 */
|
|
|
.card-info-right {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
}
|
|
|
|
|
|
.info-item {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
margin-bottom: 8rpx;
|
|
|
}
|
|
|
|
|
|
.info-label {
|
|
|
font-size: 26rpx;
|
|
|
color: #6b7280;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.info-name {
|
|
|
font-size: 30rpx;
|
|
|
font-weight: 700;
|
|
|
color: #0f172a;
|
|
|
}
|
|
|
|
|
|
.info-value {
|
|
|
font-size: 26rpx;
|
|
|
color: #374151;
|
|
|
|
|
|
&.stock-highlight {
|
|
|
color: #2563eb;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 删除按钮 */
|
|
|
.card-delete {
|
|
|
position: absolute;
|
|
|
top: -8rpx;
|
|
|
right: -8rpx;
|
|
|
width: 48rpx;
|
|
|
height: 48rpx;
|
|
|
border-radius: 24rpx;
|
|
|
background: #fee2e2;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
.delete-icon {
|
|
|
font-size: 22rpx;
|
|
|
color: #dc2626;
|
|
|
}
|
|
|
|
|
|
/* ====== 卡片下半部分:详细信息 ====== */
|
|
|
.card-bottom {
|
|
|
margin-top: 20rpx;
|
|
|
padding-top: 20rpx;
|
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
}
|
|
|
|
|
|
.detail-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
margin-bottom: 14rpx;
|
|
|
|
|
|
&:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
&.two-col {
|
|
|
justify-content: space-between;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.detail-col {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
flex: 1;
|
|
|
}
|
|
|
|
|
|
.detail-label {
|
|
|
font-size: 24rpx;
|
|
|
color: #9ca3af;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.detail-value {
|
|
|
font-size: 24rpx;
|
|
|
color: #4b5563;
|
|
|
}
|
|
|
|
|
|
/* ====== 入库数量 ====== */
|
|
|
.inbound-qty-section {
|
|
|
margin-top: 4rpx;
|
|
|
}
|
|
|
|
|
|
.qty-input-card {
|
|
|
background: #fff;
|
|
|
border-radius: 16rpx;
|
|
|
padding: 24rpx;
|
|
|
margin: 0 24rpx;
|
|
|
box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.04);
|
|
|
}
|
|
|
|
|
|
.form-field {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 12rpx;
|
|
|
}
|
|
|
|
|
|
.form-label {
|
|
|
font-size: 26rpx;
|
|
|
color: #4b5563;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
|
|
|
.form-input {
|
|
|
width: 100%;
|
|
|
height: 88rpx;
|
|
|
padding: 0 24rpx;
|
|
|
font-size: 28rpx;
|
|
|
color: #374151;
|
|
|
background: #f8fafc;
|
|
|
border-radius: 14rpx;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
.form-suffix-text {
|
|
|
display: block;
|
|
|
margin-top: 10rpx;
|
|
|
font-size: 24rpx;
|
|
|
color: #9ca3af;
|
|
|
}
|
|
|
|
|
|
/* ====== 折算后库存数量(内嵌在入库数量卡片) ====== */
|
|
|
.convert-row {
|
|
|
margin-top: 20rpx;
|
|
|
padding-top: 20rpx;
|
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
.convert-label-inline {
|
|
|
font-size: 26rpx;
|
|
|
color: #6b7280;
|
|
|
}
|
|
|
|
|
|
.convert-value-inline {
|
|
|
font-size: 36rpx;
|
|
|
font-weight: 700;
|
|
|
color: #1f2937;
|
|
|
margin-left: auto;
|
|
|
}
|
|
|
|
|
|
.convert-unit-inline {
|
|
|
font-size: 24rpx;
|
|
|
color: #64748b;
|
|
|
margin-left: 8rpx;
|
|
|
}
|
|
|
|
|
|
.convert-formula-inline {
|
|
|
margin-top: 10rpx;
|
|
|
font-size: 22rpx;
|
|
|
color: #9ca3af;
|
|
|
}
|
|
|
|
|
|
/* ====== 供应商/经办人 选择行 ====== */
|
|
|
.select-row-card {
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
background: #fff;
|
|
|
border-radius: 16rpx;
|
|
|
padding: 24rpx;
|
|
|
margin: 0 24rpx 20rpx;
|
|
|
box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.04);
|
|
|
|
|
|
.dropdown-panel {
|
|
|
position: absolute;
|
|
|
top: 100%;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
z-index: 99;
|
|
|
margin-top: 4rpx;
|
|
|
background: #fff;
|
|
|
border: 1rpx solid #e0e0e0;
|
|
|
border-radius: 12rpx;
|
|
|
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1);
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.select-row-left {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.select-row-icon {
|
|
|
font-size: 36rpx;
|
|
|
color: #3b82f6;
|
|
|
margin-right: 16rpx;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.select-row-label {
|
|
|
font-size: 28rpx;
|
|
|
color: #374151;
|
|
|
}
|
|
|
|
|
|
.full-dropdown {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
width: 100%;
|
|
|
font-size: 28rpx;
|
|
|
color: #374151;
|
|
|
|
|
|
.placeholder {
|
|
|
color: #9ca3af;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.select-row-dropdown {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
margin-left: 24rpx;
|
|
|
}
|
|
|
|
|
|
/* ====== 仓库/库区 两行布局 ====== */
|
|
|
.warehouse-area-rows {
|
|
|
width: 100%;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 16rpx;
|
|
|
}
|
|
|
|
|
|
.warehouse-area-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
.warehouse-area-label {
|
|
|
width: 80rpx;
|
|
|
font-size: 26rpx;
|
|
|
color: #6b7280;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.warehouse-area-dropdown {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
position: relative;
|
|
|
|
|
|
.dropdown-panel {
|
|
|
position: absolute;
|
|
|
top: 100%;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
z-index: 100;
|
|
|
margin-top: 4rpx;
|
|
|
background: #fff;
|
|
|
border: 1rpx solid #e0e0e0;
|
|
|
border-radius: 12rpx;
|
|
|
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1);
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.warehouse-area-card {
|
|
|
align-items: flex-start;
|
|
|
flex-wrap: wrap;
|
|
|
}
|
|
|
|
|
|
/* ====== 下拉选择器 ====== */
|
|
|
.select-dropdown {
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.dropdown-input {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
height: 64rpx;
|
|
|
padding: 0 20rpx;
|
|
|
border: 1rpx solid #e0e0e0;
|
|
|
border-radius: 10rpx;
|
|
|
background: #f9fafb;
|
|
|
}
|
|
|
|
|
|
.dropdown-value {
|
|
|
flex: 1;
|
|
|
font-size: 27rpx;
|
|
|
color: #333;
|
|
|
|
|
|
&.placeholder {
|
|
|
color: #bbb;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.dropdown-arrow {
|
|
|
font-size: 20rpx;
|
|
|
color: #999;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.dropdown-panel {
|
|
|
position: absolute;
|
|
|
top: 68rpx;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
z-index: 99;
|
|
|
background: #fff;
|
|
|
border: 1rpx solid #e0e0e0;
|
|
|
border-radius: 12rpx;
|
|
|
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1);
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.dropdown-scroll {
|
|
|
max-height: 360rpx;
|
|
|
}
|
|
|
|
|
|
.dropdown-item {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
padding: 20rpx 24rpx;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
|
|
&:last-child {
|
|
|
border-bottom: 0;
|
|
|
}
|
|
|
|
|
|
&.active {
|
|
|
background: #f0f5ff;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.dropdown-item-text {
|
|
|
font-size: 27rpx;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.dropdown-check {
|
|
|
font-size: 28rpx;
|
|
|
color: #2563eb;
|
|
|
font-weight: 700;
|
|
|
}
|
|
|
|
|
|
.dropdown-empty {
|
|
|
padding: 32rpx;
|
|
|
text-align: center;
|
|
|
color: #999;
|
|
|
font-size: 26rpx;
|
|
|
}
|
|
|
|
|
|
/* ====== 空状态 ====== */
|
|
|
.empty-wrap {
|
|
|
padding: 160rpx 24rpx;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.empty-text {
|
|
|
font-size: 28rpx;
|
|
|
color: #94a3b8;
|
|
|
}
|
|
|
|
|
|
/* ====== 底部操作栏 ====== */
|
|
|
.bottom-actions {
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
.bottom-btn {
|
|
|
flex: 1;
|
|
|
height: 84rpx;
|
|
|
line-height: 84rpx;
|
|
|
text-align: center;
|
|
|
border-radius: 16rpx;
|
|
|
font-size: 30rpx;
|
|
|
font-weight: 600;
|
|
|
|
|
|
&:active {
|
|
|
opacity: 0.85;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.cancel-btn {
|
|
|
background: #eef2f7;
|
|
|
color: #475569;
|
|
|
}
|
|
|
|
|
|
.confirm-btn {
|
|
|
background: #1f4b79;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
</style>
|