|
|
|
|
@ -56,39 +56,24 @@
|
|
|
|
|
<view class="warehouse-area-rows">
|
|
|
|
|
<view class="warehouse-area-row">
|
|
|
|
|
<text class="warehouse-area-label">关联设备</text>
|
|
|
|
|
<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>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="showDeviceDropdown" class="dropdown-panel">
|
|
|
|
|
<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>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="deviceLoading" class="dropdown-empty">加载中...</view>
|
|
|
|
|
<view v-else-if="!filteredDeviceOptions.length" class="dropdown-empty">{{ selectedPurpose === 'maintain' ? '暂无保养设备' : '暂无设备数据' }}</view>
|
|
|
|
|
<view class="warehouse-area-dropdown">
|
|
|
|
|
<picker mode="selector" :range="filteredDeviceOptions" range-key="label" :value="getDeviceIndex(selectedDevice, filteredDeviceOptions)" @change="onDeviceChange">
|
|
|
|
|
<view class="dropdown-input">
|
|
|
|
|
<text :class="['dropdown-value', { placeholder: !selectedDevice }]">{{ selectedDevice ? selectedDevice.label : '请选择' }}</text>
|
|
|
|
|
<text class="dropdown-arrow">▼</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="warehouse-area-row">
|
|
|
|
|
<text class="warehouse-area-label">{{ selectedPurpose === 'repair' ? '维修单号' : '保养单号' }}</text>
|
|
|
|
|
<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>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="showOrderDropdown" class="dropdown-panel">
|
|
|
|
|
<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>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="!currentOrderOptions.length" class="dropdown-empty">{{ selectedPurpose === 'repair' ? '暂无维修单' : '暂无保养单' }}</view>
|
|
|
|
|
<view class="warehouse-area-dropdown">
|
|
|
|
|
<picker mode="selector" :range="currentOrderOptions" range-key="label" :value="getOrderIndex(currentOrder, currentOrderOptions)" :disabled="!currentOrderOptions.length" @change="onOrderChange">
|
|
|
|
|
<view class="dropdown-input">
|
|
|
|
|
<text :class="['dropdown-value', { placeholder: !currentOrder }]">{{ currentOrder ? currentOrder.label : '请选择' }}</text>
|
|
|
|
|
<text class="dropdown-arrow">▼</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
@ -111,18 +96,21 @@
|
|
|
|
|
</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">
|
|
|
|
|
<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>
|
|
|
|
|
<view class="warehouse-area-dropdown">
|
|
|
|
|
<view class="product-search-row">
|
|
|
|
|
<input
|
|
|
|
|
v-model="areaScanInput"
|
|
|
|
|
class="scan-input"
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="扫码或输入库区码"
|
|
|
|
|
confirm-type="done"
|
|
|
|
|
@confirm="onAreaScanConfirm"
|
|
|
|
|
/>
|
|
|
|
|
<picker mode="selector" :range="areaOptions" range-key="label" :value="getAreaIndex(selectedArea, areaOptions)" @change="onAreaChange">
|
|
|
|
|
<view class="area-select-btn">
|
|
|
|
|
<text class="select-btn-text">选择</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
@ -198,23 +186,25 @@ function setPurpose(value) {
|
|
|
|
|
selectedMaintainOrder.value = null
|
|
|
|
|
repairOrderOptions.value = []
|
|
|
|
|
maintainOrderOptions.value = []
|
|
|
|
|
if (value === 'repair') loadRepairDeviceIds()
|
|
|
|
|
if (value === 'maintain') loadMaintainDeviceIds()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const deviceOptions = ref([])
|
|
|
|
|
const selectedDevice = ref(null)
|
|
|
|
|
const showDeviceDropdown = ref(false)
|
|
|
|
|
const repairOrderOptions = ref([])
|
|
|
|
|
const selectedRepairOrder = ref(null)
|
|
|
|
|
const maintainOrderOptions = ref([])
|
|
|
|
|
const selectedMaintainOrder = ref(null)
|
|
|
|
|
const maintainDeviceIds = ref(new Set())
|
|
|
|
|
const repairDeviceIds = ref(new Set())
|
|
|
|
|
const deviceLoading = ref(false)
|
|
|
|
|
|
|
|
|
|
const filteredDeviceOptions = computed(() => {
|
|
|
|
|
if (selectedPurpose.value === 'maintain') return deviceOptions.value.filter(d => maintainDeviceIds.value.has(d.value))
|
|
|
|
|
if (selectedPurpose.value === 'repair') return deviceOptions.value.filter(d => repairDeviceIds.value.has(d.value))
|
|
|
|
|
return deviceOptions.value
|
|
|
|
|
})
|
|
|
|
|
const showOrderDropdown = ref(false)
|
|
|
|
|
const currentOrder = computed(() => selectedPurpose.value === 'repair' ? selectedRepairOrder.value : selectedMaintainOrder.value)
|
|
|
|
|
const currentOrderOptions = computed(() => selectedPurpose.value === 'repair' ? repairOrderOptions.value : maintainOrderOptions.value)
|
|
|
|
|
|
|
|
|
|
@ -222,8 +212,8 @@ const warehouseOptions = ref([])
|
|
|
|
|
const selectedWarehouse = ref(null)
|
|
|
|
|
const areaOptions = ref([])
|
|
|
|
|
const selectedArea = ref(null)
|
|
|
|
|
const showAreaDropdown = ref(false)
|
|
|
|
|
const loadingAreas = ref(false)
|
|
|
|
|
const areaScanInput = ref('')
|
|
|
|
|
|
|
|
|
|
const sparepartImage = computed(() => {
|
|
|
|
|
const images = sparepart.value.images
|
|
|
|
|
@ -355,12 +345,39 @@ function handleConfirm() {
|
|
|
|
|
}, 800)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleDeviceDropdown() {
|
|
|
|
|
showDeviceDropdown.value = !showDeviceDropdown.value
|
|
|
|
|
if (showDeviceDropdown.value && selectedPurpose.value === 'maintain' && maintainDeviceIds.value.size === 0) {
|
|
|
|
|
loadMaintainDeviceIds()
|
|
|
|
|
function getDeviceIndex(selected, options) {
|
|
|
|
|
if (!selected) return -1
|
|
|
|
|
const index = options.findIndex((item) => String(item.value) === String(selected.value))
|
|
|
|
|
return index >= 0 ? index : -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getOrderIndex(selected, options) {
|
|
|
|
|
if (!selected) return -1
|
|
|
|
|
const index = options.findIndex((item) => String(item.value) === String(selected.value))
|
|
|
|
|
return index >= 0 ? index : -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function onDeviceChange(event) {
|
|
|
|
|
const index = Number(event.detail.value)
|
|
|
|
|
if (index >= 0 && index < filteredDeviceOptions.value.length) {
|
|
|
|
|
const item = filteredDeviceOptions.value[index]
|
|
|
|
|
selectedDevice.value = item
|
|
|
|
|
selectedRepairOrder.value = null; selectedMaintainOrder.value = null
|
|
|
|
|
repairOrderOptions.value = []; maintainOrderOptions.value = []
|
|
|
|
|
if (selectedPurpose.value === 'repair') loadRepairOrders(item.deviceCode)
|
|
|
|
|
else loadMaintainOrders(item.deviceCode)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onOrderChange(event) {
|
|
|
|
|
const index = Number(event.detail.value)
|
|
|
|
|
if (index >= 0 && index < currentOrderOptions.value.length) {
|
|
|
|
|
const item = currentOrderOptions.value[index]
|
|
|
|
|
if (selectedPurpose.value === 'repair') selectedRepairOrder.value = item
|
|
|
|
|
else selectedMaintainOrder.value = item
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadMaintainDeviceIds() {
|
|
|
|
|
deviceLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
@ -376,12 +393,27 @@ async function loadMaintainDeviceIds() {
|
|
|
|
|
} catch (e) { console.error('loadMaintainDeviceIds error', e) }
|
|
|
|
|
finally { deviceLoading.value = false }
|
|
|
|
|
}
|
|
|
|
|
async function handleSelectDevice(item) {
|
|
|
|
|
selectedDevice.value = item; showDeviceDropdown.value = false
|
|
|
|
|
selectedRepairOrder.value = null; selectedMaintainOrder.value = null
|
|
|
|
|
repairOrderOptions.value = []; maintainOrderOptions.value = []
|
|
|
|
|
if (selectedPurpose.value === 'repair') loadRepairOrders(item.deviceCode)
|
|
|
|
|
else loadMaintainOrders(item.deviceCode)
|
|
|
|
|
async function loadRepairDeviceIds() {
|
|
|
|
|
deviceLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
// 分页获取所有维修单(每页最大100)
|
|
|
|
|
const allRecords = []
|
|
|
|
|
for (let page = 1; page <= 5; page++) {
|
|
|
|
|
const res = await getDvRepairPage({ pageNo: page, pageSize: 100 })
|
|
|
|
|
const data = res && res.data !== undefined ? res.data : res
|
|
|
|
|
const records = Array.isArray(data) ? data : (data?.list || data?.records || [])
|
|
|
|
|
allRecords.push(...records)
|
|
|
|
|
if (records.length < 100) break
|
|
|
|
|
}
|
|
|
|
|
const deviceCodes = new Set(allRecords.map(r => r.machineryCode || r.deviceCode || r.deviceName).filter(Boolean))
|
|
|
|
|
const ids = new Set()
|
|
|
|
|
for (const d of deviceOptions.value) {
|
|
|
|
|
if (deviceCodes.has(d.deviceCode) || deviceCodes.has(d.label) || deviceCodes.has(d.deviceName)) ids.add(d.value)
|
|
|
|
|
}
|
|
|
|
|
repairDeviceIds.value = ids
|
|
|
|
|
console.log('[loadRepairDeviceIds] 维修单设备编码:', [...deviceCodes], '匹配到的设备数:', ids.size)
|
|
|
|
|
} catch (e) { console.error('loadRepairDeviceIds error', e) }
|
|
|
|
|
finally { deviceLoading.value = false }
|
|
|
|
|
}
|
|
|
|
|
async function loadDevices() {
|
|
|
|
|
try {
|
|
|
|
|
@ -401,12 +433,6 @@ async function loadDevices() {
|
|
|
|
|
}))
|
|
|
|
|
} catch (e) { console.error('loadDevices error', e) }
|
|
|
|
|
}
|
|
|
|
|
function toggleOrderDropdown() { if (!selectedDevice.value) return; showOrderDropdown.value = !showOrderDropdown.value }
|
|
|
|
|
function handleSelectOrder(item) {
|
|
|
|
|
if (selectedPurpose.value === 'repair') selectedRepairOrder.value = item
|
|
|
|
|
else selectedMaintainOrder.value = item
|
|
|
|
|
showOrderDropdown.value = false
|
|
|
|
|
}
|
|
|
|
|
async function loadMaintainOrders(deviceCode) {
|
|
|
|
|
const deviceId = selectedDevice.value?.value
|
|
|
|
|
if (deviceId) await loadMaintainOrdersById(deviceId)
|
|
|
|
|
@ -462,8 +488,43 @@ async function loadWarehouses() {
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleAreaDropdown() { if (!selectedWarehouse.value) { uni.showToast({ title: '请先选择仓库', icon: 'none' }); return }; showAreaDropdown.value = !showAreaDropdown.value }
|
|
|
|
|
function handleSelectArea(item) { selectedArea.value = item; showAreaDropdown.value = false; loadStockCount() }
|
|
|
|
|
function getAreaIndex(selected, options) {
|
|
|
|
|
if (!selected) return -1
|
|
|
|
|
const index = options.findIndex((item) => String(item.value) === String(selected.value))
|
|
|
|
|
return index >= 0 ? index : -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onAreaChange(event) {
|
|
|
|
|
const index = Number(event.detail.value)
|
|
|
|
|
if (index >= 0 && index < areaOptions.value.length) {
|
|
|
|
|
selectedArea.value = areaOptions.value[index]
|
|
|
|
|
areaScanInput.value = selectedArea.value.label
|
|
|
|
|
loadStockCount()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAreaScanId(value) {
|
|
|
|
|
const text = String(value || '').trim()
|
|
|
|
|
if (!text) return ''
|
|
|
|
|
const match = text.match(/WAREHOUSE_AREA[-_:](\d+)/i)
|
|
|
|
|
if (match) return match[1]
|
|
|
|
|
const tail = text.match(/(\d+)$/)
|
|
|
|
|
return tail ? tail[1] : text
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function onAreaScanConfirm() {
|
|
|
|
|
const areaId = getAreaScanId(areaScanInput.value)
|
|
|
|
|
if (!areaId) return
|
|
|
|
|
const area = areaOptions.value.find((item) => String(item.value) === String(areaId))
|
|
|
|
|
if (!area) {
|
|
|
|
|
uni.showToast({ title: '未找到该库区', icon: 'none' })
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
selectedArea.value = area
|
|
|
|
|
areaScanInput.value = area.label
|
|
|
|
|
loadStockCount()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadAreas(warehouseId) {
|
|
|
|
|
if (!warehouseId) return
|
|
|
|
|
loadingAreas.value = true
|
|
|
|
|
@ -489,7 +550,8 @@ onShow(async () => {
|
|
|
|
|
} catch (e) { console.error('获取备件详情失败:', e) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
loadDevices()
|
|
|
|
|
await loadDevices()
|
|
|
|
|
loadRepairDeviceIds()
|
|
|
|
|
loadWarehouses()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
@ -521,7 +583,7 @@ async function loadStockCount() {
|
|
|
|
|
} catch (e) { warehouseAreaStockCount.value = 0 }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false })
|
|
|
|
|
onHide(() => {})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
@ -592,6 +654,11 @@ onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false
|
|
|
|
|
.dropdown-check { font-size: 28rpx; color: #2563eb; font-weight: 700; }
|
|
|
|
|
.dropdown-empty { padding: 32rpx; text-align: center; color: #999; font-size: 26rpx; }
|
|
|
|
|
|
|
|
|
|
.product-search-row { display: flex; align-items: center; gap: 16rpx; }
|
|
|
|
|
.scan-input { flex: 1; min-width: 0; height: 70rpx; padding: 0 22rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 14rpx; box-sizing: border-box; font-size: 28rpx; color: #1f2937; }
|
|
|
|
|
.area-select-btn { 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; }
|
|
|
|
|
.select-btn-text { color: #ffffff; font-size: 26rpx; font-weight: 600; }
|
|
|
|
|
|
|
|
|
|
.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: #fff; 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; }
|
|
|
|
|
|