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

215 lines
4.7 KiB

  1. <template>
  2. <view class="music-container">
  3. <!-- 音色列表 -->
  4. <view class="voice-list">
  5. <view
  6. v-for="(voice, index) in voiceList"
  7. :key="voice.voiceType"
  8. class="voice-item"
  9. :class="{ 'selected': voice.voiceType === selectedVoiceId }"
  10. @click="selectedVoiceId = voice.voiceType"
  11. >
  12. <view class="voice-avatar">
  13. <view class="play-icon">
  14. <uv-icon
  15. :name="voice.voiceType === selectedVoiceId ? 'pause' : 'play-right-fill'"
  16. size="24"
  17. color="#666666"
  18. ></uv-icon>
  19. </view>
  20. </view>
  21. <view class="voice-info">
  22. <view class="voice-name">{{ voice.name }}</view>
  23. <view class="voice-desc">{{ voice.info }}</view>
  24. </view>
  25. <view v-if="voice.voiceType === selectedVoiceId" class="selected-tag">
  26. 已选择
  27. </view>
  28. </view>
  29. </view>
  30. <!-- 底部固定确认按钮 -->
  31. <view class="bottom-bar">
  32. <uv-button
  33. type="primary"
  34. text="确定"
  35. :custom-style="{
  36. width: '100%',
  37. height: '82rpx',
  38. borderRadius: '44rpx',
  39. backgroundColor: '#06DADC',
  40. fontSize: '36rpx',
  41. fontWeight: '500',
  42. border: '1px solid #06DADC'
  43. }"
  44. @click="confirmSelection"
  45. ></uv-button>
  46. <uv-safe-bottom></uv-safe-bottom>
  47. </view>
  48. </view>
  49. </template>
  50. <script>
  51. export default {
  52. data() {
  53. return {
  54. selectedVoiceId: '', // 默认选择智小虎
  55. voiceList: [
  56. ]
  57. }
  58. },
  59. computed: {
  60. // 从Vuex获取音色列表
  61. storeVoiceList() {
  62. return this.$store.state.voiceList;
  63. }
  64. },
  65. methods: {
  66. goBack() {
  67. uni.navigateBack()
  68. },
  69. selectVoice() {
  70. // console.log('选择音色:', this.selectedVoiceId)
  71. uni.$emit('selectVoice', this.selectedVoiceId)
  72. uni.navigateBack()
  73. },
  74. confirmSelection() {
  75. this.selectVoice(this.selectedVoiceId)
  76. // 保存选择的音色到Vuex
  77. this.$store.dispatch('setDefaultVoice', this.selectedVoiceId);
  78. },
  79. async getVoice(){
  80. // 优先从Vuex获取音色列表
  81. if (this.storeVoiceList && this.storeVoiceList.length > 0) {
  82. console.log('从Vuex获取音色列表:', this.storeVoiceList);
  83. this.voiceList = this.storeVoiceList;
  84. return;
  85. }
  86. // 如果Vuex中没有数据,则从API获取(兜底方案)
  87. console.log('Vuex中无音色数据,从API获取...');
  88. try {
  89. const listRes = await this.$api.music.list()
  90. if (listRes.code === 200) {
  91. this.voiceList = listRes.result
  92. // 更新Vuex中的音色列表
  93. this.$store.commit('setVoiceList', listRes.result);
  94. } else {
  95. console.error('获取音色列表失败:', listRes);
  96. }
  97. } catch (error) {
  98. console.error('获取音色列表异常:', error);
  99. }
  100. }
  101. },
  102. onLoad(options) {
  103. this.selectedVoiceId = Number(options.voiceId)
  104. // console.log( 'options.voiceId', options.voiceId );
  105. this.getVoice()
  106. }
  107. }
  108. </script>
  109. <style scoped lang="scss">
  110. .music-container {
  111. background: #fff;
  112. min-height: 100vh;
  113. display: flex;
  114. flex-direction: column;
  115. padding-bottom: 120rpx;
  116. }
  117. .voice-list {
  118. flex: 1;
  119. padding: 40rpx 32rpx 120rpx;
  120. display: flex;
  121. flex-direction: column;
  122. gap: 32rpx;
  123. }
  124. .voice-item {
  125. display: flex;
  126. align-items: center;
  127. padding: 32rpx 0;
  128. border-bottom: 4rpx solid #F8F8F8;
  129. position: relative;
  130. background: #F8F8F8;
  131. gap: 12px;
  132. opacity: 1;
  133. border-radius: 8px;
  134. padding: 8px;
  135. transition: all 0.3s ease;
  136. &:last-child {
  137. border-bottom: none;
  138. }
  139. &.selected {
  140. border-bottom: 4rpx solid $primary-color;
  141. }
  142. }
  143. .voice-avatar {
  144. width: 136rpx;
  145. height: 136rpx;
  146. border-radius: 50%;
  147. background: #666;
  148. display: flex;
  149. align-items: center;
  150. justify-content: center;
  151. // margin-right: 32rpx;
  152. position: relative;
  153. }
  154. .play-icon {
  155. display: flex;
  156. width: 60rpx;
  157. height: 60rpx;
  158. border-radius: 100rpx;
  159. background: white;
  160. align-items: center;
  161. justify-content: center;
  162. }
  163. .voice-info {
  164. flex: 1;
  165. }
  166. .voice-name {
  167. font-family: PingFang SC;
  168. font-weight: 600;
  169. font-size: 36rpx;
  170. color: #262626;
  171. margin-bottom: 8rpx;
  172. }
  173. .voice-desc {
  174. font-family: PingFang SC;
  175. font-weight: 400;
  176. font-size: 28rpx;
  177. color: #999;
  178. }
  179. .selected-tag {
  180. background: $primary-color;
  181. color: #fff;
  182. font-size: 24rpx;
  183. padding: 8rpx 16rpx;
  184. border-radius: 20rpx;
  185. font-family: PingFang SC;
  186. font-weight: 500;
  187. }
  188. .bottom-bar {
  189. position: fixed;
  190. bottom: 0;
  191. left: 0;
  192. right: 0;
  193. background: #fff;
  194. padding: 24rpx 50rpx;
  195. z-index: 999;
  196. border-top: 2rpx solid #F1F1F1
  197. }
  198. </style>