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 = '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'
|
||||
|
@ -1,26 +1,31 @@
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<transition name="emergency-modal">
|
||||
<div class="modal-mask" @click.self="$emit('close')">
|
||||
<div class="emergency-modal" :class="{ 'emergency-pulse': show }">
|
||||
<div class="modal-mask" @click="visible = false" v-if="visible">
|
||||
<div class="emergency-modal">
|
||||
<div class="glow"></div>
|
||||
<div class="modal-header">
|
||||
<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 class="modal-content">
|
||||
<p>{{ content }}</p>
|
||||
</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>
|
||||
</transition>
|
||||
@ -28,42 +33,41 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
const audioPlayer = ref(null);
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
defineProps({
|
||||
show: Boolean,
|
||||
title: {
|
||||
type: String,
|
||||
default: "紧急警报!",
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: "检测到危险操作,请立即处理!",
|
||||
},
|
||||
});
|
||||
interface TWarning {
|
||||
deviceId: string;
|
||||
useName: string;
|
||||
createTime: string;
|
||||
type: number;
|
||||
}
|
||||
|
||||
const emit = defineEmits(["close", "confirm"]);
|
||||
enum warnTypeEnum {
|
||||
"SOS告警",
|
||||
"围栏告警",
|
||||
"破坏告警",
|
||||
"低电告警",
|
||||
"心率告警",
|
||||
"血氧告警",
|
||||
"体温告警",
|
||||
}
|
||||
const router = useRouter();
|
||||
const visible = ref(false);
|
||||
const warningList = ref<TWarning[]>([]);
|
||||
defineExpose({ visible, warningList });
|
||||
|
||||
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);
|
||||
const toIncidentDispose = (id: string) => {
|
||||
router.push({
|
||||
path: "/incidentDispose",
|
||||
query: { id },
|
||||
});
|
||||
}
|
||||
});
|
||||
warningList.value = [];
|
||||
visible.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="less">
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
@ -77,10 +81,37 @@ onMounted(() => {
|
||||
justify-content: 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 {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
width: 800px;
|
||||
padding: 2rem;
|
||||
background: #2a0a0a;
|
||||
border-radius: 12px;
|
||||
@ -158,19 +189,6 @@ h2 {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes emergency-pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
|
@ -13,53 +13,44 @@
|
||||
</router-view>
|
||||
</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>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useSidebarStore } from "@/store/sidebar";
|
||||
import vHeader from "@/components/header.vue";
|
||||
import vSidebar from "@/components/sidebar.vue";
|
||||
import Alarm from "@/components/alarm.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");
|
||||
|
||||
// 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 alarmRef = ref(null);
|
||||
const audioPlayer = ref(null);
|
||||
const visible = ref(false);
|
||||
|
||||
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 alarmRef = ref();
|
||||
|
||||
const handleBeforeUnload = (event: any) => {
|
||||
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(() => {
|
||||
const isReload = localStorage.getItem("isReload");
|
||||
// const isReload = localStorage.getItem("isReload");
|
||||
// if (isReload !== "true") {
|
||||
// ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
|
||||
// confirmButtonText: "OK",
|
||||
@ -72,17 +63,13 @@ onMounted(() => {
|
||||
if (ws.socket == null) {
|
||||
ws.connect();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
ws.onMessage(onMessage);
|
||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||
});
|
||||
|
||||
// const include = getInclude(routes[0].children);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
@ -4,7 +4,7 @@ export class MapCustom {
|
||||
this.map = new AMap.Map(data.dom, {
|
||||
version: "1.4.15",
|
||||
zoom: 13,
|
||||
center: data.center || [116.397428, 39.90923], //初始化地图中心点
|
||||
center: [116.397428, 39.90923], //初始化地图中心点
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ export default class WebSocketService {
|
||||
this.sendMessage({
|
||||
username: "admin",
|
||||
password: "111111",
|
||||
type: 0,
|
||||
type: 'web',
|
||||
cmd: "webLogin",
|
||||
})
|
||||
}
|
||||
|
@ -96,7 +96,6 @@ const tableData = ref<TWarnRecord.IListRes[]>([]);
|
||||
|
||||
const getData = async () => {
|
||||
try {
|
||||
console.log(query, "queryqueryquery");
|
||||
let p = { ...paging, ...query, startDate: query.time?.[0], endDate: query.time?.[1] };
|
||||
delete p.time;
|
||||
const res = await warnRecord(p);
|
||||
|
@ -35,15 +35,15 @@
|
||||
<div class="info-box-contetn">
|
||||
<div class="item">
|
||||
<div class="label"> 当前指标:</div>
|
||||
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
|
||||
<div class="value">{{ curData.value }}{{ unitEnum[curData.warnType] }}</div>
|
||||
</div>
|
||||
<div class="item" v-if="curData.warnType == 5">
|
||||
<div class="item" v-if="curData.warnType != 5">
|
||||
<div class="label"> 最大值:</div>
|
||||
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<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>
|
||||
@ -376,6 +376,9 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
&:nth-child(1) {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ let Interval = null;
|
||||
let funcList = ref([
|
||||
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
||||
{ 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 = {
|
||||
@ -108,6 +108,7 @@ const devicePaging = reactive({
|
||||
size: 10,
|
||||
mode: undefined,
|
||||
useStatus: 1,
|
||||
status: 1,
|
||||
});
|
||||
const HealthData = ref<THealthLatestData.TRes>();
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="en">{{ item.en }}</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
|
@ -133,8 +133,12 @@ const rules = reactive<FormRules<typeof ruleForm>>({
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
let center = [116.397428, 39.90923];
|
||||
if (rowData.rails && rowData.rails.length) {
|
||||
center = [rowData.rails[0].lng, rowData.rails[0].lat];
|
||||
}
|
||||
try {
|
||||
mapInfo = new MapCustom({ dom: "mapcontainer" });
|
||||
mapInfo = new MapCustom({ dom: "mapcontainer", center, zoom: 16 });
|
||||
} catch (error) {}
|
||||
mapInfo.polyEditor(ruleForm.rails, (res) => {
|
||||
ruleForm.rails = res;
|
||||
@ -144,7 +148,7 @@ onMounted(() => {
|
||||
|
||||
const clearMap = () => {
|
||||
mapInfo.clearMap();
|
||||
ruleForm.rails = "";
|
||||
ruleForm.rails = [];
|
||||
};
|
||||
const draw = () => {
|
||||
mapInfo.draw().then((res) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user