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

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