wangguoyu 3 meses atrás
pai
commit
f89ce8049e

+ 191 - 0
pages/newEnglish/components/1111.vue

@@ -0,0 +1,191 @@
+<template>
+  <view class="container">
+    <!-- 加载状态 -->
+    <view v-if="loading" class="loading">加载中...</view>
+    
+    <!-- 单词主信息 -->
+    <view v-if="wordData" class="word-card">
+      <view class="word-header">
+        <text class="word-name">{{ wordData.name }}</text>
+        <text class="word-phonetic">{{ wordData.yinbiao }}</text>
+        
+        <!-- 主音频播放按钮 -->
+        <button 
+          v-if="wordData.yinpin"
+          class="play-btn"
+          @click="playMainAudio">
+          播放单词
+        </button>
+      </view>
+      
+      <!-- 单词释义 -->
+      <view class="word-meaning">
+        <text v-for="(meaning, index) in wordData.xiangyi" :key="index">
+          {{ meaning }}
+        </text>
+      </view>
+      
+      <!-- 音节部分 -->
+      <view v-if="wordData.yinjie" class="section">
+        <text class="section-title">音节分解</text>
+        <view class="syllable-list">
+          <view 
+            v-for="(syllable, index) in wordData.yinjie" 
+            :key="index"
+            class="syllable-item"
+            @click="playSyllableAudio(index)">
+            <text>{{ syllable.cigen }}</text>
+            <text>{{ syllable.yinbiao }}</text>
+          </view>
+        </view>
+      </view>
+      
+      <!-- 频度部分 -->
+      <view v-if="wordData.pindu" class="section">
+        <text class="section-title">频度发音</text>
+        <view class="frequency-list">
+          <view 
+            v-for="(frequency, index) in wordData.pindu" 
+            :key="index"
+            class="frequency-item"
+            @click="playFrequencyAudio(index)">
+            <text>{{ frequency.cigen }}</text>
+            <text>{{ frequency.yinbiao }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+    
+    <!-- 清理缓存按钮 -->
+    <button class="clean-btn" @click="audioManager.clearCache">
+      清理音频缓存
+    </button>
+  </view>
+</template>
+<script setup>
+import { ref, onMounted } from 'vue'
+import audioManager from '@/utils/audioManager'
+
+const wordData = ref(null)
+const loading = ref(false)
+
+// 加载单词数据
+const loadWordData = async (wordId) => {
+  try {
+    loading.value = true
+    wordData.value = await audioManager.fetchAndCacheData(wordId)
+  } catch (error) {
+    uni.showToast({ title: '加载失败', icon: 'none' })
+  } finally {
+    loading.value = false
+  }
+}
+
+// 播放主音频
+const playMainAudio = () => {
+  if (!wordData.value?.yinpin) return
+  audioManager.playAudio(`main_${wordData.value.id}`, wordData.value.yinpin)
+}
+
+// 播放音节音频
+const playSyllableAudio = (index) => {
+  const syllable = wordData.value?.yinjie?.[index]
+  if (!syllable?.yinpin) return
+  audioManager.playAudio(`syllable_${wordData.value.id}_${index}`, syllable.yinpin)
+}
+
+// 播放频度音频
+const playFrequencyAudio = (index) => {
+  const frequency = wordData.value?.pindu?.[index]
+  if (!frequency?.yinpin) return
+  audioManager.playAudio(`frequency_${wordData.value.id}_${index}`, frequency.yinpin)
+}
+
+onMounted(() => {
+  // 示例:加载ID为42的单词数据
+  loadWordData(42)
+})
+</script>
+
+
+
+<style>
+.container {
+  padding: 20rpx;
+}
+
+.loading {
+  text-align: center;
+  padding: 20rpx;
+  color: #888;
+}
+
+.word-card {
+  background: #fff;
+  border-radius: 16rpx;
+  padding: 30rpx;
+  margin-bottom: 30rpx;
+  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+}
+
+.word-header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20rpx;
+}
+
+.word-name {
+  font-size: 40rpx;
+  font-weight: bold;
+  margin-right: 20rpx;
+}
+
+.word-phonetic {
+  color: #666;
+  margin-right: 20rpx;
+}
+
+.play-btn {
+  background: #4a90e2;
+  color: white;
+  border-radius: 8rpx;
+  padding: 8rpx 16rpx;
+  font-size: 24rpx;
+}
+
+.word-meaning {
+  margin-bottom: 30rpx;
+}
+
+.section {
+  margin-bottom: 30rpx;
+}
+
+.section-title {
+  display: block;
+  font-weight: bold;
+  margin-bottom: 15rpx;
+  color: #333;
+}
+
+.syllable-list, .frequency-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20rpx;
+}
+
+.syllable-item, .frequency-item {
+  background: #f5f5f5;
+  padding: 15rpx 25rpx;
+  border-radius: 8rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.clean-btn {
+  background: #f8f8f8;
+  color: #333;
+  margin-top: 40rpx;
+}
+</style>

+ 117 - 0
pages/newEnglish/components/2222.vue

@@ -0,0 +1,117 @@
+<template>
+  <view class="container">
+    <!-- 主音频 -->
+    <view v-if="audioInfo?.main" class="audio-section">
+      <text class="section-title">单词发音</text>
+      <view class="audio-item" @click="playMainAudio">
+        <text>{{ audioInfo.main.text }}</text>
+        <text>{{ wordData.yinbiao }}</text>
+      </view>
+    </view>
+    
+    <!-- 音节音频 -->
+    <view v-if="audioInfo?.syllables?.length" class="audio-section">
+      <text class="section-title">音节分解</text>
+      <view 
+        v-for="syllable in audioInfo.syllables" 
+        :key="syllable.id"
+        class="audio-item"
+        @click="playSyllable(syllable)">
+        <text>{{ syllable.text }}</text>
+        <text>{{ syllable.index + 1 }}/{{ audioInfo.syllables.length }}</text>
+      </view>
+    </view>
+    
+    <!-- 频度音频 -->
+    <view v-if="audioInfo?.frequencies?.length" class="audio-section">
+      <text class="section-title">频度发音</text>
+      <view 
+        v-for="frequency in audioInfo.frequencies" 
+        :key="frequency.id"
+        class="audio-item"
+        @click="playFrequency(frequency)">
+        <text>{{ frequency.text }}</text>
+      </view>
+    </view>
+  </view>
+</template>
+<script setup>
+import { ref, onMounted } from 'vue'
+import audioManager from '@/utils/audioManager'
+
+const props = defineProps({
+  wordData: {
+    type: Object,
+    required: true
+  }
+})
+
+const audioInfo = ref(null)
+
+// 初始化并缓存音频
+const initAudio = async () => {
+  // 1. 从缓存获取已有信息
+  const cachedInfo = audioManager.getAudioInfoFromStorage(props.wordData.id)
+  
+  if (cachedInfo) {
+    audioInfo.value = cachedInfo
+  }
+  
+  // 2. 预加载所有音频(无论是否已有缓存)
+  await audioManager.cacheWordAudios(props.wordData)
+  
+  // 3. 更新音频信息
+  audioInfo.value = audioManager.getAudioInfoFromStorage(props.wordData.id)
+}
+
+// 播放主音频
+const playMainAudio = () => {
+  if (audioInfo.value && audioInfo.value.main) {
+    audioManager.playAudio(audioInfo.value.main)
+  }
+}
+
+// 播放音节音频
+const playSyllable = (syllable) => {
+  audioManager.playAudio(syllable)
+}
+
+// 播放频度音频
+const playFrequency = (frequency) => {
+  audioManager.playAudio(frequency)
+}
+
+onMounted(() => {
+  initAudio()
+})
+</script>
+
+
+
+<style>
+.container {
+  padding: 20rpx;
+}
+
+.audio-section {
+  margin-bottom: 30rpx;
+}
+
+.section-title {
+  display: block;
+  font-weight: bold;
+  margin-bottom: 15rpx;
+  color: #333;
+  font-size: 32rpx;
+}
+
+.audio-item {
+  padding: 20rpx;
+  margin: 10rpx 0;
+  background: #f5f5f5;
+  border-radius: 8rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+</style>

+ 216 - 0
pages/newEnglish/components/audioManager.js

@@ -0,0 +1,216 @@
+// utils/audioManager.js
+export default {
+  player: null,
+    isApp: uni.getSystemInfoSync().platform === 'ios' || uni.getSystemInfoSync().platform === 'android',
+  initPlayer() {
+    if (!this.player) {
+      this.player = uni.createInnerAudioContext()
+    //  this.player.obeyMuteSwitch = false // iOS静音模式设置
+    }
+    return this.player
+  },
+
+  // 从单词数据中提取所有音频信息
+  extractAudioInfo(wordData) {
+    const audioInfo = {
+      main: null,
+      syllables: [],
+      frequencies: []
+    }
+    
+    // 主音频
+    if (wordData.yinpin) {
+      audioInfo.main = {
+        id: `word_${wordData.id}_main`,
+        url: wordData.yinpin,
+        type: 'main',
+        text: wordData.name
+      }
+    }
+    
+    // 音节音频
+    if (wordData.yinjie && Array.isArray(wordData.yinjie)) {
+      audioInfo.syllables = wordData.yinjie.map((item, index) => ({
+        id: `word_${wordData.id}_syllable_${index}`,
+        url: item.yinpin,
+        type: 'syllable',
+        text: item.cigen,
+        index
+      })).filter(item => item.url)
+    }
+    
+    // 频度音频
+    if (wordData.pindu && Array.isArray(wordData.pindu)) {
+      audioInfo.frequencies = wordData.pindu.map((item, index) => ({
+        id: `word_${wordData.id}_frequency_${index}`,
+        url: item.yinpin,
+        type: 'frequency',
+        text: item.cigen,
+        index
+      })).filter(item => item.url)
+    }
+    
+    return audioInfo
+  },
+
+  // 缓存单词的所有音频
+  async cacheWordAudios(wordData) {
+    try {
+      // 1. 提取音频信息
+      const { main, syllables, frequencies } = this.extractAudioInfo(wordData)
+      
+      // 2. 准备所有需要缓存的音频
+      const allAudios = []
+      if (main) allAudios.push(main)
+      allAudios.push(...syllables)
+      allAudios.push(...frequencies)
+      
+
+      
+	  // App环境才进行真实下载
+	  if (this.isApp) {
+	   await this.downloadAndSaveAudios(allAudios)
+	  }
+	  
+	  
+      // 4. 保存音频信息到统一存储
+      this.saveAudioInfoToStorage(wordData.id, {
+        main,
+        syllables,
+        frequencies
+      })
+      
+      return true
+    } catch (error) {
+      console.error('音频缓存失败:', error)
+      return false
+    }
+  },
+
+  // 保存音频信息到storage(结构化存储)
+  saveAudioInfoToStorage(wordId, audioInfo) {
+    const cacheKey = `word_audio_${wordId}`
+    const cachedData = {
+      timestamp: Date.now(),
+      ...audioInfo
+    }
+    uni.setStorageSync(cacheKey, cachedData)
+  },
+
+  // 从storage获取音频信息
+  getAudioInfoFromStorage(wordId) {
+    const cacheKey = `word_audio_${wordId}`
+    return uni.getStorageSync(cacheKey) || null
+  },
+
+  // 下载并保存音频(仅App环境)
+  async downloadAndSaveAudios(audioList) {
+	  
+    const downloadPromises = audioList.map(audio => {
+      return new Promise((resolve, reject) => {
+        // 先检查是否已缓存
+        const cachedPath = uni.getStorageSync(`audio_file_${audio.id}`)
+        if (cachedPath) return resolve()
+        console.log('audio.url',audio.url);
+        uni.downloadFile({
+          url: audio.url,
+          success: (res) => {
+            if (res.statusCode === 200) {
+              uni.setStorageSync(`audio_file_${audio.id}`, res.tempFilePath)
+              resolve()
+            } else {
+              reject(new Error(`下载失败,状态码: ${res.statusCode}`))
+            }
+          },
+          fail: reject
+        })
+      }).catch(e => {
+        console.warn(`音频 ${audio.id} 预加载失败:`, e)
+        // 即使下载失败也继续其他下载
+      })
+    })
+    
+    await Promise.all(downloadPromises)
+  },
+
+  // 缓存单个音频
+  async cacheSingleAudio(id, url) {
+    return new Promise((resolve, reject) => {
+      uni.downloadFile({
+        url,
+        success: (res) => {
+          if (res.statusCode === 200) {
+            // 存储音频文件路径
+            uni.setStorageSync(`audio_file_${id}`, res.tempFilePath)
+            resolve()
+          } else {
+            reject(new Error(`下载失败,状态码: ${res.statusCode}`))
+          }
+        },
+        fail: reject
+      })
+    })
+  },
+
+  // 播放音频(优先本地,失败后回退网络)
+  playAudio(audioInfo) {
+    if (!audioInfo?.url) return
+    
+    const player = this.initPlayer()
+    player.stop()
+    console.log('this.isApp',this.isApp);
+    // 在App环境尝试使用本地缓存
+    if (this.isApp) {
+      const cachedPath = uni.getStorageSync(`audio_file_${audioInfo.id}`)
+      if (cachedPath) {
+        player.src = cachedPath
+        player.play()
+        return player
+      }
+    }
+    
+    // 非App环境或缓存失败时使用网络
+    console.warn(`使用网络音频: ${audioInfo.id}`)
+	console.log('player',player);
+	console.log('audioInfo.url',audioInfo.url);
+    player.src = audioInfo.url
+    player.play()
+    
+    // App环境下后台继续尝试缓存
+    if (this.isApp) {
+      this.downloadAndSaveAudios([audioInfo]).catch(console.error)
+    }
+    
+    // player.onError((err) => {
+    //   console.error('播放失败:', err)
+    //   uni.showToast({ title: '播放失败', icon: 'none' })
+    // })
+    
+    return player
+  },
+
+  // 清理指定单词的缓存
+  clearWordCache(wordId) {
+    // 1. 清理音频信息
+    uni.removeStorageSync(`word_audio_${wordId}`)
+    
+    // 2. 清理所有相关音频文件
+    const prefix = `word_${wordId}_`
+    const keys = uni.getStorageInfoSync().keys
+    
+    keys.filter(key => key.startsWith('audio_file_') && key.includes(prefix))
+      .forEach(key => uni.removeStorageSync(key))
+  },
+
+  // 清理所有缓存
+  clearAllCache() {
+    // 1. 清理所有音频信息
+    const keys = uni.getStorageInfoSync().keys
+    keys.filter(key => key.startsWith('word_audio_'))
+      .forEach(key => uni.removeStorageSync(key))
+    
+    // 2. 清理所有音频文件
+    keys.filter(key => key.startsWith('audio_file_'))
+      .forEach(key => uni.removeStorageSync(key))
+  }
+}

+ 188 - 0
pages/newEnglish/components/audioManager2.js

@@ -0,0 +1,188 @@
+// utils/audioManager.js
+export default {
+  player: null,
+  
+  initPlayer() {
+    if (!this.player) {
+      this.player = uni.createInnerAudioContext()
+      this.player.obeyMuteSwitch = false // iOS静音模式设置
+    }
+    return this.player
+  },
+
+  // 从单词数据中提取所有音频信息
+  extractAudioInfo(wordData) {
+    const audioInfo = {
+      main: null,
+      syllables: [],
+      frequencies: []
+    }
+    
+    // 主音频
+    if (wordData.yinpin) {
+      audioInfo.main = {
+        id: `word_${wordData.id}_main`,
+        url: wordData.yinpin,
+        type: 'main',
+        text: wordData.name
+      }
+    }
+    
+    // 音节音频
+    if (wordData.yinjie && Array.isArray(wordData.yinjie)) {
+      audioInfo.syllables = wordData.yinjie.map((item, index) => ({
+        id: `word_${wordData.id}_syllable_${index}`,
+        url: item.yinpin,
+        type: 'syllable',
+        text: item.cigen,
+        index
+      })).filter(item => item.url)
+    }
+    
+    // 频度音频
+    if (wordData.pindu && Array.isArray(wordData.pindu)) {
+      audioInfo.frequencies = wordData.pindu.map((item, index) => ({
+        id: `word_${wordData.id}_frequency_${index}`,
+        url: item.yinpin,
+        type: 'frequency',
+        text: item.cigen,
+        index
+      })).filter(item => item.url)
+    }
+    
+    return audioInfo
+  },
+
+  // 缓存单词的所有音频
+  async cacheWordAudios(wordData) {
+    try {
+      // 1. 提取音频信息
+      const { main, syllables, frequencies } = this.extractAudioInfo(wordData)
+      
+      // 2. 准备所有需要缓存的音频
+      const allAudios = []
+      if (main) allAudios.push(main)
+      allAudios.push(...syllables)
+      allAudios.push(...frequencies)
+      
+      // 3. 缓存所有音频
+      await this.cacheAllAudios(allAudios)
+      
+      // 4. 保存音频信息到统一存储
+      this.saveAudioInfoToStorage(wordData.id, {
+        main,
+        syllables,
+        frequencies
+      })
+      
+      return true
+    } catch (error) {
+      console.error('音频缓存失败:', error)
+      return false
+    }
+  },
+
+  // 保存音频信息到storage(结构化存储)
+  saveAudioInfoToStorage(wordId, audioInfo) {
+    const cacheKey = `word_audio_${wordId}`
+    const cachedData = {
+      timestamp: Date.now(),
+      ...audioInfo
+    }
+    uni.setStorageSync(cacheKey, cachedData)
+  },
+
+  // 从storage获取音频信息
+  getAudioInfoFromStorage(wordId) {
+    const cacheKey = `word_audio_${wordId}`
+    return uni.getStorageSync(cacheKey) || null
+  },
+
+  // 缓存所有音频
+  async cacheAllAudios(audioList) {
+    const cachePromises = audioList.map(audio => {
+      return this.cacheSingleAudio(audio.id, audio.url).catch(e => {
+        console.warn(`音频 ${audio.id} 预加载失败:`, e)
+        return null
+      })
+    })
+    
+    await Promise.all(cachePromises)
+  },
+
+  // 缓存单个音频
+  async cacheSingleAudio(id, url) {
+    return new Promise((resolve, reject) => {
+      uni.downloadFile({
+        url,
+        success: (res) => {
+          if (res.statusCode === 200) {
+            // 存储音频文件路径
+            uni.setStorageSync(`audio_file_${id}`, res.tempFilePath)
+            resolve()
+          } else {
+            reject(new Error(`下载失败,状态码: ${res.statusCode}`))
+          }
+        },
+        fail: reject
+      })
+    })
+  },
+
+  // 播放音频
+  playAudio(audioInfo) {
+    if (!audioInfo || !audioInfo.url) return
+    
+    const player = this.initPlayer()
+    player.stop()
+    
+    // 尝试从缓存获取
+    const cachedPath = uni.getStorageSync(`audio_file_${audioInfo.id}`)
+    
+    if (cachedPath) {
+      // 有缓存,直接播放
+      player.src = cachedPath
+      player.play()
+    } else {
+      // 无缓存,从网络播放并后台缓存
+      console.warn(`音频 ${audioInfo.id} 未缓存,从网络加载`)
+      player.src = audioInfo.url
+      player.play()
+      
+      // 后台缓存
+      this.cacheSingleAudio(audioInfo.id, audioInfo.url).catch(console.error)
+    }
+    
+    player.onError((err) => {
+      console.error('播放失败:', err)
+      uni.showToast({ title: '播放失败', icon: 'none' })
+    })
+    
+    return player
+  },
+
+  // 清理指定单词的缓存
+  clearWordCache(wordId) {
+    // 1. 清理音频信息
+    uni.removeStorageSync(`word_audio_${wordId}`)
+    
+    // 2. 清理所有相关音频文件
+    const prefix = `word_${wordId}_`
+    const keys = uni.getStorageInfoSync().keys
+    
+    keys.filter(key => key.startsWith('audio_file_') && key.includes(prefix))
+      .forEach(key => uni.removeStorageSync(key))
+  },
+
+  // 清理所有缓存
+  clearAllCache() {
+    // 1. 清理所有音频信息
+    const keys = uni.getStorageInfoSync().keys
+    keys.filter(key => key.startsWith('word_audio_'))
+      .forEach(key => uni.removeStorageSync(key))
+    
+    // 2. 清理所有音频文件
+    keys.filter(key => key.startsWith('audio_file_'))
+      .forEach(key => uni.removeStorageSync(key))
+  }
+}

+ 161 - 0
pages/newEnglish/components/audioManager3.js

@@ -0,0 +1,161 @@
+export default {
+  player: null,
+  isApp: uni.getSystemInfoSync().platform === 'ios' || uni.getSystemInfoSync().platform === 'android',
+  
+  initPlayer() {
+    if (!this.player) {
+      this.player = uni.createInnerAudioContext()
+      this.player.obeyMuteSwitch = false
+    }
+    return this.player
+  },
+
+  // 提取音频信息
+  extractAudioInfo(wordData) {
+    const audioInfo = {
+      main: null,
+      syllables: [],
+      frequencies: []
+    }
+    
+    if (wordData.yinpin) {
+      audioInfo.main = {
+        id: `word_${wordData.id}_main`,
+        url: wordData.yinpin,
+        type: 'main',
+        text: wordData.name
+      }
+    }
+    
+    if (wordData.yinjie?.length) {
+      audioInfo.syllables = wordData.yinjie.map((item, index) => ({
+        id: `word_${wordData.id}_syllable_${index}`,
+        url: item.yinpin,
+        type: 'syllable',
+        text: item.cigen,
+        index
+      })).filter(item => item.url)
+    }
+    
+    if (wordData.pindu?.length) {
+      audioInfo.frequencies = wordData.pindu.map((item, index) => ({
+        id: `word_${wordData.id}_frequency_${index}`,
+        url: item.yinpin,
+        type: 'frequency',
+        text: item.cigen,
+        index
+      })).filter(item => item.url)
+    }
+    
+    return audioInfo
+  },
+
+  // 缓存单词的所有音频
+  async cacheWordAudios(wordData) {
+    try {
+      const { main, syllables, frequencies } = this.extractAudioInfo(wordData)
+      const allAudios = []
+      
+      if (main) allAudios.push(main)
+      allAudios.push(...syllables)
+      allAudios.push(...frequencies)
+      
+      // App环境才进行真实下载
+      if (this.isApp) {
+        await this.downloadAndSaveAudios(allAudios)
+      }
+      
+      this.saveAudioInfoToStorage(wordData.id, { main, syllables, frequencies })
+      return true
+    } catch (error) {
+      console.error('音频缓存失败:', error)
+      return false
+    }
+  },
+
+  // 下载并保存音频(仅App环境)
+  async downloadAndSaveAudios(audioList) {
+    const downloadPromises = audioList.map(audio => {
+      return new Promise((resolve, reject) => {
+        // 先检查是否已缓存
+        const cachedPath = uni.getStorageSync(`audio_file_${audio.id}`)
+        if (cachedPath) return resolve()
+        
+        uni.downloadFile({
+          url: audio.url,
+          success: (res) => {
+            if (res.statusCode === 200) {
+              uni.setStorageSync(`audio_file_${audio.id}`, res.tempFilePath)
+              resolve()
+            } else {
+              reject(new Error(`下载失败,状态码: ${res.statusCode}`))
+            }
+          },
+          fail: reject
+        })
+      }).catch(e => {
+        console.warn(`音频 ${audio.id} 预加载失败:`, e)
+        // 即使下载失败也继续其他下载
+      })
+    })
+    
+    await Promise.all(downloadPromises)
+  },
+
+  // 播放音频(优先本地,失败后回退网络)
+  playAudio(audioInfo) {
+    if (!audioInfo?.url) return
+    
+    const player = this.initPlayer()
+    player.stop()
+    
+    // 在App环境尝试使用本地缓存
+    if (this.isApp) {
+      const cachedPath = uni.getStorageSync(`audio_file_${audioInfo.id}`)
+      if (cachedPath) {
+        player.src = cachedPath
+        player.play()
+        return player
+      }
+    }
+    
+    // 非App环境或缓存失败时使用网络
+    console.warn(`使用网络音频: ${audioInfo.id}`)
+    player.src = audioInfo.url
+    player.play()
+    
+    // App环境下后台继续尝试缓存
+    if (this.isApp) {
+      this.downloadAndSaveAudios([audioInfo]).catch(console.error)
+    }
+    
+    player.onError((err) => {
+      console.error('播放失败:', err)
+      uni.showToast({ title: '播放失败', icon: 'none' })
+    })
+    
+    return player
+  },
+
+  // 其他方法保持不变...
+  saveAudioInfoToStorage(wordId, audioInfo) {
+    const cacheKey = `word_audio_${wordId}`
+    uni.setStorageSync(cacheKey, {
+      timestamp: Date.now(),
+      ...audioInfo
+    })
+  },
+
+  getAudioInfoFromStorage(wordId) {
+    const cacheKey = `word_audio_${wordId}`
+    return uni.getStorageSync(cacheKey) || null
+  },
+
+  clearWordCache(wordId) {
+    uni.removeStorageSync(`word_audio_${wordId}`)
+    const prefix = `word_${wordId}_`
+    const keys = uni.getStorageInfoSync().keys
+    keys.filter(key => key.startsWith('audio_file_') && key.includes(prefix))
+      .forEach(key => uni.removeStorageSync(key))
+  }
+}

+ 320 - 0
pages/newEnglish/components/audioManager4444.js

@@ -0,0 +1,320 @@
+export default {
+  // 音频播放器实例
+  player: null,
+  
+  // 当前运行环境检测
+  isApp: null,
+  
+  // 初始化方法
+  init() {
+    // 检测运行环境
+    const systemInfo = uni.getSystemInfoSync();
+    this.isApp = systemInfo.platform === 'ios' || systemInfo.platform === 'android';
+    
+    // 初始化播放器
+    if (!this.player) {
+      this.player = uni.createInnerAudioContext();
+      this.player.obeyMuteSwitch = false; // iOS静音模式下也可播放
+      this.player.onError((err) => {
+        console.error('音频播放器错误:', err);
+        uni.showToast({ 
+          title: '播放失败,请稍后再试', 
+          icon: 'none',
+          duration: 2000
+        });
+      });
+    }
+  },
+  
+  // 从单词数据中提取所有音频信息(完整实现)
+  extractAudioInfo(wordData) {
+    if (!wordData || typeof wordData !== 'object') {
+      console.error('无效的单词数据');
+      return {
+        main: null,
+        syllables: [],
+        frequencies: []
+      };
+    }
+    
+    const audioInfo = {
+      main: null,
+      syllables: [],
+      frequencies: []
+    };
+    
+    // 处理主音频
+    if (wordData.yinpin && typeof wordData.yinpin === 'string') {
+      audioInfo.main = {
+        id: `word_${wordData.id}_main`,
+        url: this.normalizeAudioUrl(wordData.yinpin),
+        type: 'main',
+        text: wordData.name || '未知单词',
+        lastCached: 0 // 最后缓存时间戳
+      };
+    }
+    
+    // 处理音节音频
+    if (Array.isArray(wordData.yinjie)) {
+      audioInfo.syllables = wordData.yinjie
+        .filter(item => item && typeof item === 'object')
+        .map((item, index) => ({
+          id: `word_${wordData.id}_syllable_${index}`,
+          url: this.normalizeAudioUrl(item.yinpin),
+          type: 'syllable',
+          text: item.cigen || `音节${index + 1}`,
+          index,
+          lastCached: 0
+        }))
+        .filter(item => item.url);
+    }
+    
+    // 处理频度音频
+    if (Array.isArray(wordData.pindu)) {
+      audioInfo.frequencies = wordData.pindu
+        .filter(item => item && typeof item === 'object')
+        .map((item, index) => ({
+          id: `word_${wordData.id}_frequency_${index}`,
+          url: this.normalizeAudioUrl(item.yinpin),
+          type: 'frequency',
+          text: item.cigen || `频度${index + 1}`,
+          index,
+          lastCached: 0
+        }))
+        .filter(item => item.url);
+    }
+    
+    return audioInfo;
+  },
+  
+  // 标准化音频URL(完整实现)
+  normalizeAudioUrl(url) {
+    if (!url || typeof url !== 'string') return null;
+    
+    // 已经是完整URL
+    if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('blob:')) {
+      return url;
+    }
+    
+    // 处理相对路径(根据实际项目配置)
+    const baseUrl = 'https://your-audio-server.com/'; // 替换为你的音频服务器地址
+    return baseUrl + url.replace(/^\//, '');
+  },
+  
+  // 缓存单词的所有音频(完整实现)
+  async cacheWordAudios(wordData) {
+    try {
+      if (!wordData || !wordData.id) {
+        throw new Error('无效的单词数据');
+      }
+      
+      // 提取音频信息
+      const audioInfo = this.extractAudioInfo(wordData);
+      const allAudios = [];
+      
+      if (audioInfo.main) allAudios.push(audioInfo.main);
+      if (audioInfo.syllables.length) allAudios.push(...audioInfo.syllables);
+      if (audioInfo.frequencies.length) allAudios.push(...audioInfo.frequencies);
+      
+      // 真实下载音频文件(仅App环境)
+      if (this.isApp) {
+        await this.downloadAudioFiles(allAudios);
+      }
+      
+      // 保存音频信息到缓存
+      this.saveAudioInfoToStorage(wordData.id, audioInfo);
+      
+      return true;
+    } catch (error) {
+      console.error('缓存单词音频失败:', error);
+      return false;
+    }
+  },
+  
+  // 下载音频文件(完整实现)
+  async downloadAudioFiles(audioList) {
+    if (!Array.isArray(audioList)) return;
+    
+    const downloadTasks = audioList.map(audio => {
+      return new Promise((resolve, reject) => {
+        // 检查是否已有缓存
+        const cacheInfo = this.getAudioCacheInfo(audio.id);
+        if (cacheInfo && cacheInfo.cached) {
+          audio.lastCached = cacheInfo.timestamp;
+          return resolve();
+        }
+        
+        // 开始下载
+        uni.downloadFile({
+          url: audio.url,
+          success: (res) => {
+            if (res.statusCode === 200) {
+              // 保存到缓存
+              uni.setStorageSync(`audio_file_${audio.id}`, res.tempFilePath);
+              uni.setStorageSync(`audio_cache_time_${audio.id}`, Date.now());
+              
+              audio.lastCached = Date.now();
+              console.log(`音频缓存成功: ${audio.id}`);
+              resolve();
+            } else {
+              reject(new Error(`下载失败,状态码: ${res.statusCode}`));
+            }
+          },
+          fail: (err) => {
+            reject(new Error(`下载失败: ${err.errMsg}`));
+          }
+        });
+      }).catch(err => {
+        console.warn(`音频下载失败 ${audio.id}:`, err);
+        // 单个失败不影响其他
+      });
+    });
+    
+    await Promise.all(downloadTasks);
+  },
+  
+  // 获取音频缓存信息(完整实现)
+  getAudioCacheInfo(audioId) {
+    if (!audioId) return null;
+    
+    const cachedPath = uni.getStorageSync(`audio_file_${audioId}`);
+    if (!cachedPath) return null;
+    
+    return {
+      cached: true,
+      path: cachedPath,
+      timestamp: uni.getStorageSync(`audio_cache_time_${audioId}`) || 0
+    };
+  },
+  
+  // 保存音频信息到Storage(完整实现)
+  saveAudioInfoToStorage(wordId, audioInfo) {
+    if (!wordId || !audioInfo) return;
+    
+    const cacheKey = `word_audio_${wordId}`;
+    const cacheData = {
+      ...audioInfo,
+      timestamp: Date.now(),
+      wordId: wordId
+    };
+    
+    try {
+      uni.setStorageSync(cacheKey, cacheData);
+    } catch (e) {
+      console.error('存储音频信息失败:', e);
+    }
+  },
+  
+  // 从Storage获取音频信息(完整实现)
+  getAudioInfoFromStorage(wordId) {
+    if (!wordId) return null;
+    
+    const cacheKey = `word_audio_${wordId}`;
+    try {
+      return uni.getStorageSync(cacheKey) || null;
+    } catch (e) {
+      console.error('读取音频信息失败:', e);
+      return null;
+    }
+  },
+  
+  // 播放音频(完整实现)
+  playAudio(audioInfo) {
+    if (!audioInfo || !audioInfo.url) {
+      console.error('无效的音频信息');
+      return null;
+    }
+    
+    // 确保播放器初始化
+    this.init();
+    
+    // 停止当前播放
+    this.player.stop();
+    
+    // 在App环境下优先使用缓存
+    if (this.isApp) {
+      const cacheInfo = this.getAudioCacheInfo(audioInfo.id);
+      if (cacheInfo && cacheInfo.cached) {
+        console.log(`使用缓存播放: ${audioInfo.id}`);
+        this.player.src = cacheInfo.path;
+        this.player.play();
+        return this.player;
+      }
+    }
+    
+    // 无缓存或非App环境,使用网络播放
+    console.log(`使用网络播放: ${audioInfo.id}`);
+    this.player.src = audioInfo.url;
+    this.player.play();
+    
+    // App环境下后台尝试缓存
+    if (this.isApp) {
+      this.downloadAudioFiles([audioInfo]).then(() => {
+        console.log(`音频后台缓存成功: ${audioInfo.id}`);
+      }).catch(err => {
+        console.warn(`音频后台缓存失败: ${audioInfo.id}`, err);
+      });
+    }
+    
+    return this.player;
+  },
+  
+  // // 清理指定单词的缓存(完整实现)
+  // clearWordCache(wordId) {
+  //   if (!wordId) return;
+    
+  //   // 清理音频信息
+  //   uni.removeStorageSync(`word_audio_${wordId}`);
+    
+  //   // 清理所有相关音频文件
+  //   const prefix = `word_${wordId}_`;
+  //   const keys = uni.getStorageInfoSync().keys;
+    
+  //   keys.forEach(key => {
+  //     if (key.startsWith('audio_file_') && key.includes(prefix)) {
+  //       uni.removeStorageSync(key);
+  //     }
+  //     if (key.startsWith('audio_cache_time_') && key.includes(prefix)) {
+  //       uni.removeStorageSync(key);
+  //     }
+  //   });
+  // },
+  
+  // 清理所有缓存(完整实现)
+  clearAllCache() {
+    const keys = uni.getStorageInfoSync().keys;
+    
+    // 清理所有单词音频信息
+    keys.filter(key => key.startsWith('word_audio_'))
+      .forEach(key => uni.removeStorageSync(key));
+    
+    // 清理所有音频文件
+    keys.filter(key => key.startsWith('audio_file_'))
+      .forEach(key => uni.removeStorageSync(key));
+  },
+  
+  // // 获取缓存大小(完整实现)
+  // getCacheSize() {
+  //   const keys = uni.getStorageInfoSync().keys;
+  //   let size = 0;
+    
+  //   keys.filter(key => key.startsWith('audio_file_'))
+  //     .forEach(key => {
+  //       try {
+  //         const filePath = uni.getStorageSync(key);
+  //         if (filePath && typeof filePath === 'string') {
+  //           // 注意:uni-app中无法直接获取文件大小,这里返回文件数量
+  //           size += 1;
+  //         }
+  //       } catch (e) {
+  //         console.error(`获取缓存大小失败: ${key}`, e);
+  //       }
+  //     });
+    
+  //   return {
+  //     fileCount: size,
+  //     // 实际项目中可以添加更精确的大小计算
+  //     estimatedSize: size * 1024 * 100 // 假设每个文件约100KB
+  //   };
+  // }
+};

+ 69 - 7
pages/newEnglish/components/learnContent.vue

@@ -5,13 +5,35 @@
 		<selectTypesVue activeSelect="1"></selectTypesVue>
 		<view>{{activeWord.name}}</view>
 		<view>{{activeWord.yinbiao}}</view>
+		<view @click="playMainAudio">{{activeWord.yinpin}}</view>
+		<view>{{activeWord.jianyi}}</view>
+		<view>详解 ></view>
+		<view v-for="(item,index) in activeWord.yinjie" :key="index">
+			<view>{{item.cigen}}</view>
+			<view>{{item.yinbiao}}</view>
+			<view >{{item.yinpin}}</view>
+		</view>
+		<view>自然拼读</view>
+		<view>音节拆分</view>
+		<view v-if="tabFlag ==1">
+			<view>词根助记</view>
+			<view>
+				{{activeWord.cigen}}
+			</view>
+		</view>
+		
+		<view @click="clearFun">
+			asdfasdfasfasdfdasdfasdfasfadsfasdfadsfasdfasd
+		</view>
+		
 	</view>
 </template>
 
 <script setup>
 	import selectWordsVue from './selectWords.vue';
 	import selectTypesVue from './selectTypes.vue';
-	import { reactive } from 'vue';
+	import audioManager from './audioManager'
+	import { reactive,ref,onMounted } from 'vue';
 	const props = defineProps({
 		activeWord: {
 			type: Object,
@@ -20,14 +42,54 @@
 			type: Array
 		},
 	})
+	let tabFlag = ref(1)
+	// setTimeout(() => {
+	// 	console.log('activeWord',props.activeWord)
+	// })
 	
-	const data = reactive({
-		list: [],
-		selectList: [],
-	})
-	setTimeout(() => {
-		console.log('activeWord',props.activeWord)
+	const audioInfo = ref(null)
+	
+	// 初始化并缓存音频
+	const initAudio = async () => {
+	  // 1. 从缓存获取已有信息
+	  const cachedInfo = audioManager.getAudioInfoFromStorage(props.activeWord.id)
+	  
+	  if (cachedInfo) {
+	    audioInfo.value = cachedInfo
+	  }
+	  
+	  // 2. 预加载所有音频(无论是否已有缓存)
+	  await audioManager.cacheWordAudios(props.activeWord)
+	  
+	  // 3. 更新音频信息
+	  audioInfo.value = audioManager.getAudioInfoFromStorage(props.activeWord.id)
+	}
+	
+	// 播放主音频
+	const playMainAudio = () => {
+	  if (audioInfo.value && audioInfo.value.main) {
+	    audioManager.playAudio(audioInfo.value.main)
+	  }
+	}
+	
+	// 播放音节音频
+	const playSyllable = (syllable) => {
+	  audioManager.playAudio(syllable)
+	}
+	
+	// 播放频度音频
+	const playFrequency = (frequency) => {
+	  audioManager.playAudio(frequency)
+	}
+	const clearFun = (frequency) => {
+	  audioManager.clearAllCache()
+	}
+	
+	onMounted(() => {
+	  initAudio()
 	})
+	
+	
 </script>
 
 <style>

+ 7 - 1
pages/study/index.vue

@@ -502,7 +502,13 @@
 		})
 	}
 
-	function goDanciList(data, index) {
+	function goDanciList(data, index) {
+		
+		uni.redirectTo({
+			url: 	'/pages/newEnglish/index?jieId=666&wordId=42'
+		})
+
+		return
 		if (!cacheManager.get('auth')) {
 			let youkeData = {
 				subjectId: subjectId.value,

+ 5 - 5
unpackage/dist/cache/.vite/deps/_metadata.json

@@ -1,19 +1,19 @@
 {
-  "hash": "122c3a9d",
-  "configHash": "d5858f9f",
+  "hash": "dbe0ab36",
+  "configHash": "5978ec27",
   "lockfileHash": "e3b0c442",
-  "browserHash": "d8bf20c4",
+  "browserHash": "9723d4b8",
   "optimized": {
     "uview-plus": {
       "src": "../../../../../node_modules/uview-plus/index.js",
       "file": "uview-plus.js",
-      "fileHash": "c13d6800",
+      "fileHash": "81ff4469",
       "needsInterop": false
     },
     "ts-md5/dist/md5": {
       "src": "../../../../../node_modules/ts-md5/dist/md5.js",
       "file": "ts-md5_dist_md5.js",
-      "fileHash": "42fe1e3f",
+      "fileHash": "9bb684ed",
       "needsInterop": true
     }
   },