You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
besure_app/src/pages_function/pages/productCheck/warehouseSelect.vue

160 lines
6.9 KiB
Vue

<template>
<view class="page-container">
<NavBar :title="t('productCheck.selectWarehouseTitle')" />
<view class="search-bar">
<view class="search-input-wrap">
<uni-icons type="search" size="18" color="#9ca3af"></uni-icons>
<input
v-model="searchText"
class="search-input"
:placeholder="t('productCheck.searchWarehousePlaceholder')"
placeholder-class="search-placeholder"
confirm-type="search"
@confirm="loadWarehouses"
/>
<view v-if="searchText" class="search-clear" @click="clearSearch">
<uni-icons type="closeempty" size="18" color="#9ca3af"></uni-icons>
</view>
</view>
</view>
<scroll-view scroll-y class="warehouse-list" v-if="warehouseList.length">
<view
v-for="item in warehouseList"
:key="item.id"
:class="['warehouse-card', isSelected(item) ? 'active' : '']"
@click="selectedId = item.id"
>
<view class="warehouse-header">
<view class="warehouse-title-wrap">
<text class="warehouse-name">{{ textValue(item.name || item.warehouseName) }}</text>
<text class="warehouse-code">{{ textValue(item.code || item.no) }}</text>
</view>
<view class="check-badge">
<uni-icons v-if="isSelected(item)" type="checkmarkempty" size="16" color="#ffffff"></uni-icons>
</view>
</view>
<view class="info-grid">
<view class="info-cell">
<text class="info-label">{{ t('productCheck.principal') }}</text>
<text class="info-value">{{ textValue(item.principalName || item.ownerName || item.contactName) }}</text>
</view>
<view class="info-cell">
<text class="info-label">{{ t('productCheck.warehouseAddress') }}</text>
<text class="info-value">{{ textValue(item.address) }}</text>
</view>
</view>
</view>
</scroll-view>
<view v-else class="empty-wrap">
<uni-icons type="info" size="30" color="#cbd5e1"></uni-icons>
<text>{{ loading ? t('productCheck.loading') : t('productCheck.emptyWarehouse') }}</text>
</view>
<view class="action-bar">
<view :class="['action-btn', selectedId ? '' : 'action-btn-disabled']" @click="handleConfirm">{{ t('productCheck.confirm') }}</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getWarehousePage } from '@/api/mes/moldget'
const { t } = useI18n()
const warehouseList = ref([])
const selectedId = ref(null)
const searchText = ref('')
const loading = ref(false)
onLoad((options) => {
selectedId.value = options?.selectedId ? String(options.selectedId) : null
})
function textValue(v) {
if (v === 0) return '0'
if (v == null) return '-'
const s = String(v).trim()
return s || '-'
}
function normalizeList(res) {
const root = res && res.data !== undefined ? res.data : res
return Array.isArray(root) ? root : (root?.list || root?.rows || root?.records || [])
}
function isSelected(item) {
return String(selectedId.value) === String(item.id)
}
function clearSearch() {
searchText.value = ''
loadWarehouses()
}
async function loadWarehouses() {
loading.value = true
try {
const keyword = searchText.value.trim()
const res = await getWarehousePage({
pageNo: 1,
pageSize: 50,
categoryType: 1,
name: keyword || undefined
})
warehouseList.value = normalizeList(res)
} catch (e) {
uni.showToast({ title: t('productCheck.loadFailed'), icon: 'none' })
} finally {
loading.value = false
}
}
function handleConfirm() {
if (!selectedId.value) {
uni.showToast({ title: t('productCheck.selectWarehouse'), icon: 'none' })
return
}
const warehouse = warehouseList.value.find((item) => String(item.id) === String(selectedId.value))
if (!warehouse) return
getApp().globalData._productCheckWarehouseSelectResult = {
value: warehouse.id,
label: warehouse.name || warehouse.warehouseName || String(warehouse.id),
raw: warehouse
}
uni.navigateBack()
}
onShow(loadWarehouses)
</script>
<style lang="scss" scoped>
.page-container { min-height: 100vh; background: #f5f7fb; padding-bottom: calc(120rpx + env(safe-area-inset-bottom)); }
.search-bar { padding: 18rpx 24rpx; background: #ffffff; box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.03); }
.search-input-wrap { display: flex; align-items: center; gap: 12rpx; height: 76rpx; padding: 0 22rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 14rpx; box-sizing: border-box; }
.search-input { flex: 1; min-width: 0; font-size: 28rpx; color: #374151; }
.search-placeholder { color: #9ca3af; }
.search-clear { width: 44rpx; height: 44rpx; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.warehouse-list { height: calc(100vh - 294rpx); }
.warehouse-card { margin: 18rpx 24rpx 0; padding: 24rpx; background: #ffffff; border: 1rpx solid #eef2f7; border-radius: 20rpx; box-shadow: 0 6rpx 18rpx rgba(15, 23, 42, 0.04); }
.warehouse-card.active { border-color: #bfdbfe; background: #f9fbff; box-shadow: 0 8rpx 22rpx rgba(31, 124, 255, 0.08); }
.warehouse-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 18rpx; }
.warehouse-title-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8rpx; }
.warehouse-name { font-size: 30rpx; font-weight: 600; color: #1f2937; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.warehouse-code { font-size: 24rpx; color: #8a94a6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.check-badge { width: 36rpx; height: 36rpx; border-radius: 18rpx; border: 1rpx solid #d1d5db; background: #ffffff; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.warehouse-card.active .check-badge { border-color: #1f7cff; background: #1f7cff; }
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14rpx; margin-top: 20rpx; padding-top: 18rpx; border-top: 1rpx solid #f1f5f9; }
.info-cell { min-width: 0; display: flex; flex-direction: column; gap: 6rpx; }
.info-label { font-size: 23rpx; color: #9ca3af; }
.info-value { font-size: 27rpx; color: #374151; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.empty-wrap { height: calc(100vh - 294rpx); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14rpx; color: #94a3b8; font-size: 27rpx; }
.action-bar { position: fixed; left: 0; right: 0; bottom: 0; padding: 18rpx 24rpx calc(18rpx + env(safe-area-inset-bottom)); background: #ffffff; box-shadow: 0 -8rpx 24rpx rgba(15, 23, 42, 0.06); z-index: 99; }
.action-btn { height: 84rpx; border-radius: 16rpx; background: #1f4b79; color: #ffffff; display: flex; align-items: center; justify-content: center; font-size: 30rpx; font-weight: 600; }
.action-btn-disabled { background: #94a3b8; }
</style>