2025年04月22日18:31:44

This commit is contained in:
luojiayi 2025-04-22 18:31:46 +08:00
parent 55ff343e35
commit e472857a5f
10 changed files with 119 additions and 107 deletions

View File

@ -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'

View File

@ -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);

View File

@ -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">

View File

@ -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,
});
}

View File

@ -44,7 +44,7 @@ export default class WebSocketService {
this.sendMessage({
username: "admin",
password: "111111",
type: 0,
type: 'web',
cmd: "webLogin",
})
}

View File

@ -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);

View File

@ -35,15 +35,15 @@
<div class="info-box-contetn">
<div class="item">
<div class="label">&nbsp;&nbsp;当前指标</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">&nbsp;&nbsp;最大值</div>
<div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
</div>
<div class="item">
<div class="label">&nbsp;&nbsp;最小值</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;
}
}
}
}

View File

@ -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>();

View File

@ -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>

View File

@ -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) => {