guoyu/fronted_uniapp/pages/record-test.vue
2025-12-10 22:53:20 +08:00

448 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="test-page">
<view class="header">🎤 录音测试工具</view>
<!-- 设备信息 -->
<view class="card">
<view class="card-title">📱 设备信息</view>
<view class="info-item">系统: {{ deviceInfo }}</view>
</view>
<!-- 权限状态 -->
<view class="card">
<view class="card-title">🔐 权限状态</view>
<view class="info-item">{{ permissionStatus }}</view>
<button v-if="!hasPermission" @click="requestPermission" class="btn-blue">
请求录音权限
</button>
</view>
<!-- 测试1直接录音 -->
<view class="card">
<view class="card-title">测试1: 直接录音AMR格式</view>
<button @click="testRecord" :disabled="testing" class="btn-green">
{{ testing ? '测试中...' : '开始测试' }}
</button>
<view class="result">{{ result1 }}</view>
</view>
<!-- 测试2系统录音API -->
<view class="card">
<view class="card-title">测试2: 系统录音API</view>
<button @click="testSystemRecord" :disabled="testing" class="btn-orange">
{{ testing ? '测试中...' : '开始测试' }}
</button>
<view class="result">{{ result2 }}</view>
</view>
<!-- 测试3原生Intent录音 -->
<view class="card" style="border: 2px solid #667eea;">
<view class="card-title">🎯 测试3: 原生Intent录音推荐</view>
<view class="info-text">使用系统录音界面,兼容性最好</view>
<button @click="goNativeTest" class="btn-purple">
前往测试 →
</button>
</view>
<!-- 日志显示 -->
<view class="card">
<view class="card-title">📋 测试日志</view>
<view class="log-box">
<text v-for="(log, index) in logs" :key="index" class="log-line">
{{ log }}
</text>
</view>
<button @click="clearLogs" class="btn-small">清空日志</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
deviceInfo: '',
permissionStatus: '检查中...',
hasPermission: false,
testing: false,
result1: '未测试',
result2: '未测试',
logs: []
}
},
onLoad() {
this.init()
},
methods: {
// 初始化
init() {
this.log('=== 开始初始化 ===')
this.getDeviceInfo()
this.checkPermission()
},
// 添加日志
log(msg) {
const time = new Date().toLocaleTimeString()
this.logs.push(`[${time}] ${msg}`)
console.log(msg)
// 最多保留20条日志
if (this.logs.length > 20) {
this.logs.shift()
}
},
// 清空日志
clearLogs() {
this.logs = []
},
// 获取设备信息
getDeviceInfo() {
// #ifdef APP-PLUS
try {
this.deviceInfo = `${plus.os.name} ${plus.os.version} (${plus.device.model})`
this.log(`设备: ${this.deviceInfo}`)
} catch (e) {
this.deviceInfo = '获取失败'
this.log(`获取设备信息失败: ${e.message}`)
}
// #endif
},
// 检查权限
checkPermission() {
// #ifdef APP-PLUS
try {
const result = plus.android.checkPermission('android.permission.RECORD_AUDIO')
this.log(`权限检查结果: ${result} (1=已授权, 0=未授权, -1=永久拒绝)`)
if (result === 1) {
this.permissionStatus = '✅ 已授权'
this.hasPermission = true
} else if (result === 0) {
this.permissionStatus = '❌ 未授权'
this.hasPermission = false
} else {
this.permissionStatus = '❌ 永久拒绝,需手动开启'
this.hasPermission = false
}
} catch (e) {
this.permissionStatus = '检查失败'
this.log(`权限检查异常: ${e.message}`)
}
// #endif
},
// 请求权限
requestPermission() {
// #ifdef APP-PLUS
this.log('请求录音权限...')
plus.android.requestPermissions(
['android.permission.RECORD_AUDIO'],
(result) => {
this.log(`权限请求结果: ${JSON.stringify(result)}`)
if (result.granted && result.granted.length > 0) {
this.permissionStatus = '✅ 已授权'
this.hasPermission = true
uni.showToast({ title: '授权成功', icon: 'success' })
} else {
uni.showToast({ title: '授权失败', icon: 'none' })
}
},
(error) => {
this.log(`权限请求失败: ${JSON.stringify(error)}`)
}
)
// #endif
},
// 测试1直接录音
testRecord() {
if (!this.hasPermission) {
uni.showToast({ title: '请先授予录音权限', icon: 'none' })
return
}
this.testing = true
this.result1 = '测试中...'
this.log('=== 测试1 开始 ===')
// #ifdef APP-PLUS
try {
const recorder = plus.audio.getRecorder()
const filePath = '_doc/test1_' + Date.now() + '.amr'
this.log(`文件路径: ${filePath}`)
this.log('开始录音...')
// 超时保护
const timeout = setTimeout(() => {
this.log('❌ 超时5秒内未开始录音')
this.result1 = '❌ 超时失败'
this.testing = false
}, 5000)
recorder.record(
{
filename: filePath,
format: 'amr',
samplerate: '8000',
channels: '1'
},
() => {
clearTimeout(timeout)
this.log('✅ 录音已开始')
this.result1 = '录音中...'
// 3秒后停止
setTimeout(() => {
this.log('停止录音...')
recorder.stop()
this.result1 = '检查文件...'
// 检查文件
setTimeout(() => {
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
entry.file((file) => {
const sizeKB = (file.size / 1024).toFixed(2)
this.log(`文件大小: ${sizeKB}KB`)
if (file.size < 100) {
this.result1 = `⚠️ 文件过小: ${sizeKB}KB\n录音可能失败`
this.log('⚠️ 录音文件过小')
} else {
this.result1 = `✅ 成功!\n文件大小: ${sizeKB}KB`
this.log('✅ 测试1 成功')
}
this.testing = false
})
}, (error) => {
this.log(`❌ 文件不存在: ${JSON.stringify(error)}`)
this.result1 = '❌ 文件不存在'
this.testing = false
})
}, 500)
}, 3000)
},
(error) => {
clearTimeout(timeout)
this.log(`❌ 录音失败: code=${error.code}, msg=${error.message}`)
let msg = '❌ 失败\n'
if (error.code === 3) msg += '原因: 权限被拒绝'
else if (error.code === 4) msg += '原因: 麦克风被占用'
else msg += `错误码: ${error.code}`
this.result1 = msg
this.testing = false
}
)
} catch (e) {
this.log(`❌ 异常: ${e.message}`)
this.result1 = `❌ 异常: ${e.message}`
this.testing = false
}
// #endif
},
// 前往原生录音测试
goNativeTest() {
uni.navigateTo({
url: '/pages/native-record-test'
})
},
// 测试2系统录音API
testSystemRecord() {
if (!this.hasPermission) {
uni.showToast({ title: '请先授予录音权限', icon: 'none' })
return
}
this.testing = true
this.result2 = '测试中...'
this.log('=== 测试2 开始 ===')
try {
const recorderManager = uni.getRecorderManager()
recorderManager.onStart(() => {
this.log('✅ 系统API录音已开始')
this.result2 = '录音中...'
})
recorderManager.onStop((res) => {
this.log(`录音停止: ${res.tempFilePath}`)
// 获取文件信息
uni.getFileInfo({
filePath: res.tempFilePath,
success: (info) => {
const sizeKB = (info.size / 1024).toFixed(2)
this.log(`文件大小: ${sizeKB}KB`)
if (info.size < 100) {
this.result2 = `⚠️ 文件过小: ${sizeKB}KB\n录音可能失败`
this.log('⚠️ 录音文件过小')
} else {
this.result2 = `✅ 成功!\n文件大小: ${sizeKB}KB`
this.log('✅ 测试2 成功')
}
this.testing = false
},
fail: (error) => {
this.log(`❌ 获取文件信息失败: ${JSON.stringify(error)}`)
this.result2 = '❌ 获取文件信息失败'
this.testing = false
}
})
})
recorderManager.onError((error) => {
this.log(`❌ 录音错误: ${JSON.stringify(error)}`)
this.result2 = `❌ 错误: ${error.errMsg}`
this.testing = false
})
// 开始录音
this.log('启动系统API录音...')
recorderManager.start({
format: 'wav',
sampleRate: 8000,
numberOfChannels: 1
})
// 3秒后停止
setTimeout(() => {
this.log('停止系统API录音...')
recorderManager.stop()
}, 3000)
} catch (e) {
this.log(`❌ 异常: ${e.message}`)
this.result2 = `❌ 异常: ${e.message}`
this.testing = false
}
}
}
}
</script>
<style scoped>
.test-page {
min-height: 100vh;
background: #f5f7fa;
padding: 20rpx;
}
.header {
text-align: center;
font-size: 40rpx;
font-weight: bold;
padding: 30rpx;
color: #333;
}
.card {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.1);
}
.card-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
color: #333;
}
.info-item {
padding: 15rpx 0;
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
button {
width: 100%;
padding: 25rpx;
border: none;
border-radius: 12rpx;
font-size: 30rpx;
margin-top: 15rpx;
}
.btn-blue {
background: #409eff;
color: #fff;
}
.btn-green {
background: #67c23a;
color: #fff;
}
.btn-orange {
background: #e6a23c;
color: #fff;
}
.btn-purple {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
box-shadow: 0 4rpx 15rpx rgba(102, 126, 234, 0.4);
}
.btn-small {
background: #909399;
color: #fff;
padding: 15rpx;
font-size: 24rpx;
}
.info-text {
padding: 15rpx 0;
font-size: 26rpx;
color: #666;
line-height: 1.6;
}
button:disabled {
background: #ccc;
color: #999;
}
.result {
margin-top: 20rpx;
padding: 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
min-height: 80rpx;
white-space: pre-line;
color: #333;
}
.log-box {
max-height: 400rpx;
overflow-y: auto;
background: #2d2d2d;
border-radius: 8rpx;
padding: 20rpx;
margin-bottom: 15rpx;
}
.log-line {
display: block;
font-size: 24rpx;
color: #0f0;
font-family: monospace;
line-height: 1.8;
word-break: break-all;
}
</style>