style: 备件出入库扫备件码/选择备件更新

master
zhongwenkai 6 days ago
parent 226b7009b0
commit d8d58f4912

@ -4,16 +4,17 @@
<!-- 操作按钮区 -->
<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 class="scan-input-row">
<input
class="scan-input"
v-model="scanCodeInput"
placeholder="红外扫码或输入备件码"
confirm-type="done"
:focus="true"
@confirm="onScanInputConfirm"
/>
</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>
@ -43,7 +44,7 @@
</text>
<text class="form-row-arrow"></text>
<view v-if="showOperatorDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view class="dropdown-scroll">
<view
v-for="item in operatorOptions"
:key="item.value"
@ -55,7 +56,7 @@
<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>
@ -160,6 +161,44 @@ import { getSimpleUserList } from '@/api/mes/moldget'
const { t } = useI18n()
const itemList = ref([])
const scanCodeInput = ref('') // /
//
function onScanInputConfirm() {
const code = scanCodeInput.value.trim()
if (!code) return
handleScanCode(code)
}
async function handleScanCode(code) {
let sparepartId = null
if (code.toUpperCase().startsWith('SPARE-')) {
sparepartId = code.replace(/SPARE-/i, '')
} else {
const idMatch = code.match(/(\d+)$/)
if (idMatch) sparepartId = idMatch[1]
}
if (!sparepartId) {
uni.showToast({ title: '无法识别备件码', icon: 'none' })
return
}
try {
const apiRes = await getSparepartDetail(sparepartId)
const detail = apiRes?.data || apiRes
if (detail && detail.id) {
getApp().globalData._sparepartFromScan = true
getApp().globalData._sparepartBeforeConfirm = detail
uni.navigateTo({
url: '/pages_function/pages/sparepartInbound/sparepartConfirm'
})
} else {
uni.showToast({ title: '未找到备件: ' + sparepartId, icon: 'none' })
}
} catch (e) {
console.error('[备件入库] 扫码查询备件失败:', e)
uni.showToast({ title: '扫码失败', icon: 'none' })
}
}
//
const inboundDate = ref(formatDate(new Date()))
@ -209,36 +248,11 @@ function handleScan() {
uni.scanCode({
onlyFromCamera: false,
scanType: ['barCode', 'qrCode'],
success: async (res) => {
success: (res) => {
const code = (res.result || '').trim()
if (!code) return
let sparepartId = null
if (code.toUpperCase().startsWith('SPARE-')) {
sparepartId = code.replace(/SPARE-/i, '')
} else {
const idMatch = code.match(/(\d+)$/)
if (idMatch) sparepartId = idMatch[1]
}
if (!sparepartId) {
uni.showToast({ title: '无法识别备件码', icon: 'none' })
return
}
try {
const apiRes = await getSparepartDetail(sparepartId)
const detail = apiRes?.data || apiRes
if (detail && detail.id) {
getApp().globalData._sparepartFromScan = true
getApp().globalData._sparepartBeforeConfirm = detail
uni.navigateTo({
url: '/pages_function/pages/sparepartInbound/sparepartConfirm'
})
} else {
uni.showToast({ title: '未找到备件: ' + sparepartId, icon: 'none' })
}
} catch (e) {
console.error('[备件入库] 扫码查询备件失败:', e)
uni.showToast({ title: '扫码失败', icon: 'none' })
}
scanCodeInput.value = code
handleScanCode(code)
},
fail: () => {
uni.showToast({ title: '扫码失败', icon: 'none' })
@ -418,26 +432,46 @@ onHide(() => {
/* 操作按钮区 */
.action-row {
display: flex;
gap: 20rpx;
align-items: center;
gap: 16rpx;
padding: 20rpx 24rpx;
}
.action-btn {
.scan-input-row {
flex: 1;
display: flex;
align-items: center;
height: 72rpx;
border-radius: 10rpx;
overflow: hidden;
}
.scan-input {
flex: 1;
height: 72rpx;
padding: 0 20rpx;
font-size: 26rpx;
color: #333;
background: #fff;
border: 1rpx solid #d0d5dd;
border-radius: 10rpx;
}
.action-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
height: 96rpx;
border-radius: 12rpx;
height: 72rpx;
padding: 0 24rpx;
border-radius: 10rpx;
background: #1f4b79;
color: #fff;
font-size: 28rpx;
font-size: 26rpx;
font-weight: 600;
white-space: nowrap;
.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; }
.btn-text { font-size: 26rpx; font-weight: 600; color: #fff; }
}
/* 备件列表 */
@ -505,7 +539,7 @@ onHide(() => {
background: #fff; border: 1rpx solid #e0e0e0; border-radius: 12rpx;
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1); overflow: hidden;
}
.dropdown-scroll { height: 360rpx; }
.dropdown-scroll { max-height: 360rpx; overflow-y: auto; }
.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; }

@ -188,14 +188,14 @@ function textValue(v) {
function formatDateTime(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) {
const [year, month, day, hour = 0, minute = 0, second = 0] = value
const [year, month, day] = value
const pad = (n) => String(n).padStart(2, '0')
return `${year}-${pad(month)}-${pad(day)} ${pad(hour)}:${pad(minute)}:${pad(second)}`
return `${year}-${pad(month)}-${pad(day)}`
}
const date = new Date(Number(value))
if (Number.isNaN(date.getTime())) return String(value)
const pad = (n) => String(n).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
}
const STATUS_MAP = { 0: '待入库', 10: '待审核', 20: '已入库', 1: '已驳回' }

@ -110,7 +110,7 @@
<text class="dropdown-arrow"></text>
</view>
<view v-if="showWarehouseDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view class="dropdown-scroll">
<view
v-for="item in warehouseOptions"
:key="item.value"
@ -122,7 +122,7 @@
<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>
@ -136,7 +136,7 @@
<text class="dropdown-arrow"></text>
</view>
<view v-if="showAreaDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view class="dropdown-scroll">
<view
v-for="item in areaOptions"
:key="item.value"
@ -148,7 +148,7 @@
<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>
@ -470,7 +470,7 @@ onHide(() => {
.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: 200; background: #fff; border: 1rpx solid #e0e0e0; border-radius: 12rpx; box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1); overflow: hidden; }
.dropdown-scroll { height: 360rpx; }
.dropdown-scroll { max-height: 360rpx; overflow-y: auto; }
.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; }

@ -4,12 +4,17 @@
<!-- 操作按钮区 -->
<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">扫备件码</text>
<view class="scan-input-row">
<input
class="scan-input"
v-model="scanCodeInput"
placeholder="红外扫码或输入备件码"
confirm-type="done"
:focus="true"
@confirm="onScanInputConfirm"
/>
</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">选择备件</text>
</view>
</view>
@ -37,13 +42,13 @@
<text :class="{ placeholder: !selectedOperator }">{{ selectedOperator ? selectedOperator.label : '请选择经办人' }}</text>
<text class="form-row-arrow"></text>
<view v-if="showOperatorDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view 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>
@ -146,25 +151,38 @@ function handleSelectSparepart() {
uni.navigateTo({ url: '/pages_function/pages/sparepartInbound/sparepartSelect' })
}
const scanCodeInput = ref('')
function onScanInputConfirm() {
const code = scanCodeInput.value.trim()
if (!code) return
handleScanCode(code)
}
async function handleScanCode(code) {
let sparepartId = null
if (code.toUpperCase().startsWith('SPARE-')) sparepartId = code.replace(/SPARE-/i, '')
else { const idMatch = code.match(/(\d+)$/); if (idMatch) sparepartId = idMatch[1] }
if (!sparepartId) { uni.showToast({ title: '无法识别备件码', icon: 'none' }); return }
try {
const apiRes = await getSparepartDetail(sparepartId)
const detail = apiRes?.data || apiRes
if (detail && detail.id) {
getApp().globalData._sparepartFromScan = true
getApp().globalData._sparepartBeforeConfirm = detail
uni.navigateTo({ url: '/pages_function/pages/sparepartOutbound/sparepartConfirm' })
} else { uni.showToast({ title: '未找到备件: ' + sparepartId, icon: 'none' }) }
} catch (e) { console.error(e); uni.showToast({ title: '扫码失败', icon: 'none' }) }
}
function handleScan() {
uni.scanCode({
onlyFromCamera: false, scanType: ['barCode', 'qrCode'],
success: async (res) => {
success: (res) => {
const code = (res.result || '').trim()
if (!code) return
let sparepartId = null
if (code.toUpperCase().startsWith('SPARE-')) sparepartId = code.replace(/SPARE-/i, '')
else { const idMatch = code.match(/(\d+)$/); if (idMatch) sparepartId = idMatch[1] }
if (!sparepartId) { uni.showToast({ title: '无法识别备件码', icon: 'none' }); return }
try {
const apiRes = await getSparepartDetail(sparepartId)
const detail = apiRes?.data || apiRes
if (detail && detail.id) {
getApp().globalData._sparepartFromScan = true
getApp().globalData._sparepartBeforeConfirm = detail
uni.navigateTo({ url: '/pages_function/pages/sparepartOutbound/sparepartConfirm' })
} else { uni.showToast({ title: '未找到备件: ' + sparepartId, icon: 'none' }) }
} catch (e) { console.error(e); uni.showToast({ title: '扫码失败', icon: 'none' }) }
scanCodeInput.value = code
handleScanCode(code)
},
fail: () => { uni.showToast({ title: '扫码失败', icon: 'none' }) }
})
@ -251,8 +269,10 @@ onHide(() => { showOperatorDropdown.value = false })
<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; } }
.action-row { display: flex; align-items: center; gap: 16rpx; padding: 20rpx 24rpx; }
.scan-input-row { flex: 1; display: flex; align-items: center; height: 72rpx; border-radius: 10rpx; overflow: hidden; }
.scan-input { flex: 1; height: 72rpx; padding: 0 20rpx; font-size: 26rpx; color: #333; background: #fff; border: 1rpx solid #d0d5dd; border-radius: 10rpx; }
.action-btn { display: flex; align-items: center; justify-content: center; height: 72rpx; padding: 0 24rpx; border-radius: 10rpx; background: #1f4b79; color: #fff; font-size: 26rpx; font-weight: 600; white-space: nowrap; .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: 26rpx; font-weight: 600; color: #fff; } }
.form-section { padding-bottom: 16rpx; }
.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; }
@ -265,7 +285,7 @@ onHide(() => { showOperatorDropdown.value = false })
.purpose-item { flex: 1; display: flex; align-items: center; justify-content: center; height: 92rpx; background: #fff; border: 2rpx solid #e5e7eb; border-radius: 14rpx; font-size: 28rpx; color: #6b7280; &.active { border-color: #2563eb; background: #eff6ff; color: #2563eb; font-weight: 600; } }
.dropdown-panel { position: absolute; top: 100%; left: 0; right: 0; z-index: 200; 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; }
.dropdown-scroll { height: 360rpx; }
.dropdown-scroll { max-height: 360rpx; overflow-y: auto; }
.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; }

@ -115,9 +115,9 @@ let searchTimer = null
function textValue(v) { if (v === 0) return '0'; if (v == null) return '-'; const s = String(v).trim(); return s || '-' }
function formatDateTime(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) { const [y,m,d,h=0,mi=0,s=0]=value; const p=n=>String(n).padStart(2,'0'); return `${y}-${p(m)}-${p(d)} ${p(h)}:${p(mi)}:${p(s)}` }
if (Array.isArray(value) && value.length >= 3) { const [y,m,d]=value; const p=n=>String(n).padStart(2,'0'); return `${y}-${p(m)}-${p(d)}` }
const date = new Date(Number(value)); if (Number.isNaN(date.getTime())) return String(value)
const p=n=>String(n).padStart(2,'0'); return `${date.getFullYear()}-${p(date.getMonth()+1)}-${p(date.getDate())} ${p(date.getHours())}:${p(date.getMinutes())}`
const p=n=>String(n).padStart(2,'0'); return `${date.getFullYear()}-${p(date.getMonth()+1)}-${p(date.getDate())}`
}
const STATUS_MAP = { 0: '待出库', 10: '待审核', 20: '已出库', 1: '已驳回' }

@ -5,7 +5,7 @@
<view class="sparepart-section">
<view class="section-title-bar">
<view class="section-bar-line"></view>
<text class="section-title">已选备件</text>
<text class="section-title">å·²éå¤ä»?/text>
</view>
<view class="sparepart-card">
<view class="card-top">
@ -14,24 +14,24 @@
<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(sparepart.name) }}</text></view>
<view class="info-item"><text class="info-label">规格</text><text class="info-value">{{ textValue(sparepart.standard || sparepart.deviceSpec) }}</text></view>
<view class="info-item"><text class="info-label">当前库存</text><text class="info-value stock-highlight">{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.minStockUnitName || '个') }}</text></view>
<view class="info-item"><text class="info-label">å¤ä»å<EFBFBD><EFBFBD>ç§°ï¼?/text><text class="info-name">{{ textValue(sparepart.name) }}</text></view>
<view class="info-item"><text class="info-label">è§æ ¼ï¼?/text><text class="info-value">{{ textValue(sparepart.standard || sparepart.deviceSpec) }}</text></view>
<view class="info-item"><text class="info-label">å½å<EFBFBD>åºå­˜ï¼?/text><text class="info-value stock-highlight">{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.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(sparepart.purchaseUnitName) }}</text></view>
<view class="detail-col"><text class="detail-label">库存单位</text><text class="detail-value">{{ textValue(sparepart.unitName || sparepart.minStockUnitName || '个') }}</text></view>
<view class="detail-col"><text class="detail-label">éè´­å<EFBFBD>ä½<EFBFBD>ï¼?/text><text class="detail-value">{{ textValue(sparepart.purchaseUnitName) }}</text></view>
<view class="detail-col"><text class="detail-label">åºå­˜å<EFBFBD>ä½<EFBFBD>ï¼?/text><text class="detail-value">{{ textValue(sparepart.unitName || sparepart.minStockUnitName || 'ä¸?) }}</text></view>
</view>
<view class="detail-row"><text class="detail-label">换算关系</text><text class="detail-value">1{{ textValue(sparepart.purchaseUnitName) }}={{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }}</text></view>
<view class="detail-row"><text class="detail-label">æ<EFBFBD>¢ç®å³ç³»ï¼?/text><text class="detail-value">1{{ textValue(sparepart.purchaseUnitName) }}={{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }}</text></view>
</view>
</view>
<!-- 出库用途 -->
<!-- åºåºç¨é?-->
<view class="section-title-bar" style="padding-top: 24rpx;">
<view class="section-bar-line"></view>
<text class="section-title">出库用途</text>
<text class="section-title">åºåºç¨é?/text>
</view>
<view class="purpose-card">
<view class="purpose-item" :class="{ active: selectedPurpose === 'repair' }" @click="setPurpose('repair')">
@ -59,17 +59,17 @@
<view class="warehouse-area-dropdown" @click="toggleDeviceDropdown">
<view class="dropdown-input">
<text :class="['dropdown-value', { placeholder: !selectedDevice }]">{{ selectedDevice ? selectedDevice.label : '请选择' }}</text>
<text class="dropdown-arrow"></text>
<text class="dropdown-arrow">â?/text>
</view>
<view v-if="showDeviceDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view class="dropdown-scroll">
<view v-for="item in filteredDeviceOptions" :key="item.value" class="dropdown-item" :class="{ active: selectedDevice?.value === item.value }" @click.stop="handleSelectDevice(item)">
<text class="dropdown-item-text">{{ item.label }}</text>
<text v-if="selectedDevice?.value === item.value" class="dropdown-check"></text>
<text v-if="selectedDevice?.value === item.value" class="dropdown-check">�/text>
</view>
<view v-if="deviceLoading" class="dropdown-empty">...</view>
<view v-if="deviceLoading" class="dropdown-empty">加载�..</view>
<view v-else-if="!filteredDeviceOptions.length" class="dropdown-empty">{{ selectedPurpose === 'maintain' ? '暂无保养设备' : '暂无设备数据' }}</view>
</scroll-view>
</view>
</view>
</view>
</view>
@ -78,16 +78,16 @@
<view class="warehouse-area-dropdown" @click="toggleOrderDropdown">
<view class="dropdown-input">
<text :class="['dropdown-value', { placeholder: !currentOrder }]">{{ currentOrder ? currentOrder.label : '请选择' }}</text>
<text class="dropdown-arrow"></text>
<text class="dropdown-arrow">â?/text>
</view>
<view v-if="showOrderDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view class="dropdown-scroll">
<view v-for="item in currentOrderOptions" :key="item.value" class="dropdown-item" :class="{ active: currentOrder?.value === item.value }" @click.stop="handleSelectOrder(item)">
<text class="dropdown-item-text">{{ item.label }}</text>
<text v-if="currentOrder?.value === item.value" class="dropdown-check"></text>
<text v-if="currentOrder?.value === item.value" class="dropdown-check">�/text>
</view>
<view v-if="!currentOrderOptions.length" class="dropdown-empty">{{ selectedPurpose === 'repair' ? '' : '' }}</view>
</scroll-view>
<view v-if="!currentOrderOptions.length" class="dropdown-empty">{{ selectedPurpose === 'repair' ? 'æšæ ç»´ä¿®å<EFBFBD>? : 'æšæ ä¿<EFBFBD>å»å<EFBFBD>? }}</view>
</view>
</view>
</view>
</view>
@ -101,7 +101,7 @@
<view class="qty-input-card">
<view class="form-field">
<text class="form-label">出库数量</text>
<input v-model="outboundQty" class="form-input" placeholder="请输入" confirm-type="done" />
<input v-model="outboundQty" class="form-input" placeholder="请输� confirm-type="done" />
<text class="form-suffix-text">单位{{ textValue(sparepart.purchaseUnitName) }}</text>
</view>
<view class="convert-row">
@ -113,18 +113,18 @@
<view class="convert-formula-inline">{{ outboundQty || 0 }}{{ textValue(sparepart.purchaseUnitName) }} × {{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(sparepart) }}</view>
<!-- 库存不足提示 -->
<view v-if="stockExceeded" class="stock-warning">
<text class="warning-icon"></text>
<text class="warning-icon">âš?/text>
<view class="warning-text">
<text class="warning-line">当前库存不足不能出库</text>
<text class="warning-line">当前库存{{ stockCount }}{{ stockUnitLabel(sparepart) }}{{ stockPackText }}</text>
<text class="warning-line">本次出库{{ calculatedStock }}{{ stockUnitLabel(sparepart) }}{{ outboundPackText }}</text>
<text class="warning-line">å½å<EFBFBD>åºå­˜ä¸<EFBFBD>è³ï¼Œä¸<EFBFBD>能åºåº?/text>
<text class="warning-line">å½å<EFBFBD>åºå­˜ï¼š{{ stockCount }}{{ stockUnitLabel(sparepart) }}({{ stockPackText }}ï¼?/text>
<text class="warning-line">本次åºåºï¼š{{ calculatedStock }}{{ stockUnitLabel(sparepart) }}({{ outboundPackText }}ï¼?/text>
</view>
</view>
</view>
<!-- 供应商 -->
<!-- ä¾åºå?-->
<view class="section-title-bar" style="padding-top: 24rpx;">
<view class="section-bar-line"></view><text class="section-title">供应商</text>
<view class="section-bar-line"></view><text class="section-title">ä¾åºå?/text>
</view>
<view class="select-row-card">
<view class="full-dropdown">
@ -143,15 +143,15 @@
<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>
<text class="dropdown-arrow">â?/text>
</view>
<view v-if="showWarehouseDropdown" class="dropdown-panel">
<scroll-view scroll-y class="dropdown-scroll">
<view 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>
<text v-if="selectedWarehouse?.value === item.value" class="dropdown-check">�/text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
@ -159,16 +159,16 @@
<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>
<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 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>
<text v-if="selectedArea?.value === item.value" class="dropdown-check">�/text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
@ -266,7 +266,7 @@ function formatStockPack(count) {
const currentStockText = computed(() => {
const text = formatStockPack(stockCount.value)
return text ? `当前库存:${text}` : ''
return text ? `当å‰<EFBFBD>库存ï¼?{text}` : ''
})
const stockPackText = computed(() => {
@ -290,23 +290,23 @@ const defaultSupplierName = computed(() => {
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 stockUnitLabel(item) { return item.unitName || item.minStockUnitName || '� }
function handleCancel() { uni.navigateBack() }
// repair1, maintain2, other3
// ç¨é映å°ï¼šrepairâ?, maintainâ?, otherâ?
const PURPOSE_MAP = { repair: 1, maintain: 2, other: 3 }
function handleConfirm() {
if (!outboundQty.value || Number(outboundQty.value) <= 0) {
uni.showToast({ title: '请输入出库数量', icon: 'none' }); return
uni.showToast({ title: '请输入出库数�, icon: 'none' }); return
}
if (stockExceeded.value) {
uni.showModal({
title: '库存不足',
content: `当前库存:${stockCount.value}${stockUnitLabel(sparepart)}${stockPackText.value}\n本次出库${calculatedStock.value}${stockUnitLabel(sparepart)}${outboundPackText.value}`,
content: `当å‰<EFBFBD>库存ï¼?{stockCount.value}${stockUnitLabel(sparepart)}ï¼?{stockPackText.value})\n本次出库ï¼?{calculatedStock.value}${stockUnitLabel(sparepart)}ï¼?{outboundPackText.value})`,
showCancel: false,
confirmText: '知道了'
confirmText: '知é<EFBFBD>äº?
})
return
}
@ -355,7 +355,7 @@ function handleConfirm() {
}
getApp().globalData._sparepartOutboundItems.push(item)
uni.showToast({ title: '已添加: ' + (sparepart.value.name || ''), icon: 'success', duration: 1200 })
uni.showToast({ title: '已添� ' + (sparepart.value.name || ''), icon: 'success', duration: 1200 })
setTimeout(() => {
const fromScan = getApp().globalData._sparepartFromScan
getApp().globalData._sparepartFromScan = false
@ -466,8 +466,8 @@ async function loadWarehouses() {
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 || '') }))
// ""
const defaultWh = warehouseOptions.value.find(w => (w.label || '').includes('备件仓'))
// 默认é中"å¤ä»ä»?
const defaultWh = warehouseOptions.value.find(w => (w.label || '').includes('å¤ä»ä»?))
if (defaultWh) { selectedWarehouse.value = defaultWh; loadAreas(defaultWh.value) }
} catch (e) {}
}
@ -483,8 +483,8 @@ async function loadAreas(warehouseId) {
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 || '') }))
// ""
const defaultArea = areaOptions.value.find(a => (a.label || '').includes('备件库'))
// 默认é中"å¤ä»åº?
const defaultArea = areaOptions.value.find(a => (a.label || '').includes('å¤ä»åº?))
if (defaultArea) selectedArea.value = defaultArea
} catch (e) {} finally { loadingAreas.value = false }
}
@ -577,7 +577,7 @@ onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false
.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: 200; background: #fff; border: 1rpx solid #e0e0e0; border-radius: 12rpx; box-shadow: 0 8rpx 30rpx rgba(0,0,0,0.1); overflow: hidden; }
.dropdown-scroll { height: 360rpx; }
.dropdown-scroll { max-height: 360rpx; overflow-y: auto; }
.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; }

Loading…
Cancel
Save