This commit is contained in:
xingyy 2025-03-06 17:03:31 +08:00
parent 4e771fde21
commit c3852e1fb8
2 changed files with 44 additions and 119 deletions

3
.gitignore vendored
View File

@ -17,3 +17,6 @@ logs
.DS_Store .DS_Store
.fleet .fleet
.idea .idea
.history/
.history/**
**/.history/**

View File

@ -1,8 +1,9 @@
<script setup> <script setup>
import { ref, computed } from 'vue' import {ref} from 'vue'
import { goodStore } from "@/stores/goods" import {goodStore} from "@/stores/goods"
import DetailPopup from '../DetailPopup/index.vue' import DetailPopup from '../DetailPopup/index.vue'
import WaterfallFlow from '@/components/waterfallFlow/index.vue' import WaterfallFlow from '@/components/waterfallFlow/index.vue'
const { const {
itemList, itemList,
pageRef, pageRef,
@ -17,41 +18,10 @@ const localState = ref({
showDetail: false, showDetail: false,
showHeight: '' showHeight: ''
}) })
//
const imageLoadingStatus = ref({})
//
const skeletonList = computed(() => {
//
if (itemList.value && itemList.value.length > 0) return []
// 6
return Array(6).fill().map((_, index) => ({
id: `skeleton-${index}`,
isSkeletonItem: true
}))
})
//
const displayList = computed(() => {
if (itemList.value && itemList.value.length > 0) return itemList.value
return skeletonList.value
})
//
const handleImageLoad = (itemId) => {
imageLoadingStatus.value[itemId] = true
}
//
const handleImageError = (itemId) => {
imageLoadingStatus.value[itemId] = true //
}
// //
const loadMore = async () => { const loadMore = async () => {
pageRef.value.page++ pageRef.value.page++
const { finished } = await getArtworkList() const {finished} = await getArtworkList()
localState.value.finished = finished localState.value.finished = finished
} }
@ -60,9 +30,7 @@ const onRefresh = async () => {
try { try {
localState.value.refreshing = true localState.value.refreshing = true
localState.value.finished = false localState.value.finished = false
// const {finished} = await getArtworkList(true)
imageLoadingStatus.value = {}
const { finished } = await getArtworkList(true)
localState.value.finished = finished localState.value.finished = finished
} finally { } finally {
localState.value.refreshing = false localState.value.refreshing = false
@ -70,10 +38,30 @@ const onRefresh = async () => {
} }
// //
const openShow = async (item) => { const openShow = async (item) => {
if (item.isSkeletonItem) return
localState.value.showDetail = true localState.value.showDetail = true
currentItem.value = item currentItem.value = item
} }
/**
* 将数字格式化为"250XX"格式其中XX是两位数
* @param {number} num - 要格式化的数字
* @return {string} - 格式化后的字符串
*/
function formatNumber(num) {
//
if (typeof num !== 'number' && isNaN(Number(num))) {
throw new Error('输入必须是有效数字');
}
// ()
const number = Number(num);
// 0
const formattedNum = number.toString().padStart(2, '0');
// "250"
return `250${formattedNum}`;
}
</script> </script>
<template> <template>
@ -84,7 +72,8 @@ const openShow = async (item) => {
@refresh="onRefresh" @refresh="onRefresh"
> >
<template #success> <template #success>
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span> <van-icon name="success"/>
<span>{{ $t('home.refresh_show') }}</span>
</template> </template>
<van-list <van-list
v-model:loading="storeLoading" v-model:loading="storeLoading"
@ -93,54 +82,35 @@ const openShow = async (item) => {
@load="loadMore" @load="loadMore"
> >
<div class="w-full flex gap-[16px]"> <div class="w-full flex gap-[16px]">
<WaterfallFlow :items="displayList" :column-count="2"> <WaterfallFlow :items="itemList" :column-count="2">
<template #default="{ item }"> <template #default="{ item, index }">
<div <div
@click="openShow(item)" @click="openShow(item)"
class="w-full" class="w-full"
> >
<div class="relative w-full"> <div class="relative w-full">
<!-- 自定义骨架屏 --> <img
<div :src="item.artwork?.hdPic"
v-if="item.isSkeletonItem || !imageLoadingStatus[item.id]" class="w-full object-cover rounded-4px"
class="custom-skeleton rounded-4px overflow-hidden" />
<div
class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[55px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
> >
<div class="skeleton-image"></div> Lot{{ formatNumber(item.index) }}
<div class="skeleton-content">
<div class="skeleton-title"></div>
<div class="skeleton-text"></div>
<div class="skeleton-text"></div>
</div>
</div> </div>
<template v-if="!item.isSkeletonItem">
<img
:src="item.artwork?.hdPic"
class="w-full object-cover rounded-4px"
:class="{'hidden': !imageLoadingStatus[item.id]}"
@load="handleImageLoad(item.id)"
@error="handleImageError(item.id)"
/>
<div
class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[60px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
:class="{'z-10': !imageLoadingStatus[item.id]}"
>
Lot{{item.index+25000 }}
</div>
</template>
</div> </div>
<div v-if="!item.isSkeletonItem" class="pt-[8px]" :class="{'hidden': !imageLoadingStatus[item.id]}"> <div class="pt-[8px]">
<div class="text-[14px] text-[#000000] leading-[20px]"> <div class="text-[14px] text-[#000000] leading-[20px]">
{{ item?.artwork?.name }} | {{item?.artwork?.artistName}} {{ item?.artwork?.name }} | {{ item?.artwork?.artistName }}
</div> </div>
<div class="mt-[4px] text-[12px] text-[#575757]"> <div class="mt-[4px] text-[12px] text-[#575757]">
{{ $t('home.start_price') }}{{ item?.startPrice??0 }} {{ $t('home.start_price') }}{{ item?.startPrice ?? 0 }}
</div> </div>
<div <div
v-if="item.soldPrice" v-if="item.soldPrice"
class="mt-[4px] text-[12px] text-[#b58047]" class="mt-[4px] text-[12px] text-[#b58047]"
> >
{{ $t('home.close_price') }}{{ item?.soldPrice??0 }} {{ $t('home.close_price') }}{{ item?.soldPrice ?? 0 }}
</div> </div>
</div> </div>
</div> </div>
@ -158,52 +128,4 @@ const openShow = async (item) => {
overflow-y: auto; overflow-y: auto;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
/* 自定义骨架屏样式 */
.custom-skeleton {
width: 100%;
display: flex;
flex-direction: column;
background-color: #fff;
}
.skeleton-image {
width: 100%;
padding-bottom: 100%; /* 保持1:1的宽高比 */
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
background-size: 400% 100%;
animation: skeleton-loading 1.4s ease infinite;
}
.skeleton-content {
padding: 8px 0;
}
.skeleton-title {
height: 16px;
margin-bottom: 8px;
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
background-size: 400% 100%;
animation: skeleton-loading 1.4s ease infinite;
border-radius: 2px;
}
.skeleton-text {
height: 12px;
margin-top: 4px;
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
background-size: 400% 100%;
animation: skeleton-loading 1.4s ease infinite;
border-radius: 2px;
width: 60%;
}
@keyframes skeleton-loading {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
</style> </style>