Files
shj-app/scanpages/hj/barcode_search.vue
2026-09-03 09:17:52 +08:00

292 lines
6.6 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page-list">
<!-- 关键字搜索 -->
<view class="filter-header">
<view class="search-row">
<u-search
v-model="keyword"
placeholder="请输入条码关键字(至少2位)"
:show-action="false"
shape="square"
bg-color="#f5f6f8"
@change="handleSearch"
@search="handleSearch"
/>
</view>
</view>
<scroll-view
class="list-scroll"
scroll-y
@scrolltolower="loadMore"
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="handleRefresh"
>
<view class="list-wrap">
<view
v-for="(item, index) in listData"
:key="item.Id || item.BarCode || index"
class="card-item"
>
<view class="card-header">
<text class="card-code">{{ item.BarCode || '--' }}</text>
</view>
<view class="card-body">
<view class="card-row">
<text class="row-label">材料编码</text>
<text class="row-value">{{ item.MaterialCode || '--' }}</text>
</view>
<view class="card-row">
<text class="row-label">数量</text>
<text class="row-value">{{ formatQuantity(item.Quantity) }}</text>
</view>
</view>
<view class="card-footer">
<view
class="print-btn"
@click.stop="handlePrint(item)"
>
<text class="print-btn__text">打印</text>
</view>
</view>
</view>
<u-empty
v-if="!loading && listData.length === 0"
mode="list"
:text="emptyText"
/>
<view
v-if="loading && listData.length > 0"
class="loading-more"
>
<u-loading
mode="circle"
size="32"
/>
<text>加载中...</text>
</view>
<view
v-if="!loading && !hasMore && listData.length > 0"
class="no-more"
>
<text>— 没有更多了 —</text>
</view>
</view>
</scroll-view>
<!-- 标签预览与打印 -->
<nbd-print-prop
v-model="showPrint"
:labelWidth="50"
:labelHeight="30"
:margin="2"
:barcodeText="printBarcode"
:barcodeTopText="printTop"
:barcodeBottomText="printBottom"
/>
</view>
</template>
<script setup>
/**
* 条码查询:按条码关键字分页查询入库明细,支持标签预览与蓝牙打印
*/
import { computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { reqGetInputDetailBarCodes } from '@/api/base.js'
/** 最少关键字长度(文档建议 2~3) */
const MIN_KEYWORD_LEN = 2
/** 搜索关键字 */
const keyword = ref('')
/** 列表数据 */
const listData = ref([])
/** 加载中 */
const loading = ref(false)
/** 下拉刷新中 */
const refreshing = ref(false)
/** 是否还有更多 */
const hasMore = ref(true)
/** 当前页码(从 1 开始) */
const currentPage = ref(1)
/** 每页条数 */
const pageSize = 20
/** 总页数(接口 pageCount) */
const pageCount = ref(0)
/** 搜索防抖定时器 */
let searchTimer = null
/** 是否展示打印弹窗 */
const showPrint = ref(false)
/** 打印:条码内容 */
const printBarcode = ref('')
/** 打印:条码上方文案 */
const printTop = ref('')
/** 打印:条码下方文案 */
const printBottom = ref('')
/** 空状态文案 */
const emptyText = computed(() => {
const kw = keyword.value.trim()
if (!kw) return '请输入条码关键字查询'
if (kw.length < MIN_KEYWORD_LEN) return `请至少输入${MIN_KEYWORD_LEN}个字符`
return '暂无数据'
})
/**
* 数量展示
* @param {unknown} q
*/
const formatQuantity = (q) => {
if (q === undefined || q === null || q === '') return '--'
return String(q)
}
/**
* 从响应中取出当前页列表
* @param {any} data
* @returns {array}
*/
const pickList = (data) => {
if (!data || typeof data !== 'object') return []
if (Array.isArray(data.getDataList)) return data.getDataList
if (Array.isArray(data.list)) return data.list
if (Array.isArray(data)) return data
return []
}
/** 清空本地列表状态 */
const clearList = () => {
listData.value = []
hasMore.value = false
pageCount.value = 0
refreshing.value = false
loading.value = false
}
/**
* 拉取一页数据;关键字为空或过短时不请求
* @param {boolean} isRefresh
*/
const fetchData = async (isRefresh = false) => {
const kw = keyword.value.trim()
if (!kw || kw.length < MIN_KEYWORD_LEN) {
clearList()
return
}
if (loading.value || (!isRefresh && !hasMore.value)) return
loading.value = true
if (isRefresh) refreshing.value = true
try {
const res = await reqGetInputDetailBarCodes({
barCodeKeyword: kw,
pageIndex: currentPage.value,
pageSize,
})
const data = res?.data ?? {}
const pageData = pickList(data)
const totalPages = Number(data.pageCount) || 0
pageCount.value = totalPages
if (totalPages > 0) {
hasMore.value = currentPage.value < totalPages
} else {
hasMore.value = pageData.length >= pageSize
}
listData.value = isRefresh ? pageData : listData.value.concat(pageData)
} catch (e) {
console.error('条码列表加载失败:', e)
uni.showToast({ title: '加载失败,请重试', icon: 'none' })
} finally {
loading.value = false
refreshing.value = false
}
}
/** 重置到第一页并重新加载 */
const resetAndLoad = () => {
currentPage.value = 1
hasMore.value = true
listData.value = []
fetchData(true)
}
/** 下拉刷新 */
const handleRefresh = () => {
const kw = keyword.value.trim()
if (!kw || kw.length < MIN_KEYWORD_LEN) {
clearList()
return
}
resetAndLoad()
}
/** 关键字变更(防抖);清空或过短时直接清空列表 */
const handleSearch = () => {
if (searchTimer) clearTimeout(searchTimer)
searchTimer = setTimeout(() => {
const kw = keyword.value.trim()
if (!kw || kw.length < MIN_KEYWORD_LEN) {
clearList()
return
}
resetAndLoad()
}, 400)
}
/** 上拉加载更多 */
const loadMore = () => {
if (!loading.value && hasMore.value && keyword.value.trim().length >= MIN_KEYWORD_LEN) {
currentPage.value += 1
fetchData(false)
}
}
/**
* 打开标签预览与打印(与材料详情一致:图内编码为 BarCode)
* @param {object} item
*/
const handlePrint = (item) => {
const code = item.BarCode || ''
if (!code) {
uni.showToast({ title: '缺少材料编码', icon: 'none' })
return
}
printBarcode.value = code
printTop.value = item.BarCode || ''
printBottom.value = item.Quantity != null && item.Quantity !== ''
? `数量 ${item.Quantity}`
: ''
showPrint.value = true
}
onLoad(() => {
// 空关键字不自动请求
})
</script>
<style lang="scss" scoped>
.card-footer {
display: flex;
justify-content: flex-end;
padding-top: 16rpx;
border-top: 1rpx solid #f0f0f0;
margin-top: 8rpx;
}
.print-btn {
padding: 10rpx 28rpx;
border-radius: 8rpx;
background: #2979ff;
}
.print-btn__text {
font-size: 24rpx;
color: #ffffff;
}
</style>