功能调整
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<view class="search-page">
|
||||
<!-- 顶部:输入框内扫码(类似淘宝搜索) -->
|
||||
<view class="search-bar">
|
||||
<view class="search-bar__input-wrap">
|
||||
<u-icon
|
||||
name="scan"
|
||||
:size="28"
|
||||
color="#2979ff"
|
||||
@click="handleScan"
|
||||
/>
|
||||
<input
|
||||
class="search-bar__input"
|
||||
v-model="keyword"
|
||||
type="text"
|
||||
confirm-type="search"
|
||||
:placeholder="placeholder"
|
||||
:focus="autoFocus"
|
||||
@input="handleSearchInput"
|
||||
@confirm="handleSearchConfirm"
|
||||
/>
|
||||
<u-icon
|
||||
v-if="keyword"
|
||||
name="close-circle-fill"
|
||||
:size="28"
|
||||
color="#ccc"
|
||||
@click="handleClear"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 结果列表 -->
|
||||
<scroll-view
|
||||
class="result-scroll"
|
||||
scroll-y
|
||||
@scrolltolower="loadMore"
|
||||
>
|
||||
<view class="result-list">
|
||||
<view
|
||||
v-for="(item, index) in listData"
|
||||
:key="item.WeldJointId || item.Id || index"
|
||||
class="result-item"
|
||||
@click="handleSelect(item)"
|
||||
>
|
||||
<view class="result-item__main">
|
||||
<text class="result-item__code">{{ item.WeldJointCode || '--' }}</text>
|
||||
<text
|
||||
v-if="item.PipelineCode"
|
||||
class="result-item__sub"
|
||||
>管线 {{ item.PipelineCode }}</text>
|
||||
</view>
|
||||
<u-icon
|
||||
name="arrow-right"
|
||||
:size="24"
|
||||
color="#ccc"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<u-empty
|
||||
v-if="!loading && searched && listData.length === 0"
|
||||
mode="search"
|
||||
text="未找到焊口"
|
||||
/>
|
||||
|
||||
<view
|
||||
v-if="!searched && !loading"
|
||||
class="result-hint"
|
||||
>
|
||||
<text>扫码或输入焊口/管线编号搜索</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="loading && listData.length > 0"
|
||||
class="loading-more"
|
||||
>
|
||||
<u-loading
|
||||
mode="circle"
|
||||
size="28"
|
||||
/>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="!loading && !hasMore && listData.length > 0"
|
||||
class="no-more"
|
||||
>
|
||||
<text>— 没有更多了 —</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 焊口搜索中间页:扫码进入业务页,或关键字搜索后点选进入
|
||||
* 入参:target(业务页路径)、title(导航标题)
|
||||
*/
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore, useMenuStore } from '@/store'
|
||||
import { getUrlParam } from '@/utils/request.js'
|
||||
import { reqPipeJointWeldedJoints } from '@/api/hj.js'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const menuStore = useMenuStore()
|
||||
const { currentProject } = storeToRefs(userStore)
|
||||
|
||||
/** 业务目标页,如 /scanpages/hj/material_sampling */
|
||||
const targetPath = ref('')
|
||||
const placeholder = ref('搜索焊口')
|
||||
const autoFocus = ref(true)
|
||||
|
||||
const keyword = ref('')
|
||||
const listData = ref([])
|
||||
const loading = ref(false)
|
||||
const searched = ref(false)
|
||||
const hasMore = ref(true)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = 20
|
||||
let searchTimer = null
|
||||
|
||||
/**
|
||||
* 从接口响应取出列表
|
||||
* @param {any} data
|
||||
*/
|
||||
const pickList = (data) => {
|
||||
if (!data) return []
|
||||
if (Array.isArray(data)) return data
|
||||
if (Array.isArray(data.getDataList)) return data.getDataList
|
||||
if (Array.isArray(data.list)) return data.list
|
||||
if (Array.isArray(data.records)) return data.records
|
||||
if (Array.isArray(data.Items)) return data.Items
|
||||
return []
|
||||
}
|
||||
|
||||
const clearList = () => {
|
||||
listData.value = []
|
||||
hasMore.value = false
|
||||
searched.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取焊口列表
|
||||
* @param {boolean} isRefresh
|
||||
*/
|
||||
const loadList = async (isRefresh = true) => {
|
||||
const kw = keyword.value.trim()
|
||||
const projectId = currentProject.value?.ProjectId
|
||||
if (!projectId) {
|
||||
uni.showToast({ title: '请先选择项目', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!kw) {
|
||||
clearList()
|
||||
return
|
||||
}
|
||||
if (loading.value) return
|
||||
if (!isRefresh && !hasMore.value) return
|
||||
|
||||
loading.value = true
|
||||
if (isRefresh) {
|
||||
currentPage.value = 1
|
||||
hasMore.value = true
|
||||
listData.value = []
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await reqPipeJointWeldedJoints({
|
||||
projectId,
|
||||
keyword: kw,
|
||||
pageIndex: currentPage.value,
|
||||
pageSize,
|
||||
})
|
||||
const data = res?.data ?? {}
|
||||
const pageData = pickList(data)
|
||||
const totalPages = Number(data.pageCount) || 0
|
||||
const totalCount = Number(data.totalCount) || 0
|
||||
if (totalPages > 0) {
|
||||
hasMore.value = currentPage.value < totalPages
|
||||
} else if (totalCount > 0) {
|
||||
hasMore.value = listData.value.length + pageData.length < totalCount
|
||||
} else {
|
||||
hasMore.value = pageData.length >= pageSize
|
||||
}
|
||||
listData.value = isRefresh ? pageData : listData.value.concat(pageData)
|
||||
searched.value = true
|
||||
} catch (e) {
|
||||
console.error('焊口搜索失败:', e)
|
||||
if (isRefresh) listData.value = []
|
||||
searched.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearchInput = () => {
|
||||
if (searchTimer) clearTimeout(searchTimer)
|
||||
searchTimer = setTimeout(() => {
|
||||
const kw = keyword.value.trim()
|
||||
if (!kw) {
|
||||
clearList()
|
||||
return
|
||||
}
|
||||
loadList(true)
|
||||
}, 400)
|
||||
}
|
||||
|
||||
const handleSearchConfirm = () => {
|
||||
if (searchTimer) clearTimeout(searchTimer)
|
||||
loadList(true)
|
||||
}
|
||||
|
||||
const handleClear = () => {
|
||||
keyword.value = ''
|
||||
clearList()
|
||||
}
|
||||
|
||||
const loadMore = () => {
|
||||
if (!loading.value && hasMore.value && keyword.value.trim()) {
|
||||
currentPage.value += 1
|
||||
loadList(false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 进入业务页
|
||||
* @param {string} id WeldJointId
|
||||
*/
|
||||
const goTarget = (id) => {
|
||||
if (!id) {
|
||||
uni.showToast({ title: '缺少焊口信息', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!targetPath.value) {
|
||||
uni.showToast({ title: '缺少目标页面', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!menuStore.canAccessPath(targetPath.value)) {
|
||||
uni.showToast({ title: '当前岗位无此功能权限', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `${targetPath.value}?id=${encodeURIComponent(id)}`
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点选搜索结果
|
||||
* @param {object} item
|
||||
*/
|
||||
const handleSelect = (item) => {
|
||||
const id = item.WeldJointId || item.Id || item.id
|
||||
goTarget(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码:与首页菜单扫码一致,解析 id 后进入业务页
|
||||
*/
|
||||
const handleScan = () => {
|
||||
uni.scanCode({
|
||||
scanType: ['datamatrix', 'barCode', 'qrCode', 'wxCode', 'pdf417'],
|
||||
success: (res) => {
|
||||
const result = res.result || ''
|
||||
let id = getUrlParam(result, 'id')
|
||||
if (!id) {
|
||||
id = String(result).trim()
|
||||
}
|
||||
if (!id) {
|
||||
uni.showToast({ title: '未识别到焊口', icon: 'none' })
|
||||
return
|
||||
}
|
||||
goTarget(id)
|
||||
},
|
||||
fail: (err) => {
|
||||
if (err?.errMsg && String(err.errMsg).includes('cancel')) return
|
||||
uni.showToast({ title: '扫码失败,请重试', icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onLoad((opt) => {
|
||||
targetPath.value = decodeURIComponent(opt.target || '')
|
||||
const title = opt.title ? decodeURIComponent(opt.title) : '选择焊口'
|
||||
uni.setNavigationBarTitle({ title })
|
||||
if (!targetPath.value) {
|
||||
uni.showToast({ title: '入口参数错误', icon: 'none' })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f6f8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #fff;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
|
||||
&__input-wrap {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
background: #f5f6f8;
|
||||
border-radius: 36rpx;
|
||||
}
|
||||
|
||||
&__input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
height: 72rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.result-scroll {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.result-list {
|
||||
padding: 16rpx 24rpx 40rpx;
|
||||
}
|
||||
|
||||
.result-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
|
||||
&__main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
&__code {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1a2332;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
&__sub {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.result-hint {
|
||||
padding: 80rpx 0;
|
||||
text-align: center;
|
||||
font-size: 26rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.loading-more,
|
||||
.no-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
padding: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user