|
|
<template> <div class="page-wrapper page-four-wrapper"> <div class="page-four"> <div class="four-video"> <!-- {{ slideData[videoIndex].title }} --> <h4>宣传视频</h4> <el-carousel ref="carousel" indicator-position="none" :autoplay="false" :autoplay-hover-pause="true" @setActiveItem="setActiveItem" @change="carouselChange" > <div v-if="slideData && slideData.length > 0"> <el-carousel-item v-for="(item, index) in slideData" :key="index"> <video ref="videos" class="tsgz-video" width="100%" height="100%" controls preload="auto" :src="item.cover" :poster="poster" autoplay type="video/mp4" muted @ended="playNextVideo(index)" @loadedmetadata="playVideo" > 您的浏览器不支持 video 标签。 </video> </el-carousel-item> </div> <el-empty v-else description="暂无视频" style="height: 710px" :image-size="40" image="" /> </el-carousel> </div> <div class="four-right"> <div class="four-notice"> <div class="database-title">通知公告</div> <div class="seamless-warp"> <swiper ref="mySwiper" :options="swiperOption" class="big-list"> <swiper-slide v-for="(item,index) in noticeList" :key="index"> <div class="notice-text"> <div class="notice-title"> <span>{{ item.title }}</span> <span>{{ item.startTime | parseTime('{y}-{m}-{d}') }}</span> </div> <div style="width: calc(100%); height: .5rem;" /> <p :ref="el => { if (el) marqueeRefs[index] = el }" v-html="item.context" /> </div> </swiper-slide> </swiper> </div> </div> <div class="four-ranking lending-ranking"> <div class="database-title">图书借阅排行榜</div> <div class="ranking-cont"> <ul class="ranking-title"> <li style="width: 0.725rem;">排名</li> <li style="flex:1; text-align: left;">题名</li> <!-- <li style="flex:1;" /> --> <li style="width: 1.5rem; padding-right: .25rem; text-align: right;">借阅数量</li> </ul> <ul class="ranking-list"> <li v-for="(item,index) in rankingData" :key="index" :class="{ 'hovered': index === currentHover }" style="font-size: .28rem !important; line-height: 36px !important;"> <div style="width: 0.725rem; color: #79B8FF;" :class="[{'ranking-num1':index===0},{'ranking-num2':index===1},{'ranking-num3':index===2}]">{{ index>=3 ? index+1 : null }}</div> <div style="flex:1; text-align: left; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;">{{ item.TITLE }}</div> <!-- <div class="ranking-progress" style="flex:1; align-self: center;"> <el-progress :percentage="item.percentage" :stroke-width="8" :show-text="false" color="#009afb" /> </div> --> <div style="width: 1.5rem; padding-right: .25rem; text-align: right;">{{ item.TOTALNUM }}<i style="padding-left:.0625rem;">次</i></div> </li> </ul> </div> </div> <!-- <div class="four-contact"> <div class="wechat-img"> <img :src="wecharQrCodeSrc"> </div> <span>扫一扫关注我们</span> </div> --> </div> </div> </div></template>
<script>import { FetchInitSetting, FetchTotalResource, FetchNoticeList, FetchSync36 } from '@/api/library'import { swiper, swiperSlide } from 'vue-awesome-swiper'import 'swiper/dist/css/swiper.css'export default { name: 'PageFour', components: { swiper, swiperSlide }, data() { // const _self = this
return { wecharQrCodeSrc: null, currentHover: -1, poster: require('@/assets/images/poster.png'), videoIndex: 0, slideData: [], rankingData: [], noticeList: [], noticeIndex: 0, rankInterval: null, marqueeRefs: [], // 存所有 p 元素
currentIndex: 0, // 当前播放的公告索引
scrollTimer: null, // 滚动动画定时器(防止内存泄漏)
waitTimer: null, // 新增:停留等待定时器
swiperOption: { direction: 'vertical', autoHeight: true, observer: true, observeParents: true, autoplay: false, // 关闭自带自动轮播
loop: true }, config: { waitBeforeScroll: 3000, // 内容加载后先停留3秒再滚动(单位:毫秒)
waitAfterScroll: 1000, // 滚动到底部后停留1秒再切换(单位:毫秒)
scrollSpeed: 60 // 滚动速度(px/秒,数值越小越慢)
} } }, computed: { }, beforeDestroy() { this.destroy() }, created() { this.getNotice() this.getBookRanking() }, activated() { this.getVideoResource() this.load() if (this.rankingData.length !== 0) { this.currentHover = -1 this.rankInterval = setInterval(() => { this.currentHover = (this.currentHover + 1) % this.rankingData.length }, 1000) } }, deactivated() { this.destroy() }, mounted() { // 二维码部分
if (localStorage.getItem('wecharQrCodeSrc')) { this.wecharQrCodeSrc = localStorage.getItem('wecharQrCodeSrc') } else { this.getInitData() } // 缓存重要通知的index
if (localStorage.getItem('noticeIndex')) { this.$nextTick(() => { const index = localStorage.getItem('noticeIndex') this.$refs.mySwiper.swiper.slideTo(index, 1000, true) }) } }, methods: { load() { const videos = this.$refs.videos if (videos) { videos[this.videoIndex].load() videos[this.videoIndex].currentTime = localStorage.getItem('videoCurrentTime') ? localStorage.getItem('videoCurrentTime') : 0 // videos[this.videoIndex].pause()
// setTimeout(() => {
// // videos[this.videoIndex].play()
// }, 2000)
} }, destroy() { clearInterval(this.rankInterval) localStorage.setItem('videoIndex', this.videoIndex) localStorage.setItem('videoCurrentTime', this.$refs.videos[this.videoIndex].currentTime) localStorage.setItem('noticeIndex', this.noticeIndex) this.$refs.videos[this.videoIndex].pause()
this.rankInterval = null
clearTimeout(this.scrollTimer) clearTimeout(this.waitTimer) }, getInitData() { // wecharQrCode 二维码 用/downloadFile/+wecharQrCode
const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API console.log('linkSrc', linkSrc) FetchInitSetting().then(res => { const result = JSON.parse(res.data) this.wecharQrCodeSrc = linkSrc + '/downloadFile' + result.wecharQrCode }) }, getNotice() { FetchNoticeList().then(res => { this.noticeList = res.data this.$nextTick(() => { this.playNoticeByIndex(this.currentIndex) }) }).catch(error => { console.error('Error', error) }) }, // 公告
playNoticeByIndex(index) { clearTimeout(this.scrollTimer) clearTimeout(this.waitTimer)
const pEl = this.marqueeRefs[index] if (!pEl) return
// 1. 重置样式和动画,先让内容完整显示
pEl.classList.remove('scroll-animation') pEl.style.transform = 'translateY(0)' // 强制回到顶部
const container = this.$el.querySelector('.seamless-warp') const containerHeight = container.offsetHeight const contentHeight = pEl.offsetHeight
// 2. 如果内容高度 <= 容器高度(无需滚动)
if (contentHeight <= containerHeight) { // 停留指定时间后切换下一条
this.waitTimer = setTimeout(() => { this.switchToNextNotice() }, this.config.waitBeforeScroll + 2000) // 多停留2秒
return }
// 3. 内容需要滚动:先停留,再滚动
this.waitTimer = setTimeout(() => { // 设置CSS变量(精准计算滚动终点)
pEl.style.setProperty('--content-height', `${contentHeight}px`) pEl.style.setProperty('--container-height', `${containerHeight}px`)
// 计算滚动时长(速度越慢,时长越长)
const scrollDistance = contentHeight - containerHeight // 实际需要滚动的距离
const scrollDuration = scrollDistance / this.config.scrollSpeed
// 设置动画时长并启动滚动
pEl.style.setProperty('--scroll-duration', `${scrollDuration}s`) pEl.classList.add('scroll-animation') console.log('scrollDuration', scrollDuration)
// 4. 滚动完成后,停留一段时间再切换
this.scrollTimer = setTimeout(() => { // 滚动到底部后停留
this.waitTimer = setTimeout(() => { this.switchToNextNotice() }, this.config.waitAfterScroll) }, scrollDuration * 1000) // 等待滚动完成
}, this.config.waitBeforeScroll) // 先停留再滚动
},
// 切换下一条(保证循环)
switchToNextNotice() { // 计算下一个索引(循环)
this.currentIndex = (this.currentIndex + 1) % this.noticeList.length
// 切换swiper
const swiperInstance = this.$refs.mySwiper?.swiper if (swiperInstance) { swiperInstance.slideTo(this.currentIndex) }
// 切换后播放新的一条
this.$nextTick(() => { this.playNoticeByIndex(this.currentIndex) }) }, // 视频资源
getVideoResource() { FetchTotalResource().then(res => { const result = JSON.parse(res.data) const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API this.slideData = result.map((item, index) => { if (item.filePath) { item.cover = linkSrc + '/downloadFile' + item.filePath } else { item.cover = null } return item }) // 下次进入页面时优先缓存的部分
if (localStorage.getItem('videoIndex')) { this.videoIndex = parseInt(localStorage.getItem('videoIndex')) this.$nextTick(() => { this.$refs.carousel.setActiveItem(this.videoIndex) const videos = this.$refs.videos const nextVideo = videos[this.videoIndex] videos.forEach((video) => { video.pause() video.currentTime = 0 }) setTimeout(() => { nextVideo.currentTime = localStorage.getItem('videoCurrentTime') ? localStorage.getItem('videoCurrentTime') : 0 nextVideo.play() }, 2000) }) } }).catch(error => { console.error('Error', error) }) }, playVideo() { this.$refs.videos[this.videoIndex].play().catch(error => { console.error(error) }) }, setActiveItem(index) { this.$refs.carousel.setActiveItem(index) }, carouselChange(index) { const videos = this.$refs.videos this.videoIndex = index videos.forEach((video) => { video.currentTime = 0 // 将视频回到起始时间
video.pause() // 暂停视频播放
}) videos[index].play() }, playNextVideo(index) { const videos = this.$refs.videos let nextIndex = index this.videoIndex = nextIndex if (index < this.slideData.length - 1) { nextIndex = nextIndex + 1 } else { nextIndex = 0 } const carousel = this.$refs.carousel carousel.setActiveItem(nextIndex) const nextVideo = videos[nextIndex] videos.forEach((video) => { video.pause() video.currentTime = 0 }) setTimeout(() => { nextVideo.play() }, 1000) }, getBookRanking() { const currentDate = new Date() // 获取当前日期
currentDate.setDate(currentDate.getDate() - 30) // 将当前日期减去30天
const year = currentDate.getFullYear() // 获取年份
const month = currentDate.getMonth() + 1 // 获取月份(注意月份从0开始,需要加1)
const day = currentDate.getDate() // 获取日期
const formattedDate = `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`
const params = { 'libcode': this.libcode, 'starttime': formattedDate, 'endtime': this.getFormattedDate(new Date()), 'rownum': 5 } FetchSync36(params).then(res => { const result = JSON.parse(res.data) if (result.success && result.resultlist.length > 0) { this.rankingData = result.resultlist.sort((a, b) => b.TOTALNUM - a.TOTALNUM).slice(0, 6) this.rankInterval = setInterval(() => { this.currentHover = (this.currentHover + 1) % this.rankingData.length }, 1000) } else { throw new Error('Failed' + libcode) } }).catch(error => { console.error('Error', error) }) } }}</script>
<style lang="scss" scoped>@import "~@/assets/styles/index.scss";.el-carousel{ margin-top: 0.475rem !important;}::v-deep .el-carousel__container{ height: 8.875rem !important;}video { width: 100%; height: 100%;}
.big-list>.swiper-wrapper>.swiper-slide { height: 100vh; overflow: hidden;}.swiper-container-vertical .swiper-wrapper{ flex-direction: column;}.swiper-container { width: 100%; height: 100%;}</style>
|