2025-03-31 18:24:37 +08:00
|
|
|
|
<template>
|
2025-04-10 13:33:38 +08:00
|
|
|
|
<div class="container">
|
|
|
|
|
<el-row class="el-row" :gutter="20">
|
2025-04-10 19:00:17 +08:00
|
|
|
|
<el-col :span="6" class="el-row-left"
|
2025-04-24 10:12:03 +08:00
|
|
|
|
><DeviceInfo :deviceInfo="deviceInfo" :paging="devicePaging" :list="deviceData" :handelMode="handelMode" :load="handelLoad" @click="handelClickDevice"
|
2025-04-10 19:00:17 +08:00
|
|
|
|
/></el-col>
|
2025-04-10 13:33:38 +08:00
|
|
|
|
<el-col :span="18" class="el-row-right scrollbar">
|
|
|
|
|
<MonitoringTop :funcList="funcList" />
|
2025-04-25 18:23:20 +08:00
|
|
|
|
<div class="el-row-right-content" v-if="deviceInfo?.mode == 0 || deviceInfo?.mode == 2">
|
|
|
|
|
<DeviceLocationMap :device-id="deviceInfo.deviceId" />
|
|
|
|
|
<div class="box">
|
|
|
|
|
<DeviceHistory @change="handelRadio" ref="devHisRef">
|
|
|
|
|
<template #chart>
|
|
|
|
|
<div ref="chartRef" style="width: 100%; height: 100%"></div>
|
|
|
|
|
</template>
|
|
|
|
|
</DeviceHistory>
|
|
|
|
|
<DeviceRecord :deviceInfo="deviceInfo" />
|
|
|
|
|
</div>
|
2025-03-31 18:24:37 +08:00
|
|
|
|
</div>
|
2025-04-25 18:23:20 +08:00
|
|
|
|
<div class="el-row-right-content" v-else>
|
2025-03-31 18:24:37 +08:00
|
|
|
|
<el-row :gutter="20" style="margin-top: 20px">
|
2025-04-25 18:23:20 +08:00
|
|
|
|
<el-col :span="24">
|
2025-04-24 10:12:03 +08:00
|
|
|
|
<DeviceHistory @change="handelRadio" ref="devHisRef">
|
2025-03-31 18:24:37 +08:00
|
|
|
|
<template #chart>
|
2025-04-25 18:23:20 +08:00
|
|
|
|
<div ref="chartRef1" style="width: 100%; height: 350px"></div>
|
2025-03-31 18:24:37 +08:00
|
|
|
|
</template>
|
|
|
|
|
</DeviceHistory>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24" style="margin-top: 20px">
|
2025-04-10 13:33:38 +08:00
|
|
|
|
<DeviceRecord :deviceInfo="deviceInfo" />
|
2025-03-31 18:24:37 +08:00
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import DeviceInfo from "./deviceInfo.vue";
|
|
|
|
|
import MonitoringTop from "./monitoringTop.vue";
|
|
|
|
|
import DeviceHistory from "./deviceHistory.vue";
|
|
|
|
|
import DeviceRecord from "./deviceRecord.vue";
|
|
|
|
|
import * as echarts from "echarts";
|
2025-04-25 18:23:20 +08:00
|
|
|
|
import { deviceList, healthLatestData } from "@/api/index";
|
2025-04-10 13:33:38 +08:00
|
|
|
|
import { TDevice, THealthLatestData } from "@/api/index.d";
|
2025-04-25 18:23:20 +08:00
|
|
|
|
import { onMounted, ref, reactive, onUnmounted, watch, nextTick } from "vue";
|
2025-04-10 13:33:38 +08:00
|
|
|
|
import { debounce, format } from "@/utils";
|
|
|
|
|
import heart from "@/assets/img/heart.png";
|
|
|
|
|
import temperature from "@/assets/img/temperature.png";
|
|
|
|
|
import blood from "@/assets/img/blood.png";
|
2025-04-25 18:23:20 +08:00
|
|
|
|
import DeviceLocationMap from "./deviceLocationMap.vue";
|
2025-04-10 13:33:38 +08:00
|
|
|
|
|
2025-03-31 18:24:37 +08:00
|
|
|
|
const chartRef = ref(null);
|
2025-04-25 18:23:20 +08:00
|
|
|
|
const chartRef1 = ref(null);
|
2025-04-24 10:12:03 +08:00
|
|
|
|
const devHisRef = ref(null);
|
|
|
|
|
const loadFlag = ref(false);
|
2025-04-01 18:07:18 +08:00
|
|
|
|
let myChart = null;
|
2025-04-12 18:35:54 +08:00
|
|
|
|
let Interval = null;
|
2025-04-10 13:33:38 +08:00
|
|
|
|
let funcList = ref([
|
|
|
|
|
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
|
|
|
|
{ title: "当前血氧", en: "DANGQIANXUEYANG", icon: blood, unit: "%", num: 0, color: "#8B51FD" },
|
2025-04-22 18:31:46 +08:00
|
|
|
|
{ title: "当前体表温度", en: "DANGQIANTIBIAOWENDU", icon: temperature, unit: "℃", num: 0, color: "#FF6905" },
|
2025-04-10 13:33:38 +08:00
|
|
|
|
]);
|
2025-03-31 18:24:37 +08:00
|
|
|
|
|
2025-04-10 13:33:38 +08:00
|
|
|
|
const options = {
|
|
|
|
|
tooltip: {
|
|
|
|
|
trigger: "axis",
|
2025-04-12 18:35:54 +08:00
|
|
|
|
formatter: function (params) {
|
|
|
|
|
let unit = { 心率: "次/分", 血氧: "%", 体表温度: "℃" };
|
|
|
|
|
var res = format(options.times[params[0].dataIndex]) + "<br/>";
|
|
|
|
|
res += params
|
|
|
|
|
.map(function (param, index) {
|
|
|
|
|
return param.marker + param.seriesName + ":" + param.value + unit[param.seriesName] + "<br/>";
|
|
|
|
|
})
|
|
|
|
|
.join("");
|
|
|
|
|
return res;
|
|
|
|
|
},
|
2025-04-10 13:33:38 +08:00
|
|
|
|
},
|
2025-04-12 18:35:54 +08:00
|
|
|
|
times: [],
|
2025-03-31 18:24:37 +08:00
|
|
|
|
xAxis: {
|
|
|
|
|
type: "category",
|
2025-04-10 13:33:38 +08:00
|
|
|
|
data: [],
|
|
|
|
|
},
|
2025-04-25 18:23:20 +08:00
|
|
|
|
yAxis: {
|
|
|
|
|
type: "value",
|
|
|
|
|
},
|
2025-04-10 13:33:38 +08:00
|
|
|
|
grid: {
|
|
|
|
|
left: "5%",
|
|
|
|
|
right: "4%",
|
2025-04-25 18:23:20 +08:00
|
|
|
|
bottom: "20%",
|
2025-03-31 18:24:37 +08:00
|
|
|
|
},
|
2025-04-25 18:23:20 +08:00
|
|
|
|
dataZoom: [
|
|
|
|
|
{
|
|
|
|
|
show: true, // 是否显示
|
|
|
|
|
start: 0, // 开始位置,百分比
|
|
|
|
|
end: 10, // 结束位置,百分比
|
|
|
|
|
bottom: "10px",
|
|
|
|
|
height: 25,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "inside",
|
|
|
|
|
start: 0,
|
|
|
|
|
end: 100,
|
|
|
|
|
},
|
|
|
|
|
],
|
2025-04-10 13:33:38 +08:00
|
|
|
|
series: {
|
|
|
|
|
name: "",
|
|
|
|
|
data: [],
|
|
|
|
|
type: "line",
|
2025-04-12 18:35:54 +08:00
|
|
|
|
showSymbol: false,
|
2025-04-10 13:33:38 +08:00
|
|
|
|
itemStyle: {
|
|
|
|
|
color: "#ff4567", // 设置线条颜色
|
2025-03-31 18:24:37 +08:00
|
|
|
|
},
|
2025-04-10 13:33:38 +08:00
|
|
|
|
smooth: true,
|
|
|
|
|
},
|
2025-03-31 18:24:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-04-10 13:33:38 +08:00
|
|
|
|
const devicePaging = reactive({
|
|
|
|
|
page: 1,
|
|
|
|
|
size: 10,
|
|
|
|
|
mode: undefined,
|
2025-04-15 15:01:40 +08:00
|
|
|
|
useStatus: 1,
|
2025-04-22 18:31:46 +08:00
|
|
|
|
status: 1,
|
2025-04-10 13:33:38 +08:00
|
|
|
|
});
|
|
|
|
|
const HealthData = ref<THealthLatestData.TRes>();
|
|
|
|
|
const deviceInfo = ref<TDevice.IListRes>();
|
|
|
|
|
const deviceData = ref<TDevice.IListRes[]>([]);
|
2025-03-31 18:24:37 +08:00
|
|
|
|
|
2025-04-25 18:23:20 +08:00
|
|
|
|
watch(
|
|
|
|
|
() => deviceInfo,
|
|
|
|
|
(newVal) => {
|
|
|
|
|
if (newVal.value) {
|
|
|
|
|
if (newVal.value?.mode == 0 || newVal.value?.mode == 2) {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
myChart = echarts.init(chartRef.value);
|
|
|
|
|
});
|
|
|
|
|
options.grid.left = "10%";
|
|
|
|
|
options.grid.bottom = "30%";
|
|
|
|
|
} else {
|
|
|
|
|
options.grid.left = "5%";
|
|
|
|
|
options.grid.bottom = "20%";
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
myChart = echarts.init(chartRef1.value);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ deep: true }
|
|
|
|
|
);
|
|
|
|
|
|
2025-04-10 13:33:38 +08:00
|
|
|
|
const getdeviceList = async () => {
|
|
|
|
|
const res = await deviceList(devicePaging);
|
2025-04-24 10:12:03 +08:00
|
|
|
|
deviceData.value = [...deviceData.value, ...res.records];
|
|
|
|
|
if (deviceData.value.length >= res.total) {
|
|
|
|
|
loadFlag.value = true;
|
|
|
|
|
}
|
2025-04-10 13:33:38 +08:00
|
|
|
|
if (res.records.length > 0) {
|
2025-04-22 09:33:05 +08:00
|
|
|
|
deviceInfo.value = res.records[0];
|
2025-04-10 13:33:38 +08:00
|
|
|
|
getHealthLatestData();
|
2025-04-12 18:35:54 +08:00
|
|
|
|
IntervalFn();
|
2025-04-10 13:33:38 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
2025-04-10 19:00:17 +08:00
|
|
|
|
|
2025-04-10 13:33:38 +08:00
|
|
|
|
const getHealthLatestData = () => {
|
|
|
|
|
healthLatestData({ deviceId: deviceInfo.value.deviceId }).then((res) => {
|
|
|
|
|
HealthData.value = res;
|
|
|
|
|
funcList.value[0].num = res.hr;
|
|
|
|
|
funcList.value[1].num = res.bo;
|
|
|
|
|
funcList.value[2].num = res.temp;
|
2025-04-25 18:23:20 +08:00
|
|
|
|
handelRadio(devHisRef.value.radio);
|
2025-04-10 13:33:38 +08:00
|
|
|
|
});
|
2025-03-31 18:24:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-04-10 13:33:38 +08:00
|
|
|
|
const handelRadio = (val: number) => {
|
2025-04-25 18:23:20 +08:00
|
|
|
|
console.log("刷新");
|
|
|
|
|
|
2025-04-10 13:33:38 +08:00
|
|
|
|
if (val == 1) {
|
|
|
|
|
getOptionsData(HealthData.value.hrArr, "心率", "#FF0303");
|
|
|
|
|
} else if (val == 2) {
|
|
|
|
|
getOptionsData(HealthData.value.boArr, "血氧", "#983AFC");
|
|
|
|
|
} else if (val == 3) {
|
|
|
|
|
getOptionsData(HealthData.value.tempArr, "体表温度", "#FFA91F");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const getOptionsData = (list: { time: string; value: number }[], name: string, color: string) => {
|
|
|
|
|
options.xAxis.data = [];
|
|
|
|
|
options.series.data = [];
|
2025-04-10 19:00:17 +08:00
|
|
|
|
if (list && list.length) {
|
|
|
|
|
list.forEach((item) => {
|
2025-04-12 18:35:54 +08:00
|
|
|
|
options.times.push(item.time);
|
2025-04-10 19:00:17 +08:00
|
|
|
|
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
|
|
|
|
|
options.series.data.push(item.value);
|
|
|
|
|
});
|
|
|
|
|
options.series.name = name;
|
|
|
|
|
options.series.itemStyle.color = color;
|
|
|
|
|
}
|
2025-04-10 13:33:38 +08:00
|
|
|
|
myChart.setOption(options);
|
|
|
|
|
};
|
2025-04-25 18:23:20 +08:00
|
|
|
|
|
2025-04-12 18:35:54 +08:00
|
|
|
|
const IntervalFn = () => {
|
|
|
|
|
Interval = setInterval(() => {
|
|
|
|
|
getHealthLatestData();
|
|
|
|
|
}, 60000);
|
|
|
|
|
};
|
2025-04-24 10:12:03 +08:00
|
|
|
|
const handelMode = (e) => {
|
|
|
|
|
devicePaging.mode = e;
|
|
|
|
|
devicePaging.page = 1;
|
|
|
|
|
deviceData.value = [];
|
|
|
|
|
getdeviceList();
|
|
|
|
|
};
|
|
|
|
|
const handelLoad = () => {
|
|
|
|
|
if (loadFlag.value) return;
|
|
|
|
|
devicePaging.page += 1;
|
|
|
|
|
getdeviceList();
|
|
|
|
|
};
|
2025-04-10 19:00:17 +08:00
|
|
|
|
const handelClickDevice = (val: TDevice.IListRes) => {
|
2025-04-24 10:12:03 +08:00
|
|
|
|
devHisRef.value.radio = "1";
|
2025-04-10 19:00:17 +08:00
|
|
|
|
deviceInfo.value = val;
|
|
|
|
|
getHealthLatestData();
|
|
|
|
|
};
|
2025-04-25 18:23:20 +08:00
|
|
|
|
const handleResize = debounce(() => {
|
|
|
|
|
myChart.resize();
|
|
|
|
|
}, 200);
|
2025-03-31 18:24:37 +08:00
|
|
|
|
onMounted(() => {
|
2025-04-10 13:33:38 +08:00
|
|
|
|
getdeviceList();
|
2025-04-25 18:23:20 +08:00
|
|
|
|
myChart = echarts.init(chartRef.value ? chartRef.value : chartRef1.value);
|
|
|
|
|
window.addEventListener("resize", handleResize);
|
2025-03-31 18:24:37 +08:00
|
|
|
|
});
|
2025-04-12 18:35:54 +08:00
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
clearInterval(Interval);
|
2025-04-01 18:07:18 +08:00
|
|
|
|
window.removeEventListener("resize", handleResize);
|
|
|
|
|
});
|
2025-03-31 18:24:37 +08:00
|
|
|
|
</script>
|
|
|
|
|
<style scoped lang="less">
|
2025-04-10 13:33:38 +08:00
|
|
|
|
.container {
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
display: flex;
|
|
|
|
|
.el-row {
|
|
|
|
|
flex: 1;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
display: flex;
|
|
|
|
|
.el-row-left {
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
.el-row-right {
|
|
|
|
|
height: 100%;
|
|
|
|
|
overflow: auto;
|
2025-04-25 18:23:20 +08:00
|
|
|
|
.el-row-right-content {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
.box {
|
|
|
|
|
height: 388px;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-10 13:33:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-31 18:24:37 +08:00
|
|
|
|
</style>
|