feat(应急就医): WebSocket告警消息接入语音播报

心率异常/一键告警/血氧异常分别触发对应提示音,确认帮助后自动停止当前告警音效。
This commit is contained in:
2026-06-17 14:43:29 +08:00
parent 7b6d6e52b2
commit c33ad0d807
7 changed files with 115 additions and 16 deletions
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+2
View File
@@ -10,6 +10,7 @@
import { onMounted, watch } from 'vue';
import { getEmergencyCenterApi } from '/@/api/user.ts';
import { useUserStore } from '/@/store/modules/user.ts';
import { openTestModal } from '/@/utils/utils.ts';
dayjs.locale('zh-cn');
const locle = zhCN;
@@ -17,6 +18,7 @@
const userStore = useUserStore();
onMounted(async () => {
openTestModal();
try {
if (userStore.getToken) {
const { code, result } = await getEmergencyCenterApi();
+103 -9
View File
@@ -17,8 +17,64 @@ export const emergencyPath = VITE_GLOB_API_JIAN_CE;
export const xianYunPath = VITE_GLOB_API_XIAN_YUN;
//银川
export const yinChuanPath = VITE_GLOB_API_YIN_CHUAN;
let t = token || getAuthCache(TOKEN_KEY);
const t = token || getAuthCache(TOKEN_KEY);
const audioMgr = createAudioManager({
a: 'heart.mp3',
b: 'oneClick.mp3',
c: 'oxygen.mp3',
d: '13203.wav',
});
type AudioType = 'a' | 'b' | 'c' | 'd';
interface PlayerState {
audio: HTMLAudioElement;
count: number;
target: number;
}
function createAudioManager(sources: Record<AudioType, string>) {
const players: Record<string, PlayerState> = {};
for (const [type, url] of Object.entries(sources)) {
const audio = new Audio(url);
const state: PlayerState = { audio, count: 0, target: 0 };
audio.addEventListener('ended', () => {
state.count++;
if (state.count < state.target) {
state.audio.currentTime = 0;
state.audio.play();
}
});
players[type] = state;
}
return {
play(type: AudioType, times: number = 3) {
const s = players[type];
s.audio.pause();
s.count = 0;
s.target = times;
s.audio.currentTime = 0;
s.audio.play();
},
stop(type: AudioType) {
const s = players[type];
s.target = 0;
s.audio.pause();
s.audio.currentTime = 0;
},
stopAll() {
for (const s of Object.values(players)) {
s.target = 0;
s.audio.pause();
s.audio.currentTime = 0;
}
},
};
}
/**
*
* @param p websocket地址
@@ -26,11 +82,11 @@ let t = token || getAuthCache(TOKEN_KEY);
*/
export function useSocket(p = basicPath, hasTimestamp: boolean = true) {
const socket = ref();
let socketData = ref({});
let lockReconnect = ref(false); //避免ws重复连接
const path = ref(p);
const socketData = ref<any>({});
const lockReconnect = ref(false); //避免ws重复连接
const path = ref<any>(p);
function reconnect(path) {
function reconnect(path: any) {
if (lockReconnect.value) return;
lockReconnect.value = true;
setTimeout(function () {
@@ -101,11 +157,11 @@ export function useSocket(p = basicPath, hasTimestamp: boolean = true) {
heartCheck.reset().start(); //心跳检测重置
// //console.log('连接成功:' + new Date().toLocaleString());
};
socket.value.onmessage = function (event) {
socket.value.onmessage = function (event: any) {
//如果获取到消息,心跳检测重置
heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的
if (event.data != 'pong') {
let data = JSON.parse(event.data);
const data = JSON.parse(event.data);
// socketData.value = data;
setSocketData(data);
}
@@ -113,7 +169,7 @@ export function useSocket(p = basicPath, hasTimestamp: boolean = true) {
}
}
function setSocketData(data) {
function setSocketData(data: any) {
socketData.value = data;
}
@@ -123,5 +179,43 @@ export function useSocket(p = basicPath, hasTimestamp: boolean = true) {
socket.value && socket.value.hasOwnProperty('close') && socket.value.close();
}
return { socket, socketData, setSocketData, closeSocket };
function playAudio(sourceType: string) {
getAudio(sourceType);
}
function getAudio(sourceType: string) {
switch (sourceType) {
case 'heart_rate':
audioMgr.play('a', 3);
break;
case 'a_key_alarm':
audioMgr.play('b', 3);
break;
case 'spo2':
audioMgr.play('c', 3);
break;
default:
audioMgr.play('d', 1);
break;
}
}
function stopOne(sourceType: string) {
switch (sourceType) {
case 'heart_rate':
audioMgr.stop('a');
break;
case 'a_key_alarm':
audioMgr.stop('b');
break;
case 'spo2':
audioMgr.stop('c');
break;
default:
audioMgr.stop('d');
break;
}
}
return { socket, socketData, setSocketData, closeSocket, stopOne, stopAll: audioMgr.stopAll, playAudio };
}
@@ -127,7 +127,7 @@
// 健康监测工具报警
let socketUrl = handleSocketUrl(basicPath, getCenterInfo?.id);
const { socketData, setSocketData, closeSocket } = useSocket(socketUrl);
const { socketData, setSocketData, closeSocket, playAudio, stopOne } = useSocket(socketUrl);
const employeeDialogRef = ref();
watch(socketData, (nVal) => {
@@ -135,6 +135,7 @@
nextTick(() => {
setCount();
setSocketData(nVal);
playAudio(nVal?.eventType);
employeeDialogRef.value.openDialog();
});
}
@@ -167,6 +168,7 @@
// const routeUrl = router.resolve({
// path: '/home1',
// }).href;
if (data?.eventType) stopOne(data?.eventType);
sessionStorage.setItem('socketData', JSON.stringify(data));
// window.open(routeUrl, '_blank');
router.push('/home1');
+7 -6
View File
@@ -377,14 +377,14 @@
// 健康监测工具报警
let socketUrl = handleSocketUrl(basicPath, getCenterInfo?.id);
const { socketData, setSocketData, closeSocket } = useSocket(socketUrl);
const { socketData, setSocketData, closeSocket, playAudio, stopOne } = useSocket(socketUrl);
const employeeDialogRef = ref();
watch(socketData, (nVal) => {
if (nVal) {
nextTick(() => {
setCount();
setSocketData(nVal);
playAudio(nVal?.eventType);
employeeDialogRef.value.openDialog();
});
}
@@ -407,6 +407,7 @@
const showHospitalList = ref(false);
async function confirmHelp(data: any, showBottomInfo = true) {
if (data?.eventType) stopOne(data?.eventType);
showMapBottom.value = false;
Map.driveLine && Map.driveLine.clear();
try {
@@ -726,7 +727,7 @@
function employeeDialogOpen() {
setSocketData({
watchNo: 'A5GTQ24920002519',
eventType: 'a_key_alarm',
eventType: 'spo2',
eventType_dictText: '一键告警',
bindUserId: '1942871719583739905',
bindDate: '2025-07-23',
@@ -779,9 +780,9 @@
}
// setTimeout(() => {
// employeeDialogOpen();
// openEmergencyOpen();
// yunZOpen();
// employeeDialogOpen();
// openEmergencyOpen();
// yunZOpen();
// }, 5000);
</script>
<style lang="less" scoped>