liveh5-nuxt/.history/app/pages/liveRoom/components/SideButton/tangPopup_20250306133617.vue
xingyy 4e771fde21 feat(app): 新增商品详情组件和瀑布流列表
- 添加了 itemDetail 组件,用于展示商品详细信息
- 在 home 页面中集成了瀑布流列表组件
- 实现了商品列表的加载更多和下拉刷新功能
- 添加了商品详情弹窗组件
2025-03-06 15:49:31 +08:00

331 lines
10 KiB
Vue
Raw 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.

<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>