|
|
|
@ -61,12 +61,77 @@ |
|
|
|
@click="onBannerClick" |
|
|
|
></uv-swiper> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 书本列表(当选择非"全部"tab时显示) --> |
|
|
|
<view class="book-list-container" v-if="showBookList"> |
|
|
|
<view class="book-list-results"> |
|
|
|
<view |
|
|
|
v-for="(book, index) in bookList" |
|
|
|
:key="index" |
|
|
|
class="book-list-item" |
|
|
|
@click="goToBookDetail(book)" |
|
|
|
> |
|
|
|
<view class="book-list-cover"> |
|
|
|
<image :src="book.booksImg" mode="aspectFill"></image> |
|
|
|
</view> |
|
|
|
<view class="book-list-info"> |
|
|
|
<view class="book-list-title">{{ book.booksName }}</view> |
|
|
|
<view class="book-list-author">{{ book.booksAuthor }}</view> |
|
|
|
<view class="book-list-meta"> |
|
|
|
<view class="book-list-duration"> |
|
|
|
<image src="/static/play-icon.png" mode="aspectFill" class="book-list-icon"></image> |
|
|
|
<text>{{ book.duration }}</text> |
|
|
|
</view> |
|
|
|
<view class="book-list-membership" :class="classMap[book.vipInfo.title]"> |
|
|
|
{{ book.vipInfo.title }} |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<uv-loading-icon text="加载中" textSize="30rpx" v-if="isLoadingBooks"></uv-loading-icon> |
|
|
|
<uv-empty v-else-if="bookList.length === 0"></uv-empty> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 文章列表 --> |
|
|
|
<view class="article-section" v-if="articleList.length > 0 && !showBookList"> |
|
|
|
<view class="section-header"> |
|
|
|
<text class="section-title">精选文章 </text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<scroll-view |
|
|
|
show-scrollbar="false" |
|
|
|
class="article-scroll" |
|
|
|
scroll-x="true" |
|
|
|
> |
|
|
|
<view class="article-list"> |
|
|
|
<view |
|
|
|
v-for="(article, index) in articleList" |
|
|
|
:key="article.id" |
|
|
|
class="article-item" |
|
|
|
@click="goArticleDetail(article)" |
|
|
|
> |
|
|
|
<view class="article-content"> |
|
|
|
<view class="article-title">{{ article.title }}</view> |
|
|
|
<view class="article-meta"> |
|
|
|
<view class="article-tag">精选</view> |
|
|
|
<text class="article-time">{{ formatTime(article.createTime) }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="article-arrow"> |
|
|
|
<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 根据labelBooksData动态渲染书籍区块 --> |
|
|
|
<view |
|
|
|
v-for="(labelData, labelIndex) in labelBooksData" |
|
|
|
:key="labelIndex" |
|
|
|
class="section" |
|
|
|
v-if="!showBookList" |
|
|
|
> |
|
|
|
<view class="section-header" @click="goLabel(labelData.labelInfo)"> |
|
|
|
<text class="section-title">{{ labelData.labelInfo.title }}</text> |
|
|
|
@ -77,6 +142,7 @@ |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 第一个label:今日更新样式 --> |
|
|
|
<!-- |
|
|
|
<scroll-view |
|
|
|
v-if="labelIndex === 0" |
|
|
|
show-scrollbar="false" |
|
|
|
@ -103,11 +169,12 @@ |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
</scroll-view> --> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 第二个label:推荐书籍样式 --> |
|
|
|
<scroll-view |
|
|
|
v-else-if="labelIndex === 1" |
|
|
|
v-if="labelIndex === 0" |
|
|
|
show-scrollbar="false" |
|
|
|
class="content-scroll" |
|
|
|
scroll-x="true" |
|
|
|
@ -157,7 +224,7 @@ |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 推荐内容列表 --> |
|
|
|
<view class="section"> |
|
|
|
<view class="section" v-if="!showBookList"> |
|
|
|
<view class="recommend-list"> |
|
|
|
<view |
|
|
|
@click="goPlan(item.id, item.type)" |
|
|
|
@ -230,6 +297,17 @@ export default { |
|
|
|
// 根据label获取的书籍数据(二维数组) |
|
|
|
labelBooksData: [], |
|
|
|
|
|
|
|
// 书本列表数据(用于tab切换时显示) |
|
|
|
bookList: [], |
|
|
|
isLoadingBooks: false, |
|
|
|
showBookList: false, // 控制是否显示书本列表 |
|
|
|
|
|
|
|
// 类型映射表(从搜索页面复制) |
|
|
|
classMap: { |
|
|
|
'蕾朵会员': 'book-membership-premium', |
|
|
|
'盛放会员': 'book-membership-vip', |
|
|
|
'萌芽会员': 'book-membership-basic', |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 推荐列表数据 |
|
|
|
@ -237,6 +315,8 @@ export default { |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
// 文章列表数据 |
|
|
|
articleList: [], |
|
|
|
|
|
|
|
currentVideo: '', |
|
|
|
|
|
|
|
@ -273,9 +353,11 @@ export default { |
|
|
|
methods: { |
|
|
|
// 检测设备类型 |
|
|
|
detectDevice() { |
|
|
|
let screenWidth = 0 |
|
|
|
|
|
|
|
// #ifdef H5 |
|
|
|
const userAgent = navigator.userAgent |
|
|
|
const screenWidth = window.innerWidth || document.documentElement.clientWidth |
|
|
|
screenWidth = window.innerWidth || document.documentElement.clientWidth |
|
|
|
const screenHeight = window.innerHeight || document.documentElement.clientHeight |
|
|
|
|
|
|
|
// 判断是否为平板设备 |
|
|
|
@ -294,7 +376,7 @@ export default { |
|
|
|
// #ifndef H5 |
|
|
|
// 非H5环境,通过系统信息判断 |
|
|
|
const systemInfo = uni.getSystemInfoSync() |
|
|
|
const screenWidth = systemInfo.screenWidth |
|
|
|
screenWidth = systemInfo.screenWidth |
|
|
|
this.isTablet = screenWidth >= 768 |
|
|
|
// #endif |
|
|
|
}, |
|
|
|
@ -307,7 +389,15 @@ export default { |
|
|
|
// 切换Tab |
|
|
|
async switchTab(index) { |
|
|
|
this.activeTab = index |
|
|
|
await this.getBooksByLabels() |
|
|
|
|
|
|
|
if (index === 0) { |
|
|
|
// 第一个tab(全部)显示原有内容 |
|
|
|
this.showBookList = false |
|
|
|
await this.getBooksByLabels() |
|
|
|
} else { |
|
|
|
// 其他tab显示书本列表 |
|
|
|
await this.getBookList() |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 轮播图点击事件 |
|
|
|
@ -382,14 +472,32 @@ export default { |
|
|
|
})) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取文章列表 |
|
|
|
async getArticleList() { |
|
|
|
try { |
|
|
|
const articleRes = await this.$api.home.getArticle() |
|
|
|
if (articleRes.code === 200) { |
|
|
|
this.articleList = articleRes.result || [] |
|
|
|
console.log('文章列表数据:', this.articleList) |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('获取文章列表失败:', error) |
|
|
|
this.articleList = [] |
|
|
|
} |
|
|
|
}, |
|
|
|
// 获取书籍分类 |
|
|
|
async getCategory() { |
|
|
|
const categoryRes = await this.$api.book.category() |
|
|
|
if (categoryRes.code === 200){ |
|
|
|
this.tabs = categoryRes.result.map(item => ({ |
|
|
|
title:item.title, |
|
|
|
// 硬编码第一个tab为"全部" |
|
|
|
this.tabs = [ |
|
|
|
{ title: '全部', id: null }, |
|
|
|
...categoryRes.result.map(item => ({ |
|
|
|
title: item.title, |
|
|
|
id: item.id |
|
|
|
})) |
|
|
|
})) |
|
|
|
] |
|
|
|
} |
|
|
|
}, |
|
|
|
// 获取书籍标签 |
|
|
|
@ -453,6 +561,104 @@ export default { |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取书本列表(用于tab切换) |
|
|
|
async getBookList() { |
|
|
|
if (this.activeTab === 0) { |
|
|
|
// 第一个tab(全部)不显示书本列表,显示原有内容 |
|
|
|
this.showBookList = false |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
this.isLoadingBooks = true |
|
|
|
this.showBookList = true |
|
|
|
|
|
|
|
try { |
|
|
|
const params = { |
|
|
|
category: this.tabs[this.activeTab].id, |
|
|
|
pageNo: 1, |
|
|
|
pageSize: 20 |
|
|
|
} |
|
|
|
|
|
|
|
const res = await this.$api.book.list(params) |
|
|
|
if (res.code === 200) { |
|
|
|
this.bookList = res.result.records || [] |
|
|
|
} else { |
|
|
|
this.bookList = [] |
|
|
|
console.error('获取书本列表失败:', res) |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('获取书本列表出错:', error) |
|
|
|
this.bookList = [] |
|
|
|
} finally { |
|
|
|
this.isLoadingBooks = false |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 跳转到书本详情(从搜索页面复制) |
|
|
|
goToBookDetail(book) { |
|
|
|
uni.navigateTo({ |
|
|
|
url: '/subPages/home/directory?id=' + book.id |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 跳转文章详情 |
|
|
|
goArticleDetail(article) { |
|
|
|
console.log('点击文章:', article) |
|
|
|
uni.navigateTo({ |
|
|
|
url: `/subPages/home/article?id=${article.id}` |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 跳转更多文章页面 |
|
|
|
goMoreArticles() { |
|
|
|
uni.navigateTo({ |
|
|
|
url: '/subPages/home/articleList' |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 格式化时间 |
|
|
|
formatTime(timeStr) { |
|
|
|
if (!timeStr) return '' |
|
|
|
|
|
|
|
try { |
|
|
|
// 处理iOS兼容性问题,将 "2025-10-23 16:36:43" 格式转换为 "2025/10/23 16:36:43" |
|
|
|
let formattedTimeStr = timeStr.replace(/-/g, '/') |
|
|
|
const date = new Date(formattedTimeStr) |
|
|
|
|
|
|
|
// 检查日期是否有效 |
|
|
|
if (isNaN(date.getTime())) { |
|
|
|
console.warn('Invalid date format:', timeStr) |
|
|
|
return '' |
|
|
|
} |
|
|
|
const now = new Date() |
|
|
|
const diff = now - date |
|
|
|
|
|
|
|
// 小于1分钟 |
|
|
|
if (diff < 60000) { |
|
|
|
return '刚刚' |
|
|
|
} |
|
|
|
// 小于1小时 |
|
|
|
if (diff < 3600000) { |
|
|
|
return Math.floor(diff / 60000) + '分钟前' |
|
|
|
} |
|
|
|
// 小于1天 |
|
|
|
if (diff < 86400000) { |
|
|
|
return Math.floor(diff / 3600000) + '小时前' |
|
|
|
} |
|
|
|
// 小于7天 |
|
|
|
if (diff < 604800000) { |
|
|
|
return Math.floor(diff / 86400000) + '天前' |
|
|
|
} |
|
|
|
|
|
|
|
// 超过7天显示具体日期 |
|
|
|
const month = date.getMonth() + 1 |
|
|
|
const day = date.getDate() |
|
|
|
return `${month}月${day}日` |
|
|
|
} catch (error) { |
|
|
|
return '' |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 关闭视频弹窗 |
|
|
|
closeVideoModal() { |
|
|
|
this.$refs.videoModal.close() |
|
|
|
@ -485,7 +691,7 @@ export default { |
|
|
|
this.detectDevice() |
|
|
|
|
|
|
|
// 先获取基础数据 |
|
|
|
await Promise.all([this.getBanner(), this.getSignup(), this.getCategory(), this.getLabel()]) |
|
|
|
await Promise.all([this.getBanner(), this.getSignup(), this.getCategory(), this.getLabel(), this.getArticleList()]) |
|
|
|
|
|
|
|
// 根据label数据获取对应的书籍 |
|
|
|
await this.getBooksByLabels() |
|
|
|
@ -614,7 +820,31 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// 内容区块 |
|
|
|
|
|
|
|
.section { |
|
|
|
margin-top: 40rpx; |
|
|
|
|
|
|
|
@ -933,4 +1163,192 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 文章列表样式 |
|
|
|
.article-section { |
|
|
|
margin-top: 40rpx; |
|
|
|
|
|
|
|
.article-scroll { |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
.article-list { |
|
|
|
display: flex; |
|
|
|
padding: 0 30rpx; |
|
|
|
gap: 24rpx; |
|
|
|
|
|
|
|
.article-item { |
|
|
|
flex-shrink: 0; |
|
|
|
width: 580rpx; |
|
|
|
height: 120rpx; |
|
|
|
background: #f8f9fa; |
|
|
|
border-radius: 16rpx; |
|
|
|
padding: 24rpx; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
|
|
&:active { |
|
|
|
transform: scale(0.98); |
|
|
|
background: #f0f1f2; |
|
|
|
} |
|
|
|
|
|
|
|
.article-content { |
|
|
|
flex: 1; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 12rpx; |
|
|
|
|
|
|
|
.article-title { |
|
|
|
font-size: 32rpx; |
|
|
|
font-weight: 600; |
|
|
|
color: $primary-text-color; |
|
|
|
line-height: 1.4; |
|
|
|
display: -webkit-box; |
|
|
|
-webkit-box-orient: vertical; |
|
|
|
-webkit-line-clamp: 2; |
|
|
|
overflow: hidden; |
|
|
|
word-break: break-word; |
|
|
|
} |
|
|
|
|
|
|
|
.article-meta { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 16rpx; |
|
|
|
|
|
|
|
.article-tag { |
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
|
|
color: #fff; |
|
|
|
font-size: 20rpx; |
|
|
|
padding: 4rpx 12rpx; |
|
|
|
border-radius: 12rpx; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.article-time { |
|
|
|
font-size: 24rpx; |
|
|
|
color: $secondary-text-color; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.article-arrow { |
|
|
|
margin-left: 16rpx; |
|
|
|
opacity: 0.6; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 书本列表样式(从搜索页面复制) |
|
|
|
.book-list-container { |
|
|
|
background: #fff; |
|
|
|
min-height: 50vh; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-results { |
|
|
|
padding: 32rpx; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 32rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
background: #F8F8F8; |
|
|
|
height: 212rpx; |
|
|
|
gap: 16rpx; |
|
|
|
border-radius: 16rpx; |
|
|
|
padding: 0rpx 16rpx; |
|
|
|
|
|
|
|
&:last-child { |
|
|
|
border-bottom: none; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-cover { |
|
|
|
width: 136rpx; |
|
|
|
height: 180rpx; |
|
|
|
border-radius: 16rpx; |
|
|
|
overflow: hidden; |
|
|
|
margin-right: 16rpx; |
|
|
|
|
|
|
|
image { |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-info { |
|
|
|
flex: 1; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
justify-content: space-between; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-title { |
|
|
|
font-size: 32rpx; |
|
|
|
font-weight: 600; |
|
|
|
color: $primary-text-color; |
|
|
|
line-height: 48rpx; |
|
|
|
letter-spacing: 0; |
|
|
|
margin-bottom: 12rpx; |
|
|
|
overflow: hidden; |
|
|
|
text-overflow: ellipsis; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-author { |
|
|
|
font-size: 24rpx; |
|
|
|
color: $secondary-text-color; |
|
|
|
margin-bottom: 16rpx; |
|
|
|
overflow: hidden; |
|
|
|
text-overflow: ellipsis; |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-meta { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-duration { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
font-size: 22rpx; |
|
|
|
color: #999; |
|
|
|
|
|
|
|
.book-list-icon { |
|
|
|
width: 18rpx; |
|
|
|
height: 18rpx; |
|
|
|
} |
|
|
|
|
|
|
|
text { |
|
|
|
margin-left: 8rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.book-list-membership { |
|
|
|
padding: 8rpx 16rpx; |
|
|
|
border-radius: 8rpx; |
|
|
|
font-size: 24rpx; |
|
|
|
color: #211508; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.book-membership-premium { |
|
|
|
background: #E9F1FF; |
|
|
|
border: 2rpx solid #C4DAFF; |
|
|
|
} |
|
|
|
|
|
|
|
.book-membership-vip { |
|
|
|
background: #FFF4E9; |
|
|
|
border: 2rpx solid #FFE2C4; |
|
|
|
} |
|
|
|
|
|
|
|
.book-membership-basic { |
|
|
|
background: #FFE9E9; |
|
|
|
border: 2rpx solid #FFDBC4; |
|
|
|
} |
|
|
|
</style> |