| 
						 | 
						- <template>
 -     <view class="article-detail">
 -         <!-- 导航栏 -->
 -         <!-- #ifndef H5 -->
 -         <uv-navbar :placeholder="true" left-icon="arrow-left" :title="articleData.title || '文章详情'"
 -             @leftClick="goBack"></uv-navbar>
 -         <!-- #endif -->
 - 
 -         <!-- 文章内容 -->
 -         <view class="article-container" v-if="articleData.id">
 -             <!-- 文章标题 -->
 -             <view class="article-title">{{ articleData.title }}</view>
 - 
 -             <!-- 文章信息 -->
 -             <view class="article-info">
 -                 <text class="article-time">{{ formatTime(articleData.createTime) }}</text>
 -                 <!-- <text class="article-author">{{ articleData.createBy }}</text> -->
 -             </view>
 - 
 -             <!-- 文章内容 -->
 -             <view class="article-content">
 -                 <uv-parse :content="articleData.content"/>
 -             </view>
 -         </view>
 - 
 -         <!-- 加载状态 -->
 -         <view class="loading-container" v-else-if="loading">
 -             <uv-loading-icon mode="circle"></uv-loading-icon>
 -             <text class="loading-text">加载中...</text>
 -         </view>
 - 
 -         <!-- 音频播放悬浮按钮 -->
 -         <view class="audio-float-button" v-if="hasAudio && articleData.id" @click="toggleAudio">
 -             <uv-icon :name="isPlaying ? 'pause-circle-fill' : 'play-circle-fill'" size="50"
 -                 :color="isPlaying ? '#ff6b6b' : '#4CAF50'"></uv-icon>
 -         </view>
 - 
 -     </view>
 - </template>
 - 
 - <script>
 - import audioManager from '@/utils/audioManager.js'
 - 
 - export default {
 -     data() {
 -         return {
 -             articleId: '',
 -             articleData: {},
 -             loading: true,
 -             isPlaying: false,
 -             audioUrl: '',
 -             hasAudio: false
 -         }
 -     },
 - 
 -     onLoad(options) {
 -         if (options.id) {
 -             this.articleId = options.id
 -             this.getArticleDetail()
 -         }
 -         
 -         // 绑定音频管理器事件监听
 -         this.bindAudioEvents()
 -     },
 - 
 -     onUnload() {
 -         // 页面卸载时清理音频资源和事件监听
 -         this.stopAudio()
 -         this.unbindAudioEvents()
 -     },
 - 
 -     methods: {
 -         // 绑定音频管理器事件监听
 -         bindAudioEvents() {
 -             audioManager.on('play', this.onAudioPlay)
 -             audioManager.on('pause', this.onAudioPause)
 -             audioManager.on('ended', this.onAudioEnded)
 -             audioManager.on('error', this.onAudioError)
 -         },
 - 
 -         // 解绑音频管理器事件监听
 -         unbindAudioEvents() {
 -             audioManager.off('play', this.onAudioPlay)
 -             audioManager.off('pause', this.onAudioPause)
 -             audioManager.off('ended', this.onAudioEnded)
 -             audioManager.off('error', this.onAudioError)
 -         },
 - 
 -         // 音频播放开始事件
 -         onAudioPlay(data) {
 -             if (data.audioType === 'article') {
 -                 this.isPlaying = true
 -                 console.log('文章音频开始播放')
 -             }
 -         },
 - 
 -         // 音频暂停事件
 -         onAudioPause(data) {
 -             if (data.audioType === 'article') {
 -                 this.isPlaying = false
 -                 console.log('文章音频暂停播放')
 -             }
 -         },
 - 
 -         // 音频播放结束事件
 -         onAudioEnded(data) {
 -             if (data.audioType === 'article') {
 -                 this.isPlaying = false
 -                 console.log('文章音频播放结束')
 -             }
 -         },
 - 
 -         // 音频播放错误事件
 -         onAudioError(data) {
 -             if (data.audioType === 'article') {
 -                 this.isPlaying = false
 -                 console.error('文章音频播放错误:', data.error)
 -                 uni.showToast({
 -                     title: '音频播放失败',
 -                     icon: 'none'
 -                 })
 -             }
 -         },
 - 
 -         // 返回上一页
 -         goBack() {
 -             uni.navigateBack()
 -         },
 - 
 -         // 获取文章详情
 -         async getArticleDetail() {
 -             try {
 -                 this.loading = true
 -                 const res = await this.$api.home.getArticleDetail({ id: this.articleId })
 - 
 -                 if (res.code === 200) {
 -                     this.articleData = res.result
 - 
 -                     // #ifdef H5
 -                     window.document.title = this.articleData.title || '文章详情'
 -                     // #endif
 - 
 -                     // 处理音频数据
 -                     if (res.result.audios && Object.keys(res.result.audios).length > 0) {
 -                         // 获取第一个音频URL
 -                         const audioKeys = Object.keys(res.result.audios)
 -                         this.audioUrl = res.result.audios['501008'] || res.result.audios[audioKeys[0]]
 -                         this.hasAudio = true
 -                     }
 -                 } else {
 -                     uni.showToast({
 -                         title: res.message || '获取文章详情失败',
 -                         icon: 'none'
 -                     })
 -                 }
 -             } catch (error) {
 -                 console.error('获取文章详情失败:', error)
 -                 uni.showToast({
 -                     title: '网络错误,请重试',
 -                     icon: 'none'
 -                 })
 -             } finally {
 -                 this.loading = false
 -             }
 -         },
 - 
 -         // 切换音频播放状态
 -         toggleAudio() {
 -             if (!this.audioUrl) {
 -                 console.error('音频URL为空')
 -                 return
 -             }
 - 
 -             try {
 -                 if (this.isPlaying) {
 -                     // 暂停音频
 -                     this.pauseAudio()
 -                 } else {
 -                     // 播放音频
 -                     this.playAudio()
 -                 }
 -             } catch (error) {
 -                 console.error('音频播放切换异常:', error)
 -                 this.isPlaying = false
 -             }
 -         },
 - 
 -         // 播放音频
 -         async playAudio() {
 -             if (!this.audioUrl) {
 -                 console.error('音频URL为空')
 -                 return
 -             }
 - 
 -             try {
 -                 // 使用audioManager播放音频,指定音频类型为'article'
 -                 await audioManager.playAudio(this.audioUrl, 'article')
 -                 console.log('开始播放文章音频:', this.audioUrl)
 -             } catch (error) {
 -                 console.error('音频播放异常:', error)
 -                 this.isPlaying = false
 -                 uni.showToast({
 -                     title: '音频播放失败',
 -                     icon: 'none'
 -                 })
 -             }
 -         },
 - 
 -         // 暂停音频
 -         pauseAudio() {
 -             try {
 -                 audioManager.pause()
 -                 console.log('暂停文章音频')
 -             } catch (error) {
 -                 console.error('暂停音频失败:', error)
 -             }
 -         },
 - 
 -         // 停止音频
 -         stopAudio() {
 -             try {
 -                 audioManager.stopCurrentAudio()
 -                 this.isPlaying = false
 -                 console.log('停止文章音频')
 -             } catch (error) {
 -                 console.error('停止音频失败:', error)
 -             }
 -         },
 - 
 -         // 格式化时间
 -         formatTime(timeStr) {
 -             if (!timeStr) return ''
 - 
 -             // 处理iOS兼容性问题,将 "2025-10-23 16:36:43" 格式转换为 "2025/10/23 16:36:43"
 -             let formattedTimeStr = timeStr.replace(/-/g, '/')
 - 
 -             const date = new Date(formattedTimeStr)
 - 
 -             // 检查日期是否有效
 -             if (isNaN(date.getTime())) {
 -                 console.warn('Invalid date format:', timeStr)
 -                 return timeStr // 返回原始字符串
 -             }
 - 
 -             const year = date.getFullYear()
 -             const month = String(date.getMonth() + 1).padStart(2, '0')
 -             const day = String(date.getDate()).padStart(2, '0')
 -             return `${year}-${month}-${day}`
 -         }
 -     }
 - }
 - </script>
 - 
 - <style lang="scss" scoped>
 - .article-detail {
 -     min-height: 100vh;
 -     background: #fff;
 - }
 - 
 - .article-container {
 -     padding: 30rpx;
 - }
 - 
 - .article-title {
 -     font-size: 40rpx;
 -     font-weight: 600;
 -     color: #333;
 -     line-height: 1.4;
 -     margin-bottom: 30rpx;
 - }
 - 
 - .article-info {
 -     display: flex;
 -     align-items: center;
 -     gap: 30rpx;
 -     margin-bottom: 40rpx;
 -     padding-bottom: 30rpx;
 -     border-bottom: 1px solid #f0f0f0;
 - 
 -     .article-time {
 -         font-size: 26rpx;
 -         color: #999;
 -     }
 - 
 -     .article-author {
 -         font-size: 26rpx;
 -         color: #666;
 - 
 -         &::before {
 -             content: '作者:';
 -         }
 -     }
 - }
 - 
 - .article-content {
 -     font-size: 32rpx;
 -     line-height: 1.8;
 -     color: #333;
 - 
 -     // 富文本内容样式
 -     :deep(.rich-text) {
 -         p {
 -             margin-bottom: 20rpx;
 -             line-height: 1.8;
 -         }
 - 
 -         img {
 -             max-width: 100%;
 -             height: auto;
 -             border-radius: 8rpx;
 -             margin: 20rpx 0;
 -         }
 - 
 -         section {
 -             margin: 20rpx 0;
 -         }
 -     }
 - }
 - 
 - .loading-container {
 -     display: flex;
 -     flex-direction: column;
 -     align-items: center;
 -     justify-content: center;
 -     height: 400rpx;
 - 
 -     .loading-text {
 -         margin-top: 20rpx;
 -         font-size: 28rpx;
 -         color: #999;
 -     }
 - }
 - 
 - // 音频播放悬浮按钮
 - .audio-float-button {
 -     position: fixed;
 -     right: 30rpx;
 -     bottom: 100rpx;
 -     width: 100rpx;
 -     height: 100rpx;
 -     border-radius: 50%;
 -     background: rgba(255, 255, 255, 0.9);
 -     box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
 -     display: flex;
 -     align-items: center;
 -     justify-content: center;
 -     z-index: 999;
 -     transition: all 0.3s ease;
 - 
 -     &:active {
 -         transform: scale(0.95);
 -     }
 - 
 -     // 添加呼吸动画效果
 -     &::before {
 -         content: '';
 -         position: absolute;
 -         top: -10rpx;
 -         left: -10rpx;
 -         right: -10rpx;
 -         bottom: -10rpx;
 -         border-radius: 50%;
 -         background: rgba(76, 175, 80, 0.2);
 -         animation: pulse 2s infinite;
 -         z-index: -1;
 -     }
 - }
 - 
 - @keyframes pulse {
 -     0% {
 -         transform: scale(1);
 -         opacity: 1;
 -     }
 - 
 -     50% {
 -         transform: scale(1.1);
 -         opacity: 0.7;
 -     }
 - 
 -     100% {
 -         transform: scale(1);
 -         opacity: 1;
 -     }
 - }
 - </style>
 
 
  |