2025年04月22日18:31:44
This commit is contained in:
parent
55ff343e35
commit
e472857a5f
@ -1,5 +1,5 @@
|
|||||||
# VITE_APP_URL = 'http://192.168.3.116:8001/'
|
VITE_APP_URL = 'http://192.168.3.116:8001/'
|
||||||
# VITE_APP_URL_WEBSOCKET = 'http://192.168.3.116:8000/api/websocket'
|
# VITE_APP_URL_WEBSOCKET = 'http://192.168.3.116:8000/api/websocket'
|
||||||
|
|
||||||
VITE_APP_URL = 'http://api.handcuff.youaikang.cn'
|
# VITE_APP_URL = 'http://api.handcuff.youaikang.cn'
|
||||||
VITE_APP_URL_WEBSOCKET = 'ws://device.handcuff.youaikang.cn:8000/api/websocket'
|
VITE_APP_URL_WEBSOCKET = 'ws://device.handcuff.youaikang.cn:8000/api/websocket'
|
||||||
|
@ -1,26 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<transition name="emergency-modal">
|
<transition name="emergency-modal">
|
||||||
<div class="modal-mask" @click.self="$emit('close')">
|
<div class="modal-mask" @click="visible = false" v-if="visible">
|
||||||
<div class="emergency-modal" :class="{ 'emergency-pulse': show }">
|
<div class="emergency-modal">
|
||||||
<div class="glow"></div>
|
<div class="glow"></div>
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div class="warning-icon">⚠️</div>
|
<div class="warning-icon">⚠️</div>
|
||||||
<h2>{{ title }}</h2>
|
<h2>紧急警报!</h2>
|
||||||
|
</div>
|
||||||
|
<div class="alarmTable">
|
||||||
|
<div class="alarmTable-item">
|
||||||
|
<div class="alarmTable-item-text">设备号</div>
|
||||||
|
<div class="alarmTable-item-text">报警类型</div>
|
||||||
|
<div class="alarmTable-item-text">佩戴者</div>
|
||||||
|
<div class="alarmTable-item-text">触发时间</div>
|
||||||
|
<div class="alarmTable-item-text">操作</div>
|
||||||
|
</div>
|
||||||
|
<div class="alarmTable-content scrollbar">
|
||||||
|
<div class="alarmTable-item" v-for="(item, index) in warningList" :key="index">
|
||||||
|
<div class="alarmTable-item-text">{{ item.deviceId }}</div>
|
||||||
|
<div class="alarmTable-item-text">{{ warnTypeEnum[item.type] }}</div>
|
||||||
|
<div class="alarmTable-item-text">{{ item.useName }}</div>
|
||||||
|
<div class="alarmTable-item-text">{{ item.createTime }}</div>
|
||||||
|
<div class="alarmTable-item-text" @click="toIncidentDispose(item.deviceId)">去处理</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-content">
|
|
||||||
<p>{{ content }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="emergency-button" @click="handleAudioEnd">
|
|
||||||
<span class="button-text">立即处理</span>
|
|
||||||
<div class="button-glow"></div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<audio ref="audioPlayer" hidden>
|
|
||||||
<source src="../assets/audio/alarm.mp3" type="audio/mpeg" />
|
|
||||||
</audio>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
@ -28,42 +33,41 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from "vue";
|
import { ref } from "vue";
|
||||||
const audioPlayer = ref(null);
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
defineProps({
|
interface TWarning {
|
||||||
show: Boolean,
|
deviceId: string;
|
||||||
title: {
|
useName: string;
|
||||||
type: String,
|
createTime: string;
|
||||||
default: "紧急警报!",
|
type: number;
|
||||||
},
|
|
||||||
content: {
|
|
||||||
type: String,
|
|
||||||
default: "检测到危险操作,请立即处理!",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(["close", "confirm"]);
|
|
||||||
|
|
||||||
const handleAudioEnd = () => {
|
|
||||||
emit("close");
|
|
||||||
// if (audioPlayer.value) {
|
|
||||||
// audioPlayer.value.play().catch((error) => {
|
|
||||||
// console.error("自动播放被阻止:", error);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (audioPlayer.value) {
|
|
||||||
audioPlayer.value.play().catch((error) => {
|
|
||||||
console.error("自动播放被阻止:", error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum warnTypeEnum {
|
||||||
|
"SOS告警",
|
||||||
|
"围栏告警",
|
||||||
|
"破坏告警",
|
||||||
|
"低电告警",
|
||||||
|
"心率告警",
|
||||||
|
"血氧告警",
|
||||||
|
"体温告警",
|
||||||
|
}
|
||||||
|
const router = useRouter();
|
||||||
|
const visible = ref(false);
|
||||||
|
const warningList = ref<TWarning[]>([]);
|
||||||
|
defineExpose({ visible, warningList });
|
||||||
|
|
||||||
|
const toIncidentDispose = (id: string) => {
|
||||||
|
router.push({
|
||||||
|
path: "/incidentDispose",
|
||||||
|
query: { id },
|
||||||
});
|
});
|
||||||
|
warningList.value = [];
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="less">
|
||||||
.modal-mask {
|
.modal-mask {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 9998;
|
z-index: 9998;
|
||||||
@ -77,10 +81,37 @@ onMounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.alarmTable {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 475px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.alarmTable-item {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid #cf8585;
|
||||||
|
display: flex;
|
||||||
|
.alarmTable-item-text {
|
||||||
|
flex: 1;
|
||||||
|
color: #ff4444;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
&:nth-child(2) {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.alarmTable-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.emergency-modal {
|
.emergency-modal {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 300px;
|
width: 800px;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
background: #2a0a0a;
|
background: #2a0a0a;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@ -158,19 +189,6 @@ h2 {
|
|||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 动画效果 */
|
|
||||||
@keyframes emergency-pulse {
|
|
||||||
0% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: scale(1.02);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shake {
|
@keyframes shake {
|
||||||
0% {
|
0% {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
@ -13,53 +13,44 @@
|
|||||||
</router-view>
|
</router-view>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Alarm ref="alarmRef" v-if="visible" @close="visible = false" />
|
<Alarm ref="alarmRef" />
|
||||||
|
<audio ref="audioPlayer" hidden>
|
||||||
|
<source src="../assets/audio/alarm.mp3" type="audio/mpeg" />
|
||||||
|
</audio>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSidebarStore } from "@/store/sidebar";
|
import { useSidebarStore } from "@/store/sidebar";
|
||||||
import vHeader from "@/components/header.vue";
|
import vHeader from "@/components/header.vue";
|
||||||
import vSidebar from "@/components/sidebar.vue";
|
import vSidebar from "@/components/sidebar.vue";
|
||||||
import Alarm from "@/components/alarm.vue";
|
|
||||||
import { inject, onBeforeUnmount, onMounted, ref } from "vue";
|
import { inject, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import { ElMessageBox } from "element-plus";
|
import { format } from "@/utils";
|
||||||
|
import Alarm from "@/components/alarm.vue";
|
||||||
|
|
||||||
const ws: any = inject("ws");
|
const ws: any = inject("ws");
|
||||||
|
|
||||||
// import useWebSocket from "@/utils/webSocket";
|
|
||||||
// const { onMessage } = useWebSocket();
|
|
||||||
// onMessage((res) => {
|
|
||||||
// console.log(res, "WebSocket 接收服务器消息");
|
|
||||||
// if (res.cmd == "warning") {
|
|
||||||
// console.log("预警弹窗");
|
|
||||||
// visible.value = true;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
const alarmRef = ref(null);
|
|
||||||
const audioPlayer = ref(null);
|
const audioPlayer = ref(null);
|
||||||
const visible = ref(false);
|
const alarmRef = ref();
|
||||||
|
|
||||||
const getInclude = (routeList: any) => {
|
|
||||||
if (!routeList) return [];
|
|
||||||
let list = [];
|
|
||||||
routeList.forEach((item) => {
|
|
||||||
if (item.meta && item.meta.keepAlive) {
|
|
||||||
list.push(item.name);
|
|
||||||
}
|
|
||||||
if (item.children && item.children.length) {
|
|
||||||
list = [...list, ...getInclude(item.children)];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return list;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBeforeUnload = (event: any) => {
|
const handleBeforeUnload = (event: any) => {
|
||||||
localStorage.removeItem("isReload");
|
localStorage.removeItem("isReload");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onMessage = (res) => {
|
||||||
|
console.log(res, "WebSocket接收服务器消息");
|
||||||
|
if (res.cmd == "warning") {
|
||||||
|
alarmRef.value.visible = true;
|
||||||
|
alarmRef.value.warningList.unshift({ ...res, createTime: format(new Date(), "HH:mm:ss") });
|
||||||
|
if (audioPlayer.value) {
|
||||||
|
audioPlayer.value.play().catch((error) => {
|
||||||
|
console.error("自动播放被阻止:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const isReload = localStorage.getItem("isReload");
|
// const isReload = localStorage.getItem("isReload");
|
||||||
// if (isReload !== "true") {
|
// if (isReload !== "true") {
|
||||||
// ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
|
// ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
|
||||||
// confirmButtonText: "OK",
|
// confirmButtonText: "OK",
|
||||||
@ -72,17 +63,13 @@ onMounted(() => {
|
|||||||
if (ws.socket == null) {
|
if (ws.socket == null) {
|
||||||
ws.connect();
|
ws.connect();
|
||||||
}
|
}
|
||||||
});
|
ws.onMessage(onMessage);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||||
});
|
});
|
||||||
|
|
||||||
// const include = getInclude(routes[0].children);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
@ -4,7 +4,7 @@ export class MapCustom {
|
|||||||
this.map = new AMap.Map(data.dom, {
|
this.map = new AMap.Map(data.dom, {
|
||||||
version: "1.4.15",
|
version: "1.4.15",
|
||||||
zoom: 13,
|
zoom: 13,
|
||||||
center: data.center || [116.397428, 39.90923], //初始化地图中心点
|
center: [116.397428, 39.90923], //初始化地图中心点
|
||||||
...data,
|
...data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ export default class WebSocketService {
|
|||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
username: "admin",
|
username: "admin",
|
||||||
password: "111111",
|
password: "111111",
|
||||||
type: 0,
|
type: 'web',
|
||||||
cmd: "webLogin",
|
cmd: "webLogin",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,6 @@ const tableData = ref<TWarnRecord.IListRes[]>([]);
|
|||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
try {
|
try {
|
||||||
console.log(query, "queryqueryquery");
|
|
||||||
let p = { ...paging, ...query, startDate: query.time?.[0], endDate: query.time?.[1] };
|
let p = { ...paging, ...query, startDate: query.time?.[0], endDate: query.time?.[1] };
|
||||||
delete p.time;
|
delete p.time;
|
||||||
const res = await warnRecord(p);
|
const res = await warnRecord(p);
|
||||||
|
@ -35,15 +35,15 @@
|
|||||||
<div class="info-box-contetn">
|
<div class="info-box-contetn">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label"> 当前指标:</div>
|
<div class="label"> 当前指标:</div>
|
||||||
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
|
<div class="value">{{ curData.value }}{{ unitEnum[curData.warnType] }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item" v-if="curData.warnType == 5">
|
<div class="item" v-if="curData.warnType != 5">
|
||||||
<div class="label"> 最大值:</div>
|
<div class="label"> 最大值:</div>
|
||||||
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
|
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label"> 最小值:</div>
|
<div class="label"> 最小值:</div>
|
||||||
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
|
<div class="value">{{ curData.minValue }}{{ unitEnum[curData.warnType] }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -376,6 +376,9 @@ onUnmounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
&:nth-child(1) {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ let Interval = null;
|
|||||||
let funcList = ref([
|
let funcList = ref([
|
||||||
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
||||||
{ title: "当前血氧", en: "DANGQIANXUEYANG", icon: blood, unit: "%", num: 0, color: "#8B51FD" },
|
{ title: "当前血氧", en: "DANGQIANXUEYANG", icon: blood, unit: "%", num: 0, color: "#8B51FD" },
|
||||||
{ title: "当前体表温度", en: "DANGQIANTIBIAOWENDU", icon: temperature, unit: "次/分", num: 0, color: "#FF6905" },
|
{ title: "当前体表温度", en: "DANGQIANTIBIAOWENDU", icon: temperature, unit: "℃", num: 0, color: "#FF6905" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
@ -108,6 +108,7 @@ const devicePaging = reactive({
|
|||||||
size: 10,
|
size: 10,
|
||||||
mode: undefined,
|
mode: undefined,
|
||||||
useStatus: 1,
|
useStatus: 1,
|
||||||
|
status: 1,
|
||||||
});
|
});
|
||||||
const HealthData = ref<THealthLatestData.TRes>();
|
const HealthData = ref<THealthLatestData.TRes>();
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="en">{{ item.en }}</div>
|
<div class="en">{{ item.en }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-left-bottom">
|
<div class="item-left-bottom">
|
||||||
<div class="num" :style="{ color: item.color }">{{ item.num || "--" }}</div>
|
<div class="num" :style="{ color: item.color }">{{ item.num || item.num == 0 ? item.num : "--" }}</div>
|
||||||
<div class="unit" :style="{ color: item.color }">{{ item.unit }}</div>
|
<div class="unit" :style="{ color: item.color }">{{ item.unit }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -133,8 +133,12 @@ const rules = reactive<FormRules<typeof ruleForm>>({
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
let center = [116.397428, 39.90923];
|
||||||
|
if (rowData.rails && rowData.rails.length) {
|
||||||
|
center = [rowData.rails[0].lng, rowData.rails[0].lat];
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
mapInfo = new MapCustom({ dom: "mapcontainer" });
|
mapInfo = new MapCustom({ dom: "mapcontainer", center, zoom: 16 });
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
mapInfo.polyEditor(ruleForm.rails, (res) => {
|
mapInfo.polyEditor(ruleForm.rails, (res) => {
|
||||||
ruleForm.rails = res;
|
ruleForm.rails = res;
|
||||||
@ -144,7 +148,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
const clearMap = () => {
|
const clearMap = () => {
|
||||||
mapInfo.clearMap();
|
mapInfo.clearMap();
|
||||||
ruleForm.rails = "";
|
ruleForm.rails = [];
|
||||||
};
|
};
|
||||||
const draw = () => {
|
const draw = () => {
|
||||||
mapInfo.draw().then((res) => {
|
mapInfo.draw().then((res) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user