feat: 新增生命体征、生命体征历史查询

This commit is contained in:
lonewolfyx 2026-02-04 16:06:32 +08:00
parent 9f12357390
commit 64d1d5123a
6 changed files with 269 additions and 148 deletions

41
src/api/life.js Normal file
View File

@ -0,0 +1,41 @@
// 获取生命体征
import request from "@/utils/request";
export const getTakeVitalSigns = () => {
return request({
method: 'post',
url: '/system/vitalsigns/getVitalsign'
})
}
// 获取所有房间
export const getLifeRooms = () => {
return request({
method: 'post',
url: '/system/vitalsigns/equipments'
})
}
// 根据指定房间获取数据
export const getLifeRealTime = (roomId) => {
return request({
method: 'post',
url: '/system/vitalsigns/latestByEcode',
params: {
ecode: roomId
}
})
}
// 根据指定房间、时间获取数据
export const getLifeHistory = (roomId, startTime, endTime) => {
return request({
method: 'post',
url: '/system/vitalsigns/byEcodeBetweenTime',
params: {
ecode: roomId,
startTime: startTime,
endTime: endTime
}
})
}

View File

@ -1,9 +0,0 @@
// 获取生命体征
import request from "@/utils/request";
export const getTakeVitalSigns = () => {
return request({
method: 'post',
url: '/system/vitalsigns/getVitalsign'
})
}

View File

@ -1,6 +1,7 @@
<template>
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<logo v-if="showLogo" :collapse="isCollapse" />
<div>{{sidebarRouters}}</div>
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"

View File

@ -0,0 +1,189 @@
<template>
<div class="app-container">
<div style="margin-bottom: 20px">
<span style="font-size: 14px;padding-right: 10px;">默认</span>
<el-date-picker
v-model="searchDate"
end-placeholder="结束日期"
range-separator="至"
start-placeholder="开始日期"
type="datetimerange">
</el-date-picker>
</div>
<p style="font-size: 12px;color: red;">请先选择时间然后在选择房间后点击图表查看数据</p>
<el-row :gutter="24">
<el-col :span="5">
<el-tree :data="treeDara" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</el-col>
<el-col :span="19">
<div id="qushi" style="width: 100%;height: 500px"></div>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from "echarts";
import {getLifeHistory, getLifeRooms} from "@/api/life";
import dayjs from "dayjs";
export default {
name: 'lishichaxun',
data() {
return {
defaultProps: {
children: 'children',
label: 'room'
},
treeDara: [],
trendMap: {},
qushiChart: null, // echarts
qushiOption: null,
scheduler: null,
searchDate: []
}
},
async mounted() {
this.initialEcharts()
await this.getQuShiData()
},
methods: {
async getQuShiData() {
const {data} = await getLifeRooms()
this.treeDara = data
},
async handleNodeClick(data) {
const raw = await getLifeHistory(data.ecode, dayjs(this.searchDate[0]).format('YYYY-MM-DD HH:ss:mm'), dayjs(this.searchDate[1]).format('YYYY-MM-DD HH:ss:mm'));
const breathrate = raw.data.map(i => i.breathrate);
const heartrate = raw.data.map(i => i.heartrate);
const timeList = raw.data.map(i => dayjs(i.recordtime).format('YYYY-MM-DD HH:ss:mm'));
console.log('数据请求');
this.qushiChart.setOption(this.getEchartsOptions(timeList, breathrate, heartrate));
// this.scheduler = setInterval(fetchDataAndRender, 5000);
},
initialEcharts() {
if (this.qushiChart) return
const dom = document.getElementById('qushi')
this.qushiChart = echarts.init(dom)
this.qushiOption = this.getEchartsOptions()
this.qushiChart.setOption(this.qushiOption)
},
getEchartsOptions(timeList = [], breathrate = [], heartrate = []) {
return {
title: {
text: '生命体征历史数据',
textStyle: {
fontFamily: 'PingFangSC-Medium',
fontSize: 14
},
},
color: ['#52A9F1', '#1DD398'],
animation: true,
tooltip: {
trigger: 'axis'
},
legend: {
icon: "roundRect",
top: "0",
itemWidth: 24,
itemHeight: 12,
itemGap: 20,
textStyle: {
color: "#000000",
fontWeight: "bold",
},
data: ['心跳', '呼吸']
},
grid: {
top: '15%',
left: '1%',
right: '1%',
bottom: '0%',
containLabel: true
},
xAxis: [
{
show: true,
type: 'category',
boundaryGap: true,
data: timeList,
axisLabel: {
textStyle: {
color: "rgba(0,0,0,0.65)",
}
},
axisLine: {
lineStyle: {
color: "rgba(0,0,0,0.1)"
},
show: true
}
}],
yAxis: [
{
type: 'value',
// interval:250, //
// axisTick: { show: false },
axisLine: {
lineStyle: {color: "rgba(0,0,0,0)"}
},
axisLabel: {
textStyle: {color: "rgba(0,0,0,0.65)",}
},
// 线
splitLine: {
lineStyle: {
color: "rgba(0,0,0,0.1)"
}
}
}],
series: [
{
name: '心跳',
type: 'line',
smooth: true,
// data: [235, 429, 528, 324, 338, 453, 231, 326, 411, 118, 256],
data: heartrate.length > 0 ? heartrate : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
showSymbol: false,
lineStyle: {
color: '#1DD398',
type: 'dotted'
},
areaStyle: {
opacity: 0.3,
color: '#1DD398'
},
},
{
name: '呼吸',
type: 'line',
smooth: true,
// data: [25, 49, 58, 24, 38, 45, 21, 26, 11, 18, 26],
data: breathrate.length > 0 ? breathrate : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
showSymbol: false,
lineStyle: {
color: '#52A9F1',
},
areaStyle: {
opacity: 0.1,
color: '#1DD398'
},
}]
}
}
},
destroyed() {
clearInterval(this.scheduler)
}
}
</script>
<style>
#qushi {
width: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,11 @@
<template>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

View File

@ -13,11 +13,11 @@
<script>
import * as echarts from "echarts";
import {getTakeVitalSigns} from "@/api/lifte";
import {getLifeHistory, getLifeRealTime, getLifeRooms} from "@/api/life";
import dayjs from "dayjs";
export default {
name: 'physical_data',
name: 'tizhenchaxun',
data() {
return {
defaultProps: {
@ -27,7 +27,8 @@ export default {
treeDara: [],
trendMap: {},
qushiChart: null, // echarts
qushiOption: null
qushiOption: null,
scheduler: null,
}
},
async mounted() {
@ -36,143 +37,26 @@ export default {
},
methods: {
async getQuShiData() {
const {data} = await getTakeVitalSigns()
this.treeDara = data.map(item => item.equipment)
.filter(Boolean)
.filter(
(eq, index, arr) =>
arr.findIndex(e => e.id === eq.id) === index
);
this.trendMap = data.reduce((map, item) => {
const eq = item.equipment
if (!eq) return map
const key = `${eq.ecode}`
if (!map[key]) {
map[key] = []
}
map[key].push({
breathrate: item.breathrate,
heartrate: item.heartrate,
recordtime: dayjs(item.recordtime).format('YYYY-MM-DD HH:mm:ss')
})
return map
}, {})
this.handleNodeClick(this.treeDara[0])
},
getQuShi() {
const chart = echarts.init(document.getElementById('qushi'))
const option = {
title: {
text: '生命体征实时监测',
textStyle: {
fontFamily: 'PingFangSC-Medium',
fontSize: 14
},
},
color: ['#52A9F1', '#1DD398'],
animation: true,
tooltip: {
trigger: 'axis'
},
legend: {
icon: "roundRect",
top: "0",
itemWidth: 24,
itemHeight: 12,
itemGap: 20,
textStyle: {
color: "#000000",
fontWeight: "bold",
},
data: ['2022', '2023']
},
grid: {
top: '15%',
left: '1%',
right: '1%',
bottom: '0%',
containLabel: true
},
xAxis: [{
show: false,
type: 'category',
boundaryGap: true,
data: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
axisLabel: {
textStyle: {
color: "rgba(0,0,0,0.65)",
}
},
// x线 rgba(255,255,255,.2)
axisLine: {
lineStyle: {
color: "rgba(0,0,0,0.1)"
},
show: false
}
}],
yAxis: [{
type: 'value',
// interval:250, //
// axisTick: { show: false },
axisLine: {
lineStyle: {color: "rgba(0,0,0,0)"}
},
axisLabel: {
textStyle: {color: "rgba(0,0,0,0.65)",}
},
// 线
splitLine: {
lineStyle: {
color: "rgba(0,0,0,0.1)"
}
}
}],
series: [{
name: '2022',
type: 'line',
smooth: true,
data: [25, 49, 58, 24, 38, 45, 21, 26, 11, 18, 26],
showSymbol: false,
lineStyle: {
color: '#1DD398',
type: 'dotted'
},
areaStyle: {
opacity: 0.3,
color: '#1DD398'
},
},
{
name: '2023',
type: 'line',
smooth: true,
data: [25, 49, 58, 24, 38, 45, 21, 26, 11, 18, 26],
showSymbol: false,
lineStyle: {
color: '#52A9F1',
},
areaStyle: {
opacity: 0.1,
color: '#1DD398'
},
}]
}
chart.setOption(option)
const {data} = await getLifeRooms()
this.treeDara = data
},
handleNodeClick(data) {
const raw = this.trendMap[data.ecode] ?? [{breathrate: 0, heartrate: 0}]
const breathrate = raw.map(i => i.breathrate)
const heartrate = raw.map(i => i.heartrate)
this.qushiChart.setOption(this.getEchartsOptions(breathrate, heartrate))
if (this.scheduler) {
clearInterval(this.scheduler)
}
const fetchDataAndRender = async () => {
const raw = await getLifeRealTime(data.ecode);
const breathrate = raw.data.map(i => i.breathrate);
const heartrate = raw.data.map(i => i.heartrate);
const timeList = raw.data.map(i => dayjs(i.recordtime).format('YYYY-MM-DD HH:ss:mm'));
console.log('数据请求');
this.qushiChart.setOption(this.getEchartsOptions(timeList, breathrate, heartrate));
};
fetchDataAndRender();
this.scheduler = setInterval(fetchDataAndRender, 5000);
},
initialEcharts() {
if (this.qushiChart) return
@ -184,7 +68,7 @@ export default {
this.qushiChart.setOption(this.qushiOption)
},
getEchartsOptions(breathrate = [], heartrate = []) {
getEchartsOptions(timeList = [], breathrate = [], heartrate = []) {
return {
title: {
text: '生命体征实时监测',
@ -222,6 +106,7 @@ export default {
show: true,
type: 'category',
boundaryGap: true,
data: timeList,
axisLabel: {
textStyle: {
color: "rgba(0,0,0,0.65)",
@ -287,6 +172,9 @@ export default {
}
}
},
destroyed() {
clearInterval(this.scheduler)
}
}
</script>