hldy_app_mini/pages/recording/recorder.js

365 lines
8.4 KiB
JavaScript
Raw Normal View History

2026-01-04 17:09:11 +08:00
// utils/record.js
// ¼<><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
class ScreenRecorder {
constructor() {
this.recordModule = null
this.eventModule = null
this.isRecording = false
this.recordTime = 0
this.recordTimer = null
this.eventListeners = new Map()
this.init()
}
// <20><>ʼ<EFBFBD><CABC>
init() {
try {
// <20><>ȡԭ<C8A1><D4AD>ģ<EFBFBD><C4A3>
this.recordModule = uni.requireNativePlugin('Record-Module')
this.eventModule = uni.requireNativePlugin('RecordEvent-Module')
console.log(<><C2BC>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>ɹ<EFBFBD>')
} catch (error) {
console.error(<><C2BC>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ʧ<EFBFBD><CAA7>:', error)
}
}
// <20><>ʼ¼<CABC><C2BC>
start(options = {}) {
return new Promise((resolve, reject) => {
if (!this.recordModule) {
reject(new Error(<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
if (this.isRecording) {
reject(new Error('<27>Ѿ<EFBFBD><D1BE><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>'))
return
}
const defaultOptions = {
width: 720, // <20><><EFBFBD><EFBFBD>
height: 1280, // <20>߶<EFBFBD>
bitRate: 4000000, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 4Mbps
fileName: null, // <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
recordAudio: true // <20>Ƿ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>Ƶ
}
const recordOptions = { ...defaultOptions, ...options }
console.log('<27><>ʼ¼<CABC><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', recordOptions)
this.recordModule.startRecording(recordOptions, (result) => {
console.log('<27><>ʼ¼<CABC><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', result)
if (result.code === 0 && result.success) {
this.isRecording = true
this.startTimer()
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD>¼<EFBFBD>
this.emit('start', { options: recordOptions })
resolve({
success: true,
message: '<27><>ʼ¼<CABC><C2BC><EFBFBD>ɹ<EFBFBD>',
data: result
})
} else {
reject(new Error(result.message || '<27><>ʼ¼<CABC><C2BC>ʧ<EFBFBD><CAA7>'))
}
})
})
}
// ֹͣ¼<D6B9><C2BC>
stop() {
return new Promise((resolve, reject) => {
if (!this.recordModule) {
reject(new Error(<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
if (!this.isRecording) {
resolve({
success: true,
message: '<27><>ǰû<C7B0><C3BB><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>'
})
return
}
console.log('ֹͣ¼<D6B9><C2BC>')
this.recordModule.stopRecording((result) => {
console.log('ֹͣ¼<D6B9><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', result)
this.isRecording = false
this.stopTimer()
if (result.code === 0 && result.success) {
// <20><><EFBFBD><EFBFBD>ֹͣ<CDA3>¼<EFBFBD>
this.emit('stop', {})
resolve({
success: true,
message: 'ֹͣ¼<D6B9><C2BC><EFBFBD>ɹ<EFBFBD>',
data: result
})
} else {
reject(new Error(result.message || 'ֹͣ¼<D6B9><C2BC>ʧ<EFBFBD><CAA7>'))
}
})
})
}
// <20><>ȡ¼<C8A1><C2BC>״̬
getStatus() {
return new Promise((resolve, reject) => {
if (!this.recordModule) {
reject(new Error(<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
this.recordModule.getRecordingStatus((result) => {
this.isRecording = result.isRecording
resolve({
isRecording: result.isRecording,
duration: result.duration,
filePath: result.filePath,
...result
})
})
})
}
// <20><>ȡ¼<C8A1><C2BC><EFBFBD>ļ<EFBFBD><C4BC>б<EFBFBD>
getFileList() {
return new Promise((resolve, reject) => {
if (!this.recordModule) {
reject(new Error(<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
this.recordModule.getRecordFiles((result) => {
if (result.code === 0) {
resolve({
success: true,
files: result.files,
count: result.count
})
} else {
reject(new Error(result.message || '<27><>ȡ<EFBFBD>ļ<EFBFBD><C4BC>б<EFBFBD>ʧ<EFBFBD><CAA7>'))
}
})
})
}
// ɾ<><C9BE>¼<EFBFBD><C2BC><EFBFBD>ļ<EFBFBD>
deleteFile(filePath) {
return new Promise((resolve, reject) => {
if (!this.recordModule) {
reject(new Error(<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
this.recordModule.deleteRecordFile(filePath, (result) => {
if (result.code === 0 && result.success) {
resolve({
success: true,
message: <><C9BE><EFBFBD>ɹ<EFBFBD>'
})
} else {
reject(new Error(result.message || <><C9BE>ʧ<EFBFBD><CAA7>'))
}
})
})
}
// <20><><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>Ȩ<EFBFBD><C8A8>
checkPermission() {
return new Promise((resolve, reject) => {
if (!this.recordModule) {
reject(new Error(<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
this.recordModule.checkPermission((result) => {
resolve({
hasPermission: result.hasPermission,
message: result.message,
...result
})
})
})
}
// <20><>ʼ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
startListen() {
return new Promise((resolve, reject) => {
if (!this.eventModule) {
reject(new Error('<27>¼<EFBFBD>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
this.eventModule.startListen((result) => {
if (result.code === 0 && result.success) {
// <20><><EFBFBD><EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD>¼<EFBFBD>
uni.$on('recordEvent', this.handleRecordEvent.bind(this))
resolve({
success: true,
message: '<27><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>'
})
} else {
reject(new Error(result.message || '<27><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>'))
}
})
})
}
// ֹͣ<CDA3>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
stopListen() {
return new Promise((resolve, reject) => {
if (!this.eventModule) {
reject(new Error('<27>¼<EFBFBD>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
return
}
this.eventModule.stopListen((result) => {
if (result.code === 0 && result.success) {
// <20>Ƴ<EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
uni.$off('recordEvent', this.handleRecordEvent.bind(this))
resolve({
success: true,
message: 'ֹͣ<CDA3><D6B9><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>'
})
} else {
reject(new Error(result.message || 'ֹͣ<CDA3><D6B9><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>'))
}
})
})
}
// <20><><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>¼<EFBFBD>
handleRecordEvent(event) {
console.log('<27>յ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD>¼<EFBFBD>:', event)
const { type, data } = event
switch (type) {
case 'onRecordEvent':
this.handleNativeEvent(data)
break
}
}
// <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD>¼<EFBFBD>
handleNativeEvent(data) {
const { event, filePath } = data
switch (event) {
case 'start':
console.log(<><C2BC><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>:', filePath)
this.emit('started', { filePath })
break
case 'stop':
console.log(<><C2BC>ֹͣ<CDA3><D6B9><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>:', filePath)
this.emit('stopped', { filePath })
break
}
}
// <20><>ʼ<EFBFBD><CABC>ʱ<EFBFBD><CAB1>
startTimer() {
this.recordTime = 0
this.recordTimer = setInterval(() => {
this.recordTime++
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>¼<EFBFBD>
this.emit('timeupdate', {
currentTime: this.recordTime
})
}, 1000)
}
// ֹͣ<CDA3><D6B9>ʱ<EFBFBD><CAB1>
stopTimer() {
if (this.recordTimer) {
clearInterval(this.recordTimer)
this.recordTimer = null
this.recordTime = 0
}
}
// <20><>ʽ<EFBFBD><CABD>ʱ<EFBFBD><CAB1>
formatTime(seconds) {
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = seconds % 60
if (hours > 0) {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
} else {
return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
}
// <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
on(event, callback) {
if (!this.eventListeners.has(event)) {
this.eventListeners.set(event, [])
}
this.eventListeners.get(event).push(callback)
}
// ȡ<><C8A1><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
off(event, callback) {
if (this.eventListeners.has(event)) {
const listeners = this.eventListeners.get(event)
const index = listeners.indexOf(callback)
if (index > -1) {
listeners.splice(index, 1)
}
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
emit(event, data) {
if (this.eventListeners.has(event)) {
this.eventListeners.get(event).forEach(callback => {
try {
callback(data)
} catch (error) {
console.error(`ִ<EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD> ${event} <20>Ļص<C4BB>ʧ<EFBFBD><CAA7>:`, error)
}
})
}
}
// <20><><EFBFBD><EFBFBD>
destroy() {
this.stop()
this.stopListen()
this.eventListeners.clear()
this.recordModule = null
this.eventModule = null
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
let recorderInstance = null
export function getScreenRecorder() {
if (!recorderInstance) {
recorderInstance = new ScreenRecorder()
}
return recorderInstance
}
export default getScreenRecorder