远程管理

This commit is contained in:
zhaoyz 2024-04-23 09:42:25 +08:00
parent fddc1b5d25
commit 298074da1f
17 changed files with 2093 additions and 2194 deletions

17
src/api/patient.ts Normal file
View File

@ -0,0 +1,17 @@
import request from "@/utils/request";
const patientInfoUrl = "/admin/medicine/getPatientInfo";
export function getPatientInfo(name: string, id: string, date: string) {
return new Promise((resolve, reject) => {
request.postForm(patientInfoUrl, {
patientName: name,
idNum: id,
date: date
})
}).then((res: any) => {
console.log(res.data)
}).catch(error => {
reject(error)
})
}

View File

@ -10,7 +10,7 @@ const router = createRouter({
router.beforeEach((to, from, next) => {
const loginInfo = useLoginStore().getlogin()
const isLogin = loginInfo.isLogin
// const isLogin = loginInfo.isLogin
// 普通用户
const commonUser = [
'/login',
@ -49,31 +49,31 @@ router.beforeEach((to, from, next) => {
'/logs-manage/logs-manage'
]
const isViewRoute = () => {
let release = false
switch (loginInfo.permissions) {
case '超级管理员':
release = true
break;
case '高级管理员':
release = SeniorAdmin.some((p: string) => p === to.path)
break;
case '中级管理员':
release = IntermediateAdmin.some((p: string) => p === to.path)
break;
case '普通用户':
release = commonUser.some((p: string) => p === to.path)
break;
default:
break;
}
let release = true
/*switch (loginInfo.permissions) {
case '超级管理员':
release = true
break;
case '高级管理员':
release = SeniorAdmin.some((p: string) => p === to.path)
break;
case '中级管理员':
release = IntermediateAdmin.some((p: string) => p === to.path)
break;
case '普通用户':
release = commonUser.some((p: string) => p === to.path)
break;
default:
break;
}*/
return release
}
if(to.fullPath ==='/login') {
next()
return
}
if (!isLogin) next('/login') // 重定向登录页
else if(!isViewRoute()) {
/*if (!isLogin) next('/login') //
else */if(!isViewRoute()) {
ElMessage.error('无权访问!')
next(from.fullPath)
}else next()

View File

@ -1,6 +1,6 @@
export const constantRoute=[
{ path: '/:pathMatch(.*)*', name: 'not-found', redirect: '/home' },
{ path: '/:pathMatch(.*)*', name: 'not-found', redirect: '/login' },
{
path: '/login',
name: '登录',
@ -8,7 +8,7 @@ export const constantRoute=[
},
{
path: '/',
redirect: '/home',
redirect: '/login',
component: () => import('@/views/index.vue'),
children: [
{

View File

@ -0,0 +1,214 @@
import {defineStore} from "pinia";
import {Session} from "@/utils/storage";
const vitalUrl = "ws://localhost:5173/socket.io/admin/rax/vitalSignsMedicine?token=" + Session.getToken()
const medicineUrl = "ws://localhost:5173/socket.io/admin/rax/addMedicine?token=" + Session.getToken()
const chatUrl = "ws://localhost:5173/socket.io/admin/rax/chatRoom?token=" + Session.getToken()
export const useRemoteWsStore = defineStore("remoteWs", {
state: () => {
return {
patient: {} as any,
remoteTasks: [] as any,
remoteTasksCap: 10,
currentTaskIndex: 0,
varMedicine: ["丙泊酚", "舒芬太尼", "瑞芬太尼", "顺阿曲库胺"],
fixedMedicine: ["尼卡地平", "艾司洛尔", "麻黄素", "阿托品"],
exceptionType: ["BIS_except", "DBP_except", "EtCO2_except", "HR_except", "SBP_except", "ST_except"],
exceptionMsg: {
"BIS_except": "脑电双频指数异常", "DBP_except": "舒张压异常", "EtCO2_except": "呼气末二氧化碳异常",
"HR_except": "心率异常", "SBP_except": "收缩压异常", "ST_except": "ST异常"
},
}
},
actions: {
initRemoteTask() {
if (this.remoteTasks.length <= 0) {
for (let i = 0; i < 10; i++) {
this.remoteTasks.push({
isRemote: false,
isException: false,
taskName: "",
server: "",
serverun: "",
serverps: "",
patient: "",
patientId: "",
date: "",
log: [],
index: i
})
}
}
return this.remoteTasks
},
resetRemoteTask(i: number) {
this.remoteTasks[i] = Object.assign(this.remoteTasks[i], {
isRemote: false,
isException: false,
taskName: "",
server: "",
serverun: "",
serverps: "",
patient: "",
patientId: "",
date: "",
log: [],
index: i,
message: []
})
},
getActiveRemoteTask() {
for (let i = 0; i < this.remoteTasks.length; i++) {
if (this.remoteTasks[i].isRemote) return i
}
},
setRemoteLog(log: any, i: number) {
this.remoteTasks[i].log.push(log)
},
createConnect(name: string, id: string, date: string) {
if (!this.patient[name + id + date]) {
const vitalWS = new WebSocket(vitalUrl)
const medicineWS = new WebSocket(medicineUrl)
const chatWS = new WebSocket(chatUrl)
vitalWS.onopen = function () {
vitalWS.send(JSON.stringify({
patientName: name,
idNum: id,
date: date
}))
}
medicineWS.onopen = function () {
medicineWS.send(JSON.stringify({
patientName: name,
idNum: id,
date: date
}))
}
chatWS.onopen = function () {
chatWS.send(JSON.stringify({
patientName: name,
idNum: id,
date: date
}))
}
this.patient[name + id + date] = {
vitalWS,
medicineWS,
chatWS
}
}
},
disconnect(name: string, id: string, date: string) {
const patient: any = this.patient[name + id + date]
if (patient) {
patient.vitalWS.close()
patient.medicineWS.close()
patient.chatWS.close()
delete this.patient[name + id + date]
}
},
subscribeVital(name: string, id: string, date: string, cb: any) {
const patient: any = this.patient[name + id + date]
if (patient) {
patient.vitalWS.onmessage = cb
patient.vitalCB = cb
} else {
cb({
status: 1,
msg: "已断开连接"
})
}
},
unsubscribeVital(name: string, id: string, date: string) {
const patient: any = this.patient[name + id + date]
if (patient && patient.vitalWS) {
patient.vitalWS.onmessage = undefined;
patient.vitalCB = undefined;
}
},
sendMsg(name: string, id: string, date: string, msg: string, cb: any) {
const patient: any = this.patient[name + id + date]
if (patient) {
const params = {
patientName: name,
idNum: id,
date: date,
msg
}
patient.chatWS.send(JSON.stringify(params))
cb({
status: 0
})
} else {
cb({
status: 1,
msg: "已断开连接"
})
}
},
subscribeChat(name: string, id: string, date: string, cb: any) {
const patient: any = this.patient[name + id + date]
if (patient) {
patient.chatCB = cb
patient.chatWS.onmessage = cb
} else {
cb({
status: 1,
msg: "已断开连接"
})
}
},
unsubscribeChat(name: string, id: string, date: string) {
const patient: any = this.patient[name + id + date]
patient.chatCB = undefined;
patient.chatWS.onmessage = undefined;
},
sendMedicine(args: {
name: string,
id: string,
date: string,
flag: string,
medicine: string,
value: string
}, cb: any) {
const patient: any = this.patient[args.name + args.id + args.date]
if (patient) {
const params = {
patientName: args.name,
idNum: args.id,
date: args.date,
flag: args.flag,
medicine: args.medicine,
value: args.value
}
patient.medicineWS.send(JSON.stringify(params))
cb({
status: 0
})
} else {
cb({
status: 1,
msg: "已断开连接"
})
}
},
subscribeMedicine(name: string, id: string, date: string, cb: any) {
const patient = this.patient[name + id + date]
if (patient) {
patient.medicineCB = cb
patient.medicineWS.onmessage = cb
} else {
cb({
status: 1,
msg: "已断开连接"
})
}
},
unsubscribeMedicine(name: string, id: string, date: string) {
const patient: any = this.patient[name + id + date]
patient.medicineCB = undefined;
patient.medicineWS.onmessage = undefined;
}
}
})

View File

@ -4,7 +4,6 @@ export const useLoginStore = defineStore('login', {
state: () => {
return {
login: {
isLogin: false,
account: '',
name: '',
/**
@ -13,7 +12,6 @@ export const useLoginStore = defineStore('login', {
*
*
*/
permissions: '',
hospital: ''
} as any
}

View File

@ -82,32 +82,37 @@ getHospitalsData().then((res: any) => {
const menus = [] as any
switch (userInfo.permissions) {
case '超级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '后台管理', path: '/system-manage', icon: 'icon-houtaiguanli'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
break;
case '高级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
break;
case '中级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
break;
case '普通用户':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
break;
default:
break;
case '超级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '后台管理', path: '/system-manage', icon: 'icon-houtaiguanli'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
break;
case '高级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
break;
case '中级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
break;
case '普通用户':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
break;
default:
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '后台管理', path: '/system-manage', icon: 'icon-houtaiguanli'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
}
const isShowUserInfoDrawer = ref(false)

View File

@ -1,127 +1,127 @@
<template>
<div class="login-page">
<div class="left-content move_4"></div>
<div class="right-content">
<div class="select-hospital-box">
<el-select class="select-hospital" v-model="currentHospital" size="small" @change="selectHospital">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</div>
<div class="login-page">
<div class="left-content move_4"></div>
<div class="right-content">
<!-- <div class="select-hospital-box">
<el-select class="select-hospital" v-model="currentHospital" size="small" @change="selectHospital">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</div>-->
<img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png">
<div v-if="!isShowRegister" class="login-block move_2">
<div class="login-way">
<span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span>
<span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span>
</div>
<el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small">
<div class="login-form password-login" v-if="passwordLogin">
<el-form-item prop="account">
<el-input v-model="loginParams.account" placeholder="请输入用户名">
<template #prepend>
<el-icon>
<User/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码">
<template #prepend>
<el-icon>
<Lock/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button>
<span class="register-btn" @click="getCaptchaCode()">注册账号</span>
</div>
<div class="login-form code-login" v-else>
<el-form-item prop="phone">
<el-input v-model="loginParams.phone" placeholder="请输入手机号">
<template #prepend>
<div @click.stop style="display: flex;align-items: center;">
<el-dropdown @command="selectPhoneArea">
<img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png">
<div v-if="!isShowRegister" class="login-block move_2">
<div class="login-way">
<span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span>
<span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span>
</div>
<el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small">
<div class="login-form password-login" v-if="passwordLogin">
<el-form-item prop="account">
<el-input v-model="loginParams.account" placeholder="请输入用户名">
<template #prepend>
<el-icon>
<User/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码">
<template #prepend>
<el-icon>
<Lock/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button>
<span class="register-btn" @click="getCaptchaCode()">注册账号</span>
</div>
<div class="login-form code-login" v-else>
<el-form-item prop="phone">
<el-input v-model="loginParams.phone" placeholder="请输入手机号">
<template #prepend>
<div @click.stop style="display: flex;align-items: center;">
<el-dropdown @command="selectPhoneArea">
<span style="color: #909399;">{{ loginParams.phoneArea }}<el-icon>
<DCaret/>
</el-icon></span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in phoneAreas" :command="item">{{
item
}}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input v-model="loginParams.code" placeholder="请输入6位短信验证码">
<template #append>
<span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span>
</template>
</el-input>
</el-form-item>
<el-button class="login-btn" type="primary" @click="login('code')">登录</el-button>
</div>
</el-form>
</div>
<div v-else class="register-block move_2">
<div class="header-box">
<span class="title">新用户申请</span>
<el-icon @click="isShowRegister = false">
<Close/>
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in phoneAreas" :command="item">{{
item
}}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input v-model="loginParams.code" placeholder="请输入6位短信验证码">
<template #append>
<span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span>
</template>
</el-input>
</el-form-item>
<el-button class="login-btn" type="primary" @click="login('code')">登录</el-button>
</div>
</el-form>
</div>
<div v-else class="register-block move_2">
<div class="header-box">
<span class="title">新用户申请</span>
<el-icon @click="isShowRegister = false">
<Close/>
</el-icon>
</div>
<el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100">
<el-form-item label="用户名" prop="username">
<el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="registerParams.password" type="password" show-password
placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item label="医院" prop="hospital">
<el-select v-model="registerParams.hospital" style="width: 100%;">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name"
:value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="registerParams.sex">
<el-radio label="男"/>
<el-radio label="女"/>
</el-radio-group>
</el-form-item>
<el-form-item label="验证码" prop="code">
<el-input v-model="registerParams.code" placeholder="请输入验证码"
style="width: calc(100% - 110px);"></el-input>
<img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/>
<a class="change_img" @click="refreshImg" href="#">看不清</a>
</el-form-item>
<el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100">
<el-form-item label="用户名" prop="username">
<el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="registerParams.password" type="password" show-password
placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item label="医院" prop="hospital">
<el-select v-model="registerParams.hospital" style="width: 100%;">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name"
:value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="registerParams.sex">
<el-radio label="男"/>
<el-radio label="女"/>
</el-radio-group>
</el-form-item>
<el-form-item label="验证码" prop="code">
<el-input v-model="registerParams.code" placeholder="请输入验证码"
style="width: calc(100% - 110px);"></el-input>
<img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/>
<a class="change_img" @click="refreshImg" href="#">看不清</a>
</el-form-item>
</el-form>
<div class="footer-box">
<el-button type="primary" @click="register"> </el-button>
<span @click="isShowRegister = false">已有账号?</span>
</div>
</div>
</el-form>
<div class="footer-box">
<el-button type="primary" @click="register"> </el-button>
<span @click="isShowRegister = false">已有账号?</span>
</div>
</div>
</div>
</div>
<SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl"
:height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify>
</div>
</div>
<SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl"
:height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify>
</template>
<script lang='ts' setup>
@ -153,74 +153,74 @@ let loading = ref(false);
//
const validatorUserName = (rule: any, value: any, callback: any) => {
//rule:
//value:
//:callBack
//callBack,
if (/^[a-zA-Z0-9_-]{4,16}$/) {
callback();
} else {
callback(new Error('账号长度4到16位字母数字下划线减号'));
}
//rule:
//value:
//:callBack
//callBack,
if (/^[a-zA-Z0-9_-]{4,16}$/) {
callback();
} else {
callback(new Error('账号长度4到16位字母数字下划线减号'));
}
}
const validatorPassword = (rule: any, value: any, callback: any) => {
if (/^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/) {
callback();
} else {
callback(new Error('密码最少6位包括至少1个大写字母1个小写字母1个数字1个特殊字符'));
}
if (/^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/) {
callback();
} else {
callback(new Error('密码最少6位包括至少1个大写字母1个小写字母1个数字1个特殊字符'));
}
}
const validatorPhone = (rule: any, value: any, callback: any) => {
var isPhone = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
var isPhone = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
if (value.indexOf('****') >= 0) {
return callback().trim();
}
if (value.indexOf('****') >= 0) {
return callback().trim();
}
if (!isPhone.test(value)) {
callback(new Error('请输入合法手机号'));
} else {
callback();
}
if (!isPhone.test(value)) {
callback(new Error('请输入合法手机号'));
} else {
callback();
}
}
const loginRules = reactive({
account: [
{required: true, validator: validatorUserName, trigger: 'change'},
],
password: [
{required: true, validator: validatorPassword, trigger: 'change'},
],
phone: [
{required: true, validator: validatorPhone, trigger: 'blur'},
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'},
]
account: [
{required: true, validator: validatorUserName, trigger: 'change'},
],
password: [
{required: true, validator: validatorPassword, trigger: 'change'},
],
phone: [
{required: true, validator: validatorPhone, trigger: 'blur'},
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'},
]
})
const registerRules = reactive({
username: [
{required: true, validator: validatorUserName, trigger: 'change'},
],
password: [
{required: true, validator: validatorUserName, trigger: 'change'},
],
name: [
{required: true, message: '请输入用户名', trigger: 'blur'},
],
phone: [
{required: true, validator: validatorPhone, trigger: 'change'},
],
hospital: [
{required: true, message: '请选择医院', trigger: 'blur'},
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'},
]
username: [
{required: true, validator: validatorUserName, trigger: 'change'},
],
password: [
{required: true, validator: validatorUserName, trigger: 'change'},
],
name: [
{required: true, message: '请输入用户名', trigger: 'blur'},
],
phone: [
{required: true, validator: validatorPhone, trigger: 'change'},
],
hospital: [
{required: true, message: '请选择医院', trigger: 'blur'},
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'},
]
})
//
@ -234,29 +234,29 @@ const currentHospital = ref(useLoginStore().getlogin().hospital)
const isShowRegister = ref(false)
const passwordLogin = ref(true)
const loginParams = ref({
account: 'admin',
name: '',
password: '123456',
phone: '',
phoneArea: phoneAreas[0],
code: '',
isSendCode: false,
sendTimer: 0,
sendText: '获取短信验证码'
account: 'admin',
name: '',
password: '123456',
phone: '',
phoneArea: phoneAreas[0],
code: '',
isSendCode: false,
sendTimer: 0,
sendText: '获取短信验证码'
})
const registerParams = ref({
username: '',
password: '',
name: '',
phone: '',
hospital: '',
sex: '',
code: ''
username: '',
password: '',
name: '',
phone: '',
hospital: '',
sex: '',
code: ''
})
const sliderVConf = ref({
isShowSelf: false,
width: 400,
height: 200
isShowSelf: false,
width: 400,
height: 200
})
const captchaImgUrl = ref('')
@ -264,312 +264,289 @@ const sliderImgUrl = ref('')
let randomStr = ""
onMounted(() => {
hospitalApi.getHospitalList().then((res: any) => {
if (res.data) {
hospitals.value = res.data
} else {
hospitals.value.length = 0
}
})
hospitalApi.getHospitalList().then((res: any) => {
if (res.data) {
hospitals.value = res.data
} else {
hospitals.value.length = 0
}
})
})
const selectHospital = (e: string) => {
// console.log(e)
// console.log(e)
}
const register = async () => {
await registerFormRef.value.validate((valid: any, fields: any) => {
if (valid) {
loginApi.register({...registerParams.value, randomStr}).then(data => {
ElMessageBox.confirm(
'注册成功,是否登录?',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'success',
draggable: true
}
).then(() => {
loginParams.value.account = registerFormRef.value.account
loginParams.value.name = registerFormRef.value.name
currentHospital.value = registerFormRef.value.hospital
isShowRegister.value = false;
}).catch(() => {
})
})
} else {
// console.log('error submit!', fields)
}
})
await registerFormRef.value.validate((valid: any, fields: any) => {
if (valid) {
loginApi.register({...registerParams.value, randomStr}).then(data => {
ElMessageBox.confirm(
'注册成功,是否登录?',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'success',
draggable: true
}
).then(() => {
loginParams.value.account = registerFormRef.value.account
loginParams.value.name = registerFormRef.value.name
currentHospital.value = registerFormRef.value.hospital
isShowRegister.value = false;
}).catch(() => {
})
})
} else {
// console.log('error submit!', fields)
}
})
}
const selectPhoneArea = (e: string) => {
loginParams.value.phoneArea = e
loginParams.value.phoneArea = e
}
const sendCode = () => {
if (loginParams.value.isSendCode) return
let num = 60
ElMessage.success('发送成功!')
loginParams.value.isSendCode = true
loginParams.value.sendText = '请' + num + '秒后重新发送'
loginParams.value.sendTimer = setInterval(() => {
num--
if (num > 0) {
loginParams.value.sendText = '请' + num + '秒后重新发送'
} else {
loginParams.value.isSendCode = false
loginParams.value.sendText = '重新获取短信验证码'
clearInterval(loginParams.value.sendTimer)
}
if (loginParams.value.isSendCode) return
let num = 60
ElMessage.success('发送成功!')
loginParams.value.isSendCode = true
loginParams.value.sendText = '请' + num + '秒后重新发送'
loginParams.value.sendTimer = setInterval(() => {
num--
if (num > 0) {
loginParams.value.sendText = '请' + num + '秒后重新发送'
} else {
loginParams.value.isSendCode = false
loginParams.value.sendText = '重新获取短信验证码'
clearInterval(loginParams.value.sendTimer)
}
}, 1000);
}, 1000);
}
const login = async (type: string) => {
//:
loading.value=true;
const obj = loginParams.value
if (!currentHospital.value) {
ElMessage.warning('请在右上角选择院区')
return
}
//:
loading.value = true;
//
await loginFormRef.value.validate((valid: any, fields: any) => {
if (valid) {
sliderVConf.value.isShowSelf = true;
}
})
//:
loading.value = true;
/*if (!currentHospital.value) {
ElMessage.warning('请在右上角选择院区')
return
}*/
//:
loading.value = true;
//
await loginFormRef.value.validate((valid: any, fields: any) => {
if (valid) {
sliderVConf.value.isShowSelf = true;
}
})
}
function getCaptchaCode() {
isShowRegister.value = true
refreshImg()
isShowRegister.value = true
refreshImg()
}
function refreshImg() {
randomStr = v4()
captchaImgUrl.value = '/api/admin/code/textImage?randomStr=' + randomStr
randomStr = v4()
captchaImgUrl.value = '/api/admin/code/textImage?randomStr=' + randomStr
}
function sliderSuccess() {
loginApi.login({
username: loginParams.value.account, //
password: loginParams.value.password, //
randomStr: v4()
}).then((data: any) => {
sliderVConf.value.isShowSelf = false
if (data.code == 1 || data.error) {
ElMessage.error(data.msg ? data.msg : data.error)
loading.value = false
} else {
loginApi.login({
username: loginParams.value.account, //
password: loginParams.value.password, //
randomStr: v4()
}).then((data: any) => {
sliderVConf.value.isShowSelf = false
if (data.code == 1 || data.error) {
ElMessage.error(data.msg ? data.msg : data.error)
loading.value = false
} else {
// token
Session.set('token', data.access_token);
Session.set('refresh_token', data.refresh_token);
console.log(data)
toHome()
}
})
console.log(data)
ElNotification({
type: 'success',
message: '欢迎回来',
title: `HI,${getTime()}`
});
loginPost(data)
router.push('/home')
}
})
}
function sliderClose() {
loading.value = false
loading.value = false
}
const toHome = () => {
ElNotification({
type: 'success',
message: '欢迎回来',
title: `HI,${getTime()}`
});
const getPermissions = () => {
let permissions = '普通用户'
switch (loginParams.value.account) {
case 'admin':
permissions = '超级管理员'
break;
case 'dev1':
permissions = '高级管理员'
break;
case 'dev2':
permissions = '中级管理员'
break;
default:
break;
}
return permissions
}
useLoginStore().setlogin('isLogin', true)
useLoginStore().setlogin('account', loginParams.value.account)
useLoginStore().setlogin('name', loginParams.value.name || '暂未设置姓名')
useLoginStore().setlogin('hospital', currentHospital.value)
useLoginStore().setlogin('permissions', getPermissions())
router.push('/home')
const loginPost = (data: any) => {
Session.set('token', data.access_token);
Session.set('refresh_token', data.refresh_token);
useLoginStore().setlogin('account', data.username)
console.log(data)
useLoginStore().setlogin('name', data.user_info.name || '暂未设置姓名')
}
</script>
<style lang='scss' scoped>
.login-page {
width: 100%;
height: 100%;
display: flex;
background-color: #F8F8F8;
width: 100%;
height: 100%;
display: flex;
background-color: #F8F8F8;
.left-content {
width: 50%;
height: 100%;
background: url(@/assets/imgs/login/login_bck.png) no-repeat;
background-size: cover;
}
.left-content {
width: 50%;
height: 100%;
background: url(@/assets/imgs/login/login_bck.png) no-repeat;
background-size: cover;
}
.right-content {
position: relative;
width: 50%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.right-content {
position: relative;
width: 50%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.select-hospital-box {
position: absolute;
top: 25px;
right: 25px;
}
.select-hospital-box {
position: absolute;
top: 25px;
right: 25px;
}
.logo {
height: 70px;
}
.logo {
height: 70px;
}
.login-block {
width: 65%;
height: 430px;
min-width: 500px;
min-height: 300px;
padding: 50px;
margin-top: 20px;
background: white;
.login-block {
width: 65%;
height: 430px;
min-width: 500px;
min-height: 300px;
padding: 50px;
margin-top: 20px;
background: white;
.login-way {
font-size: 18px;
color: #909399;
.login-way {
font-size: 18px;
color: #909399;
span {
cursor: pointer;
margin-right: 10px;
}
span {
cursor: pointer;
margin-right: 10px;
}
.active {
color: $main-color;
font-weight: 600;
}
}
.active {
color: $main-color;
font-weight: 600;
}
}
.login-form {
:deep(.el-input) {
font-size: 16px;
margin-top: 20px;
.login-form {
:deep(.el-input) {
font-size: 16px;
margin-top: 20px;
.el-input-group__prepend,
.el-input__wrapper,
.el-input-group__append {
box-shadow: none;
border-bottom: 1px solid $border-color;
background-color: transparent;
padding: 10px 20px;
}
.el-input-group__prepend,
.el-input__wrapper,
.el-input-group__append {
box-shadow: none;
border-bottom: 1px solid $border-color;
background-color: transparent;
padding: 10px 20px;
}
.el-input-group__prepend,
.el-input-group__append {
position: relative;
.el-input-group__prepend,
.el-input-group__append {
position: relative;
&::after {
content: '';
position: absolute;
width: 1px;
height: 16px;
top: calc(50% - 8px);
right: 0;
background-color: $border-color;
}
}
&::after {
content: '';
position: absolute;
width: 1px;
height: 16px;
top: calc(50% - 8px);
right: 0;
background-color: $border-color;
}
}
.el-input-group__append::after {
right: auto;
left: 0;
}
}
.el-input-group__append::after {
right: auto;
left: 0;
}
}
.send-btn {
cursor: pointer;
color: $main-color;
font-weight: 600;
}
}
.send-btn {
cursor: pointer;
color: $main-color;
font-weight: 600;
}
}
.login-btn {
width: 100%;
margin-top: 40px;
font-size: 20px;
font-weight: 600;
padding: 25px 0 25px 0.3em;
border-radius: 0px;
letter-spacing: 0.3em;
}
.login-btn {
width: 100%;
margin-top: 40px;
font-size: 20px;
font-weight: 600;
padding: 25px 0 25px 0.3em;
border-radius: 0px;
letter-spacing: 0.3em;
}
.register-btn {
cursor: pointer;
float: right;
color: $main-color;
margin-top: 20px;
}
}
.register-btn {
cursor: pointer;
float: right;
color: $main-color;
margin-top: 20px;
}
}
.register-block {
width: 65%;
min-width: 500px;
min-height: 300px;
padding: 50px;
background: white;
.register-block {
width: 65%;
min-width: 500px;
min-height: 300px;
padding: 50px;
background: white;
.header-box {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
.header-box {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
.title {
font-size: 20px;
color: $main-color;
font-weight: 600;
}
.title {
font-size: 20px;
color: $main-color;
font-weight: 600;
}
.el-icon {
cursor: pointer;
}
}
.el-icon {
cursor: pointer;
}
}
.footer-box {
padding-left: 100px;
display: flex;
justify-content: space-between;
align-items: center;
.footer-box {
padding-left: 100px;
display: flex;
justify-content: space-between;
align-items: center;
.el-button {
font-size: 16px;
padding: 5px 50px;
}
.el-button {
font-size: 16px;
padding: 5px 50px;
}
& > span {
cursor: pointer;
font-size: 18px;
color: #909399;
}
}
}
}
& > span {
cursor: pointer;
font-size: 18px;
color: #909399;
}
}
}
}
}
</style>

View File

@ -1,197 +1,181 @@
<template>
<div class="chart-dom-box">
<div ref="chartDom" style="width: 100%; height: 100%"></div>
</div>
<div class="chart-dom-box">
<div ref="chartDom" style="width: 100%; height: 100%"></div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import {onMounted, ref} from 'vue';
import * as echarts from 'echarts';
import { dateFormater } from '@/utils/date-util';
import {dateFormater} from '@/utils/date-util';
import {useRemoteWsStore} from "@/stores/remote-ws-store";
const chartDom = ref();
interface Props {
names?: string[];
chartData: any[];
}
const props = withDefaults(defineProps<Props>(), {
names: () => ['CH1', 'CH2'],
chartData: () => [] as any[],
});
// const emit = defineEmits(['updateData']);
let chart: any;
const names = props.names; //
const color = ['#00AAB7', '#C77000'];
let xData = [] as any[]; // x
let series = [] as any[];
//
function updateChart(num: number, time?: string) {
xData.shift();
xData.push(dateFormater('HH:mm:ss', time));
// const values = [] as number[];
series.forEach((item, index) => {
item.data.shift();
// item.data.push(index === 0 ? num - 0.2 : index === 2 ? num + 0.2 : num);
// item.data.push(index === 0 ? -Math.floor(Math.random() * 50 + 40) : Math.floor(Math.random() * 50 + 40));
item.data.push(Math.floor(Math.random() * 160 + -80));
// values.push(item.data[item.data.length - 1]);
});
// emit('updateData', values); //
chart.setOption({
xAxis: {
data: xData,
},
series,
});
}
//
function formatterData() {
xData = [];
series = [];
for (let i = 0; i < 50; i++) {
if (props.chartData[i]) xData.push(dateFormater('HH:mm:ss', props.chartData[i].Time || props.chartData[i].TIME));
else xData.unshift(0);
}
names.forEach((item, index) => {
const obj = {
name: item,
type: 'line',
symbol: 'none',
lineStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
{
offset: 0,
color: 'rgba(40,94,125,0)',
},
{
offset: 0.3,
color: color[index],
},
{
offset: 0.5,
color: color[index],
},
{
offset: 0.7,
color: color[index],
},
{
offset: 1,
color: 'rgba(40,94,125,0)',
},
]),
width: 1,
},
data: [] as number[],
};
for (let i = 0; i < 50; i++) {
if (props.chartData[i]) {
const num = props.chartData[i].ST;
// obj.data.push(index === 0 ? num - 0.2 : index === 2 ? num + 0.2 : num);
// obj.data.push(index === 0 ? -Math.floor(Math.random() * 50 + 40) : Math.floor(Math.random() * 50 + 40));
obj.data.push(Math.floor(Math.random() * 160 + -80));
} else obj.data.unshift(0);
}
series.push(obj);
});
}
//
function chartSet() {
formatterData();
if (chart) chart.setOption({
xAxis: {
data: xData,
},
series,
});
}
//
function chartInit() {
chart = echarts.init(chartDom.value as HTMLElement);
chart.clear();
const option = {
color: color,
tooltip: {
trigger: 'axis',
formatter: (params: any) => {
let str = params[0].axisValue;
str += `<br>`;
names.forEach((item, index) => {
str += params[index].marker;
str += params[index].seriesName + ' ';
str += `${params[index].value} HZ`;
str += index === 0 ? '<br>' : '';
});
return str;
},
},
grid: {
left: 1,
right: 20,
bottom: 5,
top: 20,
containLabel: true,
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
axisLine: { show: false, lineStyle: { color: '#006080' } },
axisTick: { show: false },
axisLabel: { show: false },
splitLine: { show: true, lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } },
data: xData,
},
yAxis: {
show: true,
type: 'value',
min: function (value: any) {
return value.min - 40
},
max: function (value: any) {
return value.max + 40
},
axisLabel: {
formatter: `{value} HZ`
},
axisLine: { show: false, lineStyle: { color: '#006080' } },
splitLine: { lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } },
},
series,
};
chart.setOption(option);
chart.resize();
window.addEventListener('resize', () => {
chart.resize();
});
}
onMounted(() => {
chartInit();
const props = withDefaults(defineProps<{ names?: string[] }>(), {
names: ['CH1', 'CH2']
});
defineExpose({
updateChart,
chartSet
updateChartData
});
const emit = defineEmits(["exceptionEvent"]);
let chart: any;
const color = ['#00AAB7', '#C77000'];
const xData = [] as any[]; // x
const series = [] as any[];
let currentNode: any;
const remoteWsStore = useRemoteWsStore();
onMounted(() => {
chartInit();
});
function updateChartData(data: any) {
if (data) {
if (currentNode && currentNode.Time == data.Time) {
return;
} else {
currentNode = data;
}
xData.shift();
xData.push(dateFormater("HH:mm:ss", data.Time ? data.Time - 8 * 60 * 60 * 1000 : ""));
series.forEach(serie => {
serie.data.shift();
serie.data.push(data[serie] ? data[serie] : 0);
if (data[serie.name + '_except']) {
emit("exceptionEvent", remoteWsStore.exceptionMsg[serie.name + '_except']);
}
})
chart.setOption({
xAxis: {
data: xData,
},
series
});
}
}
//
function chartInit() {
chart = echarts.init(chartDom.value as HTMLElement);
chart.clear();
getXData();
getSeries();
const option = {
color: color,
tooltip: {
trigger: 'axis',
formatter: (params: any) => {
let str = params[0].axisValue;
str += `<br>`;
props.names.forEach((item, index) => {
str += params[index].marker;
str += params[index].seriesName + ' ';
str += `${params[index].value} HZ`;
str += index === 0 ? '<br>' : '';
});
return str;
},
},
grid: {
left: 1,
right: 20,
bottom: 5,
top: 20,
containLabel: true,
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
axisLine: {show: false, lineStyle: {color: '#006080'}},
axisTick: {show: false},
axisLabel: {show: false},
splitLine: {show: true, lineStyle: {color: '#D4E8F0', width: 1, type: 'solid'}},
data: xData,
},
yAxis: {
show: true,
type: 'value',
min: function (value: any) {
return value.min - 40
},
max: function (value: any) {
return value.max + 40
},
axisLabel: {
formatter: `{value} HZ`
},
axisLine: {show: false, lineStyle: {color: '#006080'}},
splitLine: {lineStyle: {color: '#D4E8F0', width: 1, type: 'solid'}},
},
series,
};
chart.setOption(option);
chart.resize();
window.addEventListener('resize', () => {
chart.resize();
});
}
function getXData() {
for (let i = 0; i < 50; i++) {
xData.push(0);
}
}
function getSeries() {
props.names.forEach((name, index) => {
const serie = {
name,
type: 'line',
symbol: 'none',
lineStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
{
offset: 0,
color: 'rgba(40,94,125,0)',
},
{
offset: 0.3,
color: color[index],
},
{
offset: 0.5,
color: color[index],
},
{
offset: 0.7,
color: color[index],
},
{
offset: 1,
color: 'rgba(40,94,125,0)',
},
]),
width: 1,
},
data: [],
};
for (let i = 0; i < 50; i++) {
serie.data.push(0);
}
series.push(serie);
});
}
</script>
<style lang="scss" scoped>
.chart-dom-box {
position: relative;
position: relative;
.chart-rate {
position: absolute;
top: 5px;
left: 30px;
color: #285e7d;
font-size: 16px;
line-height: 30px;
font-weight: 600;
}
.chart-rate {
position: absolute;
top: 5px;
left: 30px;
color: #285e7d;
font-size: 16px;
line-height: 30px;
font-weight: 600;
}
}
</style>

View File

@ -5,102 +5,73 @@
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import {onMounted, ref} from 'vue';
import * as echarts from 'echarts';
import { dateFormater } from '@/utils/date-util';
import {dateFormater} from '@/utils/date-util';
import {useRemoteWsStore} from "@/stores/remote-ws-store";
const chartDom = ref();
const props = withDefaults(defineProps<{
names: string[]
}>(), {
names: ['BIS', 'HR']
});
defineExpose({
updateChartData
});
const emit = defineEmits(["exceptionEvent"]);
let chart: any;
const xData: any = [];
const series: any = [];
const legendData: any = [];
const colors = ['#00AAB7', '#C77000'];
let currentNode: any;
const remoteWsStore = useRemoteWsStore();
interface Props {
names: string[];
chartData: any[];
}
const props = withDefaults(defineProps<Props>(), {
names: () => ['BIS', 'HR'],
chartData: () => [] as any[],
onMounted(() => {
chartInit();
});
// const emit = defineEmits(['updateData']);
let chart: any;
const names = props.names; //
const color = ['#00AAB7', '#C77000'];
let legendData = [] as any[];
let xData = [] as any[]; // x
let series = [] as any[];
//
function updateChart(ary: number[], time?: string) {
xData.shift();
xData.push(dateFormater('HH:mm:ss', time));
// const values: number[] = [];
series.forEach((item, index) => {
item.data.shift();
item.data.push(ary[index]);
// values.push(item.data[item.data.length - 1]);
});
// emit('updateData', [values]); //
chart.setOption({
xAxis: {
data: xData,
},
series,
});
function updateChartData(data: any) {
if (data) {
if (currentNode && currentNode.Time == data.Time) {
return;
} else {
currentNode = data;
}
xData.shift();
xData.push(dateFormater("HH:mm:ss", data.Time ? data.Time - 8 * 60 * 60 * 1000 : ''));
series.forEach(serie => {
serie.data.shift();
serie.data.push(data[serie.name]);
if (data[serie.name + '_except']) {
emit("exceptionEvent", remoteWsStore.exceptionMsg[serie.name + '_except']);
}
})
chart.setOption({
xAxis: {
data: xData,
},
series,
})
}
}
//
function formatterData() {
legendData = [];
xData = [];
series = [];
for (let i = 0; i < 10; i++) {
if (props.chartData[i]) xData.push(dateFormater('HH:mm:ss', props.chartData[i].Time || props.chartData[i].TIME));
else xData.unshift(0);
}
names.forEach((item, index) => {
const obj = {
name: item,
type: 'line',
symbol: 'none',
smooth: true,
data: [] as number[],
};
for (let i = 0; i < 10; i++) {
if (props.chartData[i]) obj.data.push(props.chartData[i][item]);
else obj.data.unshift(0);
}
legendData.push({
name: item,
textStyle: { color: color[index] },
});
series.push(obj);
});
}
//
function chartSet() {
formatterData();
if (chart) chart.setOption({
xAxis: {
data: xData,
},
series,
});
}
//
function chartInit() {
chart = echarts.init(chartDom.value as HTMLElement);
chart.clear();
formatterData();
const option : any = {
color,
getSeries();
getXData();
getLegendData();
const option: any = {
color: colors,
tooltip: {
trigger: 'axis',
formatter: (params: any) => {
let str = '';
str += params[0].axisValue;
str += '<br>';
names.forEach((item, index) => {
props.names.forEach((item, index) => {
str += params[index].marker;
str += params[index].seriesName + ' ';
switch (item) {
@ -145,7 +116,7 @@ function chartInit() {
lineHeight: 30,
},
formatter: (params: string) => {
const index = names.findIndex((item) => item === params);
const index = props.names.findIndex((item) => item === params);
let str = params + ' ';
switch (params) {
case 'BIS':
@ -171,7 +142,7 @@ function chartInit() {
}
return str;
},
data: legendData,
data: legendData
},
grid: {
left: 5,
@ -184,21 +155,22 @@ function chartInit() {
show: true,
type: 'category',
boundaryGap: false,
data: xData,
axisLine: { lineStyle: { color: '#006080' } }
data: [],
axisLine: {lineStyle: {color: '#006080'}}
},
yAxis: {
show: true,
type: 'value',
axisLabel: {
formatter: `{value} ${names[0] === 'BIS' ? '次/分' : names[0] === 'SBP' ? 'mmHg' : ''}`
formatter: `{value} ${props.names[0] === 'BIS' ? '次/分' : props.names[0] === 'SBP' ? 'mmHg' : ''}`
},
axisLine: { show: true, lineStyle: { color: '#006080' } },
splitLine: { lineStyle: { color: '#C0C4CC', width: 1, type: 'dashed' } },
axisLine: {show: true, lineStyle: {color: '#006080'}},
splitLine: {lineStyle: {color: '#C0C4CC', width: 1, type: 'dashed'}},
},
series,
};
if(names[0] !== 'BIS') {
if (props.names[0] !== 'BIS'
) {
option.yAxis.max = (value: any) => value.max + 20;
}
chart.setOption(option);
@ -208,13 +180,36 @@ function chartInit() {
});
}
onMounted(() => {
chartInit();
});
defineExpose({
updateChart,
chartSet
});
function getSeries() {
props.names.forEach(name => {
const serie = {
name,
type: 'line',
symbol: 'none',
smooth: true,
data: [] as number[],
};
for (let i = 0; i < 10; i++) {
serie.data.push(0);
}
series.push(serie)
});
}
function getXData() {
for (let i = 0; i < 10; i++) {
xData.push(0);
}
}
function getLegendData() {
props.names.forEach((name, index) => {
legendData.push({
name,
textStyle: {color: colors[index]},
});
});
}
</script>
<style lang="scss" scoped>

View File

@ -1,51 +1,41 @@
<template>
<div class="message-item-part">
<div class="tag-index">{{ index + 1 }}</div>
<ul ref="listRef">
<li v-for="(item, index) in logs" :key="index">
<span>{{ dateFormater('HH:mm:ss', item.time) }}</span>
<span>{{ item.title }}</span>
<span>{{ item.state }}</span>
</li>
</ul>
</div>
<div class="message-item-part">
<div class="tag-index">{{ index + 1 }}</div>
<ul ref="listRef">
<li v-for="(item, i) in remoteWsStore.remoteTasks[index]?.log || []" :key="i">
<span>{{ dateFormater('yyyy-MM-dd HH:mm:ss', item.time) }}</span>
<span>{{ item.taskName }}</span>
<span>{{ item.state }}</span>
</li>
</ul>
</div>
</template>
<script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
import type { RemoteLogItem, RemoteItem } from '@/utils/public-interface'
import { useRemoteStore } from '@/stores/remote-info-store'
import { dateFormater } from '@/utils/date-util'
interface Props {
index: number
logs: Array<RemoteLogItem>
}
const props = withDefaults(defineProps<Props>(), {
index: () => 0,
logs: () => [] as Array<RemoteLogItem>
})
import {ref} from 'vue';
import {useRemoteWsStore} from "@/stores/remote-ws-store";
import {dateFormater} from "@/utils/date-util";
const remoteWsStore = useRemoteWsStore();
const props = withDefaults(defineProps<{
index: number
}>(),
{
index: () => 0
})
const listRef = ref()
const remoteTasks: any = ref([] as Array<RemoteItem>)
defineExpose({
scrollToBottom,
scrollToBottom
})
remoteTasks.value = useRemoteStore().remoteTasks
// useRemoteStore()
// useRemoteStore().$subscribe((mutation: any, state: any) => {
// console.log(mutation, state)
// })
function scrollToBottom() {
setTimeout(() => {
listRef.value.scrollTo({
top: listRef.value.scrollHeight,
behavior: 'smooth'
})
}, 0)
setTimeout(() => {
listRef.value.scrollTo({
top: listRef.value.scrollHeight,
behavior: 'smooth'
})
}, 0)
}
</script>

View File

@ -1,47 +1,45 @@
<template>
<div class="message-part">
<div class="title">
<span>消息通知</span>
</div>
<div ref="listRef" class="content">
<el-timeline>
<el-timeline-item v-for="(item, index) in remoteStore.currentRemote.log || []" :key="index"
:timestamp="dateFormater('yyyy-MM-dd HH:mm:ss', item.time)"
:class="{ 'alarm': item.state === '连接失败' || item.state === '异常' }">
{{ item.title + ' ' + item.state }}
</el-timeline-item>
</el-timeline>
</div>
</div>
<div class="message-part">
<div class="title">
<span>消息通知</span>
</div>
<div ref="listRef" class="content">
<el-timeline>
<el-timeline-item v-for="(item, index) in remoteWsStore.remoteTasks[remoteWsStore.currentTaskIndex]?.log || []" :key="index"
:timestamp="dateFormater('yyyy-MM-dd HH:mm:ss', item.time)"
:class="{ 'alarm': item.state === '连接失败' || item.state === '异常' }">
{{ item.taskName + ' ' + item.state }}
</el-timeline-item>
</el-timeline>
</div>
</div>
</template>
<script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
import type { RemoteLogItem, RemoteItem } from '@/utils/public-interface'
import { useRemoteStore } from '@/stores/remote-info-store'
import { dateFormater } from '@/utils/date-util'
import {ref} from 'vue'
import {dateFormater} from '@/utils/date-util'
import {useRemoteWsStore} from "@/stores/remote-ws-store";
defineExpose({
setData,
scrollToBottom
setData,
scrollToBottom
})
const remoteStore = useRemoteStore()
const remoteWsStore = useRemoteWsStore()
const listRef = ref()
function setData(e: RemoteLogItem, index: number) {
remoteStore.setRemoteLog(e, index)
remoteStore.$patch({currentRemote: remoteStore.remoteTasks[index]})
function setData(e: any, index: number) {
remoteWsStore.setRemoteLog(e, index)
}
function scrollToBottom() {
setTimeout(() => {
listRef.value.scrollTo({
top: listRef.value.scrollHeight,
behavior: 'smooth'
})
}, 0)
setTimeout(() => {
listRef.value.scrollTo({
top: listRef.value.scrollHeight,
behavior: 'smooth'
})
}, 0)
}
</script>

View File

@ -1,72 +1,101 @@
<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" style="margin-left: 50px;" @click="dialogVisible = false">返回</el-button>
</div>
</el-dialog>
<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.serverun }}</p>
<p>密码*********</p>
<br>-->
<p class="input-box"><span>输入病人姓名</span>
<el-input v-model="patientInfo.patient"></el-input>
</p>
<p class="input-box"><span>输入病人身份证号</span>
<el-input v-model="patientInfo.patientId"></el-input>
</p>
<p class="input-box"><span>请选择手术时间</span>
<el-date-picker
v-model="patientInfo.date"
type="date"
placeholder="请选择日期"
/>
</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" style="margin-left: 50px;" @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()
import {ref} from 'vue'
import {ElMessage} from 'element-plus'
import {useRemoteWsStore} from "@/stores/remote-ws-store";
import {dateFormater} from "@/utils/date-util";
const emit = defineEmits(['confirmRemote', 'errorRemote', 'breakRemote'])
const dialogVisible = ref(false)
const patientInfo = ref({} as RemoteItem)
const patientInfo = ref({} as any)
const remoteWsStore = useRemoteWsStore();
defineExpose({
open,
close,
})
onMounted(() => {
open,
close,
})
function open(e: RemoteItem) {
patientInfo.value = JSON.parse(JSON.stringify(e))
dialogVisible.value = true
function open(e: number) {
patientInfo.value = remoteWsStore.remoteTasks[e]
dialogVisible.value = true
}
function close() {
dialogVisible.value = false
dialogVisible.value = false
}
const confirmRemote = () => {
if(patientInfo.value.patientCode) {
ElMessage.success('连接成功!')
patientInfo.value.isRemote = true
patientInfo.value.title = '远程控制' + (patientInfo.value.index + 1)
emit('confirmRemote', patientInfo.value)
close()
}else{
ElMessage.error('连接失败!')
emit('errorRemote', patientInfo.value)
}
if (patientInfo.value.patientId && patientInfo.value.patient) {
ElMessage.success('连接成功!')
patientInfo.value.isRemote = true
patientInfo.value.taskName = '远程控制' + (patientInfo.value.index + 1)
patientInfo.value.date = dateFormater("yyyy-MM-dd", patientInfo.value.date)
unsubscribeLastTask();
remoteWsStore.$patch({currentTaskIndex: patientInfo.value.index})
remoteWsStore.setRemoteLog({
time: new Date(),
taskName: patientInfo.value.taskName,
state: '连接成功',
type: "normal"
}, remoteWsStore.currentTaskIndex)
emit('confirmRemote', patientInfo.value)
close()
} else {
remoteWsStore.setRemoteLog({
time: new Date(),
taskName: patientInfo.value.taskName,
state: '连接失败'
}, patientInfo.value.index)
ElMessage.error('连接失败!')
emit('errorRemote', patientInfo.value)
}
}
const breakRemote = () => {
ElMessage.info('连接已断开!')
emit('breakRemote', patientInfo.value)
close()
ElMessage.info('连接已断开!')
emit('breakRemote', patientInfo.value)
close()
}
const unsubscribeLastTask = () => {
const lastTaskIndex = remoteWsStore.currentTaskIndex;
const lastTask: any = remoteWsStore.remoteTasks[lastTaskIndex];
if (lastTask) {
remoteWsStore.unsubscribeVital(lastTask.patient, lastTask.patientId, lastTask.date);
}
}
</script>
@ -115,6 +144,7 @@ const breakRemote = () => {
}
}
}
.btn-box {
display: flex;
justify-content: center;

View File

@ -1,122 +1,114 @@
<template>
<div class="remote-item-part">
<div class="title">
<span>{{ remoteTask.title || '远程控制' }}</span>
</div>
<div class="content mini" :class="{ 'is-total': remoteTask.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 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.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 class="row-item yellow" :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 yellow" :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 yellow">
<span class="label">TEMP</span>
<span class="value">{{ patientInfo.TEMP }}</span>
</div>
</div>
<div class="center-box">
<img src="@/assets/imgs/main_body_intact.png">
</div>
</div>
</div>
<div class="remote-item-part">
<div class="title">
<span>{{ remoteTask.taskName || '远程控制' }}</span>
</div>
<div class="content mini" :class="{ 'is-total': remoteTask.isRemote }">
<div class="left-box">
<div class="info-box">
<div class="row-item">
<span class="label">病人名称</span>
<span class="input-value">{{ remoteTask.patient }}</span>
</div>
<div class="row-item">
<span class="label">住院号</span>
<span class="input-value">{{ remoteTask.patientId }}</span>
</div>
<div class="row-item">
<span class="label">手术时间</span>
<span class="input-value">{{
remoteTask.date
}}</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.BIS_except }">
<span class="label">BIS</span>
<span class="value">{{ patientInfo.BIS }}</span>
</div>
<div class="row-item" :class="{ 'alarm': patientInfo.SBP_except }">
<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 class="row-item yellow" :class="{ 'alarm': patientInfo.DBP_except }">
<span class="label">DBP</span>
<span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span>
</div>
<div class="row-item yellow" :class="{ 'alarm': patientInfo.HR_except }">
<span class="label">HR</span>
<span class="value">{{ patientInfo.HR }}<span class="unit">/</span></span>
</div>
<div class="row-item yellow">
<span class="label">TEMP</span>
<span class="value">{{ patientInfo.TEMP }}</span>
</div>
</div>
<div class="center-box">
<img src="@/assets/imgs/main_body_intact.png">
</div>
</div>
</div>
</template>
<script lang='ts' setup>
import { onMounted, onBeforeUnmount, reactive, ref, toRefs, watch } from 'vue'
import type { RemoteItem, PatientInfoItem, RemoteLogItem } from '@/utils/public-interface'
import { useRemoteStore } from '@/stores/remote-info-store'
import { dateFormater } from '@/utils/date-util'
import { setRemoteLog } from '@/static-data/core'
import {onMounted, onUnmounted, ref} from 'vue'
import {useRemoteWsStore} from "@/stores/remote-ws-store";
interface Props {
index: number
}
const props = withDefaults(defineProps<Props>(), {
index: () => 0
const props = withDefaults(defineProps<{ index: number }>(), {
index: () => 0
})
const emit = defineEmits(['addLogAfter'])
const remoteStore = useRemoteStore()
const remoteTask = remoteStore.remoteTasks[props.index]
let timer = 0
const patientInfo = ref({} as PatientInfoItem)
const remoteWsStore = useRemoteWsStore();
const remoteTask = ref(remoteWsStore.remoteTasks[props.index]);
const patientInfo = ref({} as any)
onMounted(() => {
clearInterval(timer)
//
if (remoteTask.isRemote) {
timer = setInterval(() => {
initData()
}, 2000)
}
//
if (remoteTask.value.isRemote) {
initData()
}
})
onBeforeUnmount(() => {
//
clearInterval(timer)
onUnmounted(() => {
remoteWsStore.unsubscribeVital(remoteTask.value.patient, remoteTask.value.patientId, remoteTask.value.date);
})
function initData() {
remoteTask.dataAlarm = false
const obj = {
name: remoteTask.patientName,
code: '',
time: new Date(),
state: false,
BIS: Number((Math.random() * 100).toFixed(2)),
SBP: Number((Math.random() * 100).toFixed(2)),
SPO2: Number((Math.random() * 100).toFixed(2)),
DBP: Number((Math.random() * 100).toFixed(2)),
HR: Number((Math.random() * 100).toFixed(2)),
TEMP: Number((Math.random() * 100).toFixed(2))
}
setRemoteLog(obj, (title: string, size: string) => {
obj.state = true
remoteTask.dataAlarm = true
remoteStore.setRemoteLog({
time: new Date(),
title,
state: '异常'
}, props.index)
subscribeVital();
}
function subscribeVital() {
remoteWsStore.subscribeVital(remoteTask.value.patient, remoteTask.value.patientId, remoteTask.value.date, (res: any) => {
const data = JSON.parse(res.data);
if (data.vitalSignsList && data.vitalSignsList.length > 0) {
Object.assign(patientInfo.value, data.vitalSignsList[0]);
patientInfo.value.state = (patientInfo.value.BIS_except || patientInfo.value.SBP_except ||
patientInfo.value.DBP_except || patientInfo.value.HR_except);
setLog(patientInfo.value, props.index)
emit('addLogAfter', props.index)
}
})
}
function setLog(data: any, index: number) {
remoteWsStore.exceptionType.forEach((item: any) => {
if (data[item]) {
const msg: any = remoteWsStore.exceptionMsg[item];
remoteWsStore.setRemoteLog({
state: msg,
taskName: remoteTask.value.taskName,
time: new Date(),
type: "exception"
}, index);
}
})
Object.assign(patientInfo.value, obj)
emit('addLogAfter', props.index)
}
</script>

View File

@ -1,190 +1,195 @@
<template>
<div class="remote-part">
<div class="title">
<span>{{ remoteItem?.title || '远程控制' }}</span>
<el-button v-if="remoteItem" class="break-btn" @click="breakRemote">断开连接</el-button>
</div>
<!-- 小分辨率 -->
<div v-if="mediaMini800" class="content mini" :class="{'is-total': remoteItem?.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 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.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 class="row-item yellow" :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 yellow" :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 yellow">
<span class="label">TEMP</span>
<span class="value">{{ patientInfo.TEMP }}</span>
</div>
</div>
<div class="center-box">
<img src="@/assets/imgs/main_body_intact.png">
</div>
</div>
<div v-else class="content" :class="{'is-total': remoteItem?.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 class="remote-part">
<div class="title">
<span>{{ remoteItem?.taskName || '远程控制' }}</span>
<el-button v-if="remoteItem?.taskName" class="break-btn" @click="breakRemote">断开连接</el-button>
</div>
<!-- 小分辨率 -->
<div v-if="mediaMini800" class="content mini" :class="{'is-total': remoteItem?.isRemote}">
<div class="left-box">
<div class="info-box">
<div class="row-item">
<span class="label">病人名称</span>
<span class="input-value">{{ remoteItem.patient }}</span>
</div>
<div class="row-item">
<span class="label">住院号</span>
<span class="input-value">{{ remoteItem.patientId }}</span>
</div>
<div class="row-item">
<span class="label">手术时间</span>
<span class="input-value">{{
remoteItem.date
}}</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.BIS_except}">
<span class="label">BIS</span>
<span class="value">{{ patientInfo.BIS }}</span>
</div>
<div class="row-item" :class="{'alarm': patientInfo.SBP_except}">
<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 class="row-item yellow" :class="{'alarm': patientInfo.DBP_except}">
<span class="label">DBP</span>
<span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span>
</div>
<div class="row-item yellow" :class="{'alarm': patientInfo.HR_except}">
<span class="label">HR</span>
<span class="value">{{ patientInfo.HR }}<span class="unit">/</span></span>
</div>
<div class="row-item yellow">
<span class="label">TEMP</span>
<span class="value">{{ patientInfo.TEMP }}</span>
</div>
</div>
<div class="center-box">
<img src="@/assets/imgs/main_body_intact.png">
</div>
</div>
<div v-else class="content" :class="{'is-total': remoteItem?.isRemote}">
<div class="left-box">
<div class="info-box">
<div class="row-item">
<span class="label">病人名称</span>
<span class="input-value">{{ remoteItem.patient }}</span>
</div>
<div class="row-item">
<span class="label">住院号</span>
<span class="input-value">{{ remoteItem.patientId }}</span>
</div>
</div>
<div class="row-item" :class="{'alarm': patientInfo.BIS_except}">
<span class="label">BIS</span>
<span class="value">{{ patientInfo.BIS }}</span>
</div>
<div class="row-item" :class="{'alarm': patientInfo.SBP_except}">
<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">{{
remoteItem.date
}}</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_except}">
<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_except}">
<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, onBeforeUnmount, reactive, ref, toRefs, watch } from 'vue'
import { dateFormater } from '@/utils/date-util'
import { useRemoteStore } from '@/stores/remote-info-store';
import type { RemoteItem, PatientInfoItem } from '@/utils/public-interface'
import { setRemoteLog } from '@/static-data/core'
import {onUnmounted, ref} from 'vue'
import {useRemoteWsStore} from "@/stores/remote-ws-store";
const emit = defineEmits(['addLogAfter', 'breakRemote'])
const remoteStore = useRemoteStore()
let timer = 0
const mediaMini800 = ref(false)
const remoteItem = ref<RemoteItem>({} as RemoteItem)
const patientInfo = ref({} as PatientInfoItem)
initData(remoteStore.currentRemote)
const remoteItem = ref({} as any)
const patientInfo = ref({} as any)
const remoteWsStore = useRemoteWsStore()
defineExpose({
initData
})
onBeforeUnmount(() => {
//
clearInterval(timer)
})
window.addEventListener('resize', () => {
mediaMini800.value = Boolean(window.innerWidth < 801)
initData, showData
});
function initData(e?: RemoteItem) {
const obj = e || {} as RemoteItem
remoteItem.value = obj
patientInfo.value.state = obj.dataAlarm
patientInfo.value.name = obj.patientName || ''
patientInfo.value.code = 'XXXXXX'
clearInterval(timer)
if(!patientInfo.value.name) return
timer = setInterval(() => {
getData()
}, 2000)
window.addEventListener('resize', () => {
mediaMini800.value = Boolean(window.innerWidth < 801)
});
onUnmounted(() => {
remoteWsStore.unsubscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date);
})
function showData(i: number) {
const lastTaskIndex = remoteWsStore.currentTaskIndex;
const lastTask: any = remoteWsStore.remoteTasks[lastTaskIndex];
if (lastTask) {
remoteWsStore.unsubscribeVital(lastTask.patient, lastTask.patientId, lastTask.date);
}
remoteWsStore.currentTaskIndex = i
remoteItem.value = remoteWsStore.remoteTasks[remoteWsStore.currentTaskIndex]
getData()
}
function initData() {
remoteItem.value = remoteWsStore.remoteTasks[remoteWsStore.currentTaskIndex]
remoteWsStore.createConnect(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date)
getData()
}
function getData() {
remoteItem.value.dataAlarm = false
const obj = {
state: false,
BIS: Math.ceil(Math.random() * 100),
SBP: Math.ceil(Math.random() * 100),
SPO2: Math.ceil(Math.random() * 100),
DBP: Math.ceil(Math.random() * 100),
HR: Math.ceil(Math.random() * 100),
TEMP: Math.ceil(Math.random() * 100),
} as PatientInfoItem
patientInfo.value.time = new Date()
setRemoteLog(obj, (title: string, size: string) => {
obj.state = true
remoteItem.value.dataAlarm = true
remoteStore.setRemoteLog({
time: new Date(),
title,
state: '异常'
}, remoteItem.value.index)
remoteWsStore.unsubscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date);
remoteWsStore.subscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date, (res: any) => {
const data = JSON.parse(res.data);
if (data.vitalSignsList && data.vitalSignsList.length > 0) {
Object.assign(patientInfo.value, data.vitalSignsList[0]);
patientInfo.value.state = (patientInfo.value.BIS_except || patientInfo.value.SBP_except ||
patientInfo.value.DBP_except || patientInfo.value.HR_except);
setLog(patientInfo.value)
emit('addLogAfter')
}
})
}
function setLog(data: any) {
remoteWsStore.exceptionType.forEach((item: any) => {
if (data[item]) {
const msg: any = remoteWsStore.exceptionMsg[item];
remoteWsStore.setRemoteLog({
state: msg,
taskName: remoteItem.value.taskName,
time: new Date(),
type: "exception"
}, remoteWsStore.currentTaskIndex);
}
})
remoteStore.setRemoteDataAlarm(remoteItem.value.dataAlarm, remoteItem.value.index)
remoteStore.$patch({currentRemote: remoteStore.remoteTasks[remoteItem.value.index]})
Object.assign(patientInfo.value, obj)
emit('addLogAfter')
}
const breakRemote = () => {
remoteItem.value.isRemote = false
emit('breakRemote', remoteItem.value)
remoteWsStore.disconnect(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date)
remoteWsStore.resetRemoteTask(remoteWsStore.currentTaskIndex)
if (remoteWsStore.getActiveRemoteTask()) {
showData(remoteWsStore.getActiveRemoteTask())
}
emit('breakRemote')
}
</script>

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,5 @@
<template>
<div class="remote-manage-page">
<button @click="getSurgeryData">123</button>
<button @click="disconnectSurgeryData">断开</button>
<button @click="sendMsg">发送消息</button>
<button @click="closeChat">关闭消息</button>
<button @click="addMedicine">给药</button>
<button @click="closeAddMedicineWS">关闭给药</button>
<div class="header-box">
<div class="thumbnail" @click="viewThumbnail">
<el-icon>
@ -14,9 +8,9 @@
<span>缩略图</span>
</div>
<div class="task-btn-item" v-for="(item, index) in remoteTask" :key="'task-' + index"
:class="{ 'connecting': item.patientName || item.patientCode, 'alarm': item.dataAlarm }"
@click="editTask(item, index)" @dblclick="toRemoteControl(item, index)">
<span>{{ item.title || ('新建任务' + (index + 1)) }}</span>
:class="{ 'connecting': item.patient || item.patientId, 'alarm': item.isException }"
@click="editTask(item)" @dblclick="toRemoteControl(item)">
<span>{{ item.taskName || ('新建任务' + (index + 1)) }}</span>
</div>
</div>
<div class="content-box">
@ -32,65 +26,26 @@
</template>
<script lang='ts' setup>
import {ref} from 'vue'
import {onMounted, ref} from 'vue'
import {useRouter} from 'vue-router'
import {useRemoteStore} from '@/stores/remote-info-store'
import type {RemoteItem} from '@/utils/public-interface'
import RemoteDialog from './part/remote-dialog.vue'
import RemotePart from './part/remote-part.vue'
import MessagePart from './part/message-part.vue'
import {Session} from "@/utils/storage";
import {useRemoteWsStore} from "@/stores/remote-ws-store";
const router = useRouter()
const remoteStore = useRemoteStore()
const remotePartRef = ref()
const messagePartRef = ref()
const remoteDialogRef = ref()
const remoteTask = ref([] as Array<RemoteItem>)
const remoteTask = ref([] as Array<any>)
const remoteWsStore = useRemoteWsStore();
initRemoteTask()
function resetRemoteTaskItem(e: RemoteItem) {
Object.assign(remoteTask.value[e.index], {
isRemote: false,
dataAlarm: false,
title: '',
serverUser: '',
patientName: '',
patientCode: '',
index: e.index,
})
}
onMounted(() => {
initRemoteTask()
})
function initRemoteTask() {
remoteTask.value = remoteStore.remoteTasks
if (remoteTask.value.length < 1) {
while (remoteTask.value.length < 10) {
const obj = {
isRemote: false, //
dataAlarm: false, //
title: '',
serverUser: '', //
patientName: '', //
patientCode: '', //
index: remoteTask.value.length,
log: []
}
if (remoteTask.value.length < 3) {
obj.isRemote = true
obj.title = '远程控制' + (remoteTask.value.length + 1)
obj.serverUser = 'root'
obj.patientName = '测试' + (remoteTask.value.length + 1)
}
if (remoteTask.value.length == 1) obj.dataAlarm = true
remoteTask.value.push(obj)
}
remoteStore.setRemoteTasks(remoteTask.value)
if (!remoteStore.currentRemote.index) {
remoteStore.$patch({currentRemote: remoteTask.value[0]})
}
}
remoteTask.value = remoteWsStore.initRemoteTask()
}
const viewThumbnail = () => {
@ -99,201 +54,41 @@ const viewThumbnail = () => {
})
}
//
const editTask = (item: RemoteItem, index: number) => {
item.index = index
const editTask = (item: any) => {
// content
if (item.isRemote) {
confirmRemote(item)
remotePartRef.value.showData(item.index)
} else {
remoteDialogRef.value.open(item)
remoteDialogRef.value.open(item.index)
}
}
//
const toRemoteControl = (item: RemoteItem, index: number) => {
const toRemoteControl = (item: any) => {
//
if (item.isRemote) {
router.push('/remote-manage/remote-control')
} else {
editTask(item, index)
remoteDialogRef.value.open(item.index)
}
}
//
const confirmRemote = (e: RemoteItem) => {
messagePartRef.value.setData({
time: new Date(),
title: e.title,
state: '连接成功'
}, e.index)
remoteTask.value[e.index] = e //
remotePartRef.value.initData(e)
console.log(e);
getSurgeryData();
const confirmRemote = () => {
messagePartRef.value.scrollToBottom()
//
remotePartRef.value.initData()
}
//
const errorRemote = (e: RemoteItem) => {
messagePartRef.value.setData({
time: new Date(),
title: e.title,
state: '连接失败'
}, e.index)
const errorRemote = () => {
messagePartRef.value.scrollToBottom()
}
//
const breakRemote = (e: RemoteItem) => {
resetRemoteTaskItem(e)
remotePartRef.value.initData()
messagePartRef.value.setData({
time: new Date(),
title: e.title,
state: '断开连接'
}, e.index)
// disconnectSurgeryData("", "1")
const breakRemote = () => {
messagePartRef.value.scrollToBottom()
}
const addLogAfter = () => {
messagePartRef.value.scrollToBottom()
}
const ws = new WebSocket("ws://localhost:5173/socket.io/admin/rax/vitalSignsMedicine?token=" + Session.getToken());
function getSurgeryData() {
const params = {
patientName: "1111111",
idNum: "123567890",
date: "20230505"
}
ws.send(JSON.stringify(params))
}
function disconnectSurgeryData() {
ws.close();
}
ws.onmessage = function (e) {
console.log(e)
}
const chatws = new WebSocket("ws://localhost:5173/socket.io/admin/rax/chatRoom?token=" + Session.getToken());
function sendMsg() {
const params = {
patientName: "1111111",
idNum: "123567890",
date: "20230505",
msg: "测试消息"
}
chatws.send(JSON.stringify(params))
}
chatws.onmessage = function (e) {
console.log(e)
}
function closeChat() {
chatws.close()
}
const addMedicineWS = new WebSocket("ws://localhost:5173/socket.io/admin/rax/addMedicine?token=" + Session.getToken())
function addMedicine() {
const params = {
patientName: "1111111",
idNum: "123567890",
date: "20230505",
flag: "2",
medicine: "丙泊酚",
value: "1"
}
addMedicineWS.send(JSON.stringify(params))
}
addMedicineWS.onmessage = function (e) {
console.log(e)
}
function closeAddMedicineWS() {
addMedicineWS.close()
}
/*const surgeryClient = new Client({
brokerURL: 'ws://localhost:5173/socket.io/admin/rax/SurgeryData',
connectHeaders: {
token: Session.get('token')
},
reconnectDelay: 5000,
heartbeatIncoming: 60000,
heartbeatOutgoing: 60000
})
surgeryClient.activate()
surgeryClient.onConnect = (data: any) => {
console.log("connect", data);
}
surgeryClient.onWebSocketError = (error) => {
console.log('Error with websocket', error)
};
surgeryClient.onStompError = (frame) => {
console.log('Broker reported error: ' + frame.headers['message'])
console.log('Additional details: ' + frame.body)
};
function getSurgeryData(username: string, db: string) {
console.log(username, db);
surgeryClient.publish({
destination: "/front/getSurgeryData",
headers: {
token: Session.get('token')
},
body: JSON.stringify({status: "start", db})
});
const account = "admin";
surgeryClient.subscribe('/topic/user/' + account + ":" + db + '/surgeryData', (data: any) => {
console.log(data);
})
}*/
/*function disconnectSurgeryData(username: string, db: string) {
const account = "admin";
surgeryClient.unsubscribe("/topic/user/" + account + ":" + db + "/surgeryData");
}
const chatClient = new Client({
brokerURL: 'ws://localhost:5173/socket.io/admin/rax/chat',
connectHeaders: {
token: Session.get('token')
},
reconnectDelay: 5000,
heartbeatIncoming: 60000,
heartbeatOutgoing: 60000
})
chatClient.activate()
const patientName = '111'
const idNum = '111'
const date = '20230505'
function sendChatMessage() {
const message = {
patientName: patientName,
idNum: idNum,
date: date,
msg: '测试消息'
}
chatClient.publish({
destination: '/front/sendMessage',
headers: {
token: Session.get('token')
},
body: JSON.stringify(message)
})
}*/
/*chatClient.onConnect = () => {
chatClient.subscribe('/topic/user/' + patientName + idNum + date + '/chatroomMessage', (data: any) => {
console.log(data)
})
}*/
</script>
<style lang='scss' scoped>

View File

@ -1,55 +1,53 @@
<template>
<el-scrollbar style="width: 100%;height: 100%;">
<div class="remote-thumbnail-page">
<div class="remote-box row1">
<div class="remote-item" v-for="item in remoteTask.slice(0, 4)" :key="item.title" @click="openRemote(item)">
<RemoteItemPart :ref="'remoteItemPartRef' + item.index" :index="item.index" @addLogAfter="addLogAfter"></RemoteItemPart>
</div>
</div>
<div class="remote-box row2">
<div class="left-box">
<div class="remote-item" v-for="item in remoteTask.slice(4)" :key="item.title" @click="openRemote(item)">
<RemoteItemPart :ref="'remoteItemPartRef' + item.index" :index="item.index" @addLogAfter="addLogAfter"></RemoteItemPart>
</div>
</div>
<div class="right-box">
<div class="message-title">异常信息</div>
<div class="message-item" v-for="item in remoteTask" :key="'message-item' + item">
<MessageItemPart ref="messageItemPartRef" :logs="item.log" :index="item.index"></MessageItemPart>
</div>
</div>
</div>
</div>
</el-scrollbar>
<el-scrollbar style="width: 100%;height: 100%;">
<div class="remote-thumbnail-page">
<div class="remote-box row1">
<div class="remote-item" v-for="item in remoteTask.slice(0, 4)" :key="item.title" @click="openRemote(item)">
<RemoteItemPart :ref="'remoteItemPartRef' + item.index" :index="item.index"
@addLogAfter="addLogAfter"></RemoteItemPart>
</div>
</div>
<div class="remote-box row2">
<div class="left-box">
<div class="remote-item" v-for="item in remoteTask.slice(4)" :key="item.title" @click="openRemote(item)">
<RemoteItemPart :ref="'remoteItemPartRef' + item.index" :index="item.index"
@addLogAfter="addLogAfter"></RemoteItemPart>
</div>
</div>
<div class="right-box">
<div class="message-title">异常信息</div>
<div class="message-item" v-for="item in remoteTask" :key="'message-item' + item">
<MessageItemPart ref="messageItemPartRef" :index="item.index"></MessageItemPart>
</div>
</div>
</div>
</div>
</el-scrollbar>
</template>
<script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useRemoteStore } from '@/stores/remote-info-store'
import type { RemoteItem } from '@/utils/public-interface'
import RemoteItemPart from './part/remote-item-part.vue'
import MessageItemPart from './part/message-item-part.vue'
import {onMounted, ref} from 'vue';
import {useRoute, useRouter} from 'vue-router';
import RemoteItemPart from './part/remote-item-part.vue';
import MessageItemPart from './part/message-item-part.vue';
import {useRemoteWsStore} from "@/stores/remote-ws-store";
const route = useRoute()
const router = useRouter()
const route = useRoute();
const router = useRouter();
const messageItemPartRef = ref();
const remoteTask = ref([] as any);
const remoteWsStore = useRemoteWsStore();
const messageItemPartRef = ref()
const remoteTask = ref([] as Array<RemoteItem>)
remoteTask.value = useRemoteStore().getRemoteTasks()
//
router.isReady().then(() => {
console.log(route)
onMounted(() => {
console.log("remoteThumbnail", remoteWsStore.remoteTasks)
remoteTask.value = remoteWsStore.remoteTasks;
})
const openRemote = (params: RemoteItem) => {
useRemoteStore().setCurrentRemote(params)
router.push('/remote-manage/remote-manage')
const openRemote = (params: any) => {
router.push('/remote-manage/remote-manage')
}
const addLogAfter = (index: number) => {
messageItemPartRef.value[index].scrollToBottom()
messageItemPartRef.value[index].scrollToBottom()
}
</script>