This commit is contained in:
Rhett霍 2026-03-16 14:36:10 +08:00
commit 8288de681f
6 changed files with 430 additions and 0 deletions

View File

@ -41,6 +41,7 @@
"axios": "0.24.0", "axios": "0.24.0",
"clipboard": "2.0.8", "clipboard": "2.0.8",
"core-js": "3.25.3", "core-js": "3.25.3",
"dayjs": "^1.11.19",
"echarts": "5.4.0", "echarts": "5.4.0",
"element-ui": "2.15.13", "element-ui": "2.15.13",
"file-saver": "2.0.5", "file-saver": "2.0.5",
@ -62,6 +63,7 @@
"vue": "2.6.12", "vue": "2.6.12",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-cropper": "0.5.5", "vue-cropper": "0.5.5",
"vue-echarts": "^8.0.1",
"vue-meta": "2.4.0", "vue-meta": "2.4.0",
"vue-router": "3.4.9", "vue-router": "3.4.9",
"vue-video-player": "^5.0.2", "vue-video-player": "^5.0.2",

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

@ -0,0 +1,186 @@
<template>
<div class="app-container">
<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, getLifeRealTime, getLifeRooms} from "@/api/life";
import dayjs from "dayjs";
export default {
name: 'tizhenchaxun',
data() {
return {
defaultProps: {
children: 'children',
label: 'room'
},
treeDara: [],
trendMap: {},
qushiChart: null, // echarts
qushiOption: null,
scheduler: null,
}
},
async mounted() {
this.initialEcharts()
await this.getQuShiData()
},
methods: {
async getQuShiData() {
const {data} = await getLifeRooms()
this.treeDara = data
},
handleNodeClick(data) {
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
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>