mirror of
https://gitee.com/xiongmao1988/rax-medical.git
synced 2026-06-14 20:21:47 +08:00
远程连接
This commit is contained in:
parent
21b6f6a32e
commit
923d34feb8
|
|
@ -23,6 +23,9 @@
|
||||||
color: $main-color;
|
color: $main-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.el-button:not(.el-button--primary) {
|
||||||
|
color: $main-color;
|
||||||
|
}
|
||||||
.el-button.is-link {
|
.el-button.is-link {
|
||||||
color: $main-color;
|
color: $main-color;
|
||||||
&:hover,
|
&:hover,
|
||||||
|
|
@ -65,6 +68,9 @@
|
||||||
|
|
||||||
.el-dialog {
|
.el-dialog {
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
&.header-none .el-dialog__header {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
.el-dialog__header {
|
.el-dialog__header {
|
||||||
padding: 30px 30px 0 30px;
|
padding: 30px 30px 0 30px;
|
||||||
.el-dialog__headerbtn {
|
.el-dialog__headerbtn {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
}
|
}
|
||||||
$main-color: #006080;
|
$main-color: #006080;
|
||||||
$border-color: #EBEEF5;
|
$border-color: #EBEEF5;
|
||||||
|
$border1-color: #E4E7ED;
|
||||||
|
$border2-color: #DCDFE6;
|
||||||
$text-color: #303133;
|
$text-color: #303133;
|
||||||
$text1-color: #606266;
|
$text1-color: #606266;
|
||||||
$text2-color: #909399;
|
$text2-color: #909399;
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
|
@ -15,6 +15,8 @@ import './assets/font/iconfont.css';
|
||||||
import '@/assets/css/custom-element.scss'
|
import '@/assets/css/custom-element.scss'
|
||||||
import '@/assets/css/animastore.css'
|
import '@/assets/css/animastore.css'
|
||||||
|
|
||||||
|
// import '@/utils/debugger'
|
||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
const app = createApp(main)
|
const app = createApp(main)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,20 @@ const router = createRouter({
|
||||||
{
|
{
|
||||||
path: '/remote-manage',
|
path: '/remote-manage',
|
||||||
name: '远程管理',
|
name: '远程管理',
|
||||||
|
redirect: '/remote-manage/remote-manage',
|
||||||
component: () => import('@/views/remote-manage/index.vue'),
|
component: () => import('@/views/remote-manage/index.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/remote-manage/remote-manage',
|
||||||
|
name: '远程管理',
|
||||||
|
component: () => import('@/views/remote-manage/remote-manage.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/remote-manage/remote-control',
|
||||||
|
name: '远程控制',
|
||||||
|
component: () => import('@/views/remote-manage/remote-control.vue'),
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system-manage',
|
path: '/system-manage',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useRemoteStore = defineStore('remote', {
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
currentRemote: {
|
||||||
|
|
||||||
|
} as any
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 也可以这样定义
|
||||||
|
// state: () => ({ count: 0 })
|
||||||
|
actions: {
|
||||||
|
getCurrentRemote() {
|
||||||
|
return this.currentRemote
|
||||||
|
},
|
||||||
|
setCurrentRemote(e: object) {
|
||||||
|
this.currentRemote = e
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// stores/counter.js
|
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
export const useLoginStore = defineStore('login', {
|
export const useLoginStore = defineStore('login', {
|
||||||
|
|
@ -8,6 +7,12 @@ export const useLoginStore = defineStore('login', {
|
||||||
isLogin: true,
|
isLogin: true,
|
||||||
account: 'admin',
|
account: 'admin',
|
||||||
name: '管理员',
|
name: '管理员',
|
||||||
|
/**
|
||||||
|
* 公司: 后台管理
|
||||||
|
* 医院高级管理员: 首页、权限管理、患者管理、远程管理、日志管理
|
||||||
|
* 医院中级管理员: 首页、患者管理、远程管理
|
||||||
|
* 医院普通用户: 首页、患者管理
|
||||||
|
*/
|
||||||
permissions: '超级管理员',
|
permissions: '超级管理员',
|
||||||
hospital: '北京第一医院'
|
hospital: '北京第一医院'
|
||||||
} as any
|
} as any
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
setInterval(() => {
|
||||||
|
debugger
|
||||||
|
}, 1000)
|
||||||
|
|
@ -2,3 +2,13 @@ export interface MenuItem {
|
||||||
name: string
|
name: string
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RemoteItem{
|
||||||
|
isRemote: boolean
|
||||||
|
dataAlarm: boolean
|
||||||
|
title: string
|
||||||
|
serverUser: string
|
||||||
|
patientName: string
|
||||||
|
patientCode: string
|
||||||
|
index?: number
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<RouterView/>
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<template>
|
||||||
|
<div class="message-part">
|
||||||
|
<div class="title">消息通知</div>
|
||||||
|
<div class="content">
|
||||||
|
<el-timeline>
|
||||||
|
<el-timeline-item v-for="(item, index) in activities" :key="index" :timestamp="dateFormater('yyyy-MM-dd HH:mm:ss', item.time)"
|
||||||
|
:class="{ 'alarm': item.state === '连接失败' }">
|
||||||
|
{{ item.title + ' ' + item.state }}
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts' setup>
|
||||||
|
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
|
||||||
|
import { dateFormater } from '@/utils/date-util'
|
||||||
|
|
||||||
|
interface ActivitiesItem {
|
||||||
|
time: Date
|
||||||
|
title: string
|
||||||
|
state: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const activities: any = ref([] as Array<ActivitiesItem>)
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
setData,
|
||||||
|
})
|
||||||
|
|
||||||
|
function setData(e: ActivitiesItem) {
|
||||||
|
activities.value.push(e)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
.message-part {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
background: $main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
margin-top: 40px;
|
||||||
|
padding: 0 20px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
:deep(.el-timeline-item) {
|
||||||
|
color: $main-color;
|
||||||
|
|
||||||
|
.el-timeline-item__content,
|
||||||
|
.el-timeline-item__timestamp {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alarm {
|
||||||
|
color: red;
|
||||||
|
.el-timeline-item__node {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}</style>
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog class="header-none" v-model="dialogVisible" :width="700" :show-close="false">
|
||||||
|
<div class="content-box">
|
||||||
|
<img src="@/assets/imgs/remote/remote_bck.png">
|
||||||
|
<div class="info">
|
||||||
|
<h3>连接云服务器</h3>
|
||||||
|
<br>
|
||||||
|
<p>云服务器连接状态:{{ patientInfo.isRemote ? '已连接' : '未连接' }}</p>
|
||||||
|
<p>输入用户名:{{ patientInfo.serverUser }}</p>
|
||||||
|
<p>密码:*********</p>
|
||||||
|
<br>
|
||||||
|
<p class="input-box"><span>输入病人姓名:</span><el-input v-model="patientInfo.patientName"></el-input></p>
|
||||||
|
<p class="input-box"><span>输入病人身份证号:</span><el-input v-model="patientInfo.patientCode"></el-input></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn-box">
|
||||||
|
<el-button class="f18" type="primary" @click="confirmRemote">确定连接</el-button>
|
||||||
|
<el-button class="f18" @click="breakRemote">断开连接</el-button>
|
||||||
|
<el-button class="f18" @click="dialogVisible = false">返回</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts' setup>
|
||||||
|
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useRemoteStore } from '@/stores/remote-info-store';
|
||||||
|
import type { RemoteItem } from '@/utils/public-interface';
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const emit = defineEmits(['confirmRemote', 'errorRemote', 'breakRemote'])
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const patientInfo = ref({} as RemoteItem)
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open,
|
||||||
|
close,
|
||||||
|
})
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
function open(e: RemoteItem) {
|
||||||
|
if(useRemoteStore().getCurrentRemote().index === e.index) {
|
||||||
|
router.push('/remote-manage/remote-control')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
patientInfo.value = e
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
function close() {
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmRemote = () => {
|
||||||
|
if(patientInfo.value.patientCode) {
|
||||||
|
ElMessage.success('连接成功!')
|
||||||
|
emit('confirmRemote', patientInfo.value)
|
||||||
|
close()
|
||||||
|
}else{
|
||||||
|
ElMessage.error('连接失败!')
|
||||||
|
emit('errorRemote', patientInfo.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const breakRemote = () => {
|
||||||
|
ElMessage.info('连接已断开!')
|
||||||
|
emit('breakRemote', patientInfo.value)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
.content-box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
&>img {
|
||||||
|
width: 260px;
|
||||||
|
border: 1px solid #C77000;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
width: calc(100% - 290px);
|
||||||
|
color: $main-color;
|
||||||
|
line-height: 2;
|
||||||
|
font-weight: 600;
|
||||||
|
h3 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.input-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
&>span {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
:deep(.el-input) {
|
||||||
|
border-bottom: 1px solid $text3-color;
|
||||||
|
.el-input__wrapper {
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0;
|
||||||
|
input {
|
||||||
|
height: 20px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: $main-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 50px;
|
||||||
|
.el-button {
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 15px 50px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
<template>
|
||||||
|
<div class="remote-part">
|
||||||
|
<div class="title">{{ title }}</div>
|
||||||
|
<div class="content" :class="{'is-total': isRemote}">
|
||||||
|
<div class="left-box">
|
||||||
|
<div class="info-box">
|
||||||
|
<div class="row-item">
|
||||||
|
<span class="label">病人名称</span>
|
||||||
|
<span class="input-value">{{ patientInfo.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row-item">
|
||||||
|
<span class="label">住院号</span>
|
||||||
|
<span class="input-value">{{ patientInfo.code }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-item" :class="{'alarm': patientInfo.BIS < 40 || patientInfo.BIS > 60}">
|
||||||
|
<span class="label">BIS</span>
|
||||||
|
<span class="value">{{ patientInfo.BIS }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row-item" :class="{'alarm': patientInfo.SBP < 90 || patientInfo.SBP > 120}">
|
||||||
|
<span class="label">SBP</span>
|
||||||
|
<span class="value">{{ patientInfo.SBP }}<span class="unit">mmHg</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="row-item">
|
||||||
|
<span class="label">SPO2</span>
|
||||||
|
<span class="value">{{ patientInfo.SPO2 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="center-box">
|
||||||
|
<img src="@/assets/imgs/main_body_intact.png">
|
||||||
|
</div>
|
||||||
|
<div class="right-box">
|
||||||
|
<div class="info-box">
|
||||||
|
<div class="row-item">
|
||||||
|
<span class="label">手术时间</span>
|
||||||
|
<span class="input-value">{{ patientInfo.time && dateFormater('yyyy-MM-dd HH:mm:ss', patientInfo.time) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row-item">
|
||||||
|
<span class="label">手术状态</span>
|
||||||
|
<span class="tag-value" :class="{'normal': !patientInfo.state}">正常</span>
|
||||||
|
<span class="tag-value" :class="{'alarm': patientInfo.state}">异常</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-item" :class="{'alarm': patientInfo.DBP < 60 || patientInfo.DBP > 90}">
|
||||||
|
<span class="label">DBP</span>
|
||||||
|
<span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="row-item" :class="{'alarm': patientInfo.HR < 50 || patientInfo.HR > 80}">
|
||||||
|
<span class="label">HR</span>
|
||||||
|
<span class="value">{{ patientInfo.HR }}<span class="unit">次/分</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="row-item">
|
||||||
|
<span class="label">TEMP</span>
|
||||||
|
<span class="value">{{ patientInfo.TEMP }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts' setup>
|
||||||
|
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
|
||||||
|
import { dateFormater } from '@/utils/date-util'
|
||||||
|
import { useRemoteStore } from '@/stores/remote-info-store';
|
||||||
|
|
||||||
|
interface PatientInfoItem {
|
||||||
|
name: string // 病人名称
|
||||||
|
code: string // 住院号
|
||||||
|
time: Date // 手术时间
|
||||||
|
state: boolean // 手术状态 false 正常 true 异常
|
||||||
|
BIS: number
|
||||||
|
SBP: number
|
||||||
|
SPO2: number
|
||||||
|
DBP: number
|
||||||
|
HR: number
|
||||||
|
TEMP: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = ref('远程控制')
|
||||||
|
const isRemote = ref(false) // 连接状态
|
||||||
|
const patientInfo = ref({} as PatientInfoItem)
|
||||||
|
|
||||||
|
initData(useRemoteStore().getCurrentRemote())
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
initData
|
||||||
|
})
|
||||||
|
|
||||||
|
function initData(e?: any) {
|
||||||
|
const obj = e || {}
|
||||||
|
title.value = e.title
|
||||||
|
isRemote.value = e.isRemote
|
||||||
|
patientInfo.value.state = e.dataAlarm
|
||||||
|
patientInfo.value.name = obj.patientName || ''
|
||||||
|
patientInfo.value.code = 'XXXXXX'
|
||||||
|
patientInfo.value.time = new Date()
|
||||||
|
patientInfo.value.BIS = Math.ceil(Math.random() * 100)
|
||||||
|
patientInfo.value.SBP = Math.ceil(Math.random() * 100)
|
||||||
|
patientInfo.value.SPO2 = Math.ceil(Math.random() * 100)
|
||||||
|
patientInfo.value.DBP = Math.ceil(Math.random() * 100)
|
||||||
|
patientInfo.value.HR = Math.ceil(Math.random() * 100)
|
||||||
|
patientInfo.value.TEMP = Math.ceil(Math.random() * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
.remote-part {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
background: $main-color;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
padding: 20px 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
.common-box {
|
||||||
|
width: 30%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.left-box {
|
||||||
|
@extend .common-box;
|
||||||
|
.label {
|
||||||
|
background: $main-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.center-box {
|
||||||
|
@extend .common-box;
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right-box {
|
||||||
|
@extend .common-box;
|
||||||
|
.label {
|
||||||
|
background: #f8b300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.row-item {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
.label {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info-box, .row-item .value {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.is-total {
|
||||||
|
.info-box, .row-item .value {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
width: calc(50% - 10px);
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
width: 50%;
|
||||||
|
height: 40px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: $main-color;
|
||||||
|
border-color: $main-color;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-weight: 600;
|
||||||
|
.unit {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right-box .value {
|
||||||
|
color: #f8b300;
|
||||||
|
border-color: #f8b300;
|
||||||
|
}
|
||||||
|
.row-item.alarm {
|
||||||
|
.label {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
color: red;
|
||||||
|
border-color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info-box {
|
||||||
|
width: 100%;
|
||||||
|
.row-item {
|
||||||
|
padding: 10px 0;
|
||||||
|
height: 40px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
.label {
|
||||||
|
width: 70px;
|
||||||
|
height: 20px;
|
||||||
|
background: transparent;
|
||||||
|
color: $main-color;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.input-value {
|
||||||
|
width: 100%;
|
||||||
|
height: 21px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: $main-color;
|
||||||
|
border-bottom: 1px solid $border2-color;
|
||||||
|
}
|
||||||
|
.tag-value {
|
||||||
|
margin-left: 30px;
|
||||||
|
padding: 0 20px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 18px;
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
background: $border2-color;
|
||||||
|
border-radius: 8px;
|
||||||
|
&.normal {
|
||||||
|
background: $main-color;
|
||||||
|
}
|
||||||
|
&.alarm {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,910 @@
|
||||||
|
<template>
|
||||||
|
<div class="remote-box" id="screenBox">
|
||||||
|
<div class="main-box">
|
||||||
|
<div class="left-box">
|
||||||
|
<h3>{{ useRemoteStore().getCurrentRemote().title }}</h3>
|
||||||
|
<chart-line ref="chartDom1" class="chart-line" :names="['BIS', 'HR']"
|
||||||
|
:chartData="featureTable"></chart-line>
|
||||||
|
<chart-line ref="chartDom2" class="chart-line" :names="['SBP', 'DBP']"
|
||||||
|
:chartData="featureTable"></chart-line>
|
||||||
|
<chart-line ref="chartDom3" class="chart-line" :names="['SPO2', 'TEMP']"
|
||||||
|
:chartData="featureTable"></chart-line>
|
||||||
|
<chart-ecg ref="chartDom4" class="chart-ecg" :chartData="featureTable"></chart-ecg>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="center-box">
|
||||||
|
<div class="body-box">
|
||||||
|
<div class="body-img">
|
||||||
|
<img src="@/assets/imgs/main_body.png" style="width: 100%;height: 100%;" />
|
||||||
|
<img class="lung-img" :class="{ 'shake_1': lungAlarm }" :src="lungAlarm ? imgLungAlarm : imgLung">
|
||||||
|
<img class="heart-img" :class="{ 'shake_1': heartAlarm }"
|
||||||
|
:src="heartAlarm ? imgHeartAlarm : imgHeart">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="btn-box">
|
||||||
|
<el-button class="start-btn" color="#F80000" @click="getTableData(!isStart)">{{ isStart ? '终止' : '开始'
|
||||||
|
}}</el-button>
|
||||||
|
<div class="right-btn-box">
|
||||||
|
<el-button :class="{ 'active': isAIDose }" size="small" @click="getTableData(true)">AI给药</el-button>
|
||||||
|
<el-button :class="{ 'active': !isAIDose }" size="small"
|
||||||
|
@click="getTableData(false)">人工给药</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-box">
|
||||||
|
<div class="top-btn-box">
|
||||||
|
<div class="top-left-btn-box">
|
||||||
|
<el-select v-model="database" filterable placeholder="Select" style="width: 100%;"
|
||||||
|
@change="selectDatabase">
|
||||||
|
<el-option v-for="item in databaseOptions" :key="item.value" :label="item.label"
|
||||||
|
:value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
<el-button color="#C77000">患者信息</el-button>
|
||||||
|
<el-button color="#C77000">已连接</el-button>
|
||||||
|
<el-button color="#C77000">机器人运行正常</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button color="#e0e0e0" @click="backRemote"><el-icon>
|
||||||
|
<Back />
|
||||||
|
</el-icon> 返回</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="monitoring-message">
|
||||||
|
<div class="left-box">
|
||||||
|
<span class="unusual-title">异常信息</span>
|
||||||
|
<ul ref="unusualMsg" class="unusual-box">
|
||||||
|
<li v-for="item in unusual" :key="item">{{ item }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="right-box">
|
||||||
|
<div class="video-box" @click="playPause">
|
||||||
|
<div class="icon-box">
|
||||||
|
<el-icon v-if="isVideoPlay">
|
||||||
|
<VideoPause />
|
||||||
|
</el-icon>
|
||||||
|
<el-icon v-else>
|
||||||
|
<VideoPlay />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<!-- poster="@/assets/imgs/video_bck.png" -->
|
||||||
|
<video ref="liveVideo">
|
||||||
|
<source src="@/assets/medical.mp4" type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
<div class="message-box">
|
||||||
|
<ul ref="msgLog" class="message-log">
|
||||||
|
<li v-for="(item, index) in mssageList" :key="'msg-log-' + index"
|
||||||
|
:class="{ 'align-right': item.user === userName }">
|
||||||
|
<span>{{ item.msg }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="send-box">
|
||||||
|
<el-input v-model="msgVal" placeholder="请输入消息" />
|
||||||
|
<el-button color="#006080" @click="sendMsg">发送消息</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-box">
|
||||||
|
<el-table :data="tableData" height="100%" style="width: 100%">
|
||||||
|
<el-table-column prop="num" label="票号" width="40" align="center" />
|
||||||
|
<el-table-column prop="name" label="药物名称" align="center" />
|
||||||
|
<el-table-column prop="speed" label="速度(ml/h)" width="100" />
|
||||||
|
<el-table-column prop="total" label="累计药量(ml)" width="100">
|
||||||
|
<template #default="scope">—</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="state" label="工作状态" width="70" align="center" />
|
||||||
|
<el-table-column label="特殊情况人为干预" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="table-btn-box">
|
||||||
|
<el-button size="small" color="#006080" @click="tableItemPlus(scope)"><el-icon>
|
||||||
|
<Plus />
|
||||||
|
</el-icon></el-button>
|
||||||
|
<el-button size="small" color="#006080" :disabled="scope.row.speed <= 0"
|
||||||
|
@click="tableItemMinus(scope)"><el-icon>
|
||||||
|
<Minus />
|
||||||
|
</el-icon></el-button>
|
||||||
|
<el-button size="small" color="#006080" @click="tableItemConfirm(scope)"
|
||||||
|
:disabled="tableDataStore[scope.$index].speed === scope.row.speed">确定</el-button>
|
||||||
|
<el-button size="small" color="#006080" @click="tableItemCancel(scope)"
|
||||||
|
:disabled="tableDataStore[scope.$index].speed === scope.row.speed">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="setDatabaseDialog" title="请选择需要查询的病人" width="300px" align-center>
|
||||||
|
<el-select v-model="database" filterable placeholder="Select" style="width: 100%;">
|
||||||
|
<el-option v-for="item in databaseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="setDatabaseDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="setDatabase">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref, reactive } from 'vue';
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
|
import { useRemoteStore } from '@/stores/remote-info-store'
|
||||||
|
import { dateFormater } from '@/utils/date-util';
|
||||||
|
import { post } from "@/axios/index";
|
||||||
|
import chartLine from './chart/chart-line.vue';
|
||||||
|
import chartEcg from './chart/chart-ecg.vue';
|
||||||
|
import imgLung from '@/assets/imgs/lung.png';
|
||||||
|
import imgHeart from '@/assets/imgs/heart.png';
|
||||||
|
import imgLungAlarm from '@/assets/imgs/lung_alarm.png';
|
||||||
|
import imgHeartAlarm from '@/assets/imgs/heart_alarm.png';
|
||||||
|
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const medicineCustom: any[] = [
|
||||||
|
{ name: '丙泊酚', plus: 0.5, total: 50 },
|
||||||
|
{ name: '舒芬太尼', plus: 1, total: 100 },
|
||||||
|
{ name: '瑞芬太尼', plus: 0.05, total: 5 },
|
||||||
|
{ name: '顺阿曲库胺', plus: 0.02, total: 2 },
|
||||||
|
{ name: '尼卡地平', plus: 1, total: 100 },
|
||||||
|
{ name: '艾司洛尔', plus: 1, total: 100 },
|
||||||
|
{ name: '麻黄素', plus: 1, total: 100 },
|
||||||
|
{ name: '阿托品', plus: 1, total: 100 },
|
||||||
|
{ name: '罗库溴铵', plus: 0.1, total: 10 }
|
||||||
|
];
|
||||||
|
let featureTimer = 0;
|
||||||
|
let ecgTimer = 0;
|
||||||
|
let aiFlagTimer = 0;
|
||||||
|
let medicineTimer = 0;
|
||||||
|
const currentRemote = useRemoteStore().getCurrentRemote()
|
||||||
|
|
||||||
|
const chartDom1 = ref(),
|
||||||
|
chartDom2 = ref(),
|
||||||
|
chartDom3 = ref(),
|
||||||
|
chartDom4 = ref(),
|
||||||
|
liveVideo = ref(),
|
||||||
|
msgLog = ref(),
|
||||||
|
unusualMsg = ref();
|
||||||
|
|
||||||
|
const database = ref('');
|
||||||
|
const databaseOptions = ref([] as { value: string, label: string }[]);
|
||||||
|
const messageSum = ref(10);
|
||||||
|
const userName = ref('admin');
|
||||||
|
const setDatabaseDialog = ref(false);
|
||||||
|
const featureTable = ref([] as any[]);
|
||||||
|
let chartNowData = reactive({ ID: 0 });
|
||||||
|
const lungAlarm = ref(false); // 肺部警告
|
||||||
|
const heartAlarm = ref(false); // 心脏警告
|
||||||
|
const isStart = ref(false); // 是否开始
|
||||||
|
const isAIDose = ref(false); // 是否AI给药
|
||||||
|
const isVideoPlay = ref(false); // 视频是否播放
|
||||||
|
const videoSrc = ref('https://www.runoob.com/try/demo_source/mov_bbb.mp4');
|
||||||
|
const mssageList = ref([] as any);
|
||||||
|
const msgVal = ref('');
|
||||||
|
const unusual = ref([] as any);
|
||||||
|
const tableData = ref([] as any[]);
|
||||||
|
const tableDataStore = ref([] as any[]);
|
||||||
|
|
||||||
|
getDatabases();
|
||||||
|
onMounted(() => {
|
||||||
|
if(currentRemote.isRemote) {
|
||||||
|
|
||||||
|
}else{
|
||||||
|
router.replace('/remote-manage/remote-manage')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msgLogScrollBottom();
|
||||||
|
getChartData(); // 定时任务
|
||||||
|
getAIFlag(); // 定时任务
|
||||||
|
getMedicine(); // 定时任务
|
||||||
|
initScale();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function initData() {
|
||||||
|
lungAlarm.value = false;
|
||||||
|
heartAlarm.value = false;
|
||||||
|
isStart.value = false;
|
||||||
|
isAIDose.value = false;
|
||||||
|
unusual.value = [];
|
||||||
|
mssageList.value = [];
|
||||||
|
tableData.value = [];
|
||||||
|
tableDataStore.value = [];
|
||||||
|
const currentRemote = useRemoteStore().getCurrentRemote() // 当前远程连接
|
||||||
|
|
||||||
|
getFeatureTable();
|
||||||
|
getMssageLog();
|
||||||
|
getTableData(isAIDose.value);
|
||||||
|
try {
|
||||||
|
msgLogScrollBottom();
|
||||||
|
} catch (error) { }
|
||||||
|
|
||||||
|
}
|
||||||
|
// AIFlagTable 表2秒获取一次
|
||||||
|
function getAIFlag() {
|
||||||
|
let isRunTimer = true;
|
||||||
|
clearInterval(aiFlagTimer);
|
||||||
|
aiFlagTimer = setInterval(() => {
|
||||||
|
if (isRunTimer) {
|
||||||
|
isRunTimer = false;
|
||||||
|
post('/getaiflag', { database: database.value, start: 0, end: 1 }, (res: any) => {
|
||||||
|
if (res.status === 200 && res.data.length > 0) {
|
||||||
|
const flag = Boolean(res.data[0].Flag);
|
||||||
|
if (isAIDose.value !== flag) getTableData(Boolean(res.data[0].Flag));
|
||||||
|
}
|
||||||
|
isRunTimer = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
function setTableData(res: any) {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
let i = 0;
|
||||||
|
const ary: any = [];
|
||||||
|
for (let key in res.data[0]) {
|
||||||
|
if (key !== 'ID' && key !== 'Phase' && key !== 'Time' && key !== 'TIME') {
|
||||||
|
i++;
|
||||||
|
ary.push({ Phase: res.data[0].Phase, num: i, name: key, speed: res.data[0][key], total: medicineCustom.find(o => o.name === key)?.total, state: '正常' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableData.value = ary;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const defaultMedicine: string[] = ['丙泊酚', '舒芬太尼', '瑞芬太尼', '顺阿曲库胺', '尼卡地平', '艾司洛尔', '麻黄素', '阿托品'];
|
||||||
|
const ary: any = [];
|
||||||
|
defaultMedicine.forEach((item, index) => {
|
||||||
|
ary.push({ Phase: 1, num: index + 1, name: item, speed: 0, total: medicineCustom.find(o => o.name === item)?.total, state: '正常' });
|
||||||
|
});
|
||||||
|
tableData.value = ary;
|
||||||
|
}
|
||||||
|
tableDataStore.value = JSON.parse(JSON.stringify(tableData.value));
|
||||||
|
}
|
||||||
|
// AIMedicineTable、DoctorMedicineTable 表2秒获取一次
|
||||||
|
function getMedicine() {
|
||||||
|
let isRunTimer = true;
|
||||||
|
clearInterval(medicineTimer);
|
||||||
|
setInterval(() => {
|
||||||
|
if (isRunTimer && JSON.stringify(tableDataStore) === JSON.stringify(tableData) && isAIDose.value) {
|
||||||
|
isRunTimer = false;
|
||||||
|
const url = isAIDose.value ? '/getaimedicine' : '/getdoctormedicine';
|
||||||
|
post(url, { database: database.value, start: 0, end: 1 }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
setTableData(res);
|
||||||
|
}
|
||||||
|
isRunTimer = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
// FeatureTable 表2秒获取一次
|
||||||
|
function getChartData() {
|
||||||
|
let isRunTimer = true;
|
||||||
|
clearInterval(featureTimer);
|
||||||
|
clearInterval(ecgTimer);
|
||||||
|
setInterval(() => {
|
||||||
|
if (isRunTimer) {
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
setInterval(() => {
|
||||||
|
try {
|
||||||
|
chartDom4.value.updateChart(0, new Date());
|
||||||
|
} catch (error) { }
|
||||||
|
}, 1000);
|
||||||
|
function getData() {
|
||||||
|
isRunTimer = false;
|
||||||
|
post('/getfeature', { database: database.value, start: 0, end: 1 }, (res: any) => {
|
||||||
|
const obj = (res.data && res.data[0]) || {};
|
||||||
|
if (obj.ID !== chartNowData.ID) {
|
||||||
|
chartNowData = obj;
|
||||||
|
const isHR = obj.HR >= 50 && obj.HR <= 80;
|
||||||
|
const isSBP = obj.SBP >= 90 && obj.SBP <= 120;
|
||||||
|
const isDBP = obj.DBP >= 60 && obj.DBP <= 90;
|
||||||
|
// const isST = obj.ST >= -0.2 && obj.ST <= 0.2;
|
||||||
|
if (!isHR) unusualUpDate('心率异常');
|
||||||
|
if (!isSBP) unusualUpDate('收缩压异常');
|
||||||
|
if (!isDBP) unusualUpDate('舒张异常');
|
||||||
|
// if (!isST) unusualUpDate('心电图ST段变异度异常');
|
||||||
|
lungAlarm.value = Boolean(!isSBP || !isDBP);
|
||||||
|
// heartAlarm.value = Boolean(!isHR || !isST);
|
||||||
|
heartAlarm.value = Boolean(!isHR);
|
||||||
|
chartDom1.value.updateChart([obj.BIS, obj.HR], obj.Time || obj.TIME);
|
||||||
|
chartDom2.value.updateChart([obj.SBP, obj.DBP], obj.Time || obj.TIME);
|
||||||
|
chartDom3.value.updateChart([obj.SPO2, obj.TEMP], obj.Time || obj.TIME);
|
||||||
|
// chartDom4.value.updateChart(obj.ST, obj.Time || obj.TIME);
|
||||||
|
}
|
||||||
|
isRunTimer = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getFeatureTable() {
|
||||||
|
featureTable.value = [];
|
||||||
|
post('/getfeature', { database: database.value, start: 1, end: 50 }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
featureTable.value = res.data.reverse();
|
||||||
|
setTimeout(() => {
|
||||||
|
chartDom1.value.chartSet();
|
||||||
|
chartDom2.value.chartSet();
|
||||||
|
chartDom3.value.chartSet();
|
||||||
|
chartDom4.value.chartSet();
|
||||||
|
}, 0);
|
||||||
|
} else {
|
||||||
|
ElMessage({
|
||||||
|
message: res.message,
|
||||||
|
type: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getDatabases() {
|
||||||
|
post('/getdatabases', {}, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
databaseOptions.value = [];
|
||||||
|
const hideDatabase = ['information_schema', 'mysql', 'performance_schema', '北工大412824200020002000', '数据模拟412824200020002000'];
|
||||||
|
res.data.forEach((item: any, index: number) => {
|
||||||
|
if (!hideDatabase.some(e => e === item.Database)) databaseOptions.value.push({ value: item.Database, label: item.Database });
|
||||||
|
})
|
||||||
|
database.value = databaseOptions.value[0].label;
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function msgLogScrollBottom() {
|
||||||
|
msgLog.value.scrollTo({
|
||||||
|
top: msgLog.value.scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function unusualUpDate(msg: string) {
|
||||||
|
unusual.value.push(dateFormater('HH:mm:ss') + msg);
|
||||||
|
setTimeout(() => {
|
||||||
|
unusualMsg.value.scrollTo({
|
||||||
|
top: unusualMsg.value.scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getMssageLog() {
|
||||||
|
mssageList.value.push({ user: 'admin', msg: '请您把治疗单和药品给我' });
|
||||||
|
mssageList.value.push({ user: 'nurse', msg: '好的' });
|
||||||
|
mssageList.value.push({ user: 'admin', msg: '请您把治疗单和药品给我' });
|
||||||
|
mssageList.value.push({ user: 'nurse', msg: '好的' });
|
||||||
|
}
|
||||||
|
function getTableData(e: boolean) {
|
||||||
|
if (tableData.value.length > 0 && e === isAIDose.value) return;
|
||||||
|
// 人工转ai 人工给药数据插到ai给药表
|
||||||
|
let promise = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (e && tableDataStore.value.length > 0) {
|
||||||
|
let key = `Phase`;
|
||||||
|
let value = `${tableDataStore.value[0].Phase}`;
|
||||||
|
tableDataStore.value.forEach(item => {
|
||||||
|
key += `, ${item.name}`;
|
||||||
|
value += `, ${item.speed}`;
|
||||||
|
});
|
||||||
|
post('/addaimedicine', { database: database.value, key, value }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
tableDataStore.value = JSON.parse(JSON.stringify(tableData.value));
|
||||||
|
}
|
||||||
|
resolve(true)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
promise().then((e: any) => {
|
||||||
|
isStart.value = e;
|
||||||
|
isAIDose.value = e;
|
||||||
|
const url = e ? '/getaimedicine' : '/getdoctormedicine';
|
||||||
|
post(url, { database: database.value, start: 0, end: 1 }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
setTableData(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
post('/addaiflag', { database: database.value, flag: e ? 1 : 0 }, (res: any) => {
|
||||||
|
console.log(res.status);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function keepFit(designWidth: number, designHeight: number, renderDomId: string) {
|
||||||
|
let width = designWidth || 1920,
|
||||||
|
height = designHeight || 1030;
|
||||||
|
let clientHeight = document.documentElement.clientHeight - 50;
|
||||||
|
let clientWidth = document.documentElement.clientWidth;
|
||||||
|
let scale = 1;
|
||||||
|
scale = clientHeight / height;
|
||||||
|
const renderDom = document.getElementById(renderDomId);
|
||||||
|
if (renderDom) {
|
||||||
|
renderDom.style.height = clientHeight / scale + 'px';
|
||||||
|
renderDom.style.width = clientWidth / scale + 'px';
|
||||||
|
renderDom.style.transform = 'scale(' + scale + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function initScale() {
|
||||||
|
let w = 1920,
|
||||||
|
h = 1030;
|
||||||
|
keepFit(w, h, 'screenBox');
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
keepFit(w, h, 'screenBox');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectDatabase = (value: any) => {
|
||||||
|
initData();
|
||||||
|
};
|
||||||
|
const setDatabase = () => {
|
||||||
|
initData();
|
||||||
|
setDatabaseDialog.value = false;
|
||||||
|
};
|
||||||
|
const backRemote = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
const playPause = () => {
|
||||||
|
if (liveVideo.value.paused) {
|
||||||
|
liveVideo.value.play(); // 播放视频
|
||||||
|
isVideoPlay.value = true;
|
||||||
|
} else {
|
||||||
|
liveVideo.value.pause(); // 暂停视频
|
||||||
|
isVideoPlay.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sendMsg = () => {
|
||||||
|
if (msgVal.value.trim() == '') return;
|
||||||
|
mssageList.value.push({ user: userName.value, msg: msgVal.value });
|
||||||
|
msgVal.value = '';
|
||||||
|
setTimeout(() => {
|
||||||
|
msgLogScrollBottom()
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
const tableItemPlus = (e: any) => {
|
||||||
|
const obj = medicineCustom.find(item => item.name === e.row.name) || { plus: 1 };
|
||||||
|
e.row.speed += obj.plus;
|
||||||
|
e.row.speed = Number(e.row.speed.toFixed(2));
|
||||||
|
};
|
||||||
|
const tableItemMinus = (e: any) => {
|
||||||
|
const obj = medicineCustom.find(item => item.name === e.row.name) || { plus: 1 };
|
||||||
|
if (!isAIDose.value && e.row.speed - obj.plus <= 0) return;
|
||||||
|
e.row.speed -= obj.plus;
|
||||||
|
if (e.row.speed < 0) e.row.speed = 0;
|
||||||
|
else e.row.speed = Number(e.row.speed.toFixed(2));
|
||||||
|
};
|
||||||
|
const tableItemConfirm = (e: any) => {
|
||||||
|
tableDataStore.value[e.$index].speed = e.row.speed;
|
||||||
|
if (tableData.value.length < 1) return;
|
||||||
|
let key = `Phase`;
|
||||||
|
let value = `${tableData.value[0].Phase}`;
|
||||||
|
tableData.value.forEach(item => {
|
||||||
|
key += `, ${item.name}`;
|
||||||
|
value += `, ${item.speed}`;
|
||||||
|
});
|
||||||
|
post(isAIDose.value ? '/addaimedicine' : '/adddoctormedicine', { database: database.value, key, value }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
tableDataStore.value = JSON.parse(JSON.stringify(tableData.value));
|
||||||
|
ElMessage({
|
||||||
|
message: '保存成功!',
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
// 如果是ai药量表保存后同时在人工表中插入ai药量表数据
|
||||||
|
if (isAIDose.value) {
|
||||||
|
post('/adddoctormedicine', { database: database.value, key, value }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: '保存成功!',
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
getTableData(false); // 保存成功后切换为人工给药
|
||||||
|
} else {
|
||||||
|
ElMessage({
|
||||||
|
message: JSON.stringify(res),
|
||||||
|
type: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage({
|
||||||
|
message: JSON.stringify(res),
|
||||||
|
type: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const tableItemCancel = (e: any) => {
|
||||||
|
e.row.speed = tableDataStore.value[e.$index].speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.remote-box {
|
||||||
|
width: 1920px;
|
||||||
|
height: 1020px;
|
||||||
|
background: #f1f3f5;
|
||||||
|
padding-top: 10px;
|
||||||
|
transform-origin: top left;
|
||||||
|
overflow-y: auto;
|
||||||
|
.el-button {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.main-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
// min-height: 1080px;
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left-box {
|
||||||
|
width: 670px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&>h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: $main-color;
|
||||||
|
line-height: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-line {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(25% - 15px - 12.5px);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background: #e8f5f8;
|
||||||
|
border-top-left-radius: 20px;
|
||||||
|
border-top-right-radius: 20px;
|
||||||
|
// overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-ecg {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(25% - 15px - 12.5px);
|
||||||
|
border-left: 1px solid #92b3c1;
|
||||||
|
border-bottom: 1px solid #92b3c1;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 0;
|
||||||
|
left: -5px;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
border-bottom: 15px solid #285e7d;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
bottom: -5px;
|
||||||
|
right: 0;
|
||||||
|
border-left: 15px solid #285e7d;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 5px solid transparent;
|
||||||
|
border-top: 5px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-box {
|
||||||
|
width: calc(100% - 1500px);
|
||||||
|
min-width: 500px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.body-box {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 110px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.body-img {
|
||||||
|
position: relative;
|
||||||
|
// width: 400px;
|
||||||
|
// height: 650px;
|
||||||
|
width: 500px;
|
||||||
|
height: 812.5px;
|
||||||
|
min-height: 650px;
|
||||||
|
|
||||||
|
.lung-img {
|
||||||
|
position: absolute;
|
||||||
|
width: 500px;
|
||||||
|
height: auto;
|
||||||
|
top: 240px;
|
||||||
|
left: 0;
|
||||||
|
transition: all 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart-img {
|
||||||
|
position: absolute;
|
||||||
|
width: 500px;
|
||||||
|
height: auto;
|
||||||
|
top: 420px;
|
||||||
|
left: 0;
|
||||||
|
transition: all 2s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-box {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 110px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.start-btn {
|
||||||
|
width: 230px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 20px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-btn-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 70px;
|
||||||
|
height: 62px;
|
||||||
|
top: calc(50% - 31px);
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
height: 25px;
|
||||||
|
line-height: 22px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
color: #616161;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: $main-color;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-box {
|
||||||
|
width: 670px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.top-btn-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 34px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.top-left-btn-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
border-radius: 16px;
|
||||||
|
height: 31px;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #c77000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>.el-button {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: $main-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitoring-message {
|
||||||
|
width: 670px;
|
||||||
|
height: 550px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&>.left-box {
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.unusual-title {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 38px;
|
||||||
|
color: #C77000;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px dashed #C1C1C1;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unusual-box {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 45px);
|
||||||
|
// background: #F8F8F8;
|
||||||
|
border-left: 1px dashed #C1C1C1;
|
||||||
|
// border-radius: 4px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
li {
|
||||||
|
color: #F80000;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>.right-box {
|
||||||
|
width: calc(100% - 205px);
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.video-box {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 270px;
|
||||||
|
background: $main-color;
|
||||||
|
/* background: url(@/assets/imgs/video_bck.png);
|
||||||
|
background-size: 100% 100%; */
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.icon-box {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-box {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
font-size: 60px;
|
||||||
|
color: white;
|
||||||
|
background: rgba(black, .3);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 270px;
|
||||||
|
// margin-bottom: 5px;
|
||||||
|
|
||||||
|
.message-log {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
padding: 16px 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #c8c8c8;
|
||||||
|
background: #f8f8f8;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
li {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 5px 0;
|
||||||
|
|
||||||
|
&.align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 80%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
background: $main-color;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
width: calc(100% - 110px);
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
background-color: #F2F3F5;
|
||||||
|
border-color: #C1C1C1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
padding: 0;
|
||||||
|
width: 100px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-box {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 589px);
|
||||||
|
|
||||||
|
:deep(.el-table__inner-wrapper) {
|
||||||
|
.el-table__cell {
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table__header-wrapper {
|
||||||
|
tr {
|
||||||
|
background-color: $main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.el-table__cell {
|
||||||
|
color: white;
|
||||||
|
background-color: $main-color;
|
||||||
|
padding: 8px 0;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-btn-box {
|
||||||
|
.el-button {
|
||||||
|
padding: 0 7px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}</style>
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user