|
|
@@ -0,0 +1,388 @@
|
|
|
+<template>
|
|
|
+ <div class="activity-container">
|
|
|
+ <!-- 返回按钮 -->
|
|
|
+ <div class="back-button" @click="goBackToIndex">
|
|
|
+ <img src="@/assets/indexPage/icon_back.png" alt="" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 标题 -->
|
|
|
+ <div class="section-title">线上展览</div>
|
|
|
+
|
|
|
+ <!-- 活动列表 -->
|
|
|
+ <div v-if="loading && exhibitionList.length === 0" class="loading-container">
|
|
|
+ <div class="loading-text">加载中...</div>
|
|
|
+ </div>
|
|
|
+ <div v-else class="content-section">
|
|
|
+ <div class="collection-list">
|
|
|
+ <div
|
|
|
+ class="exhibition-item"
|
|
|
+ v-for="exhibition in exhibitionList"
|
|
|
+ :key="exhibition.exhibitId"
|
|
|
+ @click="viewExhibition(exhibition)"
|
|
|
+ >
|
|
|
+ <img :src="getImg(exhibition)" alt="展览" class="exhibition-img" />
|
|
|
+ <div class="exhibition-info">
|
|
|
+ <h4 class="exhibition-title">{{ getTitle(exhibition) }}</h4>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <div v-if="exhibitionList.length === 0" class="empty-state">
|
|
|
+ <div class="empty-text">暂无展览数据</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 加载更多指示器 -->
|
|
|
+ <div v-if="exhibitionList.length > 0 && isLoadingMore" class="loading-more">
|
|
|
+ <div class="loading-more-text">加载中...</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 没有更多数据提示 -->
|
|
|
+ <div v-if="exhibitionList.length > 0 && !exhibitionHasMore && !isLoadingMore" class="no-more">
|
|
|
+ <div class="no-more-text">没有更多数据了</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ name: 'OnlineList',
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { onMounted, computed, nextTick, onUnmounted } from 'vue'
|
|
|
+import { useRouter, useRoute } from 'vue-router'
|
|
|
+import { useIndexPageApi } from '@/setup/useIndexPageApi'
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const route = useRoute()
|
|
|
+
|
|
|
+// 检查是否为预览模式
|
|
|
+const isPreviewMode = computed(() => {
|
|
|
+ return route.query.preview === '1'
|
|
|
+})
|
|
|
+
|
|
|
+// 获取字段值的通用方法,优先获取带B后缀的字段
|
|
|
+const getFieldValue = (item, fieldName) => {
|
|
|
+ if (isPreviewMode.value) {
|
|
|
+ return item[fieldName + 'B'] || item[fieldName]
|
|
|
+ }
|
|
|
+ return item[fieldName]
|
|
|
+}
|
|
|
+// 获取图片的方法
|
|
|
+const getImg = (item) => {
|
|
|
+ return getFieldValue(item, 'img')
|
|
|
+}
|
|
|
+// 获取标题的方法
|
|
|
+const getTitle = (item) => {
|
|
|
+ return getFieldValue(item, 'title')
|
|
|
+}
|
|
|
+// 使用组合式函数获取API方法和响应式数据
|
|
|
+const { getExhibitionList, loading, exhibitionList, exhibitionHasMore, loadMoreExhibitions } =
|
|
|
+ useIndexPageApi()
|
|
|
+
|
|
|
+// 滚动加载相关
|
|
|
+const isLoadingMore = computed(() => loading.value && exhibitionList.value.length > 0)
|
|
|
+
|
|
|
+// 滚动事件处理
|
|
|
+const handleScroll = async () => {
|
|
|
+ const container = document.querySelector('.activity-container')
|
|
|
+ if (!container) return
|
|
|
+
|
|
|
+ const { scrollTop, scrollHeight, clientHeight } = container
|
|
|
+ const threshold = 100 // 距离底部100px时触发加载
|
|
|
+
|
|
|
+ if (
|
|
|
+ scrollTop + clientHeight >= scrollHeight - threshold &&
|
|
|
+ !isLoadingMore.value &&
|
|
|
+ exhibitionHasMore.value
|
|
|
+ ) {
|
|
|
+ await loadMore()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 加载更多数据
|
|
|
+const loadMore = async () => {
|
|
|
+ try {
|
|
|
+ const params = {}
|
|
|
+ // 如果是预览模式,设置status为-1
|
|
|
+ if (isPreviewMode.value) {
|
|
|
+ params.status = -1
|
|
|
+ }
|
|
|
+ await loadMoreExhibitions(params)
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载更多展览数据失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 页面初始化时获取展览数据
|
|
|
+onMounted(async () => {
|
|
|
+ try {
|
|
|
+ const params = { pageNum: 1, pageSize: 5 }
|
|
|
+ // 如果是预览模式,设置status为-1
|
|
|
+ if (isPreviewMode.value) {
|
|
|
+ params.status = -1
|
|
|
+ }
|
|
|
+ await getExhibitionList(params)
|
|
|
+
|
|
|
+ // 添加滚动事件监听
|
|
|
+ await nextTick()
|
|
|
+ const container = document.querySelector('.activity-container')
|
|
|
+ if (container) {
|
|
|
+ container.addEventListener('scroll', handleScroll)
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取展览数据失败:', error)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 组件卸载时移除滚动事件监听
|
|
|
+onUnmounted(() => {
|
|
|
+ const container = document.querySelector('.activity-container')
|
|
|
+ if (container) {
|
|
|
+ container.removeEventListener('scroll', handleScroll)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 返回首页函数
|
|
|
+const goBackToIndex = () => {
|
|
|
+ if (isPreviewMode.value) {
|
|
|
+ router.replace({
|
|
|
+ path: '/indexPage',
|
|
|
+ query: { preview: '1' },
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ router.replace('/indexPage')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 查看展览详情
|
|
|
+const viewExhibition = (item) => {
|
|
|
+ console.log('查看展览详情:', item)
|
|
|
+ // 跳转到详情页,传递展览ID和类型参数
|
|
|
+ let url = getFieldValue(item, 'webSite')
|
|
|
+ console.log(url, 777)
|
|
|
+ window.open(url, '_blank')
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.activity-container {
|
|
|
+ position: relative;
|
|
|
+ height: 100vh;
|
|
|
+ min-width: 375px;
|
|
|
+ padding: 20px;
|
|
|
+ background: url('@/assets/indexPage/bg.png') no-repeat;
|
|
|
+ background-size: cover;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+// @media (min-width: 1024px) {
|
|
|
+// .exhibition-container {
|
|
|
+// width: 400px;
|
|
|
+// }
|
|
|
+// }
|
|
|
+.back-button {
|
|
|
+ position: absolute;
|
|
|
+ top: 20px;
|
|
|
+ left: 20px;
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 50%;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #584735;
|
|
|
+ margin: 54px 0 10px 0;
|
|
|
+ position: relative;
|
|
|
+ padding-bottom: 10px;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 2px;
|
|
|
+ background: linear-gradient(90deg, rgba(91, 71, 46, 0.5) 0%, rgba(91, 71, 46, 0) 100%);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.collection-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+// 展览项
|
|
|
+.exhibition-item {
|
|
|
+ position: relative;
|
|
|
+ flex: 0 0 auto;
|
|
|
+ width: 100%;
|
|
|
+ height: 206px;
|
|
|
+ margin-right: 10px;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ margin-top: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-right: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .exhibition-img {
|
|
|
+ width: 100%;
|
|
|
+ height: 206px;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ .exhibition-info {
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ opacity: 0.8;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ background: #b1967b;
|
|
|
+
|
|
|
+ .exhibition-title {
|
|
|
+ font-size: 16px;
|
|
|
+ margin: 0;
|
|
|
+ color: #fff;
|
|
|
+ font-weight: bold;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ font-family: 'heavy';
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.item-image-container {
|
|
|
+ position: relative;
|
|
|
+ height: 218px;
|
|
|
+ overflow: hidden;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ .item-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ .view-button {
|
|
|
+ position: absolute;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 80px;
|
|
|
+ height: 36px;
|
|
|
+ top: 12px;
|
|
|
+ right: 12px;
|
|
|
+ background-color: rgba(0, 0, 0, 0.2);
|
|
|
+ color: #fff;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 50px;
|
|
|
+ font-size: 12px;
|
|
|
+ border: 1px solid #fff;
|
|
|
+
|
|
|
+ span {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-right: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.item-info {
|
|
|
+ position: absolute;
|
|
|
+ width: 90%;
|
|
|
+ bottom: 16px;
|
|
|
+ left: 24px;
|
|
|
+
|
|
|
+ .item-category {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .item-title {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #fff;
|
|
|
+ font-family: 'heavy';
|
|
|
+ }
|
|
|
+
|
|
|
+ .item-description {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #fff;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 加载状态样式
|
|
|
+.loading-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 200px;
|
|
|
+
|
|
|
+ .loading-text {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #584735;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 空状态样式
|
|
|
+.empty-state {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 200px;
|
|
|
+ margin-top: 50px;
|
|
|
+
|
|
|
+ .empty-text {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #584735;
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 加载更多样式
|
|
|
+.loading-more {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 60px;
|
|
|
+ margin-top: 20px;
|
|
|
+
|
|
|
+ .loading-more-text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #584735;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 没有更多数据样式
|
|
|
+.no-more {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 60px;
|
|
|
+ margin-top: 20px;
|
|
|
+
|
|
|
+ .no-more-text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #584735;
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|