<template>
	<view class="speech-evaluation-container">
		<!-- 顶部导航栏 -->
		<view class="top-header">
			<view class="header-left" @click="goBack">
				<text class="back-icon">‹</text>
				<text class="back-text">返回</text>
			</view>
			<text class="header-title">语音测评</text>
			<view class="header-right"></view>
		</view>

		<!-- 内容选择区域 -->
		<view class="content-select-section" v-if="!selectedContent">
			<view class="section-title">📚 选择测评内容</view>
			<view class="content-list" v-if="contentList.length > 0">
				<view 
					v-for="(item, index) in contentList" 
					:key="item.id || index"
					class="content-item"
					@click="selectContent(item)"
				>
					<view class="content-item-header">
						<text class="content-item-title">{{ item.title || '未命名题目' }}</text>
						<text class="content-item-difficulty" :class="'difficulty-' + (item.difficulty || 'medium')">
							{{ getDifficultyText(item.difficulty) }}
						</text>
					</view>
					<view class="content-item-preview">
						{{ item.content ? (item.content.length > 50 ? item.content.substring(0, 50) + '...' : item.content) : '暂无内容' }}
					</view>
				</view>
			</view>
			<view v-else-if="!loadingContent" class="empty-tip">
				<text class="empty-icon">📭</text>
				<text>暂无测评内容</text>
			</view>
			<view v-else class="loading-tip">
				<text>加载中...</text>
			</view>
		</view>

		<!-- 测评内容显示区域 -->
		<view class="content-display-section" v-if="selectedContent">
			<view class="section-header">
				<text class="section-title">📝 测评内容</text>
				<text class="change-btn" @click="changeContent">更换</text>
			</view>
			<view class="content-text">
				<text>{{ selectedContent.content }}</text>
			</view>
		</view>

		<!-- 语音识别状态 -->
		<view class="status-section" v-if="selectedContent">
			<view class="status-item">
				<text class="status-label">识别状态：</text>
				<text class="status-value" :class="{ 
					'status-ready': isReady && !isRecording, 
					'status-recording': isRecording,
					'status-loading': isLoading 
				}">
					{{ statusText }}
				</text>
			</view>
			<!-- 调试信息 -->
			<view class="debug-info" v-if="debugInfo">
				<text class="debug-text">{{ debugInfo }}</text>
			</view>
			<view class="recording-tip" v-if="isRecording">
				<view class="recording-dots">
					<view class="dot dot1"></view>
					<view class="dot dot2"></view>
					<view class="dot dot3"></view>
				</view>
				<text class="recording-text">正在识别，请清晰朗读，每句话后稍作停顿...</text>
			</view>
		</view>
		
		<!-- 语音识别操作区域 -->
		<view class="action-section" v-if="selectedContent">
			<!-- 未准备好时显示初始化按钮 -->
			<button 
				v-if="!isReady && !isLoading"
				class="action-btn btn-init" 
				@click="initSpeechModel"
			>
				<text class="btn-icon">🔄</text>
				<text class="btn-text">重新初始化</text>
			</button>
			
			<!-- 准备好后显示开始按钮 -->
			<button 
				v-if="isReady"
				class="action-btn" 
				:class="{ 'btn-recording': isRecording, 'btn-ready': !isRecording }"
				:disabled="isLoading"
				@click="handleStart"
			>
				<text class="btn-icon">{{ isRecording ? '🎤' : '🎙️' }}</text>
				<text class="btn-text">{{ isRecording ? '正在识别...' : '开始说话' }}</text>
			</button>
			<button v-if="isRecording" class="action-btn btn-stop" @click="handleStop">
				<text class="btn-text">停止识别</text>
			</button>
			
			<!-- 手动输入按钮 -->
			<button class="manual-input-btn" @click="showManualInput">
				<text>📝 手动输入文本</text>
			</button>
			
			<!-- 工具按钮 -->
			<view class="tool-buttons">
				<button class="tool-btn" @click="clearModelCache">
					<text>🗑️ 清除缓存重新加载</text>
				</button>
				<button class="tool-btn" @click="testMicrophone">
					<text>🎤 测试麦克风</text>
				</button>
			</view>
		</view>
		
		<!-- 识别结果区域 -->
		<view class="result-section" v-if="selectedContent && (recognizedText || isRecording)">
			<view class="section-title">🎯 识别结果</view>
			<view class="recognition-progress" v-if="isRecording">
				<view class="progress-dots">
					<view class="progress-dot dot1"></view>
					<view class="progress-dot dot2"></view>
					<view class="progress-dot dot3"></view>
				</view>
				<text class="progress-text">实时识别中...</text>
			</view>
			<view class="result-content">
				<scroll-view class="result-scroll" scroll-y :scroll-top="scrollTop" scroll-with-animation>
					<text class="result-text" v-if="recognizedText">{{ recognizedText }}</text>
					<text class="result-text text-loading" v-else-if="isRecording">正在启动语音识别，请稍候...</text>
					<view class="typing-cursor" v-if="isRecording && recognizedText">|</view>
				</scroll-view>
			</view>
			<button 
				class="evaluate-btn" 
				@click="evaluateScore"
				:loading="isEvaluating"
				:disabled="!recognizedText || recognizedText.trim() === ''"
				v-if="!isRecording"
			>
				{{ isEvaluating ? '评分中...' : '开始评分' }}
			</button>
		</view>

		<!-- 评分结果区域 -->
		<view class="score-section" v-if="scoreResult">
			<view class="section-title">📊 评分结果</view>
			<view class="score-main">
				<text class="score-main-value">{{ scoreResult.totalScore }}</text>
				<text class="score-main-label">总分</text>
			</view>
			<view class="score-details">
				<view class="score-item">
					<view class="score-item-header">
						<text class="score-item-label">准确度</text>
						<text class="score-item-value">{{ scoreResult.accuracy }}分</text>
					</view>
					<view class="score-progress">
						<view class="score-progress-bar" :style="{ width: scoreResult.accuracy + '%' }"></view>
					</view>
				</view>
				<view class="score-item">
					<view class="score-item-header">
						<text class="score-item-label">完整度</text>
						<text class="score-item-value">{{ scoreResult.completeness }}分</text>
					</view>
					<view class="score-progress">
						<view class="score-progress-bar" :style="{ width: scoreResult.completeness + '%' }"></view>
					</view>
				</view>
				<view class="score-item">
					<view class="score-item-header">
						<text class="score-item-label">流畅度</text>
						<text class="score-item-value">{{ scoreResult.fluency }}分</text>
					</view>
					<view class="score-progress">
						<view class="score-progress-bar" :style="{ width: scoreResult.fluency + '%' }"></view>
					</view>
				</view>
				<view class="score-item">
					<view class="score-item-header">
						<text class="score-item-label">发音</text>
						<text class="score-item-value">{{ scoreResult.pronunciation }}分</text>
					</view>
					<view class="score-progress">
						<view class="score-progress-bar" :style="{ width: scoreResult.pronunciation + '%' }"></view>
					</view>
				</view>
			</view>
			<view class="score-info" v-if="scoreResult.details">
				<view class="info-item">
					<text class="info-label">相似度：</text>
					<text class="info-value">{{ scoreResult.details.similarity }}%</text>
				</view>
				<view class="info-item">
					<text class="info-label">正确字符：</text>
					<text class="info-value">{{ scoreResult.details.correctChars }}/{{ scoreResult.details.totalChars }}</text>
				</view>
			</view>
			<view class="submit-section" v-if="currentEvaluationId && !isSubmitted">
				<button @click="submitEvaluation" class="btn-submit" :loading="isSubmitting">
					{{ isSubmitting ? '提交中...' : '提交评测' }}
				</button>
			</view>
			<view class="submit-status-section" v-if="isSubmitted">
				<text class="submit-status-text">✓ 已提交</text>
			</view>
			<view class="action-buttons">
				<button class="btn-retry" @click="resetEvaluation">重新测评</button>
				<button class="btn-change" @click="changeContent">更换内容</button>
			</view>
		</view>
	</view>
</template>

<script>
import { getVoiceEvaluationContents, evaluateSpeechRecognition, saveVoiceScore, submitVoiceEvaluation } from '@/api/study/voiceEvaluation.js'

// #ifdef APP-PLUS
import { initVoskModel, startSpeechVoice, stopSpeechVoice } from '@/uni_modules/xwq-speech-to-text'
import { initPerssion } from '@/uni_modules/xwq-speech-to-text/utssdk/app-android/getPermission.uts'
// #endif

export default {
	data() {
		return {
			contentList: [],
			loadingContent: false,
			selectedContent: null,
			modelPath: '',
			recognizedText: '',
			isReady: false,
			isRecording: false,
			isLoading: false,
			statusText: '准备中...',
			debugInfo: '', // 调试信息
			scrollTop: 0,
			scrollTimer: null,
			hasFirstResult: false,
			scoreResult: null,
			isEvaluating: false,
			currentEvaluationId: null,
			isSubmitted: false,
			isSubmitting: false,
			isSaving: false,
			pageUnloaded: false // 页面卸载标记
		}
	},
	onLoad(options) {
		if (options.contentId) {
			this.loadContentById(options.contentId)
		} else {
			this.loadContentList()
		}
		// #ifdef APP-PLUS
		// 检查UTS插件是否可用
		try {
			if (typeof initVoskModel === 'undefined') {
				this.statusText = '语音识别插件未加载'
				this.debugInfo = '需要制作自定义基座才能使用语音识别功能。\n\n步骤：\n1. HBuilderX菜单：发行 → 原生App-制作自定义调试基座\n2. 选择Android平台\n3. 等待打包完成\n4. 安装自定义基座到手机'
				console.log('[Speech] UTS插件未加载，需要自定义基座')
			} else {
				// 请求麦克风权限
				initPerssion(['android.permission.RECORD_AUDIO']).then(res => {
					console.log('[Speech] 麦克风权限结果:', res)
					if (res.isPass) {
						console.log('[Speech] 麦克风权限已授予')
						this.initSpeechModel()
					} else {
						console.error('[Speech] 麦克风权限被拒绝')
						this.statusText = '需要麦克风权限'
						this.debugInfo = '语音识别需要麦克风权限，请在设置中授予权限'
						uni.showToast({ title: '请授予麦克风权限', icon: 'none', duration: 3000 })
					}
				}).catch(err => {
					console.error('[Speech] 权限请求失败:', err)
					// 即使权限请求失败，也尝试初始化（可能已有权限）
					this.initSpeechModel()
				})
			}
		} catch(e) {
			this.statusText = '语音识别插件加载失败'
			this.debugInfo = '错误：' + (e.message || JSON.stringify(e)) + '\n\n需要制作自定义基座才能使用语音识别功能。'
			console.error('[Speech] 插件加载失败:', e)
		}
		// #endif
		// #ifndef APP-PLUS
		this.statusText = '语音识别仅支持APP端'
		this.debugInfo = '请在APP端使用语音识别功能'
		// #endif
	},
	onUnload() {
		console.log('[Speech] 页面卸载，清理资源')
		// 标记页面已卸载，防止回调继续执行
		this.pageUnloaded = true
		
		// #ifdef APP-PLUS
		// 安全地停止语音识别
		if (this.isRecording) {
			this.isRecording = false
			try { 
				if (typeof stopSpeechVoice === 'function') {
					stopSpeechVoice() 
				}
			} catch(e) {
				console.error('[Speech] 停止识别时出错:', e)
			}
		}
		// #endif
		this.stopAutoScroll()
		// 清理定时器
		if (this.scrollTimer) {
			clearInterval(this.scrollTimer)
			this.scrollTimer = null
		}
	},
	onHide() {
		console.log('[Speech] 页面隐藏，暂停识别')
		// 页面切换到后台时停止识别
		if (this.isRecording) {
			this.handleStop()
		}
	},
	methods: {
		async loadContentList() {
			this.loadingContent = true
			try {
				const result = await getVoiceEvaluationContents()
				if (result.code === 200 && result.data) {
					this.contentList = Array.isArray(result.data) ? result.data : result.data.list || []
				} else {
					this.contentList = []
				}
			} catch (error) {
				console.error('加载内容列表失败', error)
				this.contentList = []
			} finally {
				if (this.contentList.length === 0) {
					this.contentList = this.getMockData()
				}
				this.loadingContent = false
			}
		},
		getMockData() {
			return [
				{ id: 1, title: '基础拼音练习', content: '春眠不觉晓，处处闻啼鸟。夜来风雨声，花落知多少。', difficulty: 'easy' },
				{ id: 2, title: '古诗朗诵', content: '床前明月光，疑是地上霜。举头望明月，低头思故乡。', difficulty: 'medium' },
				{ id: 3, title: '绕口令练习', content: '四是四，十是十，十四是十四，四十是四十。', difficulty: 'hard' }
			]
		},
		async loadContentById(contentId) {
			this.loadingContent = true
			try {
				const result = await getVoiceEvaluationContents({ id: contentId })
				if (result.code === 200 && result.data) {
					const data = Array.isArray(result.data) ? result.data : result.data.list || []
					if (data.length > 0) this.selectedContent = data[0]
				}
			} catch (error) {
				console.error('加载内容失败', error)
			} finally {
				this.loadingContent = false
			}
		},
		selectContent(item) {
			this.selectedContent = item
			this.recognizedText = ''
			this.scoreResult = null
			this.currentEvaluationId = null
			this.isSubmitted = false
		},
		changeContent() {
			this.selectedContent = null
			this.recognizedText = ''
			this.scoreResult = null
			this.currentEvaluationId = null
			this.isSubmitted = false
			this.loadContentList()
		},

		// #ifdef APP-PLUS
		initSpeechModel() {
			console.log('[Speech] ========== 开始初始化语音模型 ==========')
			this.isLoading = true
			this.statusText = '正在初始化模型...'
			this.debugInfo = '检查模型缓存...'
			
			try {
				// 先检查是否有已保存的模型路径
				const savedModelPath = uni.getStorageSync('vosk_model_path')
				console.log('[Speech] 已保存的模型路径:', savedModelPath)
				
				if (savedModelPath) {
					this.debugInfo = '加载已解压模型: ' + savedModelPath.substring(savedModelPath.length - 30)
					this.statusText = '正在加载已解压模型...'
					
					initVoskModel({ 
						modelPath: savedModelPath, 
						zipModelPath: '' 
					}, (result) => {
						console.log('[Speech] 加载已保存模型结果:', JSON.stringify(result))
						if (result && result.data && result.data.modelPath) {
							this.modelPath = result.data.modelPath
							this.isReady = true
							this.isLoading = false
							this.statusText = '准备就绪，可以开始说话'
							this.debugInfo = '模型已加载: ' + this.modelPath.substring(this.modelPath.length - 20)
							console.log('[Speech] 模型加载成功:', this.modelPath)
						} else {
							console.log('[Speech] 已保存模型加载失败，尝试从静态资源加载')
							// 清除无效的缓存
							uni.removeStorageSync('vosk_model_path')
							this.initFromStatic()
						}
					})
				} else {
					this.initFromStatic()
				}
			} catch (error) {
				console.error('[Speech] 初始化错误:', error)
				this.isLoading = false
				this.statusText = '初始化失败'
				this.debugInfo = '错误: ' + (error.message || JSON.stringify(error))
				uni.showToast({ title: '模型初始化失败', icon: 'none' })
			}
		},
		
		initFromStatic() {
			console.log('[Speech] ========== 从静态资源加载模型 ==========')
			this.statusText = '正在解压模型文件...'
			this.debugInfo = '首次加载，正在解压模型（约需30秒）...'
			
			try {
				// 模型文件路径
				const staticZipPath = '/static/vosk-model-small-cn-0.22.zip'
				let resolvedPath = staticZipPath
				
				// 转换路径
				if (typeof plus !== 'undefined' && plus.io && typeof plus.io.convertLocalFileSystemURL === 'function') {
					resolvedPath = plus.io.convertLocalFileSystemURL(staticZipPath)
					console.log('[Speech] 转换后的路径:', resolvedPath)
				}
				
				this.debugInfo = '模型路径: ' + resolvedPath
				
				initVoskModel({ 
					zipModelPath: resolvedPath 
				}, (result) => {
					console.log('[Speech] 静态资源加载结果:', JSON.stringify(result))
					
					if (result && result.data && result.data.modelPath) {
						this.modelPath = result.data.modelPath
						// 保存模型路径，下次直接加载
						uni.setStorageSync('vosk_model_path', result.data.modelPath)
						this.isReady = true
						this.isLoading = false
						this.statusText = '准备就绪，可以开始说话'
						this.debugInfo = '模型解压成功'
						console.log('[Speech] 模型解压成功:', this.modelPath)
						uni.showToast({ title: '模型加载成功', icon: 'success', duration: 2000 })
					} else {
						console.error('[Speech] 模型加载失败，结果:', result)
						this.isLoading = false
						this.statusText = '模型加载失败'
						this.debugInfo = '加载失败: ' + JSON.stringify(result)
						uni.showToast({ title: '模型加载失败，请检查模型文件', icon: 'none', duration: 3000 })
					}
				})
			} catch (error) {
				console.error('[Speech] 加载静态资源失败:', error)
				this.isLoading = false
				this.statusText = '模型加载失败'
				this.debugInfo = '异常: ' + (error.message || JSON.stringify(error))
			}
		},
		
		handleStart() {
			// 检查模型是否准备好
			if (!this.isReady) {
				uni.showToast({ title: '模型未准备好，请稍候', icon: 'none' })
				return
			}
			
			// 防止重复点击
			if (this.isRecording) {
				console.log('[Speech] 已在录音中，忽略重复点击')
				return
			}
			
			// 检查模型路径是否有效
			if (!this.modelPath) {
				uni.showToast({ title: '模型路径无效，请重新初始化', icon: 'none' })
				this.isReady = false
				return
			}
			
			console.log('[Speech] ========== 开始语音识别 ==========')
			console.log('[Speech] 模型路径:', this.modelPath)
			
			this.isRecording = true
			this.statusText = '正在识别中...'
			this.recognizedText = ''
			this.scoreResult = null
			this.hasFirstResult = false
			this.debugInfo = '识别中...'
			this.startAutoScroll()
			
			try {
				const self = this
				startSpeechVoice((res) => {
					// 检查页面是否已卸载
					if (self.pageUnloaded) {
						console.log('[Speech] 页面已卸载，忽略回调')
						return
					}
					
					// 检查是否仍在录音状态，如果已停止则忽略回调
					if (!self.isRecording) {
						console.log('[Speech] 已停止录音，忽略回调')
						return
					}
					
					console.log('[Speech] 识别回调:', JSON.stringify(res))
					
					// 检查是否有错误（code === -1 表示错误）
					if (res && res.code === -1) {
						console.error('[Speech] 识别出错:', res.data?.errorMsg)
						self.isRecording = false
						self.statusText = '识别出错'
						self.debugInfo = '错误: ' + (res.data?.errorMsg || '未知错误')
						self.stopAutoScroll()
						uni.showToast({ title: res.data?.errorMsg || '语音识别出错', icon: 'none', duration: 2000 })
						return
					}
					
					if (res && res.data && res.data.text) {
						const text = res.data.text
						console.log('[Speech] 识别到文本:', text, '长度:', text.length)
						
						// 实时显示识别结果（vosk会持续返回实时结果）
						if (text && text.trim()) {
							self.recognizedText = text
							self.hasFirstResult = true
							self.debugInfo = '实时识别中: ' + text.length + '字'
							self.$nextTick(() => { self.scrollToBottom() })
						}
					}
				})
			} catch (error) {
				console.error('[Speech] 开始识别错误:', error)
				this.isRecording = false
				this.statusText = '识别启动失败'
				this.debugInfo = '启动失败: ' + (error.message || JSON.stringify(error))
				uni.showToast({ title: '识别启动失败', icon: 'none' })
			}
		},
		
		handleStop() {
			console.log('[Speech] ========== 停止语音识别 ==========')
			
			// 防止重复调用
			if (!this.isRecording) {
				console.log('[Speech] 未在录音中，忽略停止请求')
				return
			}
			
			// 先设置状态为非录音，这样回调会被忽略
			this.isRecording = false
			this.stopAutoScroll()
			
			try {
				// 安全地停止语音识别
				if (typeof stopSpeechVoice === 'function') {
					stopSpeechVoice()
				}
				this.statusText = '识别完成'
				
				// 延迟检查结果，等待最后的回调处理完成
				setTimeout(() => {
					if (!this.hasFirstResult || !this.recognizedText || this.recognizedText.trim() === '') {
						this.debugInfo = '未识别到有效语音'
						uni.showToast({ title: '未识别到有效语音，请重试或手动输入', icon: 'none', duration: 2000 })
					} else {
						this.debugInfo = '识别完成，共' + this.recognizedText.length + '字'
						uni.showToast({ title: '识别完成', icon: 'success', duration: 1500 })
					}
				}, 300)
			} catch (error) {
				console.error('[Speech] 停止识别错误:', error)
				this.statusText = '已停止识别'
				this.debugInfo = '停止时出错: ' + (error.message || '')
			}
		},
		// #endif
		
		// #ifndef APP-PLUS
		handleStart() { 
			uni.showToast({ title: '语音识别仅支持APP端', icon: 'none' }) 
		},
		handleStop() {},
		initSpeechModel() {
			this.statusText = '语音识别仅支持APP端'
		},
		// #endif
		
		// 手动输入文本
		showManualInput() {
			uni.showModal({
				title: '手动输入识别文本',
				editable: true,
				placeholderText: '请输入您要朗读的内容',
				success: (res) => {
					if (res.confirm && res.content) {
						this.recognizedText = res.content.trim()
						this.hasFirstResult = true
						this.statusText = '已手动输入文本'
						this.debugInfo = '手动输入: ' + this.recognizedText.length + '字'
					}
				}
			})
		},
		
		// 清除模型缓存并重新加载
		clearModelCache() {
			uni.showModal({
				title: '清除缓存',
				content: '将清除已解压的模型缓存，重新从静态资源解压。这可能需要30秒左右，确定继续？',
				success: (res) => {
					if (res.confirm) {
						// 清除缓存
						uni.removeStorageSync('vosk_model_path')
						this.modelPath = ''
						this.isReady = false
						this.debugInfo = '缓存已清除，正在重新加载...'
						// 重新初始化
						// #ifdef APP-PLUS
						this.initFromStatic()
						// #endif
					}
				}
			})
		},
		
		// 测试麦克风
		testMicrophone() {
			this.debugInfo = '正在测试麦克风...'
			// #ifdef APP-PLUS
			const recorderManager = uni.getRecorderManager()
			
			recorderManager.onStart(() => {
				this.debugInfo = '麦克风正常，正在录音...'
				uni.showToast({ title: '正在录音...', icon: 'none', duration: 3000 })
			})
			
			recorderManager.onStop((res) => {
				console.log('[Speech] 测试录音结果:', res)
				if (res.tempFilePath) {
					this.debugInfo = '麦克风测试成功！录音文件: ' + res.tempFilePath.substring(res.tempFilePath.length - 30)
					uni.showToast({ title: '麦克风正常', icon: 'success' })
					
					// 播放录音
					const innerAudioContext = uni.createInnerAudioContext()
					innerAudioContext.src = res.tempFilePath
					innerAudioContext.play()
					innerAudioContext.onEnded(() => {
						this.debugInfo += '\n录音播放完成'
					})
				} else {
					this.debugInfo = '麦克风测试失败：未获取到录音文件'
					uni.showToast({ title: '麦克风测试失败', icon: 'none' })
				}
			})
			
			recorderManager.onError((err) => {
				console.error('[Speech] 麦克风测试错误:', err)
				this.debugInfo = '麦克风错误: ' + (err.errMsg || JSON.stringify(err))
				uni.showToast({ title: '麦克风错误', icon: 'none' })
			})
			
			// 开始录音3秒
			recorderManager.start({
				duration: 3000,
				sampleRate: 16000,
				numberOfChannels: 1,
				format: 'mp3'
			})
			// #endif
			// #ifndef APP-PLUS
			this.debugInfo = '麦克风测试仅支持APP端'
			// #endif
		},

		scrollToBottom() { this.scrollTop = 99999 },
		startAutoScroll() {
			this.stopAutoScroll()
			this.scrollTimer = setInterval(() => { if (this.isRecording) this.scrollToBottom() }, 500)
		},
		stopAutoScroll() {
			if (this.scrollTimer) { clearInterval(this.scrollTimer); this.scrollTimer = null }
		},
		async evaluateScore() {
			if (!this.recognizedText || !this.selectedContent) {
				uni.showToast({ title: '请先完成语音识别', icon: 'none' })
				return
			}
			this.isEvaluating = true
			try {
				const result = await evaluateSpeechRecognition(this.selectedContent.content, this.recognizedText)
				if (result.code === 200 && result.data) {
					this.scoreResult = result.data
					await this.saveScoreToBackend(result.data)
					uni.showToast({ title: '评分完成', icon: 'success', duration: 2000 })
					this.$nextTick(() => { uni.pageScrollTo({ selector: '.score-section', duration: 300 }) })
				} else {
					throw new Error(result.msg || '评分失败')
				}
			} catch (error) {
				console.error('评分失败', error)
				uni.showToast({ title: error.message || '评分失败', icon: 'none', duration: 3000 })
			} finally {
				this.isEvaluating = false
			}
		},
		async saveScoreToBackend(scoreData) {
			if (!this.selectedContent || !this.recognizedText) return
			this.isSaving = true
			try {
				const resultDetail = JSON.stringify({
					recognizedText: this.recognizedText,
					originalText: this.selectedContent.content,
					details: scoreData.details || {}
				})
				const result = await saveVoiceScore(
					this.selectedContent.content, this.recognizedText,
					scoreData.totalScore, scoreData.accuracy, scoreData.completeness,
					scoreData.fluency, scoreData.pronunciation, null, resultDetail
				)
				let evaluation = null
				if (result.code === 200) {
					if (result.data && result.data.evaluation) evaluation = result.data.evaluation
					else if (result.evaluation) evaluation = result.evaluation
					else if (result.data && result.data.id) evaluation = result.data
				}
				if (evaluation && evaluation.id) {
					this.currentEvaluationId = evaluation.id
					const submitted = evaluation.isSubmitted
					this.isSubmitted = submitted === 1 || submitted === true || submitted === '1'
				}
			} catch (error) {
				console.error('保存评分到后端失败', error)
			} finally {
				this.isSaving = false
			}
		},
		async submitEvaluation() {
			if (!this.currentEvaluationId) {
				uni.showToast({ title: '请先完成评分', icon: 'none' })
				return
			}
			if (this.isSubmitted) {
				uni.showToast({ title: '该评测已提交', icon: 'none' })
				return
			}
			uni.showModal({
				title: '确认提交',
				content: '提交后，管理员将看到您的评测结果，是否确认提交？',
				success: async (res) => {
					if (res.confirm) {
						this.isSubmitting = true
						try {
							const result = await submitVoiceEvaluation(this.currentEvaluationId)
							if (result.code === 200) {
								this.isSubmitted = true
								uni.showToast({ title: '提交成功', icon: 'success', duration: 2000 })
							} else {
								throw new Error(result.msg || '提交失败')
							}
						} catch (error) {
							console.error('提交失败', error)
							uni.showToast({ title: error.message || '提交失败', icon: 'none', duration: 3000 })
						} finally {
							this.isSubmitting = false
						}
					}
				}
			})
		},
		resetEvaluation() {
			this.recognizedText = ''
			this.scoreResult = null
			this.currentEvaluationId = null
			this.isSubmitted = false
		},
		getDifficultyText(difficulty) {
			const map = { 'easy': '简单', 'medium': '中等', 'hard': '困难' }
			return map[difficulty] || '中等'
		},
		goBack() {
			const pages = getCurrentPages()
			if (pages.length > 1) {
				uni.navigateBack({ delta: 1, fail: () => { uni.switchTab({ url: '/pages/index/index' }) } })
			} else {
				uni.switchTab({ url: '/pages/index/index' })
			}
		}
	}
}
</script>


<style scoped>
.speech-evaluation-container {
	padding: 20rpx;
	padding-top: calc(var(--status-bar-height) + 20rpx);
	background: linear-gradient(to bottom, #f5f7fa 0%, #c3cfe2 100%);
	min-height: 100vh;
}
.top-header {
	background: linear-gradient(135deg, rgb(55 140 224) 0%, rgb(45 120 200) 100%);
	padding: 30rpx;
	padding-top: calc(30rpx + var(--status-bar-height));
	margin: -20rpx -20rpx 30rpx -20rpx;
	margin-top: calc(-20rpx - var(--status-bar-height));
	display: flex;
	justify-content: space-between;
	align-items: center;
	box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.header-left {
	display: flex;
	align-items: center;
	gap: 8rpx;
	padding: 10rpx 20rpx;
	border-radius: 20rpx;
	background: rgba(255, 255, 255, 0.2);
}
.back-icon { font-size: 48rpx; font-weight: bold; color: #fff; line-height: 1; }
.back-text { font-size: 28rpx; color: #fff; }
.header-title { font-size: 36rpx; font-weight: bold; color: #fff; flex: 1; text-align: center; }
.header-right { width: 120rpx; }
.content-select-section, .content-display-section, .status-section, .action-section, .result-section, .score-section {
	background: #fff;
	border-radius: 20rpx;
	padding: 30rpx;
	margin-bottom: 30rpx;
	box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
}
.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20rpx; }
.section-title { font-size: 32rpx; font-weight: bold; color: #333; margin-bottom: 20rpx; display: block; }
.change-btn { font-size: 26rpx; color: #409eff; padding: 8rpx 20rpx; border: 1px solid #409eff; border-radius: 20rpx; }
.content-list { display: flex; flex-direction: column; gap: 20rpx; }
.content-item { padding: 24rpx; background: #f8f9fa; border-radius: 12rpx; border-left: 4rpx solid #409eff; }
.content-item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
.content-item-title { font-size: 30rpx; font-weight: bold; color: #333; }
.content-item-difficulty { font-size: 24rpx; padding: 4rpx 12rpx; border-radius: 12rpx; }
.difficulty-easy { background: #e8f5e9; color: #4caf50; }
.difficulty-medium { background: #fff3e0; color: #ff9800; }
.difficulty-hard { background: #ffebee; color: #f44336; }
.content-item-preview { font-size: 26rpx; color: #666; line-height: 1.6; }
.content-text { font-size: 30rpx; line-height: 2; color: #333; padding: 30rpx; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); border-radius: 12rpx; border-left: 4rpx solid #409eff; min-height: 200rpx; }
.status-section { margin-bottom: 20rpx; }
.status-item { display: flex; align-items: center; justify-content: space-between; }
.status-label { font-size: 28rpx; color: #666; }
.status-value { font-size: 28rpx; font-weight: 600; }
.status-ready { color: #52c41a; }
.status-recording { color: #f5576c; animation: pulse 1.5s ease-in-out infinite; }
.status-loading { color: #1890ff; animation: pulse 1.5s ease-in-out infinite; }
/* 调试信息样式 */
.debug-info { margin-top: 16rpx; padding: 16rpx; background: #f0f0f0; border-radius: 8rpx; }
.debug-text { font-size: 24rpx; color: #666; word-break: break-all; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
.recording-tip { display: flex; align-items: center; gap: 16rpx; margin-top: 20rpx; padding: 20rpx; background: rgba(245, 87, 108, 0.1); border-radius: 12rpx; border-left: 4rpx solid #f5576c; }
.recording-dots { display: flex; gap: 8rpx; align-items: center; }
.dot { width: 12rpx; height: 12rpx; border-radius: 50%; background: #f5576c; animation: dot-bounce 1.4s ease-in-out infinite; }
.dot1 { animation-delay: 0s; } .dot2 { animation-delay: 0.2s; } .dot3 { animation-delay: 0.4s; }
@keyframes dot-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: 0.7; } 30% { transform: translateY(-10rpx); opacity: 1; } }
.recording-text { font-size: 26rpx; color: #f5576c; flex: 1; }

.action-section { display: flex; flex-direction: column; align-items: center; gap: 20rpx; }
.action-btn { width: 400rpx; height: 400rpx; border-radius: 50%; border: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20rpx; box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.2); transition: all 0.3s; }
.btn-ready { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #fff; }
.btn-recording { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: #fff; animation: pulse-ring 1.5s ease-out infinite; }
.btn-init { background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%); color: #333; }
@keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 rgba(245, 87, 108, 0.7); } 50% { box-shadow: 0 0 0 40rpx rgba(245, 87, 108, 0); } 100% { box-shadow: 0 0 0 0 rgba(245, 87, 108, 0); } }
.btn-stop { width: 300rpx; height: 100rpx; border-radius: 50rpx; background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: #fff; }
.btn-icon { font-size: 80rpx; }
.btn-text { font-size: 32rpx; font-weight: bold; }
/* 手动输入按钮 */
.manual-input-btn { margin-top: 30rpx; padding: 20rpx 40rpx; background: #f5f5f5; border-radius: 30rpx; border: 1px solid #ddd; font-size: 28rpx; color: #666; }
/* 工具按钮 */
.tool-buttons { display: flex; gap: 20rpx; margin-top: 30rpx; flex-wrap: wrap; justify-content: center; }
.tool-btn { padding: 16rpx 24rpx; background: #fff; border: 1px solid #e0e0e0; border-radius: 20rpx; font-size: 24rpx; color: #666; }
.result-content { margin-bottom: 20rpx; }
.result-scroll { max-height: 400rpx; width: 100%; }
.result-text { font-size: 30rpx; line-height: 1.8; color: #333; word-break: break-all; min-height: 100rpx; }
.typing-cursor { display: inline-block; font-size: 30rpx; color: #409eff; animation: blink 1s infinite; margin-left: 4rpx; }
@keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
.recognition-progress { display: flex; align-items: center; gap: 16rpx; margin-bottom: 20rpx; padding: 16rpx 20rpx; background: rgba(64, 158, 255, 0.1); border-radius: 12rpx; border-left: 4rpx solid #409eff; }
.progress-dots { display: flex; gap: 8rpx; align-items: center; }
.progress-dot { width: 12rpx; height: 12rpx; border-radius: 50%; background: #409eff; animation: progress-bounce 1.4s ease-in-out infinite; }
.progress-dot.dot1 { animation-delay: 0s; } .progress-dot.dot2 { animation-delay: 0.2s; } .progress-dot.dot3 { animation-delay: 0.4s; }
@keyframes progress-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: 0.7; } 30% { transform: translateY(-8rpx); opacity: 1; } }
.progress-text { font-size: 26rpx; color: #409eff; font-weight: 500; }
.text-loading { color: #999; font-style: italic; }
.evaluate-btn:disabled { opacity: 0.5; background: #ccc !important; }
.evaluate-btn { width: 100%; background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%); color: #fff; border: none; padding: 24rpx; border-radius: 12rpx; font-size: 32rpx; font-weight: bold; }
.score-main { text-align: center; padding: 40rpx; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 20rpx; margin-bottom: 30rpx; }
.score-main-value { display: block; font-size: 100rpx; font-weight: bold; color: #fff; line-height: 1; }
.score-main-label { display: block; font-size: 28rpx; color: rgba(255, 255, 255, 0.9); margin-top: 10rpx; }
.score-details { display: flex; flex-direction: column; gap: 24rpx; margin-bottom: 30rpx; }
.score-item { padding: 20rpx; background: #f8f9fa; border-radius: 12rpx; }
.score-item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
.score-item-label { font-size: 28rpx; color: #333; font-weight: 500; }
.score-item-value { font-size: 32rpx; font-weight: bold; color: #409eff; }
.score-progress { width: 100%; height: 12rpx; background: #e4e7ed; border-radius: 6rpx; overflow: hidden; }
.score-progress-bar { height: 100%; background: linear-gradient(90deg, #67c23a 0%, #85ce61 100%); border-radius: 6rpx; transition: width 0.5s; }
.score-info { padding: 20rpx; background: #f8f9fa; border-radius: 12rpx; margin-bottom: 30rpx; }
.info-item { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
.info-item:last-child { margin-bottom: 0; }
.info-label { font-size: 26rpx; color: #666; }
.info-value { font-size: 28rpx; font-weight: bold; color: #333; }
.action-buttons { display: flex; gap: 20rpx; }
.btn-retry, .btn-change { flex: 1; padding: 24rpx; border-radius: 12rpx; font-size: 28rpx; font-weight: bold; border: none; }
.btn-retry { background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%); color: #fff; }
.btn-change { background: #f0f0f0; color: #333; }
.submit-section { margin-top: 30rpx; margin-bottom: 20rpx; }
.btn-submit { width: 100%; background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%); color: #fff; border: none; padding: 30rpx; border-radius: 12rpx; font-size: 32rpx; font-weight: bold; box-shadow: 0 4rpx 12rpx rgba(103, 194, 58, 0.3); }
.submit-status-section { margin-top: 20rpx; margin-bottom: 20rpx; text-align: center; }
.submit-status-text { font-size: 28rpx; color: #67c23a; padding: 16rpx 32rpx; background: rgba(103, 194, 58, 0.1); border-radius: 20rpx; border: 1px solid #67c23a; display: inline-block; }
.empty-tip, .loading-tip { text-align: center; padding: 80rpx 40rpx; color: #999; font-size: 28rpx; display: flex; flex-direction: column; align-items: center; gap: 20rpx; }
.empty-icon { font-size: 80rpx; }
</style>