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

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