四零语境前端代码仓库
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.

240 lines
5.0 KiB

  1. <template>
  2. <view class="custom-tabbar" :class="{ 'tabbar-hidden': !showNavbar }">
  3. <!-- 音频控制栏组件 -->
  4. <AudioControls
  5. :current-page="currentPage"
  6. :course-id="courseId"
  7. :voice-id="voiceId"
  8. :book-pages="bookPages"
  9. :is-text-page="isTextPage"
  10. :should-load-audio="shouldLoadAudio"
  11. :is-member="isMember"
  12. :current-page-requires-member="currentPageRequiresMember"
  13. :page-pay="pagePay"
  14. :is-word-audio-playing="isWordAudioPlaying"
  15. @previous-page="previousPage"
  16. @next-page="nextPage"
  17. @audio-state-change="onAudioStateChange"
  18. @highlight-change="onHighlightChange"
  19. @voice-change-complete="onVoiceChangeComplete"
  20. @voice-change-error="onVoiceChangeError"
  21. @page-data-needed="onPageDataNeeded"
  22. ref="audioControls"
  23. />
  24. <view style="background-color: #fff;position: relative;z-index: 100">
  25. <view class="tabbar-content">
  26. <view class="tabbar-left">
  27. <view class="tab-button" @click="toggleCoursePopup">
  28. <image src="/static/course-icon.png" class="tab-icon" />
  29. <text class="tab-text">课程</text>
  30. </view>
  31. <view class="tab-button" @click="toggleSound">
  32. <image src="/static/voice-switch-icon.png" class="tab-icon" />
  33. <text class="tab-text">音色切换</text>
  34. </view>
  35. </view>
  36. <view class="tabbar-right">
  37. <view class="page-controls">
  38. <view class="page-numbers">
  39. <view
  40. v-for="(page, index) in bookPages"
  41. :key="index"
  42. class="page-number"
  43. :class="{ 'active': (index + 1) === currentPage }"
  44. @click="goToPage(index + 1)"
  45. >
  46. {{ index + 1 }}
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. <uv-safe-bottom></uv-safe-bottom>
  53. </view>
  54. </view>
  55. </template>
  56. <script>
  57. import AudioControls from '../AudioControls.vue'
  58. export default {
  59. name: 'CustomTabbar',
  60. components: {
  61. AudioControls
  62. },
  63. props: {
  64. showNavbar: {
  65. type: Boolean,
  66. default: true
  67. },
  68. currentPage: {
  69. type: Number,
  70. default: 1
  71. },
  72. courseId: {
  73. type: String,
  74. default: ''
  75. },
  76. voiceId: {
  77. type: Number,
  78. default: null
  79. },
  80. bookPages: {
  81. type: Array,
  82. default: () => []
  83. },
  84. isTextPage: {
  85. type: Boolean,
  86. default: false
  87. },
  88. shouldLoadAudio: {
  89. type: Boolean,
  90. default: false
  91. },
  92. isMember: {
  93. type: Boolean,
  94. default: false
  95. },
  96. currentPageRequiresMember: {
  97. type: Boolean,
  98. default: false
  99. },
  100. pagePay: {
  101. type: Array,
  102. default: () => []
  103. },
  104. isWordAudioPlaying: {
  105. type: Boolean,
  106. default: false
  107. }
  108. },
  109. methods: {
  110. toggleCoursePopup() {
  111. this.$emit('toggle-course-popup')
  112. },
  113. toggleSound() {
  114. this.$emit('toggle-sound')
  115. },
  116. goToPage(pageNumber) {
  117. this.$emit('go-to-page', pageNumber)
  118. },
  119. previousPage() {
  120. this.$emit('previous-page')
  121. },
  122. nextPage() {
  123. this.$emit('next-page')
  124. },
  125. onAudioStateChange(audioState) {
  126. this.$emit('audio-state-change', audioState)
  127. },
  128. onHighlightChange(highlightData) {
  129. this.$emit('highlight-change', highlightData)
  130. },
  131. onVoiceChangeComplete(data) {
  132. this.$emit('voice-change-complete', data)
  133. },
  134. onVoiceChangeError(error) {
  135. this.$emit('voice-change-error', error)
  136. },
  137. onPageDataNeeded(pageNumber) {
  138. this.$emit('page-data-needed', pageNumber)
  139. },
  140. // onScrollToText(refName) {
  141. // this.$emit('scroll-to-text', refName)
  142. // }
  143. }
  144. }
  145. </script>
  146. <style lang="scss" scoped>
  147. .custom-tabbar {
  148. position: fixed;
  149. bottom: 0;
  150. left: 0;
  151. right: 0;
  152. border-top: 1rpx solid #EEEEEE;
  153. z-index: 1000;
  154. transition: transform 0.3s ease;
  155. &.tabbar-hidden {
  156. transform: translateY(100%);
  157. }
  158. }
  159. .tabbar-content {
  160. display: flex;
  161. align-items: center;
  162. justify-content: space-between;
  163. padding: 24rpx 62rpx;
  164. height: 88rpx;
  165. }
  166. .tabbar-left {
  167. display: flex;
  168. align-items: center;
  169. gap: 35rpx;
  170. }
  171. .tab-button {
  172. display: flex;
  173. align-items: center;
  174. flex-direction: column;
  175. gap: 8rpx;
  176. }
  177. .tab-icon {
  178. width: 52rpx;
  179. height: 52rpx;
  180. }
  181. .tab-text {
  182. font-family: PingFang SC;
  183. font-size: 22rpx;
  184. color: #999;
  185. line-height: 24rpx;
  186. }
  187. .tabbar-right {
  188. flex: 1;
  189. display: flex;
  190. justify-content: flex-end;
  191. }
  192. .page-controls {
  193. display: flex;
  194. align-items: center;
  195. }
  196. .page-numbers {
  197. display: flex;
  198. align-items: center;
  199. gap: 8rpx;
  200. overflow-x: auto;
  201. max-width: 400rpx;
  202. &::-webkit-scrollbar {
  203. display: none;
  204. }
  205. }
  206. .page-number {
  207. min-width: 84rpx;
  208. height: 58rpx;
  209. display: flex;
  210. align-items: center;
  211. justify-content: center;
  212. border-radius: 100rpx;
  213. font-family: PingFang SC;
  214. font-size: 30rpx;
  215. color: #3B3D3D;
  216. background-color: transparent;
  217. border: 1px solid #3B3D3D;
  218. transition: all 0.3s ease;
  219. &.active {
  220. border: 1px solid #06DADC;
  221. color: #06DADC;
  222. }
  223. }
  224. </style>