/**
|
* 音频管理工具
|
* 负责语音播放、音频队列管理等功能
|
*/
|
|
export class AudioManager {
|
constructor() {
|
this.audioContext = null;
|
this.audioTimer = null;
|
this.audioInterval = 3000;
|
this.isAudioPlaying = false;
|
this.audioQueue = [];
|
this.audioPlayEnabled = true;
|
this.language = 'zh';
|
|
// 多语言语音文件配置
|
this.audioFiles = {
|
zh: {
|
red: '/static/chvoice/voice2/red.mp3',
|
yellow: '/static/chvoice/voice2/yellow.mp3',
|
green: '/static/chvoice/voice2/green.mp3'
|
},
|
en: {
|
red: '/static/envoice/voice2/red.mp3',
|
yellow: '/static/envoice/voice2/yellow.mp3',
|
green: '/static/envoice/voice2/green.mp3'
|
},
|
ru: {
|
red: '/static/pyvoice/voice2/red.mp3',
|
yellow: '/static/pyvoice/voice2/yellow.mp3',
|
green: '/static/pyvoice/voice2/green.mp3'
|
}
|
};
|
}
|
|
/**
|
* 初始化音频上下文
|
*/
|
initAudioContext() {
|
try {
|
this.audioContext = uni.createInnerAudioContext();
|
this.audioContext.onError((res) => {
|
console.error('音频播放失败:', res);
|
this.isAudioPlaying = false;
|
this.playNextInQueue();
|
});
|
this.audioContext.onEnded(() => {
|
this.isAudioPlaying = false;
|
this.playNextInQueue();
|
});
|
console.log('音频上下文初始化成功');
|
} catch (error) {
|
console.error('音频上下文初始化失败:', error);
|
}
|
}
|
|
/**
|
* 检查音频播放状态
|
*/
|
checkAudioPlaybackStatus() {
|
try {
|
if (this.audioContext) {
|
this.audioContext.destroy();
|
}
|
this.initAudioContext();
|
} catch (error) {
|
console.error('检查音频播放状态失败:', error);
|
}
|
}
|
|
/**
|
* 播放语音
|
*/
|
playVoice(layer, language = null) {
|
if (!this.audioPlayEnabled || this.isAudioPlaying) {
|
return;
|
}
|
|
const lang = language || this.language;
|
const audioFile = this.audioFiles[lang]?.[layer];
|
|
if (!audioFile) {
|
console.error('语音文件不存在:', layer, lang);
|
return;
|
}
|
|
this.playAudioFile(audioFile);
|
}
|
|
/**
|
* 播放音频文件
|
*/
|
playAudioFile(audioFile) {
|
if (!this.audioContext || this.isAudioPlaying) {
|
return;
|
}
|
|
try {
|
this.isAudioPlaying = true;
|
this.audioContext.src = audioFile;
|
this.audioContext.play();
|
console.log('开始播放音频:', audioFile);
|
} catch (error) {
|
console.error('播放音频失败:', error);
|
this.isAudioPlaying = false;
|
}
|
}
|
|
/**
|
* 添加音频到播放队列
|
*/
|
addToAudioQueue(layer, language = null) {
|
if (!this.audioPlayEnabled) return;
|
|
const lang = language || this.language;
|
const audioFile = this.audioFiles[lang]?.[layer];
|
|
if (audioFile) {
|
this.audioQueue.push(audioFile);
|
console.log('添加音频到队列:', audioFile);
|
|
if (!this.isAudioPlaying) {
|
this.playNextInQueue();
|
}
|
}
|
}
|
|
/**
|
* 播放队列中的下一个音频
|
*/
|
playNextInQueue() {
|
if (this.audioQueue.length === 0 || this.isAudioPlaying) {
|
return;
|
}
|
|
const nextAudio = this.audioQueue.shift();
|
this.playAudioFile(nextAudio);
|
}
|
|
/**
|
* 清空音频队列
|
*/
|
clearAudioQueue() {
|
this.audioQueue = [];
|
console.log('音频队列已清空');
|
}
|
|
/**
|
* 停止音频播放
|
*/
|
stopAudio() {
|
if (this.audioContext) {
|
this.audioContext.stop();
|
this.isAudioPlaying = false;
|
}
|
this.clearAudioQueue();
|
}
|
|
/**
|
* 设置语言
|
*/
|
setLanguage(language) {
|
this.language = language;
|
console.log('音频语言已设置为:', language);
|
}
|
|
/**
|
* 设置音频播放开关
|
*/
|
setAudioEnabled(enabled) {
|
this.audioPlayEnabled = enabled;
|
if (!enabled) {
|
this.stopAudio();
|
}
|
console.log('音频播放开关:', enabled ? '开启' : '关闭');
|
}
|
|
/**
|
* 设置音频播放间隔
|
*/
|
setAudioInterval(interval) {
|
this.audioInterval = interval;
|
console.log('音频播放间隔已设置为:', interval, 'ms');
|
}
|
|
/**
|
* 销毁音频上下文
|
*/
|
destroy() {
|
if (this.audioContext) {
|
this.audioContext.destroy();
|
this.audioContext = null;
|
}
|
this.isAudioPlaying = false;
|
this.clearAudioQueue();
|
console.log('音频管理器已销毁');
|
}
|
}
|
|
/**
|
* 扇形状态管理工具类
|
*/
|
export class SectorStateManager {
|
constructor() {
|
this.activeSectors = new Map();
|
this.updateTimer = null;
|
this.updateInterval = APP_CONFIG.SECTOR.UPDATE_INTERVAL;
|
}
|
|
/**
|
* 启动扇形更新定时器
|
*/
|
startSectorUpdateTimer() {
|
// 清除之前的定时器
|
if (this.updateTimer) {
|
clearInterval(this.updateTimer);
|
}
|
|
// 启动扇形更新定时器
|
this.updateTimer = setInterval(() => {
|
this.updateSectorDisplay();
|
}, this.updateInterval);
|
|
console.log('扇形更新定时器已启动');
|
}
|
|
/**
|
* 更新活跃扇形状态
|
* @param {Map} newSectors - 新的扇形状态
|
*/
|
updateActiveSectors(newSectors) {
|
// 清空当前活跃扇形
|
this.activeSectors.clear();
|
|
// 添加新的活跃扇形
|
newSectors.forEach((sectorInfo, sectorKey) => {
|
this.activeSectors.set(sectorKey, sectorInfo);
|
});
|
|
console.log('活跃扇形状态已更新,当前活跃扇形数量:', this.activeSectors.size);
|
}
|
|
/**
|
* 更新扇形显示
|
* @param {Array} circleColors - 扇形颜色数组
|
* @param {boolean} isOffline - 是否离线
|
* @param {Function} updateCallback - 更新回调函数
|
*/
|
updateSectorDisplay(circleColors, isOffline, updateCallback) {
|
// 先重置所有扇形为灰色
|
this.resetAllColors(circleColors);
|
|
// 如果处于离线状态,保持灰色
|
if (isOffline) {
|
console.log('离线状态,保持扇形灰色');
|
return;
|
}
|
|
// 显示当前活跃的扇形
|
let updatedCount = 0;
|
this.activeSectors.forEach((sectorInfo, sectorKey) => {
|
const { layerIndex, sectorIndex, color } = sectorInfo;
|
|
// 验证索引有效性
|
if (layerIndex >= 0 && layerIndex < circleColors.length &&
|
sectorIndex >= 0 && sectorIndex < circleColors[layerIndex].length) {
|
|
// 更新扇形颜色
|
updateCallback(layerIndex, sectorIndex, color);
|
updatedCount++;
|
} else {
|
console.warn('扇形索引无效:', { layerIndex, sectorIndex, sectorKey });
|
}
|
});
|
|
if (updatedCount > 0) {
|
console.log(`扇形显示已更新,更新了${updatedCount}个扇形`);
|
}
|
}
|
|
/**
|
* 重置所有扇形为灰色
|
* @param {Array} circleColors - 扇形颜色数组
|
*/
|
resetAllColors(circleColors) {
|
for (let layerIndex = 0; layerIndex < circleColors.length; layerIndex++) {
|
for (let sectorIndex = 0; sectorIndex < circleColors[layerIndex].length; sectorIndex++) {
|
circleColors[layerIndex][sectorIndex] = APP_CONFIG.COLORS.DEFAULT_SECTOR;
|
}
|
}
|
}
|
|
/**
|
* 清空所有扇形
|
*/
|
clearAllSectors() {
|
// 清空活跃扇形状态
|
this.activeSectors.clear();
|
console.log('所有扇形已清空');
|
}
|
|
/**
|
* 强制触发扇形更新
|
* @param {Array} circleColors - 扇形颜色数组
|
* @param {boolean} isOffline - 是否离线
|
* @param {Function} updateCallback - 更新回调函数
|
*/
|
forceUpdateSectors(circleColors, isOffline, updateCallback) {
|
console.log('强制触发扇形更新');
|
this.updateSectorDisplay(circleColors, isOffline, updateCallback);
|
}
|
|
/**
|
* 销毁扇形状态管理器
|
*/
|
destroy() {
|
if (this.updateTimer) {
|
clearInterval(this.updateTimer);
|
this.updateTimer = null;
|
}
|
this.activeSectors.clear();
|
}
|
}
|
|
/**
|
* 离线检测管理工具类
|
*/
|
export class OfflineDetectionManager {
|
constructor() {
|
this.lastDataTime = 0;
|
this.offlineTimer = null;
|
this.offlineTimeout = APP_CONFIG.OFFLINE.TIMEOUT;
|
this.checkInterval = APP_CONFIG.OFFLINE.CHECK_INTERVAL;
|
this.isOffline = false;
|
}
|
|
/**
|
* 启动离线检测机制
|
*/
|
startOfflineDetection() {
|
// 清除之前的定时器
|
if (this.offlineTimer) {
|
clearInterval(this.offlineTimer);
|
}
|
|
// 启动离线检测定时器
|
this.offlineTimer = setInterval(() => {
|
const currentTime = Date.now();
|
const timeSinceLastData = currentTime - this.lastDataTime;
|
|
// 如果超过超时时间没有收到数据,判定为离线
|
if (timeSinceLastData > this.offlineTimeout && !this.isOffline) {
|
console.log('检测到离线状态,清空所有扇形');
|
this.isOffline = true;
|
this.onOfflineDetected();
|
}
|
}, this.checkInterval);
|
|
console.log('离线检测机制已启动');
|
}
|
|
/**
|
* 更新最后数据接收时间
|
*/
|
updateLastDataTime() {
|
this.lastDataTime = Date.now();
|
this.isOffline = false;
|
}
|
|
/**
|
* 离线检测回调
|
* @param {Function} callback - 离线检测回调函数
|
*/
|
setOfflineCallback(callback) {
|
this.onOfflineDetected = callback;
|
}
|
|
/**
|
* 重置离线状态
|
*/
|
resetOfflineState() {
|
this.isOffline = false;
|
this.lastDataTime = Date.now();
|
}
|
|
/**
|
* 销毁离线检测管理器
|
*/
|
destroy() {
|
if (this.offlineTimer) {
|
clearInterval(this.offlineTimer);
|
this.offlineTimer = null;
|
}
|
}
|
}
|
|
/**
|
* 获取当前时间字符串
|
* @returns {string} 时间字符串
|
*/
|
export function getTime() {
|
const now = new Date();
|
const hour = String(now.getHours()).padStart(2, '0');
|
const minute = String(now.getMinutes()).padStart(2, '0');
|
const second = String(now.getSeconds()).padStart(2, '0');
|
return `${hour}:${minute}:${second}`;
|
}
|