331 lines
10 KiB
Vue
331 lines
10 KiB
Vue
|
<script setup>
|
|||
|
import xPopup from '@/components/x-popup/index.vue'
|
|||
|
import {goodStore} from "@/stores/goods/index.js";
|
|||
|
import xImage from '@/components/x-image/index.vue'
|
|||
|
import DetailPopup from '@/pages/home/components/DetailPopup/index.vue'
|
|||
|
import {liveStore} from "~/stores/live/index.js";
|
|||
|
import {ref, nextTick, watch, onMounted} from "vue";
|
|||
|
|
|||
|
const {pageRef, itemList, getArtworkList, loading: storeLoading} = goodStore();
|
|||
|
const {auctionData} = liveStore()
|
|||
|
const showDetail = ref(false)
|
|||
|
const localState = ref({
|
|||
|
finished: false,
|
|||
|
refreshing: false,
|
|||
|
showDetail: false,
|
|||
|
showHeight: '',
|
|||
|
isSearchingCurrentItem: false,
|
|||
|
debugInfo: '' // 添加调试信息字段
|
|||
|
})
|
|||
|
|
|||
|
// DOM引用
|
|||
|
const listContainerRef = ref(null)
|
|||
|
|
|||
|
const onRefresh = async () => {
|
|||
|
try {
|
|||
|
localState.value.refreshing = true
|
|||
|
localState.value.finished = false
|
|||
|
const { finished } = await getArtworkList(true)
|
|||
|
localState.value.finished = finished
|
|||
|
} finally {
|
|||
|
localState.value.refreshing = false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const props = defineProps({
|
|||
|
show: Boolean,
|
|||
|
title: {
|
|||
|
type: String,
|
|||
|
default: ''
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
// 设置调试信息的辅助函数
|
|||
|
const setDebugInfo = (info) => {
|
|||
|
console.log('调试信息:', info)
|
|||
|
localState.value.debugInfo = info
|
|||
|
}
|
|||
|
|
|||
|
// 增强版的滚动到当前拍品函数
|
|||
|
const scrollToCurrentItem = async () => {
|
|||
|
if (!auctionData.value?.artwork?.index) {
|
|||
|
setDebugInfo('当前拍品索引不存在')
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
const targetIndex = auctionData.value.artwork.index
|
|||
|
setDebugInfo(`开始查找目标拍品: LOT${targetIndex}`)
|
|||
|
|
|||
|
let currentIndex = itemList.value.findIndex(item => targetIndex === item?.index)
|
|||
|
|
|||
|
if (currentIndex === -1) {
|
|||
|
try {
|
|||
|
localState.value.isSearchingCurrentItem = true
|
|||
|
setDebugInfo(`当前列表中未找到目标拍品,开始加载更多数据...`)
|
|||
|
|
|||
|
// 尝试搜索特定拍品
|
|||
|
await searchSpecificItem(targetIndex)
|
|||
|
|
|||
|
// 检查是否找到了
|
|||
|
currentIndex = itemList.value.findIndex(item => targetIndex === item?.index)
|
|||
|
setDebugInfo(`加载数据后,拍品索引位置: ${currentIndex}`)
|
|||
|
|
|||
|
if (currentIndex > -1) {
|
|||
|
// 等待列表渲染完成
|
|||
|
await new Promise(resolve => setTimeout(resolve, 300))
|
|||
|
await nextTick()
|
|||
|
scrollToElement(currentIndex)
|
|||
|
} else {
|
|||
|
setDebugInfo(`加载后仍未找到目标拍品 LOT${targetIndex}`)
|
|||
|
}
|
|||
|
} finally {
|
|||
|
localState.value.isSearchingCurrentItem = false
|
|||
|
}
|
|||
|
} else {
|
|||
|
setDebugInfo(`在现有列表中找到拍品,位置: ${currentIndex}`)
|
|||
|
// 等待列表渲染完成
|
|||
|
await new Promise(resolve => setTimeout(resolve, 300))
|
|||
|
await nextTick()
|
|||
|
scrollToElement(currentIndex)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 搜索特定拍品的优化函数
|
|||
|
const searchSpecificItem = async (targetIndex) => {
|
|||
|
try {
|
|||
|
// 保存原始设置
|
|||
|
const originalPage = pageRef.value.page
|
|||
|
const originalPageSize = pageRef.value.pageSize
|
|||
|
|
|||
|
setDebugInfo(`尝试使用更大页面大小搜索拍品LOT${targetIndex}`)
|
|||
|
|
|||
|
// 策略1: 直接设置大页面大小加载首页数据
|
|||
|
pageRef.value.page = 1
|
|||
|
pageRef.value.pageSize = 100 // 使用较大的页面大小
|
|||
|
await getArtworkList(true)
|
|||
|
|
|||
|
// 检查是否找到
|
|||
|
let found = itemList.value.some(item => targetIndex === item?.index)
|
|||
|
setDebugInfo(`策略1结果: ${found ? '找到' : '未找到'}`)
|
|||
|
|
|||
|
// 策略2: 如果没找到,尝试基于目标索引估算页码
|
|||
|
if (!found) {
|
|||
|
// 估算目标页面 (假设每页20个拍品)
|
|||
|
const estimatedPage = Math.ceil(targetIndex / 10)
|
|||
|
setDebugInfo(`尝试策略2: 估算页码 ${estimatedPage}`)
|
|||
|
|
|||
|
pageRef.value.page = estimatedPage > 0 ? estimatedPage : 1
|
|||
|
await getArtworkList(true)
|
|||
|
|
|||
|
found = itemList.value.some(item => targetIndex === item?.index)
|
|||
|
setDebugInfo(`策略2结果: ${found ? '找到' : '未找到'}`)
|
|||
|
}
|
|||
|
|
|||
|
// 恢复原始设置
|
|||
|
pageRef.value.page = originalPage
|
|||
|
pageRef.value.pageSize = originalPageSize
|
|||
|
|
|||
|
return found
|
|||
|
} catch (error) {
|
|||
|
console.error('搜索特定拍品时出错:', error)
|
|||
|
setDebugInfo(`搜索出错: ${error.message}`)
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 改进滚动到元素的函数
|
|||
|
const scrollToElement = (index) => {
|
|||
|
setDebugInfo(`尝试滚动到元素 index=${index}`)
|
|||
|
|
|||
|
// 获取容器和目标元素
|
|||
|
const allItems = document.querySelectorAll('.item-wrapper')
|
|||
|
|
|||
|
if (!listContainerRef.value || !allItems.length || index >= allItems.length) {
|
|||
|
setDebugInfo(`无法滚动: 容器或元素不存在 (找到${allItems.length}个元素)`)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
const targetElement = allItems[index]
|
|||
|
const container = listContainerRef.value
|
|||
|
|
|||
|
if (targetElement && container) {
|
|||
|
try {
|
|||
|
setDebugInfo(`找到目标元素和容器,执行滚动`)
|
|||
|
|
|||
|
// 使用 Element.scrollIntoView 更可靠的滚动方法
|
|||
|
targetElement.scrollIntoView({
|
|||
|
behavior: 'smooth',
|
|||
|
block: 'center'
|
|||
|
})
|
|||
|
|
|||
|
// 添加高亮效果
|
|||
|
targetElement.classList.add('highlight-item')
|
|||
|
setTimeout(() => {
|
|||
|
targetElement.classList.remove('highlight-item')
|
|||
|
}, 2000)
|
|||
|
|
|||
|
setDebugInfo(`滚动完成并应用高亮效果`)
|
|||
|
} catch (error) {
|
|||
|
setDebugInfo(`滚动过程出错: ${error.message}`)
|
|||
|
console.error('滚动过程出错:', error)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const emit = defineEmits(['update:show'])
|
|||
|
const showDetailInfo = ref(null)
|
|||
|
const close = () => emit('update:show', false);
|
|||
|
const openShow = (item) => {
|
|||
|
showDetailInfo.value=item
|
|||
|
showDetail.value=true
|
|||
|
}
|
|||
|
|
|||
|
const loadMore = async () => {
|
|||
|
pageRef.value.page++
|
|||
|
const { finished } = await getArtworkList()
|
|||
|
localState.value.finished = finished
|
|||
|
}
|
|||
|
|
|||
|
// 监听拍品变化
|
|||
|
watch(() => auctionData.value?.artwork?.index, (newValue, oldValue) => {
|
|||
|
if (newValue && newValue !== oldValue && props.show) {
|
|||
|
setDebugInfo(`检测到拍品索引变化: ${oldValue} -> ${newValue}`)
|
|||
|
nextTick(() => {
|
|||
|
scrollToCurrentItem()
|
|||
|
})
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
// 监听弹窗显示状态
|
|||
|
watch(() => props.show, (newValue) => {
|
|||
|
if (newValue) {
|
|||
|
setDebugInfo('弹窗显示,准备滚动到当前拍品')
|
|||
|
// 延迟执行,确保DOM已渲染
|
|||
|
setTimeout(() => {
|
|||
|
scrollToCurrentItem()
|
|||
|
}, 500)
|
|||
|
}
|
|||
|
})
|
|||
|
</script>
|
|||
|
|
|||
|
<template>
|
|||
|
<div>
|
|||
|
<x-popup :show="show" @update:show="close">
|
|||
|
<template #title>
|
|||
|
<div class="text-#000 text-16px">{{ $t('home.tab1')}}</div>
|
|||
|
<div class="text-#939393 text-16px ml-14px">{{ $t('live_room.total') }}{{ pageRef.itemCount }}{{ $t('live_room.lots_num') }}</div>
|
|||
|
</template>
|
|||
|
<div>
|
|||
|
<van-pull-refresh
|
|||
|
v-model="localState.refreshing"
|
|||
|
:success-text="$t('home.refresh_show')"
|
|||
|
:success-duration="700"
|
|||
|
@refresh="onRefresh"
|
|||
|
>
|
|||
|
<template #success>
|
|||
|
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
|||
|
</template>
|
|||
|
|
|||
|
<!-- 搜索提示 -->
|
|||
|
<div v-if="localState.isSearchingCurrentItem" class="searching-item-tip">
|
|||
|
{{ $t('live_room.searching_current_lot') || '正在查找当前拍品...' }}
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 调试信息区域,可在生产环境中移除 -->
|
|||
|
<div v-if="localState.debugInfo" class="debug-info">
|
|||
|
{{ localState.debugInfo }}
|
|||
|
</div>
|
|||
|
|
|||
|
<van-list
|
|||
|
v-model:loading="storeLoading"
|
|||
|
:finished="localState.finished"
|
|||
|
:finished-text="$t('home.finished_text')"
|
|||
|
@load="loadMore"
|
|||
|
class="list-container"
|
|||
|
ref="listContainerRef"
|
|||
|
>
|
|||
|
<div
|
|||
|
v-for="(item) of itemList"
|
|||
|
:key="item.uuid"
|
|||
|
class="flex mb-21px item-wrapper"
|
|||
|
@click="openShow(item)"
|
|||
|
:class="{'current-item': auctionData?.artwork?.index === item?.index}"
|
|||
|
>
|
|||
|
<div
|
|||
|
class="mr-10px flex-shrink-0 rounded-4px overflow-hidden cursor-pointer relative"
|
|||
|
>
|
|||
|
<xImage
|
|||
|
:preview="false"
|
|||
|
class="w-80px h-80px"
|
|||
|
:src="item.artwork?.hdPic"
|
|||
|
:alt="item?.artworkTitle"
|
|||
|
loading="lazy"
|
|||
|
/>
|
|||
|
<div class="w-45px h-17px bg-#2B53AC text-12px line-height-none flex justify-center items-center absolute top-2px left-2px text-#fff">LOT{{item.index}}</div>
|
|||
|
<div v-show="auctionData?.artwork?.index===item?.index" class="w-80px h-20px bg-#B58047 flex line-height-none justify-center items-center text-#fff text-12px bottom-0 absolute blink">{{ $t('live_room.cast') }}</div>
|
|||
|
</div>
|
|||
|
<div>
|
|||
|
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
|||
|
{{ item.artworkTitle }}
|
|||
|
</div>
|
|||
|
<div class="text-14px text-#575757">{{ $t('home.start_price') }}:{{item?.startPriceCurrency}} {{item?.startPrice}}</div>
|
|||
|
<div class="text-14px text-#B58047" v-if="item.soldPrice">{{ $t('home.close_price') }}:{{item.soldPrice}}</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</van-list>
|
|||
|
</van-pull-refresh>
|
|||
|
</div>
|
|||
|
</x-popup>
|
|||
|
<DetailPopup v-model:show="showDetail" :detail-info="showDetailInfo"></DetailPopup>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<style scoped>
|
|||
|
.ellipsis {
|
|||
|
display: -webkit-box;
|
|||
|
-webkit-box-orient: vertical;
|
|||
|
-webkit-line-clamp: 2;
|
|||
|
overflow: hidden;
|
|||
|
text-overflow: ellipsis;
|
|||
|
}
|
|||
|
.blink {
|
|||
|
animation: fade 1s linear infinite;
|
|||
|
}
|
|||
|
|
|||
|
@keyframes fade {
|
|||
|
0%, 100% { opacity: 1; }
|
|||
|
50% { opacity: 0.5; }
|
|||
|
}
|
|||
|
|
|||
|
.searching-item-tip {
|
|||
|
text-align: center;
|
|||
|
padding: 10px 0;
|
|||
|
color: #B58047;
|
|||
|
font-size: 14px;
|
|||
|
}
|
|||
|
|
|||
|
.highlight-item {
|
|||
|
animation: highlight-pulse 2s ease-in-out;
|
|||
|
}
|
|||
|
|
|||
|
@keyframes highlight-pulse {
|
|||
|
0% { box-shadow: 0 0 0 0 rgba(181, 128, 71, 0.7); }
|
|||
|
50% { box-shadow: 0 0 0 10px rgba(181, 128, 71, 0); }
|
|||
|
100% { box-shadow: 0 0 0 0 rgba(181, 128, 71, 0); }
|
|||
|
}
|
|||
|
|
|||
|
.current-item {
|
|||
|
background-color: rgba(181, 128, 71, 0.1);
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
.debug-info {
|
|||
|
padding: 8px;
|
|||
|
background-color: #f5f5f5;
|
|||
|
border: 1px solid #ddd;
|
|||
|
color: #333;
|
|||
|
font-size: 12px;
|
|||
|
margin: 5px 0;
|
|||
|
word-break: break-all;
|
|||
|
}
|
|||
|
</style>
|