feat: add 生命体征监测

This commit is contained in:
lonewolfyx 2026-02-02 11:08:44 +08:00
parent db9e1e998e
commit 9f12357390
4 changed files with 351 additions and 40 deletions

View File

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

9
src/api/lifte.js Normal file
View File

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

View File

@ -0,0 +1,298 @@
<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 {getTakeVitalSigns} from "@/api/lifte";
import dayjs from "dayjs";
export default {
name: 'physical_data',
data() {
return {
defaultProps: {
children: 'children',
label: 'room'
},
treeDara: [],
trendMap: {},
qushiChart: null, // echarts
qushiOption: null
}
},
async mounted() {
this.initialEcharts()
await this.getQuShiData()
},
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)
},
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))
},
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(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,
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'
},
}]
}
}
},
}
</script>
<style>
#qushi {
width: 100%;
height: 100%;
}
</style>

View File

@ -39,12 +39,14 @@ module.exports = {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
// target: `http://192.168.0.180:8099`,
target: `http://192.168.0.151:8099`, //服务器
// target: `http://192.168.0.151:8099`, //服务器
// target: `http://192.168.3.10:8099`, //耗子
// target: `http://106.15.139.36:8099`,
// target: `http://120.79.202.7:443`,
// target: `http://100.100.10.216:8099`,
// target: `http://100.100.10.216:8099`,
// target: 'http://106.15.139.36:18090',
target: 'http://127.0.0.1:18098',
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
@ -56,7 +58,7 @@ module.exports = {
css: {
loaderOptions: {
sass: {
sassOptions: { outputStyle: "expanded" }
sassOptions: {outputStyle: "expanded"}
}
}
},
@ -125,44 +127,44 @@ module.exports = {
.end()
config.when(process.env.NODE_ENV !== 'development', config => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single'),
{
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
to: './' //到根目录下
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single'),
{
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
to: './' //到根目录下
}
})
}
}