大湾社区城市书房智慧大屏
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

408 lines
14 KiB

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