100j控制面板功能完成
This commit is contained in:
@ -8,10 +8,20 @@ export const deviceDeatil = (id: string) => {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 灯光模式
|
// 警示灯爆闪模式
|
||||||
|
export const strobeMode = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/hby100j/device/strobeMode`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 灯光亮度
|
||||||
function lightModeSettings (data: any) {
|
function lightModeSettings (data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: `/app/hby100j/device/lightAdjustment`,
|
url: `/api/hby100j/device/lightAdjustment`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -19,7 +29,7 @@ function lightModeSettings (data: any) {
|
|||||||
//频率调节
|
//频率调节
|
||||||
function staticPowerSetting (data: any) {
|
function staticPowerSetting (data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: `/app/hby100j/device/strobeFrequency`,
|
url: `/api/hby100j/device/strobeFrequency`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -27,7 +37,7 @@ function staticPowerSetting (data: any) {
|
|||||||
// 修改音量
|
// 修改音量
|
||||||
function settingUpdateVolume (data: any) {
|
function settingUpdateVolume (data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: `/app/hby100j/device/updateVolume`,
|
url: `/api/hby100j/device/updateVolume`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -36,7 +46,7 @@ function settingUpdateVolume (data: any) {
|
|||||||
// 强制报警
|
// 强制报警
|
||||||
function SosSetting (data: any) {
|
function SosSetting (data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: `/app/hby100j/device/forceAlarmActivation`,
|
url: `/api/hby100j/device/forceAlarmActivation`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -98,6 +108,14 @@ export function deviceUpdateVoice(data:any) {
|
|||||||
data:data
|
data:data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 语音播放
|
||||||
|
export function deviceVoiceBroadcast(data:any) {
|
||||||
|
return request({
|
||||||
|
url: `/app/hby100j/device/voiceBroadcast`,
|
||||||
|
method: 'post',
|
||||||
|
data:data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
deviceDeatil,
|
deviceDeatil,
|
||||||
@ -111,5 +129,7 @@ export default {
|
|||||||
deviceUpdateVoice,
|
deviceUpdateVoice,
|
||||||
videTtsToOss,
|
videTtsToOss,
|
||||||
uploadAudioToOss,
|
uploadAudioToOss,
|
||||||
extractText
|
extractText,
|
||||||
|
strobeMode,
|
||||||
|
deviceVoiceBroadcast
|
||||||
};
|
};
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { string } from "vue-types";
|
||||||
|
|
||||||
export interface deviceQuery {
|
export interface deviceQuery {
|
||||||
groupId: string;
|
groupId: string;
|
||||||
pageNum: number;
|
pageNum: number;
|
||||||
@ -39,7 +41,9 @@ export interface DeviceDetail {
|
|||||||
strobeFrequency: string;
|
strobeFrequency: string;
|
||||||
volume: string;
|
volume: string;
|
||||||
chargeState: string;
|
chargeState: string;
|
||||||
alarmStatus: number
|
alarmStatus: number,
|
||||||
|
voiceStrobeAlarm?:number
|
||||||
|
voiceBroadcast?:number
|
||||||
}
|
}
|
||||||
// 定义灯光模式的类型接口
|
// 定义灯光模式的类型接口
|
||||||
export interface LightMode {
|
export interface LightMode {
|
||||||
|
|||||||
@ -15,17 +15,9 @@
|
|||||||
|
|
||||||
<!-- 主体内容区域 -->
|
<!-- 主体内容区域 -->
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<el-row :gutter="20" class="content-row" :class="deviceDetail.alarmStatus == 1 ? '' : 'displayNone'">
|
|
||||||
<el-col :lg="24" :xs="24">
|
|
||||||
<div class="staticRwo" :class="deviceDetail.alarmStatus == 1 ? '' : 'displayNone'"
|
|
||||||
@click="showClose()">
|
|
||||||
设备强制报警中!
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<!-- 第一行:灯光模式 + 灯光亮度、强制报警、位置信息 -->
|
<!-- 第一行:灯光模式 + 灯光亮度、强制报警、位置信息 -->
|
||||||
<el-row :gutter="20" class="content-row">
|
<el-row :gutter="20" class="content-row">
|
||||||
<el-col :lg="8" :xs="24">
|
<el-col :lg="9" :xs="24">
|
||||||
<div class="content-card">
|
<div class="content-card">
|
||||||
<h4 class="section-title">报警模式</h4>
|
<h4 class="section-title">报警模式</h4>
|
||||||
<div class="light-mode">
|
<div class="light-mode">
|
||||||
@ -43,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="8" :xs="24">
|
<el-col :lg="9" :xs="24">
|
||||||
<div class="content-card1">
|
<div class="content-card1">
|
||||||
<h4 class="section-title">警示灯爆闪</h4>
|
<h4 class="section-title">警示灯爆闪</h4>
|
||||||
<div class="light-mode">
|
<div class="light-mode">
|
||||||
@ -68,11 +60,15 @@
|
|||||||
<div class="voice-select">
|
<div class="voice-select">
|
||||||
<el-select v-model="currentVoiceId" placeholder="请选择语音" style="width: 100%;">
|
<el-select v-model="currentVoiceId" placeholder="请选择语音" style="width: 100%;">
|
||||||
<el-option v-for="item in voiceList" :key="item.id" :label="item.fileNameExt"
|
<el-option v-for="item in voiceList" :key="item.id" :label="item.fileNameExt"
|
||||||
:value="item.id">
|
:value="item.id" ite>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" class="play-btn" @click="playCurrentVoice">播放</el-button>
|
<el-button type="primary" class="play-btn" @click="playCurrentVoice(1)"
|
||||||
|
v-if="deviceDetail.voiceBroadcast !== 1">
|
||||||
|
播放</el-button>
|
||||||
|
<el-button v-else type="info" class="play-btn" @click="playCurrentVoice(0)"> 暂停
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="voice-manage-section">
|
<div class="voice-manage-section">
|
||||||
<span class="voice-label">语音管理</span>
|
<span class="voice-label">语音管理</span>
|
||||||
@ -106,14 +102,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="8" :xs="24">
|
<el-col :lg="6" :xs="24">
|
||||||
<div class="brightness-alarm alarm-btn-wrapper">
|
<div class="brightness-alarm alarm-btn-wrapper">
|
||||||
<el-button type="danger" class="alarm-btn" @click="forceAlarm" :loading="forceAlarmLoading"
|
<el-button type="danger" class="alarm-btn" @click="forceAlarm" :loading="forceAlarmLoading"
|
||||||
v-if="deviceDetail.voiceStrobeAlarm === 0 || deviceDetail.voiceStrobeAlarm === null"
|
:loading-text="forceAlarmLoading ? '报警中...' : '强制报警'"> {{ deviceDetail.voiceStrobeAlarm ===
|
||||||
:loading-text="forceAlarmLoading ? '报警中...' : '强制报警'"> {{
|
1 ? '报警中' : '强制报警' }}</el-button>
|
||||||
forceAlarmLoading ? '报警中' : '强制报警' }}</el-button>
|
<el-button type="default" class="alarm-btn cancel" @click="showClose">解除报警</el-button>
|
||||||
<el-button type="default" class="alarm-btn cancel" @click="showClose"
|
|
||||||
v-if="deviceDetail.voiceStrobeAlarm === 1">解除</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content-card_gps">
|
<div class="content-card_gps">
|
||||||
<h4 class="section-title">位置信息</h4>
|
<h4 class="section-title">位置信息</h4>
|
||||||
@ -177,7 +171,8 @@
|
|||||||
<!-- 波形图 -->
|
<!-- 波形图 -->
|
||||||
<div class="waveform-container">
|
<div class="waveform-container">
|
||||||
<div class="waveform" v-if="isRecording">
|
<div class="waveform" v-if="isRecording">
|
||||||
<span v-for="i in 30" :key="i" class="wave-bar" :style="{ height: `${Math.random() * 40 + 10}px` }"></span>
|
<span v-for="i in 30" :key="i" class="wave-bar"
|
||||||
|
:style="{ height: `${Math.random() * 40 + 10}px` }"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="waveform-placeholder" v-else>
|
<div class="waveform-placeholder" v-else>
|
||||||
<span class="wave-placeholder"></span>
|
<span class="wave-placeholder"></span>
|
||||||
@ -186,22 +181,29 @@
|
|||||||
<!-- 录制控制区 -->
|
<!-- 录制控制区 -->
|
||||||
<div class="record-control">
|
<div class="record-control">
|
||||||
<div class="mic-icon" :class="{ recording: isRecording }">
|
<div class="mic-icon" :class="{ recording: isRecording }">
|
||||||
<el-icon><Microphone /></el-icon>
|
<el-icon>
|
||||||
|
<Microphone />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="record-time">{{ formatTime(recordDuration) }}</div>
|
<div class="record-time">{{ formatTime(recordDuration) }}</div>
|
||||||
<div class="record-play-btn">
|
<div class="record-play-btn">
|
||||||
<el-button v-if="isRecording" type="danger" circle @click="stopRecordVoice">
|
<el-button v-if="isRecording" type="danger" circle @click="stopRecordVoice">
|
||||||
<el-icon><Pause /></el-icon>
|
<el-icon>
|
||||||
|
<!-- <Pause /> -->
|
||||||
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-else type="primary" circle @click="startRecordVoice">
|
<el-button v-else type="primary" circle @click="startRecordVoice">
|
||||||
<el-icon><VideoPlay /></el-icon>
|
<el-icon>
|
||||||
|
<VideoPlay />
|
||||||
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 底部操作 -->
|
<!-- 底部操作 -->
|
||||||
<div class="record-footer">
|
<div class="record-footer">
|
||||||
<el-button link type="primary" @click="resetRecord" :disabled="isRecording">重新录制</el-button>
|
<el-button link type="primary" @click="resetRecord" :disabled="isRecording">重新录制</el-button>
|
||||||
<el-button type="primary" class="record-confirm" @click="saveRecordVoice" :disabled="!recordedBlob">完成</el-button>
|
<el-button type="primary" class="record-confirm" @click="saveRecordVoice"
|
||||||
|
:disabled="!recordedBlob">完成</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -209,13 +211,12 @@
|
|||||||
<!-- 上传语音弹窗 -->
|
<!-- 上传语音弹窗 -->
|
||||||
<el-dialog title="上传语音" v-model="uploadVoiceDialog" width="480px" class="voice-dialog" :show-close="true">
|
<el-dialog title="上传语音" v-model="uploadVoiceDialog" width="480px" class="voice-dialog" :show-close="true">
|
||||||
<div class="upload-content">
|
<div class="upload-content">
|
||||||
<div class="upload-area" :class="{ dragOver: isDragOver }"
|
<div class="upload-area" :class="{ dragOver: isDragOver }" @dragover.prevent="isDragOver = true"
|
||||||
@dragover.prevent="isDragOver = true"
|
@dragleave.prevent="isDragOver = false" @drop.prevent="handleDrop" @click="triggerFileInput">
|
||||||
@dragleave.prevent="isDragOver = false"
|
|
||||||
@drop.prevent="handleDrop"
|
|
||||||
@click="triggerFileInput">
|
|
||||||
<div class="upload-icon">
|
<div class="upload-icon">
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon>
|
||||||
|
<Document />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" class="select-file-btn" @click="triggerFileInput">选择文件</el-button>
|
<el-button type="primary" class="select-file-btn" @click="triggerFileInput">选择文件</el-button>
|
||||||
<div class="upload-tip">将文件拖拽至此区域</div>
|
<div class="upload-tip">将文件拖拽至此区域</div>
|
||||||
@ -224,7 +225,8 @@
|
|||||||
<span class="file-size">{{ (uploadFile.size / 1024).toFixed(2) }} KB</span>
|
<span class="file-size">{{ (uploadFile.size / 1024).toFixed(2) }} KB</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input ref="uploadFileInput" type="file" accept="audio/*" style="display: none" @change="handleFileUpload" />
|
<input ref="uploadFileInput" type="file" accept="audio/*" style="display: none"
|
||||||
|
@change="handleFileUpload" />
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="uploadVoiceDialog = false">取消</el-button>
|
<el-button @click="uploadVoiceDialog = false">取消</el-button>
|
||||||
@ -235,20 +237,23 @@
|
|||||||
<!-- 文字转语音弹窗 -->
|
<!-- 文字转语音弹窗 -->
|
||||||
<el-dialog title="文字转语音" v-model="textToVoiceDialog" width="520px" class="voice-dialog" :show-close="true">
|
<el-dialog title="文字转语音" v-model="textToVoiceDialog" width="520px" class="voice-dialog" :show-close="true">
|
||||||
<div class="tts-content">
|
<div class="tts-content">
|
||||||
<el-input v-model="textToVoiceForm.content" type="textarea" rows="4" placeholder="请输入要转换的文字内容" class="tts-textarea"></el-input>
|
<el-input v-model="textToVoiceForm.content" type="textarea" rows="4" placeholder="请输入要转换的文字内容"
|
||||||
|
class="tts-textarea"></el-input>
|
||||||
<div class="tts-actions">
|
<div class="tts-actions">
|
||||||
<el-button link type="primary" @click="handleUploadText">上传文本</el-button>
|
<!-- <el-button link type="primary" @click="handleUploadText">上传文本</el-button> -->
|
||||||
<el-button type="primary" @click="convertTextToVoice" :loading="ttsLoading">开始转换</el-button>
|
<el-button type="primary" @click="convertTextToVoice" :loading="ttsLoading">开始转换</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 转换后预览 -->
|
<!-- 转换后预览 -->
|
||||||
<div class="tts-preview" v-if="ttsResultUrl">
|
<div class="tts-preview" v-if="ttsResultUrl">
|
||||||
<div class="waveform-container">
|
<div class="waveform-container">
|
||||||
<div class="waveform">
|
<div class="waveform">
|
||||||
<span v-for="i in 30" :key="i" class="wave-bar" :style="{ height: `${Math.random() * 40 + 10}px` }"></span>
|
<span v-for="i in 30" :key="i" class="wave-bar"
|
||||||
|
:style="{ height: `${Math.random() * 40 + 10}px` }"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="audio-player">
|
<div class="audio-player">
|
||||||
<el-slider v-model="ttsCurrentTime" :max="ttsDuration" :show-tooltip="false" style="flex: 1;"></el-slider>
|
<el-slider v-model="ttsCurrentTime" :max="ttsDuration" :show-tooltip="false"
|
||||||
|
style="flex: 1;"></el-slider>
|
||||||
<div class="time-info">
|
<div class="time-info">
|
||||||
<span>{{ formatTime(ttsCurrentTime) }}</span>
|
<span>{{ formatTime(ttsCurrentTime) }}</span>
|
||||||
<span>{{ formatTime(ttsDuration) }}</span>
|
<span>{{ formatTime(ttsDuration) }}</span>
|
||||||
@ -256,7 +261,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="player-controls">
|
<div class="player-controls">
|
||||||
<el-button circle @click="toggleTtsPlay">
|
<el-button circle @click="toggleTtsPlay">
|
||||||
<el-icon><VideoPlay v-if="!ttsPlaying" /><Pause v-else /></el-icon>
|
<el-icon>
|
||||||
|
<VideoPlay v-if="!ttsPlaying" />
|
||||||
|
<!-- <Pause v-else /> -->
|
||||||
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="preview-actions">
|
<div class="preview-actions">
|
||||||
@ -273,24 +281,23 @@
|
|||||||
<div class="voice-list">
|
<div class="voice-list">
|
||||||
<div class="voice-item" v-for="item in voiceList" :key="item.id">
|
<div class="voice-item" v-for="item in voiceList" :key="item.id">
|
||||||
<div class="voice-info">
|
<div class="voice-info">
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon>
|
||||||
|
<Document />
|
||||||
|
</el-icon>
|
||||||
<span class="voice-name">{{ item.fileNameExt }}</span>
|
<span class="voice-name">{{ item.fileNameExt }}</span>
|
||||||
|
<span>{{ item.duration }}秒</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="voice-player" v-if="playingVoiceId === item.id">
|
<div class="voice-actions">
|
||||||
<el-slider v-model="voiceCurrentTime" :max="voiceDuration" :show-tooltip="false" style="flex: 1;"></el-slider>
|
<el-button link type="primary" @click="toggleVoicePlay(item.id)">
|
||||||
<div class="time-info">
|
{{ playingVoiceId === item.id && voicePlaying ? '暂停' : '播放' }}
|
||||||
<span>{{ formatTime(voiceCurrentTime) }}</span>
|
|
||||||
<span>{{ formatTime(voiceDuration) }}</span>
|
|
||||||
</div>
|
|
||||||
<el-button circle @click="toggleVoicePlay(item.id)">
|
|
||||||
<el-icon><VideoPlay v-if="!voicePlaying" /><Pause v-else /></el-icon>
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
|
||||||
<div class="voice-actions" v-else>
|
|
||||||
<el-button link type="primary" @click="playVoiceById(item.id)">播放</el-button>
|
|
||||||
<el-button link type="danger" @click="deleteVoiceById(item.fileId)">删除</el-button>
|
<el-button link type="danger" @click="deleteVoiceById(item.fileId)">删除</el-button>
|
||||||
<el-button link type="primary" @click="renameVoice(item.fileId)">重命名</el-button>
|
<el-button link type="primary" @click="renameVoice(item)">重命名</el-button>
|
||||||
<el-button type="primary" @click="useVoice(item.id)">使用</el-button>
|
<el-button link type="primary"
|
||||||
|
:class="{ 'active': item.useStatus, 'btn-default': !item.useStatus }"
|
||||||
|
:disabled="item.useStatus == 1" @click="useVoice(item.id)">
|
||||||
|
{{ item.useStatus == 1 ? '使用中' : '使用' }}
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -312,7 +319,6 @@
|
|||||||
|
|
||||||
<script setup name="DeviceControl" lang="ts">
|
<script setup name="DeviceControl" lang="ts">
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import { useMqtt } from '@/utils/mqtt';
|
import { useMqtt } from '@/utils/mqtt';
|
||||||
import api from '@/api/controlCenter/controlPanel/100J';
|
import api from '@/api/controlCenter/controlPanel/100J';
|
||||||
import { DeviceDetail, LightMode } from '@/api/controlCenter/controlPanel/types';
|
import { DeviceDetail, LightMode } from '@/api/controlCenter/controlPanel/types';
|
||||||
@ -322,7 +328,7 @@ import { getDeviceStatus } from '@/utils/function';
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
import request from '@/utils/request';
|
||||||
// 导入图片资源
|
// 导入图片资源
|
||||||
import closeDefault from '@/assets/images/close.png';
|
import closeDefault from '@/assets/images/close.png';
|
||||||
import closeActive from '@/assets/images/close_HL.png';
|
import closeActive from '@/assets/images/close_HL.png';
|
||||||
@ -330,6 +336,7 @@ import rb from '@/assets/images/rb.png';
|
|||||||
import rbAc from '@/assets/images/rbAc.png';
|
import rbAc from '@/assets/images/rbAc.png';
|
||||||
import sg from '@/assets/images/sg.png';
|
import sg from '@/assets/images/sg.png';
|
||||||
import sgAc from '@/assets/images/sgAc.png';
|
import sgAc from '@/assets/images/sgAc.png';
|
||||||
|
import { object } from 'vue-types';
|
||||||
|
|
||||||
// 基础状态
|
// 基础状态
|
||||||
const forceAlarmLoading = ref(false);
|
const forceAlarmLoading = ref(false);
|
||||||
@ -422,13 +429,13 @@ const saveRecordVoice = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('voiceFile', recordedBlob.value, `record_${new Date().getTime()}.mp3`);
|
formData.append('file', recordedBlob.value, `record_${new Date().getTime()}.mp3`);
|
||||||
formData.append('deviceId', route.params.deviceId as string);
|
formData.append('deviceId', route.params.deviceId as string);
|
||||||
proxy?.$modal.loading('保存中...', { lock: true });
|
proxy?.$modal.loading('保存中...');
|
||||||
api.uploadAudioToOss(formData).then(res => {
|
api.uploadAudioToOss(formData).then(res => {
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('语音录制并保存成功');
|
proxy?.$modal.msgSuccess('保存成功');
|
||||||
recordVoiceDialog.value = false;
|
recordVoiceDialog.value = false;
|
||||||
queryAudioFileInfo();
|
queryAudioFileInfo();
|
||||||
resetRecord();
|
resetRecord();
|
||||||
@ -478,9 +485,9 @@ const handleFileUpload = (e: Event) => {
|
|||||||
const confirmUploadVoice = () => {
|
const confirmUploadVoice = () => {
|
||||||
if (!uploadFile.value) return;
|
if (!uploadFile.value) return;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('voiceFile', uploadFile.value);
|
formData.append('file', uploadFile.value);
|
||||||
formData.append('deviceId', route.params.deviceId as string);
|
formData.append('deviceId', route.params.deviceId as string);
|
||||||
proxy?.$modal.loading('上传中...', { lock: true });
|
proxy?.$modal.loading('上传中...');
|
||||||
api.uploadAudioToOss(formData).then(res => {
|
api.uploadAudioToOss(formData).then(res => {
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -511,11 +518,6 @@ const ttsPlaying = ref(false);
|
|||||||
const ttsCurrentTime = ref(0);
|
const ttsCurrentTime = ref(0);
|
||||||
const ttsDuration = ref(0);
|
const ttsDuration = ref(0);
|
||||||
let ttsAudio: HTMLAudioElement | null = null;
|
let ttsAudio: HTMLAudioElement | null = null;
|
||||||
|
|
||||||
const handleUploadText = () => {
|
|
||||||
proxy?.$modal.msgInfo('上传文本功能开发中');
|
|
||||||
};
|
|
||||||
|
|
||||||
const convertTextToVoice = async () => {
|
const convertTextToVoice = async () => {
|
||||||
if (!textToVoiceForm.value.content.trim()) {
|
if (!textToVoiceForm.value.content.trim()) {
|
||||||
proxy?.$modal.msgWarning('请输入要转换的文字内容');
|
proxy?.$modal.msgWarning('请输入要转换的文字内容');
|
||||||
@ -525,17 +527,17 @@ const convertTextToVoice = async () => {
|
|||||||
try {
|
try {
|
||||||
const res = await api.videTtsToOss({
|
const res = await api.videTtsToOss({
|
||||||
deviceId: route.params.deviceId,
|
deviceId: route.params.deviceId,
|
||||||
content: textToVoiceForm.value.content
|
text: textToVoiceForm.value.content
|
||||||
});
|
});
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ttsResultUrl.value = res.data.url;
|
ttsResultUrl.value = res.data;
|
||||||
ttsDuration.value = res.data.duration || 145;
|
ttsDuration.value = res.data;
|
||||||
proxy?.$modal.msgSuccess('文字转语音成功');
|
proxy?.$modal.msgSuccess('文字转语音成功');
|
||||||
|
textToVoiceDialog.value = false
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError('转换失败:' + res.msg);
|
proxy?.$modal.msgError(res.msg);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
proxy?.$modal.msgError('转换失败');
|
|
||||||
} finally {
|
} finally {
|
||||||
ttsLoading.value = false;
|
ttsLoading.value = false;
|
||||||
}
|
}
|
||||||
@ -552,7 +554,7 @@ const toggleTtsPlay = () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (ttsPlaying.value) {
|
if (ttsPlaying.value) {
|
||||||
ttsAudio.pause();
|
// ttsAudio.pause();
|
||||||
ttsPlaying.value = false;
|
ttsPlaying.value = false;
|
||||||
} else {
|
} else {
|
||||||
ttsAudio.play();
|
ttsAudio.play();
|
||||||
@ -570,7 +572,7 @@ const useTtsResult = () => {
|
|||||||
proxy?.$modal.msgSuccess('语音已设置为当前使用');
|
proxy?.$modal.msgSuccess('语音已设置为当前使用');
|
||||||
textToVoiceDialog.value = false;
|
textToVoiceDialog.value = false;
|
||||||
};
|
};
|
||||||
|
// 上传语音
|
||||||
const handleTextToVoice = () => {
|
const handleTextToVoice = () => {
|
||||||
textToVoiceDialog.value = true;
|
textToVoiceDialog.value = true;
|
||||||
textToVoiceForm.value = { content: '' };
|
textToVoiceForm.value = { content: '' };
|
||||||
@ -583,71 +585,75 @@ const handleTextToVoice = () => {
|
|||||||
const allVoiceDialog = ref(false);
|
const allVoiceDialog = ref(false);
|
||||||
const playingVoiceId = ref('');
|
const playingVoiceId = ref('');
|
||||||
const voicePlaying = ref(false);
|
const voicePlaying = ref(false);
|
||||||
const voiceCurrentTime = ref(0);
|
|
||||||
const voiceDuration = ref(0);
|
|
||||||
let voiceAudio: HTMLAudioElement | null = null;
|
let voiceAudio: HTMLAudioElement | null = null;
|
||||||
|
// 播放弹框
|
||||||
const playVoiceById = async (voiceId: string) => {
|
const toggleVoicePlay = async (voiceId: string) => {
|
||||||
|
// 如果当前点击的是正在播放的语音,直接暂停
|
||||||
if (playingVoiceId.value === voiceId && voicePlaying.value) {
|
if (playingVoiceId.value === voiceId && voicePlaying.value) {
|
||||||
voiceAudio?.pause();
|
voiceAudio?.pause();
|
||||||
voicePlaying.value = false;
|
voicePlaying.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
playingVoiceId.value = voiceId;
|
// 如果有其他语音正在播放,先暂停
|
||||||
|
if (voicePlaying.value && voiceAudio) {
|
||||||
|
voiceAudio.pause();
|
||||||
|
voicePlaying.value = false;
|
||||||
|
}
|
||||||
|
// 播放当前选中的语音
|
||||||
const voice = voiceList.value.find(v => v.id === voiceId);
|
const voice = voiceList.value.find(v => v.id === voiceId);
|
||||||
if (!voice) return;
|
if (!voice || !voice.fileUrl) {
|
||||||
if (voiceAudio) voiceAudio.pause();
|
proxy?.$modal.msgWarning('语音文件不存在');
|
||||||
voiceAudio = new Audio(voice.url);
|
return;
|
||||||
voiceDuration.value = voice.duration || 145;
|
}
|
||||||
voiceAudio.ontimeupdate = () => voiceCurrentTime.value = Math.floor(voiceAudio!.currentTime);
|
try {
|
||||||
|
playingVoiceId.value = voiceId;
|
||||||
|
voiceAudio = new Audio(voice.fileUrl);
|
||||||
|
// 仅保留播放结束后的状态重置
|
||||||
voiceAudio.onended = () => {
|
voiceAudio.onended = () => {
|
||||||
voicePlaying.value = false;
|
voicePlaying.value = false;
|
||||||
voiceCurrentTime.value = 0;
|
playingVoiceId.value = '';
|
||||||
};
|
};
|
||||||
await voiceAudio.play();
|
await voiceAudio.play();
|
||||||
voicePlaying.value = true;
|
voicePlaying.value = true;
|
||||||
};
|
} catch (err: any) {
|
||||||
|
proxy?.$modal.msgError(err.msg);
|
||||||
const toggleVoicePlay = (voiceId: string) => {
|
playingVoiceId.value = '';
|
||||||
if (voicePlaying.value) {
|
|
||||||
voiceAudio?.pause();
|
|
||||||
voicePlaying.value = false;
|
voicePlaying.value = false;
|
||||||
} else {
|
|
||||||
playVoiceById(voiceId);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// 删除语音
|
||||||
const deleteVoiceById = async (fileId: string) => {
|
const deleteVoiceById = async (fileId: string) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除该语音?', '提示');
|
await ElMessageBox.confirm('确定要删除该语音?', '提示');
|
||||||
const res = await api.deviceDeleteAudioFile({ deviceId: route.params.deviceId, fileId });
|
const res = await api.deviceDeleteAudioFile({ deviceId: route.params.deviceId, fileId });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
queryAudioFileInfo();
|
queryAudioFileInfo();
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError('删除失败');
|
proxy?.$modal.msgError(res.msg);
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) { }
|
||||||
};
|
};
|
||||||
|
// 重命名
|
||||||
const renameVoice = async (fileId: string) => {
|
const renameVoice = async (item: any) => {
|
||||||
const { value } = await ElMessageBox.prompt('请输入新名称', '重命名', { inputPlaceholder: '请输入新名称' });
|
const { value } = await ElMessageBox.prompt('请输入新名称', '重命名', { inputPlaceholder: '请输入新名称' });
|
||||||
if (value) {
|
if (value) {
|
||||||
const res = await api.videRenameAudioFile({ deviceId: route.params.deviceId, fileId, fileName: value });
|
const res = await api.videRenameAudioFile({ deviceId: route.params.deviceId, fileId:item.fileId, fileName: value });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('重命名成功');
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
queryAudioFileInfo();
|
queryAudioFileInfo();
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError('重命名失败');
|
proxy?.$modal.msgError(res.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// 使用
|
||||||
const useVoice = async (voiceId: string) => {
|
const useVoice = async (voiceId: string) => {
|
||||||
const res = await api.deviceUpdateVoice({ id: voiceId });
|
const res = await api.deviceUpdateVoice({ id: voiceId });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('已设置为当前语音');
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
currentVoiceId.value = voiceId;
|
currentVoiceId.value = voiceId;
|
||||||
|
await queryAudioFileInfo()
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError('设置失败');
|
proxy?.$modal.msgError('设置失败');
|
||||||
}
|
}
|
||||||
@ -661,7 +667,7 @@ const handleAllVoice = () => {
|
|||||||
// ====================== 原有功能 ======================
|
// ====================== 原有功能 ======================
|
||||||
const sta_VoiceType = ref([
|
const sta_VoiceType = ref([
|
||||||
{ id: '0', name: '公安', icon: sg, activeIcon: sgAc, switchStatusVioice: true, active: true },
|
{ id: '0', name: '公安', icon: sg, activeIcon: sgAc, switchStatusVioice: true, active: true },
|
||||||
{ id: 'fire', name: '消防', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
{ id: '1', name: '消防', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
||||||
{ id: '2', name: '应急', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
{ id: '2', name: '应急', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
||||||
{ id: '3', name: '交警', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
{ id: '3', name: '交警', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
||||||
{ id: '4', name: '市政', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
{ id: '4', name: '市政', icon: sg, activeIcon: sgAc, switchStatusVioice: false, active: false },
|
||||||
@ -681,22 +687,23 @@ const lightModes = ref<LightMode[]>([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const deviceDetail = ref<DeviceDetail & { typeName: string }>({
|
const deviceDetail = ref<DeviceDetail & { typeName: string }>({
|
||||||
lightBrightness: '50',
|
lightBrightness: '20',
|
||||||
deviceName: 'HBY100',
|
deviceName: '',
|
||||||
deviceImei: 'HBY100J',
|
deviceImei: '',
|
||||||
onlineStatus: 1,
|
onlineStatus: 1,
|
||||||
batteryPercentage: 80,
|
batteryPercentage: 80,
|
||||||
batteryRemainingTime: '1小时55分钟',
|
batteryRemainingTime: '',
|
||||||
longitude: '114.1167',
|
longitude: '',
|
||||||
latitude: '30.4744',
|
latitude: '',
|
||||||
address: '湖北省武汉市洪山区光谷大国际企业中心',
|
address: '',
|
||||||
sendMsg: '',
|
sendMsg: '',
|
||||||
chargeState: '0',
|
chargeState: '0',
|
||||||
typeName: '',
|
typeName: '',
|
||||||
alarmStatus: 0,
|
alarmStatus: 0,
|
||||||
strobeFrequency: '50',
|
strobeFrequency: '10',
|
||||||
volume: '50',
|
volume: '50',
|
||||||
voiceStrobeAlarm: 0
|
voiceStrobeAlarm: 0,
|
||||||
|
voiceBroadcast: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const isUpdatingStatus = ref(false);
|
const isUpdatingStatus = ref(false);
|
||||||
@ -704,26 +711,51 @@ const isSyncingStatus = ref(false);
|
|||||||
|
|
||||||
const queryAudioFileInfo = () => {
|
const queryAudioFileInfo = () => {
|
||||||
api.queryAudioFileList({ deviceId: route.params.deviceId }).then(res => {
|
api.queryAudioFileList({ deviceId: route.params.deviceId }).then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
voiceList.value = res.data || [];
|
voiceList.value = res.data || [];
|
||||||
|
const activeVoice = voiceList.value.find(item => item.useStatus === 1);
|
||||||
|
if (activeVoice) {
|
||||||
|
currentVoiceId.value = activeVoice.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}).catch(err => proxy?.$modal.msgError('获取语音列表失败'));
|
}).catch(err => proxy?.$modal.msgError('获取语音列表失败'));
|
||||||
};
|
};
|
||||||
|
// 报警模式
|
||||||
const handleVoiceType = async (targetId: string) => {
|
const handleVoiceType = async (targetId: string) => {
|
||||||
const deviceId = route.params.deviceId as string;
|
const deviceId = route.params.deviceId as string;
|
||||||
if (!deviceId) return;
|
if (!deviceId) return;
|
||||||
const targetMode = sta_VoiceType.value.find(mode => mode.id === targetId);
|
const targetMode = sta_VoiceType.value.find(mode => mode.id === targetId);
|
||||||
if (!targetMode || targetMode.active) return;
|
if (!targetMode) return;
|
||||||
|
|
||||||
|
//切换选中状态
|
||||||
|
const isCurrentlyActive = targetMode.active;
|
||||||
sta_VoiceType.value.forEach(mode => {
|
sta_VoiceType.value.forEach(mode => {
|
||||||
mode.active = mode.id === targetId;
|
mode.active = false;
|
||||||
mode.switchStatusVioice = mode.active;
|
mode.switchStatusVioice = false;
|
||||||
});
|
});
|
||||||
const params = { deviceIds: [deviceId], voiceStrobeAlarm: 1, mode: targetId };
|
// 如果当前是未选中状态,则选中;如果是选中状态,则取消
|
||||||
|
if (!isCurrentlyActive) {
|
||||||
|
targetMode.active = true;
|
||||||
|
targetMode.switchStatusVioice = true;
|
||||||
|
}
|
||||||
|
// 只有在报警中时,才发送请求
|
||||||
|
if (deviceDetail.value.voiceStrobeAlarm == 1) {
|
||||||
|
const params = {
|
||||||
|
deviceIds: [deviceId],
|
||||||
|
voiceStrobeAlarm: 1,
|
||||||
|
mode: isCurrentlyActive ? '' : targetId
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
const res = await api.SosSetting(params);
|
const res = await api.SosSetting(params);
|
||||||
if (res.code === 200) proxy?.$modal.msgSuccess(res.msg);
|
if (res.code === 200) proxy?.$modal.msgSuccess(res.msg);
|
||||||
} catch (error) { await getList(); }
|
} catch (error) {
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 警示灯爆闪模
|
||||||
const handleModeClick = async (modeId: string) => {
|
const handleModeClick = async (modeId: string) => {
|
||||||
if (isUpdatingStatus.value || isSyncingStatus.value) return;
|
if (isUpdatingStatus.value || isSyncingStatus.value) return;
|
||||||
try {
|
try {
|
||||||
@ -732,11 +764,26 @@ const handleModeClick = async (modeId: string) => {
|
|||||||
const targetMode = lightModes.value.find(m => m.id === modeId);
|
const targetMode = lightModes.value.find(m => m.id === modeId);
|
||||||
if (!targetMode || !targetMode.instructValue) return;
|
if (!targetMode || !targetMode.instructValue) return;
|
||||||
isUpdatingStatus.value = true;
|
isUpdatingStatus.value = true;
|
||||||
const res = await api.lightModeSettings({ deviceId, instructValue: targetMode.instructValue, deviceImei: deviceDetail.value.deviceImei, typeName: deviceDetail.value.typeName });
|
const isCurrentlyActive = targetMode.active;
|
||||||
|
const enable = isCurrentlyActive ? 0 : 1; // 选中则关闭,未选中则开启
|
||||||
|
//关闭时传 enable:0,开启时传 enable:1
|
||||||
|
const res = await api.strobeMode({
|
||||||
|
deviceId,
|
||||||
|
mode: targetMode.instructValue,
|
||||||
|
enable
|
||||||
|
});
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.closeAll();
|
ElMessage.closeAll();
|
||||||
proxy?.$modal.msgSuccess(res.msg);
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
if (enable === 0) {
|
||||||
|
lightModes.value.forEach(mode => {
|
||||||
|
mode.active = false;
|
||||||
|
mode.switchStatus = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
setActiveLightMode(modeId);
|
setActiveLightMode(modeId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError(res.msg);
|
proxy?.$modal.msgError(res.msg);
|
||||||
const prevActiveMode = lightModes.value.find(m => m.active);
|
const prevActiveMode = lightModes.value.find(m => m.active);
|
||||||
@ -745,9 +792,11 @@ const handleModeClick = async (modeId: string) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
const prevActiveMode = lightModes.value.find(m => m.active);
|
const prevActiveMode = lightModes.value.find(m => m.active);
|
||||||
if (prevActiveMode) setActiveLightMode(prevActiveMode.id);
|
if (prevActiveMode) setActiveLightMode(prevActiveMode.id);
|
||||||
} finally { isUpdatingStatus.value = false; }
|
} finally {
|
||||||
|
isUpdatingStatus.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
// 全局性的方法
|
||||||
const setActiveLightMode = (targetModeId: string) => {
|
const setActiveLightMode = (targetModeId: string) => {
|
||||||
isSyncingStatus.value = true;
|
isSyncingStatus.value = true;
|
||||||
lightModes.value.forEach(mode => {
|
lightModes.value.forEach(mode => {
|
||||||
@ -757,31 +806,43 @@ const setActiveLightMode = (targetModeId: string) => {
|
|||||||
isSyncingStatus.value = false;
|
isSyncingStatus.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 列表详情
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
try {
|
try {
|
||||||
const deviceId = route.params.deviceId;
|
const deviceId = route.params.deviceId;
|
||||||
if (!deviceId) return;
|
if (!deviceId) return;
|
||||||
const res = await api.deviceDeatil(deviceId as string);
|
const res = await api.deviceDeatil(deviceId as string);
|
||||||
deviceDetail.value = res.data;
|
deviceDetail.value = res.data;
|
||||||
|
// 警示灯模式初始化
|
||||||
const mainLightMode = String(res.data.strobeMode);
|
const mainLightMode = String(res.data.strobeMode);
|
||||||
const matchedMode = lightModes.value.find(mode => mode.instructValue === mainLightMode);
|
const matchedMode = lightModes.value.find(mode => mode.instructValue === mainLightMode);
|
||||||
if (matchedMode) setActiveLightMode(matchedMode.id);
|
if (matchedMode) setActiveLightMode(matchedMode.id);
|
||||||
|
|
||||||
|
// 报警模式初始化
|
||||||
const alarmMode = String(res.data.alarmMode);
|
const alarmMode = String(res.data.alarmMode);
|
||||||
const voiceStrobeAlarm = String(res.data.voiceStrobeAlarm);
|
const voiceStrobeAlarm = String(res.data.voiceStrobeAlarm);
|
||||||
sta_VoiceType.value.forEach(mode => {
|
sta_VoiceType.value.forEach(mode => {
|
||||||
mode.active = false;
|
mode.active = false;
|
||||||
mode.switchStatusVioice = false;
|
mode.switchStatusVioice = false;
|
||||||
});
|
});
|
||||||
|
//如果接口返回无选中,默认选中第一个
|
||||||
|
let hasActiveMode = false;
|
||||||
if (voiceStrobeAlarm === '1') {
|
if (voiceStrobeAlarm === '1') {
|
||||||
const matchedVoiceMode = sta_VoiceType.value.find(mode => mode.id === alarmMode);
|
const matchedVoiceMode = sta_VoiceType.value.find(mode => mode.id === alarmMode);
|
||||||
if (matchedVoiceMode) {
|
if (matchedVoiceMode) {
|
||||||
matchedVoiceMode.active = true;
|
matchedVoiceMode.active = true;
|
||||||
matchedVoiceMode.switchStatusVioice = true;
|
matchedVoiceMode.switchStatusVioice = true;
|
||||||
|
hasActiveMode = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) { console.error('获取设备详情失败:', error); }
|
// 无选中时默认选中第一个
|
||||||
|
if (!hasActiveMode) {
|
||||||
|
sta_VoiceType.value[0].active = true;
|
||||||
|
sta_VoiceType.value[0].switchStatusVioice = true;
|
||||||
|
}
|
||||||
|
} catch (error) { console.log('获取设备详情失败:', error); }
|
||||||
};
|
};
|
||||||
|
// 灯光亮度
|
||||||
const saveBtnlight = () => {
|
const saveBtnlight = () => {
|
||||||
lightModesLoading.value = true;
|
lightModesLoading.value = true;
|
||||||
const data = { deviceId: route.params.deviceId, brightness: deviceDetail.value.lightBrightness };
|
const data = { deviceId: route.params.deviceId, brightness: deviceDetail.value.lightBrightness };
|
||||||
@ -792,6 +853,7 @@ const saveBtnlight = () => {
|
|||||||
}).catch(() => lightModesLoading.value = false);
|
}).catch(() => lightModesLoading.value = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 爆闪频率
|
||||||
const saveBtnstrobe = () => {
|
const saveBtnstrobe = () => {
|
||||||
const data = { deviceId: route.params.deviceId, frequency: deviceDetail.value.strobeFrequency };
|
const data = { deviceId: route.params.deviceId, frequency: deviceDetail.value.strobeFrequency };
|
||||||
api.staticPowerSetting(data).then(res => {
|
api.staticPowerSetting(data).then(res => {
|
||||||
@ -799,6 +861,7 @@ const saveBtnstrobe = () => {
|
|||||||
}).catch(err => proxy?.$modal.msgError('保存爆闪频率失败'));
|
}).catch(err => proxy?.$modal.msgError('保存爆闪频率失败'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 音 量
|
||||||
const saveBtnVolume = () => {
|
const saveBtnVolume = () => {
|
||||||
const data = { deviceId: route.params.deviceId, volume: deviceDetail.value.volume };
|
const data = { deviceId: route.params.deviceId, volume: deviceDetail.value.volume };
|
||||||
api.settingUpdateVolume(data).then(res => {
|
api.settingUpdateVolume(data).then(res => {
|
||||||
@ -806,44 +869,98 @@ const saveBtnVolume = () => {
|
|||||||
}).catch(err => proxy?.$modal.msgError('保存音量失败'));
|
}).catch(err => proxy?.$modal.msgError('保存音量失败'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 解除报警
|
||||||
const showClose = async () => {
|
const showClose = async () => {
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确定要对该设备解除报警?', '提示');
|
await proxy?.$modal.confirm('确定要对该设备解除报警?', '提示');
|
||||||
const data = { deviceIds: [route.params.deviceId], typeName: deviceDetail.value.typeName, deviceImeiList: [deviceDetail.value.deviceImei], instructValue: '0' };
|
// 获取当前选中的mode
|
||||||
const res = await api.forceAlarm(data);
|
const currentMode = sta_VoiceType.value.find(mode => mode.active)?.id || '0';
|
||||||
|
const data = {
|
||||||
|
deviceIds: [route.params.deviceId],
|
||||||
|
voiceStrobeAlarm: 0,
|
||||||
|
mode: currentMode
|
||||||
|
};
|
||||||
|
const res = await api.SosSetting(data);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('解除报警成功');
|
deviceDetail.value.voiceStrobeAlarm = 0;
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
} catch (error: any) { if (error !== 'cancel') proxy?.$modal.msgError('解除报警失败'); }
|
} catch (error: any) {
|
||||||
|
proxy?.$modal.msgError(error.msg);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 强制报警
|
||||||
const forceAlarm = async () => {
|
const forceAlarm = async () => {
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确定要对该设备开启强制报警?', '提示');
|
await proxy?.$modal.confirm('确定要对该设备开启强制报警?', '提示');
|
||||||
forceAlarmLoading.value = true;
|
forceAlarmLoading.value = true;
|
||||||
const data = { deviceIds: [route.params.deviceId], typeName: deviceDetail.value.typeName, deviceImeiList: [deviceDetail.value.deviceImei], instructValue: '1' };
|
// 获取当前选中的mode
|
||||||
const res = await api.forceAlarm(data);
|
const currentMode = sta_VoiceType.value.find(mode => mode.active)?.id || '0';
|
||||||
|
const data = {
|
||||||
|
deviceIds: [route.params.deviceId],
|
||||||
|
voiceStrobeAlarm: 1,
|
||||||
|
mode: currentMode
|
||||||
|
};
|
||||||
|
const res = await api.SosSetting(data);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('强制报警已开启');
|
deviceDetail.value.voiceStrobeAlarm = 1;
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
} catch (error: any) { if (error !== 'cancel') proxy?.$modal.msgError('强制报警失败'); } finally { forceAlarmLoading.value = false; }
|
} catch (error: any) {
|
||||||
|
proxy?.$modal.msgError(error.msg);
|
||||||
|
} finally {
|
||||||
|
forceAlarmLoading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
// 查看跳转到地图设备
|
||||||
const lookMap = (row: any) => {
|
const lookMap = (row: any) => {
|
||||||
router.push({ path: '/controlCenter/controlPanel', query: { view: 'map', deviceId: row.deviceId } });
|
router.push({ path: '/controlCenter/controlPanel', query: { view: 'map', deviceId: row.deviceId } });
|
||||||
};
|
};
|
||||||
|
// 播放如果,在强制报警中,点击播放的时候描会报警语音,如果没有报警中,就是的单纯的播放语音这个逻辑
|
||||||
const playCurrentVoice = () => {
|
const playCurrentVoice = async () => {
|
||||||
if (!currentVoiceId.value) {
|
// 1. 报警中场景:播放/切换报警语音
|
||||||
proxy?.$modal.msgWarning('请先选择语音');
|
if (deviceDetail.value.voiceStrobeAlarm === 1) {
|
||||||
return;
|
try {
|
||||||
|
const currentMode = sta_VoiceType.value.find(mode => mode.active)?.id || '0';
|
||||||
|
const data = {
|
||||||
|
deviceIds: [route.params.deviceId],
|
||||||
|
voiceStrobeAlarm: 1,
|
||||||
|
mode: currentMode
|
||||||
|
};
|
||||||
|
const res = await api.SosSetting(data);
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
await getList();
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgError(res.msg);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
proxy?.$modal.msgError(err.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. 非报警中场景:单纯播放/暂停语音
|
||||||
|
else {
|
||||||
|
const targetStatus = deviceDetail.value.voiceBroadcast === 1 ? 0 : 1;
|
||||||
|
try {
|
||||||
|
const res = await api.deviceVoiceBroadcast({
|
||||||
|
deviceId: route.params.deviceId,
|
||||||
|
voiceBroadcast: targetStatus
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
deviceDetail.value.voiceBroadcast = targetStatus;
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
await getList();
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgError(res.msg);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
proxy?.$modal.msgError(err.msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
api.playVoice({ deviceId: route.params.deviceId, voiceId: currentVoiceId.value }).then(res => {
|
|
||||||
if (res.code === 200) proxy?.$modal.msgSuccess('开始播放语音');
|
|
||||||
else proxy?.$modal.msgError('播放语音失败:' + res.msg);
|
|
||||||
}).catch(err => proxy?.$modal.msgError('播放语音失败'));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@ -856,7 +973,7 @@ onUnmounted(() => {
|
|||||||
if (recordTimer) clearInterval(recordTimer);
|
if (recordTimer) clearInterval(recordTimer);
|
||||||
if (mediaRecorder.value && isRecording.value) mediaRecorder.value.stop();
|
if (mediaRecorder.value && isRecording.value) mediaRecorder.value.stop();
|
||||||
if (audioStream) audioStream.getTracks().forEach(track => track.stop());
|
if (audioStream) audioStream.getTracks().forEach(track => track.stop());
|
||||||
if (ttsAudio) ttsAudio.pause();
|
// if (ttsAudio) ttsAudio.pause();
|
||||||
if (voiceAudio) voiceAudio.pause();
|
if (voiceAudio) voiceAudio.pause();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -882,13 +999,20 @@ onUnmounted(() => {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
.device-status {
|
.device-status {
|
||||||
.online { color: #00ff00; }
|
.online {
|
||||||
.offline { color: rgb(224, 52, 52); }
|
color: #00ff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline {
|
||||||
|
color: rgb(224, 52, 52);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
.content-row { margin-bottom: 20px; }
|
.content-row {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.content-card {
|
.content-card {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -914,6 +1038,7 @@ onUnmounted(() => {
|
|||||||
background: white;
|
background: white;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
|
min-height: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
@ -985,6 +1110,7 @@ onUnmounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brightness-alarm {
|
.brightness-alarm {
|
||||||
@ -1030,13 +1156,13 @@ onUnmounted(() => {
|
|||||||
.alarm-btn {
|
.alarm-btn {
|
||||||
background-color: rgba(224, 52, 52, 1);
|
background-color: rgba(224, 52, 52, 1);
|
||||||
border-color: rgba(224, 52, 52, 1);
|
border-color: rgba(224, 52, 52, 1);
|
||||||
padding: 8px 20px;
|
padding: 20px 20px;
|
||||||
border-radius: 27px;
|
border-radius: 30px;
|
||||||
|
|
||||||
&.cancel {
|
&.cancel {
|
||||||
background-color: #f0f0f0;
|
background-color: rgba(224, 52, 52, 0.08);
|
||||||
border-color: #dcdfe6;
|
border-color: rgba(224, 52, 52, 0.08);
|
||||||
color: #606266;
|
color: rgba(224, 52, 52, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1141,18 +1267,22 @@ onUnmounted(() => {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-dialog__header) {
|
:deep(.el-dialog__header) {
|
||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-dialog__headerbtn) {
|
:deep(.el-dialog__headerbtn) {
|
||||||
top: 16px;
|
top: 16px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-dialog__body) {
|
:deep(.el-dialog__body) {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-dialog__footer) {
|
:deep(.el-dialog__footer) {
|
||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
border-top: 1px solid #ebeef5;
|
border-top: 1px solid #ebeef5;
|
||||||
@ -1422,13 +1552,19 @@ onUnmounted(() => {
|
|||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
box-shadow: 0 0 0 0 rgba(64, 158, 255, 0.7);
|
box-shadow: 0 0 0 0 rgba(64, 158, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
70% {
|
70% {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
box-shadow: 0 0 0 10px rgba(64, 158, 255, 0);
|
box-shadow: 0 0 0 10px rgba(64, 158, 255, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
box-shadow: 0 0 0 0 rgba(64, 158, 255, 0);
|
box-shadow: 0 0 0 0 rgba(64, 158, 255, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
color: #3333;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user