guoyu/fronted_uniapp/pages/record-test.vue

448 lines
14 KiB
Vue
Raw Permalink Normal View History

2025-12-10 22:53:20 +08:00
<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>