|
|
|
@ -8,10 +8,8 @@ |
|
|
|
<view class="navbar-left" @click="goBack"> |
|
|
|
<uv-icon name="arrow-left" size="20" color="#262626"></uv-icon> |
|
|
|
</view> |
|
|
|
<view class="navbar-title">{{ bookTitle }}</view> |
|
|
|
<view class="navbar-right" @click="showMenu"> |
|
|
|
<uv-icon name="more-dot-fill" size="20" color="#262626"></uv-icon> |
|
|
|
</view> |
|
|
|
<view class="navbar-title">{{ currentPageTitle }}</view> |
|
|
|
|
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
@ -20,7 +18,6 @@ |
|
|
|
class="content-swiper" |
|
|
|
:current="currentPage - 1" |
|
|
|
@change="onSwiperChange" |
|
|
|
|
|
|
|
> |
|
|
|
<swiper-item |
|
|
|
v-for="(page, index) in bookPages" |
|
|
|
@ -29,61 +26,197 @@ |
|
|
|
> |
|
|
|
<view class="content-area" @click="toggleNavbar"> |
|
|
|
<!-- 图片卡片页面 --> |
|
|
|
<view v-if="page.type === 'card'" class="card-content"> |
|
|
|
<view class="card-line"> |
|
|
|
<image src="/static/划重点图标.png" class="card-line-image" mode="aspectFill" /> |
|
|
|
<text class="card-line-text">划线重点</text> |
|
|
|
<view v-for="(item, index) in page" :key="index"> |
|
|
|
<view v-if="item.type === 'card'" class="card-content"> |
|
|
|
<view class="card-line"> |
|
|
|
<image src="/static/划重点图标.png" class="card-line-image" mode="aspectFill" /> |
|
|
|
<text class="card-line-text">划线重点</text> |
|
|
|
</view> |
|
|
|
<image class="card-image" :src="item.image" mode="aspectFill"></image> |
|
|
|
<text class="english-text" user-select @longpress="showWordMeaning(item.wordMeaning)">{{ item.englishText }}</text> |
|
|
|
<text class="chinese-text" user-select>{{ item.chineseText }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 文本页面 --> |
|
|
|
<view v-else-if="item.type === 'text'" class="text-content"> |
|
|
|
<text class="content-text" user-select>{{ item.content }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 文本页面 --> |
|
|
|
<view v-else-if="item.type === 'image'" class="image-container"> |
|
|
|
<image class="content-image" :src="item.imageUrl" mode="aspectFill"></image> |
|
|
|
</view> |
|
|
|
<image class="card-image" :src="page.image" mode="aspectFill"></image> |
|
|
|
<text class="english-text">{{ page.englishText }}</text> |
|
|
|
<text class="chinese-text">{{ page.chineseText }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 文本页面 --> |
|
|
|
<view v-else-if="page.type === 'text'" class="text-content"> |
|
|
|
<text class="content-text">{{ page.content }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 视频页面 --> |
|
|
|
<view v-else-if="page.type === 'video'" class="video-content"> |
|
|
|
<video :src="page.video" class="video-player" controls></video> |
|
|
|
<!-- 视频页面 --> |
|
|
|
<view v-else-if="item.type === 'video'" class="video-content"> |
|
|
|
<video :src="item.video" class="video-player" controls :poster="item.poster"></video> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 会员限制页面 --> |
|
|
|
<view v-else-if="item.type === 'member'" class="member-content"> |
|
|
|
<text class="member-title">{{ item.title }}</text> |
|
|
|
<view class="member-button" @click="unlockBook"> |
|
|
|
<text class="member-button-text">{{ item.buttonText }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</swiper-item> |
|
|
|
</swiper> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 自定义底部控制栏 --> |
|
|
|
<view class="custom-tabbar" :class="{ 'tabbar-hidden': !showNavbar }"> |
|
|
|
<view class="tabbar-content"> |
|
|
|
<view class="tabbar-left"> |
|
|
|
<view class="tab-button" @click="toggleSound"> |
|
|
|
<image src="/static/课程图标.png" class="tab-icon" /> |
|
|
|
<text class="tab-text">课程</text> |
|
|
|
</view> |
|
|
|
<view class="tab-button" @click="toggleSound"> |
|
|
|
<image src="/static/音色切换图标.png" class="tab-icon" /> |
|
|
|
<text class="tab-text">音色切换</text> |
|
|
|
<!-- 音频控制栏 --> |
|
|
|
<view class="audio-controls" :class="{ 'audio-hidden': !isTextPage }"> |
|
|
|
<view class="audio-time"> |
|
|
|
<text class="time-text">{{ formatTime(currentTime) }}</text> |
|
|
|
<view class="progress-container"> |
|
|
|
<view class="progress-bar"> |
|
|
|
<view class="progress-fill" :style="{ width: progressPercent + '%' }"></view> |
|
|
|
<view class="progress-thumb" :style="{ left: progressPercent + '%' }"></view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<text class="time-text">{{ formatTime(totalTime) }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="tabbar-right"> |
|
|
|
<view class="page-controls"> |
|
|
|
<view class="page-numbers"> |
|
|
|
<view |
|
|
|
v-for="(page, index) in bookPages" |
|
|
|
:key="index" |
|
|
|
class="page-number" |
|
|
|
:class="{ 'active': (index + 1) === currentPage }" |
|
|
|
@click="goToPage(index + 1)" |
|
|
|
> |
|
|
|
{{ index + 1 }} |
|
|
|
<view class="audio-controls-row"> |
|
|
|
<view class="control-btn" @click="toggleLoop"> |
|
|
|
<uv-icon name="reload" size="20" :color="isLoop ? '#06DADC' : '#999'"></uv-icon> |
|
|
|
<text class="control-text">循环</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="control-btn" @click="previousPage"> |
|
|
|
<text class="control-text">上一页</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="play-btn" @click="togglePlay"> |
|
|
|
<uv-icon :name="isPlaying ? 'pause-circle-fill' : 'play-circle-fill'" size="40" color="#666"></uv-icon> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="control-btn" @click="nextPage"> |
|
|
|
<text class="control-text">下一页</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="control-btn" @click="toggleSpeed"> |
|
|
|
<text class="control-text">{{ playSpeed }}x</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<view style="background-color: #fff;position: relative;z-index: 100" > |
|
|
|
<view class="tabbar-content"> |
|
|
|
<view class="tabbar-left"> |
|
|
|
<view class="tab-button" @click="toggleCoursePopup"> |
|
|
|
<image src="/static/课程图标.png" class="tab-icon" /> |
|
|
|
<text class="tab-text">课程</text> |
|
|
|
</view> |
|
|
|
<view class="tab-button" @click="toggleSound"> |
|
|
|
<image src="/static/音色切换图标.png" class="tab-icon" /> |
|
|
|
<text class="tab-text">音色切换</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="tabbar-right"> |
|
|
|
<view class="page-controls"> |
|
|
|
<view class="page-numbers"> |
|
|
|
<view |
|
|
|
v-for="(page, index) in bookPages" |
|
|
|
:key="index" |
|
|
|
class="page-number" |
|
|
|
:class="{ 'active': (index + 1) === currentPage }" |
|
|
|
@click="goToPage(index + 1)" |
|
|
|
> |
|
|
|
{{ index + 1 }} |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<uv-safe-bottom></uv-safe-bottom> |
|
|
|
</view> |
|
|
|
<uv-safe-bottom></uv-safe-bottom> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 课程选择弹出窗 --> |
|
|
|
<uv-popup |
|
|
|
mode="bottom" |
|
|
|
ref="coursePopup" |
|
|
|
round="32rpx" |
|
|
|
bg-color="#f8f8f8" |
|
|
|
> |
|
|
|
<view class="course-popup"> |
|
|
|
<view class="popup-header"> |
|
|
|
<view> |
|
|
|
<uv-icon name="arrow-down" color="black" size="20"></uv-icon> |
|
|
|
</view> |
|
|
|
<view class="popup-title">课程</view> |
|
|
|
<view class="popup-title" @click="toggleSort"> |
|
|
|
倒序 |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="course-list"> |
|
|
|
<view |
|
|
|
v-for="(course, index) in displayCourseList" |
|
|
|
:key="course.id" |
|
|
|
class="course-item" |
|
|
|
:class="{ 'active': course.id === currentCourse }" |
|
|
|
@click="selectCourse(course.id)" |
|
|
|
> |
|
|
|
<view class="course-number " :class="{ 'highlight': course.id === currentCourse }">{{ String(course.index).padStart(2, '0') }}</view> |
|
|
|
<view class="course-content"> |
|
|
|
<view class="course-english" :class="{ 'highlight': course.id === currentCourse }">{{ course.english }}</view> |
|
|
|
<view class="course-chinese" :class="{ 'highlight': course.id === currentCourse }">{{ course.chinese }}</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</uv-popup> |
|
|
|
|
|
|
|
<!-- 释义弹出窗 --> |
|
|
|
<uv-popup |
|
|
|
mode="bottom" |
|
|
|
ref="meaningPopup" |
|
|
|
round="32rpx" |
|
|
|
bg-color="#FFFFFF" |
|
|
|
:overlay="true" |
|
|
|
> |
|
|
|
<view class="meaning-popup" v-if="currentWordMeaning"> |
|
|
|
<view class="meaning-header"> |
|
|
|
<view class="close-btn" @click="closeMeaningPopup"> |
|
|
|
<text class="close-text">关闭</text> |
|
|
|
</view> |
|
|
|
<view class="meaning-title">释义</view> |
|
|
|
<view style="width: 80rpx;"></view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="meaning-content"> |
|
|
|
<image class="meaning-image" src="/static/默认图片.png" mode="aspectFill"></image> |
|
|
|
|
|
|
|
<view class="word-info"> |
|
|
|
<view class="word-main"> |
|
|
|
<text class="word-text">{{ currentWordMeaning.word }}</text> |
|
|
|
</view> |
|
|
|
<view class="phonetic-container"> |
|
|
|
<uv-icon name="volume-fill" size="16" color="#000"></uv-icon> |
|
|
|
<text class="phonetic-text">{{ currentWordMeaning.phonetic }}</text> |
|
|
|
</view> |
|
|
|
<view class="word-meaning"> |
|
|
|
<text class="part-of-speech">{{ currentWordMeaning.partOfSpeech }}</text> |
|
|
|
<text class="meaning-text">{{ currentWordMeaning.meaning }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="knowledge-gain"> |
|
|
|
<view class="knowledge-header"> |
|
|
|
<image src="/static/知识收获图标.png" class="knowledge-icon" mode="aspectFill" /> |
|
|
|
<text class="knowledge-title">知识收获</text> |
|
|
|
</view> |
|
|
|
<text class="knowledge-content">{{ currentWordMeaning.knowledgeGain }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</uv-popup> |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -91,52 +224,206 @@ |
|
|
|
export default { |
|
|
|
data() { |
|
|
|
return { |
|
|
|
courseId: '', |
|
|
|
showNavbar: true, |
|
|
|
currentPage: 1, |
|
|
|
bookTitle: '看,乔治!', |
|
|
|
currentCourse: 1, // 当前课程索引 |
|
|
|
currentWordMeaning: null, // 当前显示的单词释义 |
|
|
|
isReversed: false, // 是否倒序显示 |
|
|
|
// 音频控制相关数据 |
|
|
|
isPlaying: false, |
|
|
|
currentTime: 0, |
|
|
|
totalTime: 317, // 5:17 = 317秒 |
|
|
|
isLoop: false, |
|
|
|
playSpeed: 1.0, |
|
|
|
speedOptions: [1.0, 1.25, 1.5, 2.0], |
|
|
|
courseIdList: [], |
|
|
|
bookTitle: '', |
|
|
|
courseList: [ |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
// 二维数组 代表每个页面 |
|
|
|
bookPages: [ |
|
|
|
{ |
|
|
|
type: 'card', |
|
|
|
englishText: 'I ought to have judged by deeds and not by words.', |
|
|
|
chineseText: '要对一个人下定论,不应听其言,而应观其行。', |
|
|
|
image: '/static/画重点图片.png' |
|
|
|
}, |
|
|
|
{ |
|
|
|
type: 'video', |
|
|
|
video: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4' |
|
|
|
}, |
|
|
|
{ |
|
|
|
type: 'text', |
|
|
|
content: '索菲达以南几英里处,萨利和斯坦对着近旁河岸的斜坡流淌,水深且绿意盎然。水也很温暖,因为它在阳光下闪烁着,清澈黄色的沙子,才到达深深的池塘。河的一侧,金色的山丘斜坡向上蜿蜒,通往坚固多岩石的加比亚山脉,但在山谷一侧,水边排列着树木——柳树在春天新鲜而翠绿,它们的低垂接触处充满着各天的冰水残留物;还有枫树,它们现实的,白色的横枝条和树枝;吉他也是绿色的地塘,在河下游的河岸上,叶子能发出很大的啪啪声。傍晚时分,兔子们从灌木中出现,坐在沙子上,湖泊的平地上覆盖着沉重的夜晚迹,还有来自农场的狗的散布的垫子,以及前来暗黑中饮水的鹿的分裂形足迹。' |
|
|
|
}, |
|
|
|
{ |
|
|
|
type: 'text', |
|
|
|
content: '有一条穿过柳树和榆树之间的路,这条路从农场下来的男孩们踏得又硬又深;他们来深池游泳,也被那些上游运送货物公路上下来的流浪汉使得又硬又深。他们在水边停歇,在一棵巨大的榆树低垂的水平树枝前,有一个由许多火堆形成的灰烬堆,核桃被坐在上面的人留下光滑。' |
|
|
|
} |
|
|
|
] |
|
|
|
|
|
|
|
], |
|
|
|
// 存储每个页面的标题 |
|
|
|
pageTitles: [], |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
displayCourseList() { |
|
|
|
return this.isReversed ? [...this.courseList].reverse() : this.courseList; |
|
|
|
}, |
|
|
|
// 判断当前页面是否为文字类型 |
|
|
|
isTextPage() { |
|
|
|
const currentPageData = this.bookPages[this.currentPage - 1]; |
|
|
|
// currentPageData是一个数组 其中的一个元素的type是text就会返回true |
|
|
|
return currentPageData && currentPageData.some(item => item.type === 'text'); |
|
|
|
}, |
|
|
|
// 计算音频播放进度百分比 |
|
|
|
progressPercent() { |
|
|
|
return this.totalTime > 0 ? (this.currentTime / this.totalTime) * 100 : 0; |
|
|
|
}, |
|
|
|
// 动态页面标题 |
|
|
|
currentPageTitle() { |
|
|
|
return this.pageTitles[this.currentPage - 1] || this.bookTitle; |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
toggleNavbar() { |
|
|
|
this.showNavbar = !this.showNavbar |
|
|
|
|
|
|
|
}, |
|
|
|
goBack() { |
|
|
|
uni.navigateBack() |
|
|
|
}, |
|
|
|
showMenu() { |
|
|
|
console.log('显示菜单') |
|
|
|
toggleCoursePopup() { |
|
|
|
if (this.$refs.coursePopup) { |
|
|
|
this.$refs.coursePopup.open() |
|
|
|
} |
|
|
|
// console.log('123123123'); |
|
|
|
|
|
|
|
}, |
|
|
|
toggleSort() { |
|
|
|
this.isReversed = !this.isReversed |
|
|
|
}, |
|
|
|
selectCourse(courseId) { |
|
|
|
this.currentCourse = courseId |
|
|
|
if (this.$refs.coursePopup) { |
|
|
|
this.$refs.coursePopup.close() |
|
|
|
} |
|
|
|
// 这里可以添加切换课程的逻辑 |
|
|
|
// console.log('选择课程:', courseId) |
|
|
|
this.getCourseList(courseId) |
|
|
|
}, |
|
|
|
showWordMeaning(wordMeaning) { |
|
|
|
if (wordMeaning) { |
|
|
|
this.currentWordMeaning = wordMeaning |
|
|
|
if (this.$refs.meaningPopup) { |
|
|
|
this.$refs.meaningPopup.open() |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
closeMeaningPopup() { |
|
|
|
if (this.$refs.meaningPopup) { |
|
|
|
this.$refs.meaningPopup.close() |
|
|
|
} |
|
|
|
this.currentWordMeaning = null |
|
|
|
}, |
|
|
|
// 音频控制方法 |
|
|
|
togglePlay() { |
|
|
|
this.isPlaying = !this.isPlaying; |
|
|
|
// 这里可以添加实际的音频播放/暂停逻辑 |
|
|
|
}, |
|
|
|
toggleLoop() { |
|
|
|
this.isLoop = !this.isLoop; |
|
|
|
}, |
|
|
|
toggleSpeed() { |
|
|
|
const currentIndex = this.speedOptions.indexOf(this.playSpeed); |
|
|
|
const nextIndex = (currentIndex + 1) % this.speedOptions.length; |
|
|
|
this.playSpeed = this.speedOptions[nextIndex]; |
|
|
|
}, |
|
|
|
async previousPage() { |
|
|
|
if (this.currentPage > 1) { |
|
|
|
this.currentPage--; |
|
|
|
// 获取对应页面的数据(如果还没有获取过) |
|
|
|
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) { |
|
|
|
await this.getBookPages(this.courseIdList[this.currentPage - 1]); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
async nextPage() { |
|
|
|
if (this.currentPage < this.bookPages.length) { |
|
|
|
this.currentPage++; |
|
|
|
// 获取对应页面的数据(如果还没有获取过) |
|
|
|
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) { |
|
|
|
await this.getBookPages(this.courseIdList[this.currentPage - 1]); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
formatTime(seconds) { |
|
|
|
const mins = Math.floor(seconds / 60); |
|
|
|
const secs = Math.floor(seconds % 60); |
|
|
|
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; |
|
|
|
}, |
|
|
|
toggleSound() { |
|
|
|
console.log('音色切换') |
|
|
|
uni.navigateTo({ |
|
|
|
url: '/subPages/home/music' |
|
|
|
}) |
|
|
|
}, |
|
|
|
goToPage(page) { |
|
|
|
unlockBook() { |
|
|
|
console.log('解锁全书') |
|
|
|
// 这里可以跳转到会员页面或者调用解锁接口 |
|
|
|
uni.navigateTo({ |
|
|
|
url: '/pages/index/member' |
|
|
|
}) |
|
|
|
}, |
|
|
|
async goToPage(page) { |
|
|
|
this.currentPage = page |
|
|
|
console.log('跳转到页面:', page) |
|
|
|
// 获取对应页面的数据(如果还没有获取过) |
|
|
|
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) { |
|
|
|
await this.getBookPages(this.courseIdList[this.currentPage - 1]); |
|
|
|
} |
|
|
|
}, |
|
|
|
onSwiperChange(e) { |
|
|
|
async onSwiperChange(e) { |
|
|
|
this.currentPage = e.detail.current + 1 |
|
|
|
// 获取对应页面的数据(如果还没有获取过) |
|
|
|
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) { |
|
|
|
await this.getBookPages(this.courseIdList[this.currentPage - 1]); |
|
|
|
} |
|
|
|
}, |
|
|
|
async getCourseList(id) { |
|
|
|
const res = await this.$api.book.coursePage({ |
|
|
|
id: id |
|
|
|
}) |
|
|
|
if (res.code === 200) { |
|
|
|
this.courseIdList = res.result.map(item => item.id) |
|
|
|
// 初始化二维数组 换一种方式 |
|
|
|
this.bookPages = this.courseIdList.map(() => []) |
|
|
|
// 初始化标题数组 |
|
|
|
this.pageTitles = this.courseIdList.map(() => '') |
|
|
|
// 初始化第一页 |
|
|
|
if (this.courseIdList.length > 0) { |
|
|
|
await this.getBookPages(this.courseIdList[0]) |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
async getBookPages(id) { |
|
|
|
const res = await this.$api.book.coursesPageDetail({ |
|
|
|
id: id |
|
|
|
}) |
|
|
|
if (res.code === 200) { |
|
|
|
// 使用$set确保响应式更新 |
|
|
|
// 确保当前页面存在 |
|
|
|
if (this.currentPage - 1 < this.bookPages.length) { |
|
|
|
this.$set(this.bookPages, this.currentPage - 1, JSON.parse(res.result.content)) |
|
|
|
// 保存页面标题 |
|
|
|
this.$set(this.pageTitles, this.currentPage - 1, res.result.title || '') |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
// 获取课程列表 |
|
|
|
async getCoursePageList (bookId) { |
|
|
|
const res = await this.$api.book.course({ |
|
|
|
id: bookId |
|
|
|
}) |
|
|
|
if (res.code === 200) { |
|
|
|
this.courseList = res.result.records |
|
|
|
// 打上序列号 |
|
|
|
this.courseList = this.courseList.map((item, index) => ({ |
|
|
|
...item, |
|
|
|
index, |
|
|
|
})) |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
async onLoad(args) { |
|
|
|
this.courseId = args.courseId |
|
|
|
// 先获取点进来的课程的页面列表 |
|
|
|
await Promise.all([this.getCourseList(this.courseId), this.getCoursePageList(args.bookId)]) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
@ -181,10 +468,13 @@ export default { |
|
|
|
} |
|
|
|
|
|
|
|
.navbar-right { |
|
|
|
|
|
|
|
justify-content: flex-end; |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.navbar-title { |
|
|
|
transform: translateX(-50rpx); |
|
|
|
flex: 1; |
|
|
|
text-align: center; |
|
|
|
font-family: PingFang SC; |
|
|
|
@ -196,8 +486,8 @@ export default { |
|
|
|
|
|
|
|
.content-swiper { |
|
|
|
flex: 1; |
|
|
|
height: calc(100vh - 200rpx); |
|
|
|
margin-top: 100rpx; |
|
|
|
height: calc(100vh - 100rpx); |
|
|
|
// margin-top: 100rpx; |
|
|
|
margin-bottom: 100rpx; |
|
|
|
} |
|
|
|
|
|
|
|
@ -208,6 +498,7 @@ export default { |
|
|
|
.content-area { |
|
|
|
flex: 1; |
|
|
|
padding: 0 40rpx; |
|
|
|
padding-top: 100rpx; |
|
|
|
// background: linear-gradient(180deg, #DEFFFF 0%, #FBFEFF 22.65%, #F0FBFF 100%); |
|
|
|
height: 100%; |
|
|
|
box-sizing: border-box; |
|
|
|
@ -254,36 +545,80 @@ export default { |
|
|
|
// margin-bottom: 20rpx; |
|
|
|
} |
|
|
|
.english-text { |
|
|
|
display: block; |
|
|
|
display: block; |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 600; |
|
|
|
font-size: 32rpx; |
|
|
|
line-height: 48rpx; |
|
|
|
color: #3B3D3D; |
|
|
|
// margin-bottom: 16rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.chinese-text { |
|
|
|
display: block; |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 400; |
|
|
|
font-size: 28rpx; |
|
|
|
line-height: 48rpx; |
|
|
|
color: #4F4F4F; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 会员限制页面样式 */ |
|
|
|
.member-content { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
height: 90%; |
|
|
|
background-color: #F8F8F8; |
|
|
|
padding: 40rpx; |
|
|
|
margin: -40rpx; |
|
|
|
box-sizing: border-box; |
|
|
|
} |
|
|
|
|
|
|
|
.member-title { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 600; |
|
|
|
font-size: 32rpx; |
|
|
|
line-height: 48rpx; |
|
|
|
color: #3B3D3D; |
|
|
|
// margin-bottom: 16rpx; |
|
|
|
font-weight: 500; |
|
|
|
font-size: 40rpx; |
|
|
|
line-height: 1; |
|
|
|
color: #6f6f6f; |
|
|
|
text-align: center; |
|
|
|
margin-bottom: 48rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.member-button { |
|
|
|
width: 670rpx; |
|
|
|
height: 72rpx; |
|
|
|
background: #06DADC; |
|
|
|
border-radius: 200rpx; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
} |
|
|
|
|
|
|
|
.chinese-text { |
|
|
|
display: block; |
|
|
|
.member-button-text { |
|
|
|
font-family: PingFang SC; |
|
|
|
// font-weight: 400; |
|
|
|
font-size: 28rpx; |
|
|
|
line-height: 48rpx; |
|
|
|
color: #4F4F4F; |
|
|
|
font-weight: 400; |
|
|
|
font-size: 30rpx; |
|
|
|
color: #FFFFFF; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.video-content { |
|
|
|
width: 100vw; |
|
|
|
margin: 200rpx -40rpx 0; |
|
|
|
height: 500rpx; |
|
|
|
background-color: #FFFFFF; |
|
|
|
padding: 40rpx; |
|
|
|
// padding: 40rpx; |
|
|
|
border-radius: 24rpx; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
|
|
|
|
.video-player{ |
|
|
|
width: 670rpx; |
|
|
|
margin: 0 auto; |
|
|
|
height: 376rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -313,7 +648,7 @@ export default { |
|
|
|
bottom: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
background-color: #fff; |
|
|
|
// background-color: #fff; |
|
|
|
border-top: 1rpx solid #EEEEEE; |
|
|
|
z-index: 1000; |
|
|
|
transition: transform 0.3s ease; |
|
|
|
@ -328,6 +663,9 @@ export default { |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
padding: 24rpx 62rpx; |
|
|
|
// z-index: 100; |
|
|
|
// position: relative; |
|
|
|
// background-color: #fff; |
|
|
|
// padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
|
|
|
height: 88rpx; |
|
|
|
} |
|
|
|
@ -401,4 +739,297 @@ export default { |
|
|
|
color: $primary-color; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 课程弹出窗样式 */ |
|
|
|
.course-popup { |
|
|
|
padding: 0 32rpx; |
|
|
|
max-height: 80vh; |
|
|
|
} |
|
|
|
|
|
|
|
.popup-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding: 20rpx 0; |
|
|
|
border-bottom: 2rpx solid #EEEEEE |
|
|
|
// margin-bottom: 40rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.popup-title { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 500; |
|
|
|
font-size: 34rpx; |
|
|
|
color: #181818; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.course-list { |
|
|
|
max-height: 60vh; |
|
|
|
overflow-y: auto; |
|
|
|
} |
|
|
|
|
|
|
|
.course-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 24rpx; |
|
|
|
padding-top: 24rpx; |
|
|
|
padding-right: 8rpx; |
|
|
|
padding-bottom: 24rpx; |
|
|
|
padding-left: 8rpx; |
|
|
|
|
|
|
|
border-bottom: 1px solid #EEEEEE; |
|
|
|
cursor: pointer; |
|
|
|
|
|
|
|
&:last-child { |
|
|
|
border-bottom: none; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.course-number { |
|
|
|
width: 80rpx; |
|
|
|
font-family: PingFang SC; |
|
|
|
// font-weight: 400; |
|
|
|
font-size: 36rpx; |
|
|
|
color: #999; |
|
|
|
&.highlight { |
|
|
|
color: $primary-color; |
|
|
|
} |
|
|
|
// margin-right: 24rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.course-content { |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.course-english { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 600; |
|
|
|
font-size: 36rpx; |
|
|
|
line-height: 44rpx; |
|
|
|
color: #252545; |
|
|
|
margin-bottom: 8rpx; |
|
|
|
|
|
|
|
&.highlight { |
|
|
|
color: $primary-color; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.course-chinese { |
|
|
|
font-size: 28rpx; |
|
|
|
line-height: 48rpx; |
|
|
|
color: #3B3D3D; |
|
|
|
&.highlight { |
|
|
|
color: $primary-color; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 释义弹窗样式 */ |
|
|
|
.meaning-popup { |
|
|
|
// width: 670rpx; |
|
|
|
background-color: #FFFFFF; |
|
|
|
// border-radius: 32rpx; |
|
|
|
overflow: hidden; |
|
|
|
} |
|
|
|
|
|
|
|
.meaning-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding: 32rpx; |
|
|
|
border-bottom: 2rpx solid #EEEEEE; |
|
|
|
} |
|
|
|
|
|
|
|
.close-btn { |
|
|
|
width: 80rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.close-text { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-size: 32rpx; |
|
|
|
color: #8b8b8b; |
|
|
|
} |
|
|
|
|
|
|
|
.meaning-title { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 500; |
|
|
|
font-size: 34rpx; |
|
|
|
color: #181818; |
|
|
|
} |
|
|
|
|
|
|
|
.meaning-content { |
|
|
|
padding: 32rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.meaning-image { |
|
|
|
width: 670rpx; |
|
|
|
height: 268rpx; |
|
|
|
border-radius: 24rpx; |
|
|
|
margin-bottom: 32rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.word-info { |
|
|
|
margin-bottom: 32rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.word-main { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 16rpx; |
|
|
|
margin-bottom: 8rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.word-text { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 500; |
|
|
|
font-size: 40rpx; |
|
|
|
color: #181818; |
|
|
|
} |
|
|
|
|
|
|
|
.phonetic-container{ |
|
|
|
display: flex; |
|
|
|
gap: 24rpx; |
|
|
|
.phonetic-text { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-size: 28rpx; |
|
|
|
color: #262626; |
|
|
|
margin-bottom: 16rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.word-meaning { |
|
|
|
display: flex; |
|
|
|
gap: 16rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.part-of-speech { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-size: 28rpx; |
|
|
|
color: #262626; |
|
|
|
} |
|
|
|
|
|
|
|
.meaning-text { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-size: 28rpx; |
|
|
|
color: #181818; |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.knowledge-gain { |
|
|
|
background: linear-gradient(180deg, #DEFFFF 0%, #FBFEFF 22.65%, #F0FBFF 100%); |
|
|
|
border-radius: 24rpx; |
|
|
|
padding: 32rpx 40rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.knowledge-header { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 16rpx; |
|
|
|
margin-bottom: 20rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.knowledge-icon { |
|
|
|
width: 48rpx; |
|
|
|
height: 48rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.knowledge-title { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-weight: 600; |
|
|
|
font-size: 30rpx; |
|
|
|
color: #3B3D3D; |
|
|
|
} |
|
|
|
|
|
|
|
.knowledge-content { |
|
|
|
font-family: PingFang SC; |
|
|
|
font-size: 28rpx; |
|
|
|
color: #4f4f4f; |
|
|
|
line-height: 48rpx; |
|
|
|
} |
|
|
|
|
|
|
|
/* 音频控制栏样式 */ |
|
|
|
.audio-controls { |
|
|
|
background: #fff; |
|
|
|
padding: 20rpx 40rpx; |
|
|
|
border-bottom: 1rpx solid #eee; |
|
|
|
transition: transform 0.3s ease; |
|
|
|
position: relative; |
|
|
|
z-index: 10; |
|
|
|
&.audio-hidden { |
|
|
|
transform: translateY(100%); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.audio-time { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 20rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.time-text { |
|
|
|
font-size: 28rpx; |
|
|
|
color: #999; |
|
|
|
min-width: 80rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.progress-container { |
|
|
|
flex: 1; |
|
|
|
margin: 0 20rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.progress-bar { |
|
|
|
position: relative; |
|
|
|
height: 6rpx; |
|
|
|
background: #f0f0f0; |
|
|
|
border-radius: 3rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.progress-fill { |
|
|
|
position: absolute; |
|
|
|
left: 0; |
|
|
|
top: 0; |
|
|
|
height: 100%; |
|
|
|
background: #06DADC; |
|
|
|
border-radius: 3rpx; |
|
|
|
transition: width 0.1s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.progress-thumb { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
width: 16rpx; |
|
|
|
height: 16rpx; |
|
|
|
background: #06DADC; |
|
|
|
border-radius: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
transition: left 0.1s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.audio-controls-row { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
} |
|
|
|
|
|
|
|
.control-btn { |
|
|
|
display: flex; |
|
|
|
// flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
|
|
|
|
padding: 10rpx; |
|
|
|
gap: 8rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.control-text { |
|
|
|
font-size: 28rpx; |
|
|
|
color: #4A4A4A; |
|
|
|
// margin-top: 8rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.play-btn { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
padding: 10rpx; |
|
|
|
} |
|
|
|
</style> |