| <template> | |
|   <view class="custom-tabbar" :class="{ 'tabbar-hidden': !showNavbar }"> | |
|     <!-- 音频控制栏组件 --> | |
|     <AudioControls | |
|       :current-page="currentPage" | |
|       :course-id="courseId" | |
|       :voice-id="voiceId" | |
|       :book-pages="bookPages" | |
|       :is-text-page="isTextPage" | |
|       :should-load-audio="shouldLoadAudio" | |
|       :is-member="isMember" | |
|       :current-page-requires-member="currentPageRequiresMember" | |
|       :page-pay="pagePay" | |
|       :is-word-audio-playing="isWordAudioPlaying" | |
|       @previous-page="previousPage" | |
|       @next-page="nextPage" | |
|       @audio-state-change="onAudioStateChange" | |
|       @highlight-change="onHighlightChange" | |
|       @voice-change-complete="onVoiceChangeComplete" | |
|       @voice-change-error="onVoiceChangeError" | |
|       ref="audioControls" | |
|     /> | |
|    | |
|     <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/course-icon.png" class="tab-icon" /> | |
|             <text class="tab-text">课程</text> | |
|           </view> | |
|           <view class="tab-button" @click="toggleSound"> | |
|             <image src="/static/voice-switch-icon.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> | |
|   </view> | |
| </template> | |
| 
 | |
| <script> | |
| import AudioControls from '../AudioControls.vue' | |
| 
 | |
| export default { | |
|   name: 'CustomTabbar', | |
|   components: { | |
|     AudioControls | |
|   }, | |
|   props: { | |
|     showNavbar: { | |
|       type: Boolean, | |
|       default: true | |
|     }, | |
|     currentPage: { | |
|       type: Number, | |
|       default: 1 | |
|     }, | |
|     courseId: { | |
|       type: String, | |
|       default: '' | |
|     }, | |
|     voiceId: { | |
|       type: Number, | |
|       default: null | |
|     }, | |
|     bookPages: { | |
|       type: Array, | |
|       default: () => [] | |
|     }, | |
|     isTextPage: { | |
|       type: Boolean, | |
|       default: false | |
|     }, | |
|     shouldLoadAudio: { | |
|       type: Boolean, | |
|       default: false | |
|     }, | |
|     isMember: { | |
|       type: Boolean, | |
|       default: false | |
|     }, | |
|     currentPageRequiresMember: { | |
|       type: Boolean, | |
|       default: false | |
|     }, | |
|     pagePay: { | |
|       type: Array, | |
|       default: () => [] | |
|     }, | |
|     isWordAudioPlaying: { | |
|       type: Boolean, | |
|       default: false | |
|     } | |
|   }, | |
|   methods: { | |
|     toggleCoursePopup() { | |
|       this.$emit('toggle-course-popup') | |
|     }, | |
|     toggleSound() { | |
|       this.$emit('toggle-sound') | |
|     }, | |
|     goToPage(pageNumber) { | |
|       this.$emit('go-to-page', pageNumber) | |
|     }, | |
|     previousPage() { | |
|       this.$emit('previous-page') | |
|     }, | |
|     nextPage() { | |
|       this.$emit('next-page') | |
|     }, | |
|     onAudioStateChange(audioState) { | |
|       this.$emit('audio-state-change', audioState) | |
|     }, | |
|     onHighlightChange(highlightData) { | |
|       this.$emit('highlight-change', highlightData) | |
|     }, | |
|     onVoiceChangeComplete(data) { | |
|       this.$emit('voice-change-complete', data) | |
|     }, | |
|     onVoiceChangeError(error) { | |
|       this.$emit('voice-change-error', error) | |
|     } | |
|   } | |
| } | |
| </script> | |
| 
 | |
| <style lang="scss" scoped> | |
| .custom-tabbar { | |
|   position: fixed; | |
|   bottom: 0; | |
|   left: 0; | |
|   right: 0; | |
|   border-top: 1rpx solid #EEEEEE; | |
|   z-index: 1000; | |
|   transition: transform 0.3s ease; | |
|    | |
|   &.tabbar-hidden { | |
|     transform: translateY(100%); | |
|   } | |
| } | |
| 
 | |
| .tabbar-content { | |
|   display: flex; | |
|   align-items: center; | |
|   justify-content: space-between; | |
|   padding: 24rpx 62rpx; | |
|   height: 88rpx; | |
| } | |
| 
 | |
| .tabbar-left { | |
|   display: flex; | |
|   align-items: center; | |
|   gap: 35rpx; | |
| } | |
| 
 | |
| .tab-button { | |
|   display: flex; | |
|   align-items: center; | |
|   flex-direction: column; | |
|   gap: 8rpx; | |
| } | |
| 
 | |
| .tab-icon { | |
|   width: 52rpx; | |
|   height: 52rpx; | |
| } | |
| 
 | |
| .tab-text { | |
|   font-family: PingFang SC; | |
|   font-size: 22rpx; | |
|   color: #999; | |
|   line-height: 24rpx; | |
| } | |
| 
 | |
| .tabbar-right { | |
|   flex: 1; | |
|   display: flex; | |
|   justify-content: flex-end; | |
| } | |
| 
 | |
| .page-controls { | |
|   display: flex; | |
|   align-items: center; | |
| } | |
| 
 | |
| .page-numbers { | |
|   display: flex; | |
|   align-items: center; | |
|   gap: 8rpx; | |
|   overflow-x: auto; | |
|   max-width: 400rpx; | |
|    | |
|   &::-webkit-scrollbar { | |
|     display: none; | |
|   } | |
| } | |
| 
 | |
| .page-number { | |
|   min-width: 84rpx; | |
|   height: 58rpx; | |
|   display: flex; | |
|   align-items: center; | |
|   justify-content: center; | |
|   border-radius: 100rpx; | |
|   font-family: PingFang SC; | |
|   font-size: 30rpx; | |
|   color: #3B3D3D; | |
|   background-color: transparent; | |
|   border: 1px solid #3B3D3D; | |
|   transition: all 0.3s ease; | |
|    | |
|   &.active { | |
|     border: 1px solid #06DADC; | |
|     color: #06DADC; | |
|   } | |
| } | |
| </style> |