|
|
- <template>
- <view class="home-container">
- <!-- 開動頁面組件 -->
- <SplashScreen @close="onSplashClose" />
-
- <!-- 状态栏安全区域 -->
- <uv-status-bar></uv-status-bar>
-
- <!-- 顶部搜索栏 -->
- <view class="header">
- <view class="search-container" @click="goSearch">
- <uv-search
- placeholder="请输入要查询的内容"
- :show-action="false"
- shape="round"
- bg-color="#f5f5f5"
- color="#666"
- height="38"
- margin="0 200rpx 0 0"
- placeholderColor="#c6c6c6"
- ></uv-search>
- </view>
-
- </view>
-
- <!-- Tab栏 -->
- <view class="tab-container">
- <scroll-view show-scrollbar="false" class="tab-scroll" scroll-x="true" >
- <view class="tab-list">
- <view
- v-for="(tab, index) in tabs"
- :key="index"
- class="tab-item"
- :class="{ active: activeTab === index }"
- @click="switchTab(index)"
- >
- {{ tab.title }}
- </view>
- </view>
- </scroll-view>
- </view>
-
- <!-- 轮播图 -->
- <view class="swiper-container">
- <uv-swiper
- :list="bannerList"
- keyName="image"
- height="121"
- radius="12"
- indicator
- ndicatorInactiveColor="#fff"
- :loading="false"
- indicatorMode="dot"
- indicatorActiveColor="#F95A01"
- @click="onBannerClick"
- ></uv-swiper>
- </view>
-
- <!-- 根据labelBooksData动态渲染书籍区块 -->
- <view
- v-for="(labelData, labelIndex) in labelBooksData"
- :key="labelIndex"
- class="section"
- >
- <view class="section-header" @click="goLabel(labelData.labelInfo)">
- <text class="section-title">{{ labelData.labelInfo.title }}</text>
- <view class="section-more">
- <text>更多</text>
- <uv-icon name="arrow-right" size="14" color="#888"></uv-icon>
- </view>
- </view>
-
- <!-- 第一个label:今日更新样式 -->
- <scroll-view
- v-if="labelIndex === 0"
- show-scrollbar="false"
- class="content-scroll"
- scroll-x="true"
- >
- <view class="content-list">
- <view
- v-for="(item, index) in labelData.books"
- :key="index"
- class="content-item"
- @click="goBook(item)"
- >
- <view class="item-cover">
- <image :src="item.booksImg || '/static/default-image.png'" mode="aspectFill"></image>
- </view>
- <view class="item-info">
- <text class="item-title">{{ item.booksName }}</text>
- <text class="item-author">{{ item.booksAuthor }}</text>
- <view class="item-duration">
- <image src="/static/play-icon.png" class="item-icon" />
- <text>{{ item.duration }}</text>
- </view>
- </view>
- </view>
- </view>
- </scroll-view>
-
- <!-- 第二个label:推荐书籍样式 -->
- <scroll-view
- v-else-if="labelIndex === 1"
- show-scrollbar="false"
- class="content-scroll"
- scroll-x="true"
- >
- <view class="book-list">
- <view
- v-for="(book, index) in labelData.books"
- :key="index"
- class="book-item"
- @click="goBook(book)"
- >
- <view class="book-cover">
- <image :src="book.booksImg || '/static/default-image.png'" mode="aspectFill"></image>
- <view class="book-overlay">
- <view class="book-duration" v-if="book.duration">
- <image src="/static/alarm-icon.png" class="book-duration-icon" />
- <text class="book-duration-text">{{ book.duration }}</text>
- </view>
- <view class="book-title">{{ book.booksName }}</view>
- </view>
- </view>
- </view>
- </view>
- </scroll-view>
-
- <!-- 第三个及以后的label:网格样式 -->
- <view v-else class="book-grid">
- <view
- v-for="(book, index) in labelData.books"
- :key="index"
- class="book-grid-item"
- @click="goBook(book)"
- >
- <view class="book-grid-cover">
- <image :src="book.booksImg || '/static/default-image.png'" mode="aspectFill"></image>
- </view>
- <!-- <view class="book-grid-info">
- <text class="book-grid-title">{{ book.booksName }}</text>
- <view class="book-grid-meta">
- <text class="book-grid-grade">{{ book.categoryName }}/</text>
- <image src="/static/play-icon.png" class="book-grid-duration-icon" />
- <text class="book-grid-duration">{{ book.duration }}</text>
- </view>
- </view> -->
- </view>
- </view>
- </view>
-
- <!-- 推荐内容列表 -->
- <view class="section">
- <view class="recommend-list">
- <view
- @click="goPlan(item.id, item.type)"
- v-for="(item, index) in recommendList"
- :key="index"
- class="recommend-item"
- >
- <image :src="item.img" mode="aspectFill" class="recommend-image"></image>
- </view>
- </view>
- </view>
-
- <!-- 视频播放弹窗 -->
- <uv-modal
- ref="videoModal"
- title="视频播放"
- :show-cancel-button="false"
- :show-confirm-button="false"
- width="90%"
- :close-on-click-overlay="true"
- @close="closeVideoModal"
- >
- <template #default>
- <view class="video-container">
- <video
- v-if="currentVideo"
- :src="currentVideo"
- controls
- autoplay
- :show-fullscreen-btn="true"
- :show-play-btn="true"
- :show-center-play-btn="true"
- style="width: 100%; height: 400rpx; border-radius: 8rpx;"
- @error="onVideoError"
- @play="onVideoPlay"
- @pause="onVideoPause"
- ></video>
- <view v-else class="video-loading">
- <text>视频加载中...</text>
- </view>
- </view>
- </template>
- </uv-modal>
- </view>
- </template>
-
- <script>
- import SplashScreen from '../components/SplashScreen.vue'
-
- export default {
- components: {
- SplashScreen
- },
- data() {
- return {
- // Tab数据
- tabs: [ ],
- activeTab: 0,
-
- // 轮播图数据
- bannerList: [
-
- ],
-
- // 书籍分类
- labels: [
-
- ],
-
- // 根据label获取的书籍数据(二维数组)
- labelBooksData: [],
-
-
-
- // 推荐列表数据
- recommendList: [
-
- ],
-
-
- currentVideo: ''
- }
- },
-
- methods: {
- // 開動頁面關閉處理
- onSplashClose() {
- console.log('開動頁面已關閉')
- // 可以在這裡添加其他邏輯,比如統計、初始化等
- },
-
- // 切换Tab
- async switchTab(index) {
- this.activeTab = index
- await this.getBooksByLabels()
- },
-
- // 轮播图点击事件
- onBannerClick(index) {
- console.log('点击轮播图:', index)
- const bannerItem = this.bannerList[index]
- if (!bannerItem) return
-
- // 根据 typ 字段判断跳转类型
- switch(bannerItem.typ) {
- case '1': // 课程详情
- if (bannerItem.bookId) {
- uni.navigateTo({
- url: '/subPages/home/directory?id=' + bannerItem.bookId
- })
- }
- break
- case '2': // 视频播放
- if (bannerItem.video) {
- this.$refs.videoModal.open()
- this.currentVideo = bannerItem.video
- }
- break
- case '0': // 富文本内容
- if (bannerItem.content) {
- uni.navigateTo({
- url: '/subPages/home/richtext?content=' + encodeURIComponent(bannerItem.content)
- })
- }
- break
- default:
- console.log('未知的轮播图类型:', bannerItem.typ)
- }
- },
- // 跳转计划定制
- goPlan(id, type) {
- uni.navigateTo({
- url: '/subPages/home/plan?id=' + id + '&type=' + type
- })
- },
- goSearch() {
- uni.navigateTo({
- url: '/subPages/home/search'
- })
- },
- goBook(book) {
- uni.navigateTo({
- url: '/subPages/home/directory?id=' + book.id
- })
- },
- async getBanner() {
- const bannerRes = await this.$api.home.getBanner()
- if (bannerRes.code === 200){
- this.bannerList = bannerRes.result.map(item => ({
- image: item.img,
- title: item.title,
- typ: item.typ,
- bookId: item.bookId,
- video: item.video,
- content: item.content,
- id: item.id
- }))
- }
- },
- async getSignup() {
- const signupRes = await this.$api.home.getLink()
- if (signupRes.code === 200){
- this.recommendList = signupRes.result.map(item => ({
- img: item.img,
- id: item.id,
- type: item.type
- }))
- }
- },
- // 获取书籍分类
- async getCategory() {
- const categoryRes = await this.$api.book.category()
- if (categoryRes.code === 200){
- this.tabs = categoryRes.result.map(item => ({
- title:item.title,
- id: item.id
- }))
- }
- },
- // 获取书籍标签
- async getLabel() {
- const labelRes = await this.$api.book.label()
- if (labelRes.code === 200){
- this.labels = labelRes.result.map(item => ({
- title:item.lable,
- id: item.id
- }))
- }
- },
-
-
- // 根据label数组获取书籍数据
- async getBooksByLabels() {
- if (!this.labels || this.labels.length === 0) {
- console.log('labels数据为空,无法获取书籍')
- return
- }
-
- try {
- // 创建请求数组,每个label发起一次请求
- const requests = this.labels.map(label =>
- this.$api.book.list({
- label: label.id,
- pageNo: 1,
- pageSize: 6,
- category: this.tabs[this.activeTab].id
- }, false)
- )
-
- // 并发执行所有请求
- const responses = await Promise.all(requests)
-
- // 创建二维数组存储结果
- this.labelBooksData = responses.map((response, index) => {
- if (response.code === 200) {
- return {
- labelInfo: this.labels[index],
- books: response.result.records || []
- }
- } else {
- console.error(`获取label ${this.labels[index].title} 的书籍失败:`, response)
- return {
- labelInfo: this.labels[index],
- books: []
- }
- }
- })
-
- console.log('根据label获取的书籍数据:', this.labelBooksData)
- } catch (error) {
- console.error('获取书籍数据失败:', error)
- this.labelBooksData = []
- }
- },
- goLabel(label){
- uni.navigateTo({
- url: '/subPages/home/search?label=' + label.id
- })
- },
-
- // 关闭视频弹窗
- closeVideoModal() {
- this.$refs.videoModal.close()
- this.currentVideo = ''
- },
-
- // 视频错误处理
- onVideoError(e) {
- console.error('视频播放错误:', e)
- uni.showToast({
- title: '视频播放失败',
- icon: 'error'
- })
- this.closeVideoModal()
- },
-
- // 视频开始播放
- onVideoPlay() {
- console.log('视频开始播放')
- },
-
- // 视频暂停
- onVideoPause() {
- console.log('视频暂停播放')
- }
- },
-
- async onShow() {
- // 先获取基础数据
- await Promise.all([this.getBanner(), this.getSignup(), this.getCategory(), this.getLabel()])
-
- // 根据label数据获取对应的书籍
- await this.getBooksByLabels()
- }
- }
- </script>
-
- <style lang="scss" scoped>
- .home-container {
- background: #fff;
- min-height: 100vh;
- padding-bottom: 80rpx;
- }
-
- // 顶部搜索栏
- .header {
-
- display: flex;
- align-items: center;
- padding: 6rpx 32rpx;
- background: #fff;
-
- .search-container {
- flex: 1;
- }
-
- }
-
- // Tab栏
- .tab-container {
- background: #fff;
- // border-bottom: 1px solid #f0f0f0;
-
- top: 0;
- left: 0;
- right: 0;
- z-index: 999;
- .tab-scroll {
- white-space: nowrap;
-
- .tab-list {
- display: flex;
- padding: 0 20rpx;
-
- .tab-item {
- flex-shrink: 0;
- padding: 20rpx 20rpx;
- font-size: 32rpx;
- color: #666;
- position: relative;
-
- &.active {
- color: $primary-text-color;
- font-weight: 700;
-
- &::after {
- content: '';
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 22rpx;
- height: 4rpx;
- background: $primary-text-color;
- border-radius: 2rpx;
- }
- }
- }
- }
- }
- }
-
- // 轮播图容器
- .swiper-container {
- margin: 20rpx;
- border-radius: 12rpx;
- overflow: hidden;
- }
-
- // 内容区块
- .section {
- margin-top: 40rpx;
-
- .section-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 30rpx ;
- margin-bottom: 24rpx;
- .section-title {
- font-size: 36rpx;
- // font-weight: 600;
- color: $primary-text-color;
- }
-
- .section-more {
- display: flex;
- align-items: center;
- gap: 4rpx;
-
- text {
- font-size: 24rpx;
- color: $secondary-text-color;
- }
- }
- }
-
- .content-scroll {
- white-space: nowrap;
- }
- }
-
- // 今日更新列表
- .content-list {
- display: flex;
- padding: 0 30rpx;
- gap: 32rpx;
-
- .content-item {
- flex-shrink: 0;
- width: 602rpx;
- height: 212rpx;
- display: flex;
- align-items: center;
- background: #F8F8F8;
- padding: 16rpx;
- border-radius: 16rpx;
- gap: 16rpx;
- .item-cover {
- width: 136rpx;
- height: 200rpx;
- border-radius: 16rpx;
- // overflow: hidden;
-
- image {
- width: 136rpx;
- height: 200rpx;
- }
- }
-
- .item-info {
- // padding-top: 20rpx;
- gap: 16rpx;
- display: flex;
- flex-direction: column;
- .item-title {
-
- font-size: 32rpx;
- font-weight: 700;
- color: $primary-text-color;
- letter-spacing: 0;
- line-height: 48rpx;
- // margin-bottom: 12rpx;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .item-author {
-
- font-size: 24rpx;
- color: $secondary-text-color;
- // margin-bottom: 8rpx;
- letter-spacing: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .item-duration {
- gap: 12rpx;
- display: flex;
- align-items: center;
- font-size: 22rpx;
- letter-spacing: 0;
- color: $secondary-text-color;
- .item-icon{
- width: 22rpx;
- height: 25rpx;
- }
- }
- }
- }
- }
-
- // 推荐书籍列表
- .book-list {
- display: flex;
- padding: 0 30rpx;
- gap: 32rpx;
-
- .book-item {
- flex-shrink: 0;
- width: 270rpx;
- transition: transform 0.3s ease, box-shadow 0.3s ease;
-
- &:active {
- transform: scale(0.98);
- }
-
- .book-cover {
- width: 100%;
- height: 360rpx;
- border-radius: 16rpx;
- overflow: hidden;
- position: relative;
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.15);
- transition: box-shadow 0.3s ease, transform 0.3s ease;
-
- &:active {
- box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.25);
- transform: translateY(-2rpx);
- }
-
- image {
- width: 100%;
- height: 100%;
- transition: transform 0.3s ease;
- }
-
-
- .book-overlay {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- width: 100%;
- height: 140rpx;
- padding: 20rpx 16rpx 12rpx;
- box-sizing: border-box;
-
- /* 优化的渐变遮罩效果 */
- background: linear-gradient(
- 180deg,
- rgba(0, 0, 0, 0) 0%,
- rgba(0, 0, 0, 0.3) 30%,
- rgba(0, 0, 0, 0.7) 70%,
- rgba(0, 0, 0, 0.85) 100%
- );
-
- /* 增强的毛玻璃效果 */
- backdrop-filter: blur(8px) saturate(1.2);
- -webkit-backdrop-filter: blur(8px) saturate(1.2);
-
- /* 添加微妙的边框 */
- border-top: 1px solid rgba(255, 255, 255, 0.1);
-
- /* 平滑过渡效果 */
- transition: all 0.3s ease;
-
- .book-duration{
- display: flex;
- align-items: center;
- gap: 6rpx;
- margin-bottom: 8rpx;
-
- &-icon{
- width: 22rpx;
- height: 22rpx;
- opacity: 0.9;
- }
- &-text{
- font-size: 20rpx;
- font-weight: 500;
- color: rgba(255, 255, 255, 0.9);
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
- }
- }
-
- .book-title {
- max-width: 220rpx;
- font-size: 24rpx;
- font-weight: 600;
- line-height: 1.3;
- color: #ffffff;
- text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
-
- /* 文本截断优化 */
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- overflow: hidden;
- word-break: break-word;
- white-space: normal;
- }
- }
- }
-
- }
- }
-
- // 书籍网格布局
- .book-grid {
- display: flex;
- flex-wrap: wrap;
- padding: 0 30rpx;
- gap: 32rpx;
-
- .book-grid-item {
- width: 208rpx;
- display: flex;
- flex-direction: column;
- // backdrop-filter: red;
- .book-grid-cover {
- box-shadow: 0px 4px 4px 0px #C0BCBA75;
-
- width: 100%;
- height: 278rpx;
- border-radius: 16rpx;
- overflow: hidden;
- margin-bottom: 16rpx;
-
- image {
- width: 100%;
- height: 100%;
- }
- }
-
- .book-grid-info {
- width: 208rpx;
- padding: 6rpx;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- .book-grid-title {
- font-size: 28rpx;
- font-weight: 700;
- color: $primary-text-color;
- margin-bottom: 14rpx;
-
- }
-
- .book-grid-meta {
- display: flex;
- align-items: center;
- // gap: 16rpx;
- .book-grid-duration-icon {
- width: 24rpx;
- height: 24rpx;
- margin-right: 12rpx;
- }
- .book-grid-grade {
- font-size: 24rpx;
- color: $secondary-text-color;
- margin-right: 8rpx;
- }
-
- .book-grid-duration {
- font-size: 24rpx;
- color: $secondary-text-color;
- }
- }
- }
- }
- }
-
- // 推荐列表样式
- .recommend-list {
- padding: 0 30rpx;
-
- .recommend-item {
- width: 100%;
- height: 200rpx;
- margin-bottom: 48rpx;
- border-radius: 32rpx;
- overflow: hidden;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- .recommend-image {
- width: 100%;
- height: 100%;
- }
- }
- }
-
- // 视频弹窗样式
- .video-container {
- position: relative;
- padding: 20rpx 0;
-
- .video-loading {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 400rpx;
- background: #f5f5f5;
- border-radius: 8rpx;
-
- text {
- font-size: 28rpx;
- color: #999;
- }
- }
- }
- </style>
|