Merge branch 'refs/heads/dev'

# Conflicts:
#	src/views/login/login.vue
#	src/views/remote-manage/part/remote-dialog.vue
This commit is contained in:
zhaoyz 2024-04-24 15:19:10 +08:00
commit 198b34f732
26 changed files with 2922 additions and 2778 deletions

View File

@ -12,7 +12,7 @@
"dependencies": { "dependencies": {
"@stomp/stompjs": "^7.0.0", "@stomp/stompjs": "^7.0.0",
"axios": "^1.3.3", "axios": "^1.3.3",
"crypto-js": "4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"element-plus": "2.3.1", "element-plus": "2.3.1",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",

57
src/api/daily-plan.ts Normal file
View File

@ -0,0 +1,57 @@
import request from "@/utils/request";
const addDailyPlanUrl = "/admin/dailyPlan/saveOrUpdate";
const getDailyPlanListUrl = "/admin/dailyPlan/getListByDate";
const deleteByIdUrl = "/admin/dailyPlan/deleteById";
const getPlanDateListUrl = "/admin/dailyPlan/getPlanDateList";
const getTodoCountByDateUrl = "/admin/dailyPlan/getTodoCountByDate";
export function saveOrUpdate(param: any) {
return new Promise((resolve, reject) => {
request.postForm(addDailyPlanUrl, param).then((res: any) => {
resolve(res.data);
}).catch(err => {
reject(err);
})
})
}
export function getDailyPlanList(date: string) {
return new Promise((resolve, reject) => {
request.postForm(getDailyPlanListUrl, {date}).then((res: any) => {
resolve(res.data);
}).catch(err => {
reject(err);
})
})
}
export function deleteById(id: string) {
return new Promise((resolve, reject) => {
request.postForm(deleteByIdUrl, {id}).then((res: any) => {
resolve(res.data);
}).catch(err => {
reject(err);
})
})
}
export function getPlanDateList(startDate: string, endDate: string) {
return new Promise((resolve, reject) => {
request.postForm(getPlanDateListUrl, {startDate, endDate}).then((res: any) => {
resolve(res.data);
}).catch(err => {
reject(err);
})
})
}
export function getTodoCountByDate(date: string) {
return new Promise((resolve, reject) => {
request.postForm(getTodoCountByDateUrl, {date}).then((res: any) => {
resolve(res.data);
}).catch(err => {
reject(err);
})
});
}

View File

@ -1,21 +1,32 @@
import request, {CommonHeaderEnum} from "@/utils/request"; import request, {CommonHeaderEnum} from "@/utils/request";
const getMonthlyLogCountUrl = '/admin/log/getMonthlyLogCount' const getMonthlyLogCountUrl = '/admin/log/getMonthlyLogCount'
const getPageUrl = "/admin/log/page";
export function getMonthlyLogCount(startTime: string, endTime: string) { export function getMonthlyLogCount(startTime: string, endTime: string) {
return new Promise(resolve => { return new Promise(resolve => {
request({ request({
url: getMonthlyLogCountUrl, url: getMonthlyLogCountUrl,
method: 'post', method: 'post',
data: { data: {
startTime, startTime,
endTime endTime
}, },
headers: { headers: {
'Content-Type': CommonHeaderEnum.FORM_CONTENT_TYPE, 'Content-Type': CommonHeaderEnum.FORM_CONTENT_TYPE,
}, },
}).then(res => { }).then(res => {
resolve(res.data); resolve(res.data);
}) })
}) })
}
export function getPage(current: number, size: number) {
return new Promise((resolve, reject) => {
request.get(getPageUrl + `?current=${current}&size=${size}`).then((res: any) => {
resolve(res.data);
}).catch(err => {
reject(err);
})
})
} }

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) => {
resolve(res.data);
}).catch(error => {
reject(error);
});
});
}

View File

@ -1,23 +1,28 @@
<template> <template>
<el-timeline> <el-timeline>
<el-timeline-item v-for="(item, index) in activities" :key="index" :timestamp="item.time"> <el-timeline-item v-for="(item, index) in activities" :key="index" :timestamp="item.createTime">
{{ item.title + '-' + item.ip }} {{ item.title + '-' + item.remoteAddr }}
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import { dateFormater } from '@/utils/date-util'; import * as logManageApi from "@/api/log-manage";
const activities: any = [] const activities = ref([] as any);
while (activities.length < 10) { onMounted(function () {
activities.push({ getLogList();
time: dateFormater('yyyy-MM-dd HH:mm:ss'), });
title: '登录成功',
ip: '127.0.0.1' function getLogList() {
}) logManageApi.getPage(0, 100).then((res: any) => {
if (res.code == 0) {
activities.value = res.data.records;
console.log(activities.value)
}
})
} }
</script> </script>

View File

@ -1,82 +1,100 @@
import { createRouter, createWebHistory } from 'vue-router' import {createRouter, createWebHistory} from 'vue-router'
import { useLoginStore } from '@/stores/user-info-store' import {useLoginStore} from '@/stores/user-info-store'
import { ElMessage, ElMessageBox } from 'element-plus' import {ElMessage} from 'element-plus'
import { constantRoute } from './routes' import {constantRoute} from './routes'
import {decrypt, decryption, encrypt, encryption, isBase64} from "@/utils/other";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: constantRoute, routes: constantRoute,
stringifyQuery: stringifyQuery,
parseQuery: parseQuery,
}) })
const kk = "raxipnenttlewe";
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const loginInfo = useLoginStore().getlogin() const loginInfo = useLoginStore().getlogin()
const isLogin = loginInfo.isLogin // const isLogin = loginInfo.isLogin
// 普通用户 // 普通用户
const commonUser = [ const commonUser = [
'/login', '/login',
'/home', '/home',
'/patients-manage', '/patients-manage',
'/patients-manage/patients-manage', '/patients-manage/patients-manage',
'/patients-manage/surgery-info' '/patients-manage/surgery-info'
] ]
// 中级管理员 // 中级管理员
const IntermediateAdmin = [ const IntermediateAdmin = [
'/login', '/login',
'/home', '/home',
'/patients-manage', '/patients-manage',
'/patients-manage/patients-manage', '/patients-manage/patients-manage',
'/patients-manage/surgery-info', '/patients-manage/surgery-info',
'/remote-manage', '/remote-manage',
'/remote-manage/remote-manage', '/remote-manage/remote-manage',
'/remote-manage/remote-control' '/remote-manage/remote-control'
] ]
// 高级管理员 // 高级管理员
const SeniorAdmin = [ const SeniorAdmin = [
'/login', '/login',
'/home', '/home',
'/patients-manage', '/patients-manage',
'/patients-manage/patients-manage', '/patients-manage/patients-manage',
'/patients-manage/surgery-info', '/patients-manage/surgery-info',
'/remote-manage', '/remote-manage',
'/remote-manage/remote-manage', '/remote-manage/remote-manage',
'/remote-manage/remote-control', '/remote-manage/remote-control',
'/permissions-manage', '/permissions-manage',
'/permissions-manage/doctor-manage', '/permissions-manage/doctor-manage',
'/permissions-manage/role-manage', '/permissions-manage/role-manage',
'/permissions-manage/menu-manage', '/permissions-manage/menu-manage',
'/logs-manage', '/logs-manage',
'/logs-manage/message-manage', '/logs-manage/message-manage',
'/logs-manage/logs-manage' '/logs-manage/logs-manage'
] ]
const isViewRoute = () => { const isViewRoute = () => {
let release = false let release = true
switch (loginInfo.permissions) { /*switch (loginInfo.permissions) {
case '超级管理员': case '超级管理员':
release = true release = true
break; break;
case '高级管理员': case '高级管理员':
release = SeniorAdmin.some((p: string) => p === to.path) release = SeniorAdmin.some((p: string) => p === to.path)
break; break;
case '中级管理员': case '中级管理员':
release = IntermediateAdmin.some((p: string) => p === to.path) release = IntermediateAdmin.some((p: string) => p === to.path)
break; break;
case '普通用户': case '普通用户':
release = commonUser.some((p: string) => p === to.path) release = commonUser.some((p: string) => p === to.path)
break; break;
default: default:
break; break;
} }*/
return release return release
} }
if(to.fullPath ==='/login') { if (to.fullPath === '/login') {
next() next()
return return
} }
if (!isLogin) next('/login') // 重定向登录页 /*if (!isLogin) next('/login') //
else if(!isViewRoute()) { else */
ElMessage.error('无权访问!') if (!isViewRoute()) {
next(from.fullPath) ElMessage.error('无权访问!')
}else next() next(from.fullPath)
} else next()
}); });
function stringifyQuery(query: any) {
return btoa(encrypt(JSON.stringify(query), kk));
}
function parseQuery(query: any) {
if (isBase64(query)) {
return JSON.parse(decrypt(atob(query), kk));
} else {
return query;
}
}
export default router export default router

View File

@ -1,6 +1,6 @@
export const constantRoute=[ export const constantRoute=[
{ path: '/:pathMatch(.*)*', name: 'not-found', redirect: '/home' }, { path: '/:pathMatch(.*)*', name: 'not-found', redirect: '/login' },
{ {
path: '/login', path: '/login',
name: '登录', name: '登录',
@ -8,7 +8,7 @@ export const constantRoute=[
}, },
{ {
path: '/', path: '/',
redirect: '/home', redirect: '/login',
component: () => import('@/views/index.vue'), component: () => import('@/views/index.vue'),
children: [ 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: () => { state: () => {
return { return {
login: { login: {
isLogin: false,
account: '', account: '',
name: '', name: '',
/** /**
@ -13,7 +12,6 @@ export const useLoginStore = defineStore('login', {
* *
* *
*/ */
permissions: '',
hospital: '' hospital: ''
} as any } as any
} }

View File

@ -26,51 +26,64 @@ export function dateFormater(formater: string, time?: any) {
* @returns * @returns
*/ */
export function getMonthDays(time: any) { export function getMonthDays(time: any) {
if (!time) time = new Date(); if (!time) time = new Date();
const now = new Date(time); const now = new Date(time);
const year = now.getFullYear(); const year = now.getFullYear();
const month = now.getMonth() + 1; const month = now.getMonth() + 1;
const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
const daysInMonth = month === 2 const daysInMonth = month === 2
? isLeapYear ? 29 : 28 ? isLeapYear ? 29 : 28
: month === 4 || month === 6 || month === 9 || month === 11 : month === 4 || month === 6 || month === 9 || month === 11
? 30 ? 30
: 31; : 31;
return daysInMonth; return daysInMonth;
} }
/** /**
* i:1,2,3,4,5,6,7 * i:1,2,3,4,5,6,7
* @returns * @returns
*/ */
export function getFirstDayOfWeek(date: Date, i: number) { export function getFirstDayOfWeek(date: string | Date | number, i: number) {
if (i < 1 || i > 7) { let temp: any;
return null; if (!(date instanceof Date)) {
} if (typeof date == "number") {
const day = date.getDay() || 7; temp = new Date(date);
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + i - day); } else {
const s = date.replace(/-/g, "/");
temp = new Date(s);
}
} else {
temp = new Date(date.getTime())
}
if (i < 1 || i > 7) {
return null;
}
const day = temp.getDay() || 7;
return new Date(temp.getFullYear(), temp.getMonth(), temp.getDate() + i - day);
} }
/** /**
* *
* @returns * @returns
*/ */
const weekArray = ['周天', '周一', '周二', '周三', '周四', '周五', '周六']; const weekArray = ['周天', '周一', '周二', '周三', '周四', '周五', '周六'];
export function getCurrentDate(date: any) {
let myDate = new Date();
if (date) {
if (date instanceof Date) {
myDate = date;
} else {
date = date.replace(/-/g, '/');
myDate = new Date(date);
}
}
const days = myDate.getDay(); export function getCurrentDate(date: any) {
return weekArray[days]; let myDate = new Date();
if (date) {
if (date instanceof Date) {
myDate = date;
} else {
date = date.replace(/-/g, '/');
myDate = new Date(date);
}
}
const days = myDate.getDay();
return weekArray[days];
} }
/** /**
@ -78,17 +91,20 @@ export function getCurrentDate(date: any) {
* @returns * @returns
*/ */
export function getDays(date: any, days: number) { export function getDays(date: any, days: number) {
if (date) { if (date) {
if (!(date instanceof Date)) { let temp: any;
date = date.replace(/-/g, '/'); if (!(date instanceof Date)) {
date = new Date(date); date = date.replace(/-/g, '/');
} temp = new Date(date);
} else {
temp = new Date(date.getTime());
}
const time = date.setDate(date.getDate() + days); // 天数 const time = temp.setDate(temp.getDate() + days);
return new Date(time); return new Date(time);
} }
} }
export function getEndOfMonth(year: number, month: number) { export function getEndOfMonth(year: number, month: number) {
return new Date(year, month, 0).getDate() return new Date(year, month, 0).getDate()
} }

View File

@ -5,29 +5,47 @@ import * as CryptoJS from 'crypto-js';
* *
*/ */
export function encryption(src: string, keyWord: string) { export function encryption(src: string, keyWord: string) {
const key = CryptoJS.enc.Utf8.parse(keyWord); const key = CryptoJS.enc.Utf8.parse(keyWord);
// 加密 // 加密
let encrypted = CryptoJS.AES.encrypt(src, key, { const encrypted = CryptoJS.AES.encrypt(src, key, {
iv: key, iv: key,
mode: CryptoJS.mode.CBC, mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7, padding: CryptoJS.pad.Pkcs7,
}); });
return encrypted.toString(); return encrypted.toString();
} }
/** /**
* *
* @param {*} params
* @returns * @returns
* @param src
* @param keyWord
*/ */
export function decryption(src: string, keyWord: string) { export function decryption(src: string, keyWord: string) {
const key = CryptoJS.enc.Utf8.parse(keyWord); const key = keyWord;
// 解密逻辑 // 解密逻辑
let decryptd = CryptoJS.AES.decrypt(src, key, { const decryptd = CryptoJS.AES.decrypt(src, key, {
iv: key, iv: key,
mode: CryptoJS.mode.CBC, mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7, padding: CryptoJS.pad.Pkcs7,
}); });
return decryptd.toString(CryptoJS.enc.Utf8); return decryptd.toString(CryptoJS.enc.Utf8);
}
export function encrypt(src: string, key: string) {
return CryptoJS.AES.encrypt(src, key).toString()
}
export function decrypt(src: string, key: string) {
return CryptoJS.AES.decrypt(src, key).toString(CryptoJS.enc.Utf8)
}
export function isBase64(s: string) {
if (s == "" || s.trim() == "") return false;
try {
return window.btoa(window.atob(s)) == s;
} catch (e) {
return false;
}
} }

View File

@ -1,72 +1,75 @@
<template> <template>
<div class="home-page"> <div class="home-page">
<div class="background-box"> <div class="background-box">
<div class="left-content"> <div class="left-content">
<div class="message-box"> <div class="message-box">
<el-carousel height="32px" direction="vertical" indicator-position="none" autoplay> <el-carousel height="32px" direction="vertical" indicator-position="none" autoplay>
<el-carousel-item v-for="(item, index) in messages" :key="'message-' + index"> <el-carousel-item v-for="(item, index) in messages" :key="'message-' + index">
<p class="text-row-1" style="line-height: 32px;" :class="{'is-link': item.link}" @click="() => {item.link && router.push(item.link)}">{{ item.type }} {{ item.content }}</p> <p class="text-row-1" style="line-height: 32px;" :class="{'is-link': item.link}"
</el-carousel-item> @click="() => {item.link && router.push(item.link)}">{{ item.type }} {{ item.content }}</p>
</el-carousel> </el-carousel-item>
</div> </el-carousel>
<div class="header-box"> </div>
<div class="header-item"> <div class="header-box">
<span class="main-color f20" style="font-weight: 600;">{{ userInfo.name }}</span> <div class="header-item">
<span class="text2-color f14">{{ userInfo.permissions }}</span> <span class="main-color f20" style="font-weight: 600;">{{ userInfo.name }}</span>
</div> <span class="text2-color f14">{{ userInfo.permissions }}</span>
<div class="header-item"> </div>
<el-icon class="text1-color" style="font-size: 26px;margin-right: 20px;"> <div class="header-item">
<Calendar /> <el-icon class="text1-color" style="font-size: 26px;margin-right: 20px;">
</el-icon> <Calendar/>
<div> </el-icon>
<p class="text1-color f14">待办任务</p> <div>
<p class="main-color f20">{{ total }}</p> <p class="text1-color f14">待办任务</p>
</div> <p class="main-color f20">{{ total }}</p>
</div> </div>
</div> </div>
<div class="echart-box"> </div>
<div class="echart-item"> <div class="echart-box">
<NumberChart /> <div class="echart-item">
</div> <NumberChart/>
<div class="echart-item"> </div>
<NumberPieChart /> <div class="echart-item">
</div> <NumberPieChart/>
<div class="echart-item"> </div>
<TimeChart /> <div class="echart-item">
</div> <TimeChart/>
<div class="echart-item"> </div>
<TimeBarChart /> <div class="echart-item">
</div> <TimeBarChart/>
</div> </div>
</div> </div>
<div class="right-content"> </div>
<div class="week-calendar"> <div class="right-content">
<WeekCalendar /> <div class="week-calendar">
</div> <WeekCalendar/>
<div class="system-logs"> </div>
<div class="title"> <div class="system-logs">
<span>系统日志</span> <div class="title">
<span class="f14" style="cursor: pointer;" @click="router.push('./logs-manage/logs-manage')">更多</span> <span>系统日志</span>
</div> <span class="f14" style="cursor: pointer;" @click="router.push('./logs-manage/logs-manage')">更多</span>
<div class="content"> </div>
<SystemLogs /> <div class="content">
</div> <SystemLogs/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import { useRouter } from 'vue-router' import {useRouter} from 'vue-router'
import { useLoginStore } from '@/stores/user-info-store' import {useLoginStore} from '@/stores/user-info-store'
import NumberChart from "./number-chart.vue"; import NumberChart from "./number-chart.vue";
import NumberPieChart from "./number-pie-chart.vue"; import NumberPieChart from "./number-pie-chart.vue";
import TimeChart from "./time-chart.vue"; import TimeChart from "./time-chart.vue";
import TimeBarChart from "./time-bar-chart.vue"; import TimeBarChart from "./time-bar-chart.vue";
import WeekCalendar from "./week-calendar.vue"; import WeekCalendar from "./week-calendar.vue";
import SystemLogs from "@/components/system-logs.vue"; import SystemLogs from "@/components/system-logs.vue";
import * as dailyPlanApi from "@/api/daily-plan";
import {dateFormater} from "@/utils/date-util";
const router = useRouter() const router = useRouter()
@ -75,127 +78,153 @@ const userInfo = useLoginStore().getlogin()
const messages = ref([] as any) const messages = ref([] as any)
const total = ref(0) // const total = ref(0) //
messages.value.push({type: '通知', content: '测试测试测试测试测试测试测试测试测试测试', link: '/system-manage/system-home'}) messages.value.push({
messages.value.push({type: '公告', content: '公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试'}) type: '通知',
content: '测试测试测试测试测试测试测试测试测试测试',
link: '/system-manage/system-home'
})
messages.value.push({
type: '公告',
content: '公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试'
})
onMounted(() => {
getTodoCount();
})
function getTodoCount() {
dailyPlanApi.getTodoCountByDate(dateFormater("yyyy-MM-dd", new Date())).then((res: any) => {
if (res.code == 0) {
total.value = res.data;
}
});
}
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.home-page { .home-page {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 15px; padding: 15px;
overflow-y: auto; overflow-y: auto;
.background-box { .background-box {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: white; background: white;
padding: 20px 35px; padding: 20px 35px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
min-height: 900px; min-height: 900px;
} }
.left-content { .left-content {
width: calc(100% - 350px); width: calc(100% - 350px);
height: 100%; height: 100%;
.message-box {
height: 34px;
background: #f8f8f8;
color: $text-color;
padding: 0 30px;
border: 1px solid $border1-color;
margin-bottom: 20px;
.is-link {
cursor: pointer;
color: $main-color;
}
}
.header-box {
width: 100%;
height: 90px;
display: flex;
justify-content: space-between;
.header-item { .message-box {
width: calc(60% - 20px); height: 34px;
height: 100%; background: #f8f8f8;
border: 1px solid $border-color; color: $text-color;
border-radius: 5px; padding: 0 30px;
box-shadow: 1px 1px 5px $border2-color; border: 1px solid $border1-color;
padding: 0 90px; margin-bottom: 20px;
line-height: 1.5;
display: flex;
flex-direction: column;
justify-content: center;
&~.header-item { .is-link {
width: 40%; cursor: pointer;
flex-direction: row; color: $main-color;
justify-content: flex-start; }
align-items: center; }
}
}
}
.echart-box { .header-box {
width: 100%; width: 100%;
height: calc(100% - 164px); height: 90px;
margin-top: 20px; display: flex;
display: flex; justify-content: space-between;
flex-wrap: wrap;
justify-content: space-between;
.echart-item { .header-item {
width: calc(60% - 20px); width: calc(60% - 20px);
height: calc(50% - 10px); height: 100%;
border: 1px solid $border-color; border: 1px solid $border-color;
border-radius: 5px; border-radius: 5px;
padding: 20px; box-shadow: 1px 1px 5px $border2-color;
box-shadow: 1px 1px 5px $border2-color; padding: 0 90px;
line-height: 1.5;
display: flex;
flex-direction: column;
justify-content: center;
&:nth-child(even) { & ~ .header-item {
width: 40%; width: 40%;
} flex-direction: row;
&:nth-child(n + 3) { justify-content: flex-start;
margin-top: 20px; align-items: center;
} }
} }
} }
}
.right-content { .echart-box {
width: 330px; width: 100%;
height: 100%; height: calc(100% - 164px);
.week-calendar { margin-top: 20px;
width: 100%; display: flex;
height: 50%; flex-wrap: wrap;
} justify-content: space-between;
.system-logs {
width: 100%;
height: calc(50% - 20px);
margin-top: 20px;
overflow: hidden;
.title { .echart-item {
width: 100%; width: calc(60% - 20px);
height: 40px; height: calc(50% - 10px);
padding: 0 20px; border: 1px solid $border-color;
display: flex; border-radius: 5px;
justify-content: space-between; padding: 20px;
align-items: center; box-shadow: 1px 1px 5px $border2-color;
}
.content { &:nth-child(even) {
width: 100%; width: 40%;
height: calc(100% - 50px); }
margin-top: 10px;
border: 1px solid $border-color; &:nth-child(n + 3) {
padding: 30px; margin-top: 20px;
overflow-x: hidden; }
overflow-y: auto; }
} }
} }
}
.right-content {
width: 330px;
height: 100%;
.week-calendar {
width: 100%;
height: 50%;
}
.system-logs {
width: 100%;
height: calc(50% - 20px);
margin-top: 20px;
overflow: hidden;
.title {
width: 100%;
height: 40px;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.content {
width: 100%;
height: calc(100% - 50px);
margin-top: 10px;
border: 1px solid $border-color;
padding: 30px;
overflow-x: hidden;
overflow-y: auto;
}
}
}
}</style> }</style>

View File

@ -1,146 +1,173 @@
<template> <template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100"> <el-form ref="formRef" :model="formData" :rules="rules" label-width="100">
<el-form-item label="标题" prop="title"> <el-form-item label="标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入标题"></el-input> <el-input v-model="formData.title" placeholder="请输入标题"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="类型" prop="type"> <el-form-item label="类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择类型"> <el-select v-model="formData.type" placeholder="请选择类型">
<el-option v-for="item in typeOption" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in typeOption" :key="item.value" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="state" placeholder="请选择状态"> <el-form-item label="状态" prop="status" placeholder="请选择状态">
<el-select v-model="formData.state"> <el-select v-model="formData.status">
<el-option v-for="item in stateOption" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in stateOption" :key="item.value" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="日期" prop="date"> <el-form-item label="日期" prop="date">
<el-date-picker v-model="formData.date" type="date" placeholder="请输入日期" /> <el-date-picker v-model="formData.date" type="date" placeholder="请输入日期"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="时间" prop="time"> <el-form-item label="时间" prop="time">
<el-time-picker v-model="formData.time" placeholder="请输入时间" /> <el-time-picker v-model="formData.time" placeholder="请输入时间"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="内容" prop="content"> <el-form-item label="内容" prop="content">
<el-input v-model="formData.content" type="textarea" :rows="10" placeholder="请输入内容"></el-input> <el-input v-model="formData.content" type="textarea" :rows="10" placeholder="请输入内容"></el-input>
</el-form-item> </el-form-item>
<div style="text-align: right;" > <div style="text-align: right;">
<el-button v-if="formData.isSaveBtn" class="f18" type="primary" @click="saveData">保存</el-button> <el-button v-if="isSaveBtn" class="f18" type="primary" @click="saveData">保存</el-button>
<el-button v-if="formData.isRemoveBtn" class="f18" @click="removeData">删除</el-button> <el-button v-if="isRemoveBtn" class="f18" @click="removeData">删除</el-button>
</div> </div>
</el-form> </el-form>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, reactive, ref} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import {dateFormater} from "@/utils/date-util";
const emit = defineEmits(['close', 'saveData']) import * as dailyPlanApi from "@/api/daily-plan";
const emit = defineEmits(['close', 'saveData', "removeEvent"])
defineExpose({
resetData
})
const typeOption = [ const typeOption = [
{ label: '手术', value: '手术' }, {label: '手术', value: '手术'},
{ label: '会议', value: '会议' }, {label: '会议', value: '会议'},
] ]
const stateOption = [ const stateOption = [
{ label: '已处理', value: '已处理' }, {label: '已处理', value: '已处理'},
{ label: '未处理', value: '未处理' }, {label: '未处理', value: '未处理'},
] ]
const rules = reactive({ const rules = reactive({
title: [ title: [
{ required: true, message: '请输入标题', trigger: 'blur' }, {required: true, message: '请输入标题', trigger: 'blur'},
], ],
type: [ type: [
{ required: true, message: '请选择类型', trigger: 'blur' }, {required: true, message: '请选择类型', trigger: 'blur'},
], ],
state: [ status: [
{ required: true, message: '请选择状态', trigger: 'blur' }, {required: true, message: '请选择状态', trigger: 'blur'},
], ],
date: [ date: [
{ required: true, message: '请输入日期', trigger: 'blur' }, {required: true, message: '请输入日期', trigger: 'blur'},
], ],
time: [ time: [
{ required: true, message: '请输入时间', trigger: 'blur' }, {required: true, message: '请输入时间', trigger: 'blur'},
], ],
content: [ content: [
{ required: true, message: '请输入内容', trigger: 'blur' }, {required: true, message: '请输入内容', trigger: 'blur'},
] ]
}) })
const formRef = ref() const formRef = ref()
const formData = ref({ const formData = ref({
id: '', id: '',
title: '', title: '',
type: '', type: '',
state: '', status: '',
date: '', date: '',
time: '', time: '',
content: '', content: '',
isSaveBtn: true,
isRemoveBtn: true
}) })
const isSaveBtn = ref(true);
const isRemoveBtn = ref(true);
onMounted(() => { onMounted(() => {
formData.value = { formData.value = {
id: '', id: '',
title: '', title: '',
type: '', type: '',
state: '', status: '',
date: '', date: '',
time: '', time: '',
content: '', content: '',
isSaveBtn: true, }
isRemoveBtn: true
}
}) })
defineExpose({
formData,
resetData,
})
function close() { function close() {
emit('close') emit('close')
} }
function resetData() {
formRef.value.resetFields() function resetData(hasRmBtn: boolean, date?: string, form?: any) {
Object.assign(formData.value, { formRef.value.resetFields()
id: '', if (form) {
title: '', const tempForm = Object.assign({}, form);
type: '', const planDate = new Date(tempForm.date + " " + tempForm.time);
state: '', tempForm.date = planDate;
date: '', tempForm.time = planDate;
time: '', formData.value = tempForm;
content: '' } else {
}) Object.assign(formData.value, {
id: '',
title: '',
type: '',
status: '',
date: date ? date : '',
time: '',
content: ''
})
}
isRemoveBtn.value = hasRmBtn;
} }
const saveData = async () => {
await formRef.value.validate((valid: any, fields: any) => { const saveData = () => {
if (valid) { formRef.value.validate((valid: any, fields: any) => {
ElMessage.success('保存成功!') if (valid) {
emit('saveData', formData.value) const form = JSON.parse(JSON.stringify(formData.value));
close() form.time = dateFormater("HH:mm:ss", new Date(form.time));
} else { form.date = dateFormater("yyyy-MM-dd", new Date(form.date));
// console.log('error submit!', fields) dailyPlanApi.saveOrUpdate(form).then((res: any) => {
} if (res.code == 0) {
}) ElMessage.success('保存成功!');
emit('saveData', form);
close();
} else {
ElMessage.error(res.msg);
}
}).catch(error => {
ElMessage.error("服务端异常");
})
} else {
// console.log('error submit!', fields)
}
})
} }
const removeData = () => { const removeData = () => {
ElMessageBox.confirm( ElMessageBox.confirm(
'是否确认删除?', '是否确认删除?',
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
draggable: true draggable: true
} }
).then(() => { ).then(() => {
ElMessage.success('删除成功!') dailyPlanApi.deleteById(formData.value.id).then((res: any) => {
close() if (res.code == 0) {
}).catch(() => { }) ElMessage.success('删除成功!');
close();
emit("removeEvent");
} else {
ElMessage.error(res.msg);
}
});
}).catch(() => {
ElMessage.error("服务器异常");
})
} }
</script> </script>

View File

@ -1,304 +1,334 @@
<template> <template>
<div class="week-calendar-part"> <div class="week-calendar-part">
<div class="header-box"> <div class="header-box">
<el-icon @click="setWeek('up')"> <el-icon @click="minusWeek()">
<ArrowLeft /> <ArrowLeft/>
</el-icon> </el-icon>
<div class="date-block"> <div class="date-block">
<span @click="handleOpen">{{ formatDate(month) }}</span> <span @click="handleDatePickerOpen">{{ getMonthTitle() }}</span>
<el-date-picker ref="datePicker" popper-class="week-calendar-picker" class="month-date-pick" v-model="month" <el-date-picker ref="datePickerRef"
type="month" @change="setWeek()" /> popper-class="week-calendar-picker"
</div> class="month-date-pick"
<el-icon @click="setWeek('down')"> v-model="month"
<ArrowRight /> type="month"
</el-icon> @change="setMonthWeek()"/>
</div> </div>
<div class="week-box"> <el-icon @click="addWeek()">
<table> <ArrowRight/>
<tr class="text1-color"> </el-icon>
<th v-for="item in weekEn" :key="item">{{ item }}</th> </div>
</tr> <div class="week-box">
<tr v-if="week.length > 0" class=""> <table>
<td v-for="item in week" :key="item" :class="{ <tr class="text1-color">
'record-mark': recordWeek.some((r: any) => dateFormater('yyyy-MM-dd', r.date) === dateFormater('yyyy-MM-dd', item)), <th v-for="item in weekCn" :key="item">{{ item }}</th>
'active': dateFormater('yyyy-MM-dd', item) === dateFormater('yyyy-MM-dd', currentDate) </tr>
}"> <tr v-if="week.length > 0" class="">
<td v-for="item in week" :key="item"
:class="{
'record-mark': recordWeek.some((r: any) => r == dateFormater('yyyy-MM-dd', item)),
'active':
dateFormater('yyyy-MM-dd', item) == dateFormater('yyyy-MM-dd', currentDate)}">
<span :class="{ <span :class="{
'text2-color': item.getDate() > week[6].getDate() 'text2-color': item.getDate() > week[6].getDate()
}" @click="setDate(item)">{{ dateFormater('dd', item) }}</span> }" @click="setDate(item)">{{ dateFormater('dd', item) }}</span>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
<el-button text icon="Plus" style="width: 100%;margin-bottom: 5px;" @click="addRecord()">新建</el-button> <el-button text icon="Plus" style="width: 100%;margin-bottom: 5px;" @click="addRecord()">新建</el-button>
<div class="record-box "> <div class="record-box ">
<el-empty v-if="record.length < 1" :description="dateFormater('MM月dd日', currentDate) + '没有任何记录'" style="padding: 0;" /> <el-empty v-if="record.length < 1" :description="dateFormater('MM月dd日', currentDate) + '没有任何记录'"
<div class="record-item" v-for="(item, index) in record" :key="'record-' + index" @click="viewRecord(item)"> style="padding: 0;"/>
<div class="icon-box"> <div class="record-item" v-for="(item, index) in record" :key="'record-' + index" @click="viewRecord(item)">
<i class="icon-RectangleCopy"></i> <div class="icon-box">
</div> <i class="icon-RectangleCopy"></i>
<div class="text-box"> </div>
<p class="main-color" style="font-weight: 600;cursor: pointer;">{{ <div class="text-box">
item.title }}</p> <p class="main-color" style="font-weight: 600;cursor: pointer;">{{
<p p class=" text2-color font14">{{ dateFormater('yyyy-MM-dd HH:mm:ss', item.time) }}</p> item.title
</div> }}</p>
<el-icon class="remove-icon" @click.stop="remoteRecord(item, index)"> <p p class=" text2-color font14">{{ item.date + " " + item.time }}</p>
<Close /> </div>
</el-icon> <el-icon class="remove-icon" @click.stop="remoteRecord(item, index)">
</div> <Close/>
</div> </el-icon>
</div>
</div>
<el-dialog v-model="isRecordDialog" title="详情"> <el-dialog v-model="isRecordDialog" title="详情">
<RecordForm ref="recordFormRef" @close="isRecordDialog = false" @saveData="saveData" /> <RecordForm ref="recordFormRef" @remove-event="planRemoveEvent" @close="isRecordDialog = false"
</el-dialog> @saveData="saveData"/>
</div> </el-dialog>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import RecordForm from './record-form.vue' import RecordForm from './record-form.vue'
import { ElMessage, ElMessageBox } from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import { dateFormater, getFirstDayOfWeek, getDays } from '@/utils/date-util' import {dateFormater, getDays, getFirstDayOfWeek} from '@/utils/date-util'
import * as dailyPlanApi from "@/api/daily-plan";
const monthCn = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
const weekCn = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const datePickerRef = ref();
const recordFormRef = ref();
const isRecordDialog = ref(false);
const month = ref(new Date());
const week = ref([] as any);
const recordWeek = ref([] as any);
const record = ref([] as any);
const currentDate = ref<Date>(new Date());
const monthEn = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'] onMounted(init)
const weekEn = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
const datePicker = ref() function init() {
const recordFormRef = ref() setMonthWeek();
const isRecordDialog = ref(false)
const month = ref(new Date())
const week = ref([] as any)
const recordWeek = ref([] as any)
const record = ref([] as any)
const currentDate = ref<Date>(new Date())
setWeek()
function formatDate(date: any) {
return monthEn[new Date(date).getMonth()] + '月 ' + new Date(date).getFullYear()
} }
function getMonthTitle() {
return monthCn[new Date(month.value).getMonth()] + '月 ' + new Date(month.value).getFullYear();
}
function addWeek() {
const date: any = getDays(month.value, 7);
month.value = date;
setWeek(date);
}
function minusWeek() {
const date: any = getDays(month.value, -7);
month.value = date;
setWeek(date);
}
function setMonthWeek() {
setWeek(month.value);
setDate(month.value);
}
/** /**
* 设置周 * 设置周
* @param type * @param type
* 获取一周的数据然后给每天打 record-mark 标记 * 获取一周的数据然后给每天打 record-mark 标记
*/ */
function setWeek(type?: 'up' | 'down') { function setWeek(date: any) {
const date = (type && getDays(month.value, type === 'up' ? -7 : 7)) || month.value week.value = [];
currentDate.value = date setTimeout(() => {
const e = date for (let i = 0; i < 7; i++) {
week.value = [] week.value.push(getFirstDayOfWeek(date, i + 1));
recordWeek.value = [] }
recordWeek.value = [ getWeekPlanList(week.value[0], week.value[6]);
{ }, 0)
id: '1',
title: '月度会议',
type: '',
state: '',
date: getFirstDayOfWeek(e, 1),
time: getFirstDayOfWeek(e, 1),
content: '测试测试'
},
{
id: '2',
title: '手术提醒',
type: '',
state: '',
date: getFirstDayOfWeek(e, 4),
time: getFirstDayOfWeek(e, 4),
content: '测试测试'
}
]
//
setTimeout(() => {
for (let i = 0; i < 7; i++) {
week.value.push(getFirstDayOfWeek(date, i + 1))
}
}, 0)
setDate(currentDate.value)
} }
const handleOpen = () => { function getWeekPlanList(startDate: any, endDate: any) {
datePicker.value.handleOpen() recordWeek.value = [];
dailyPlanApi.getPlanDateList(dateFormater("yyyy-MM-dd", startDate),
dateFormater("yyyy-MM-dd", endDate)).then((res: any) => {
if (res.code == 0) {
recordWeek.value = res.data;
}
});
} }
const handleDatePickerOpen = () => {
datePickerRef.value.handleOpen();
}
function setDate(e: Date) { function setDate(e: Date) {
currentDate.value = e currentDate.value = e
record.value = recordWeek.value.filter((r: any) => dateFormater('yyyy-MM-dd', r.date) === dateFormater('yyyy-MM-dd', e)) getWeekPlanList(week.value[0], week.value[6]);
getDatePlanList();
} }
function getDatePlanList() {
dailyPlanApi.getDailyPlanList(dateFormater("yyyy-MM-dd", currentDate.value)).then((res: any) => {
if (res.code == 0) {
record.value = res.data;
}
});
}
const addRecord = () => { const addRecord = () => {
const e = currentDate.value || new Date() const e = currentDate.value || new Date()
isRecordDialog.value = true isRecordDialog.value = true
setTimeout(() => { setTimeout(() => {
recordFormRef.value.resetData() recordFormRef.value.resetData(false, dateFormater("yyyy-MM-dd", e));
recordFormRef.value.formData.date = e }, 0)
recordFormRef.value.formData.isRemoveBtn = false
}, 0)
} }
const viewRecord = (e: any) => { const viewRecord = (e: any) => {
isRecordDialog.value = true isRecordDialog.value = true
setTimeout(() => { setTimeout(() => {
recordFormRef.value.resetData() recordFormRef.value.resetData(true, null, e);
recordFormRef.value.formData = Object.assign({}, recordFormRef.value.formData, e) }, 0)
recordFormRef.value.formData.isRemoveBtn = true
// console.log(recordFormRef.value.formData)
}, 0)
} }
const remoteRecord = (item: any, index: number) => { const remoteRecord = (item: any, index: number) => {
ElMessageBox.confirm( ElMessageBox.confirm(
'是否确认删除?', '是否确认删除?',
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
draggable: true draggable: true
} }
).then(() => { ).then(() => {
ElMessage.success('删除成功!') dailyPlanApi.deleteById(item.id).then((res: any) => {
recordWeek.value = recordWeek.value.filter((r: any) => r.id !== item.id) if (res.code == 0) {
setDate(item.date) ElMessage.success('删除成功!');
}).catch(() => { }) setDate(item.date);
} else {
ElMessage.error(res.msg);
}
}).catch(err => {
ElMessage.error("服务器异常");
})
})
} }
const saveData = (e: any) => { const saveData = (e: any) => {
recordWeek.value.push(e) setDate(new Date(e.date));
setDate(e.date) }
const planRemoveEvent = () => {
setDate(currentDate.value)
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.week-calendar-part { .week-calendar-part {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
.header-box { .header-box {
width: 100%; width: 100%;
height: 50px; height: 50px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
.el-icon { .el-icon {
cursor: pointer; cursor: pointer;
} }
.date-block { .date-block {
position: relative; position: relative;
&>span { & > span {
cursor: pointer; cursor: pointer;
} }
:deep(.month-date-pick) { :deep(.month-date-pick) {
position: absolute; position: absolute;
width: 0; width: 0;
height: 0; height: 0;
bottom: 0; bottom: 0;
left: 50%; left: 50%;
overflow: hidden; overflow: hidden;
} }
} }
} }
.week-box { .week-box {
width: 100%; width: 100%;
height: 80px; height: 80px;
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
table { table {
width: 100%; width: 100%;
height: 80px; height: 80px;
text-align: center; text-align: center;
tr { tr {
td { td {
font-weight: 600; font-weight: 600;
color: black; color: black;
span { span {
cursor: pointer; cursor: pointer;
width: 30px; width: 30px;
height: 30px; height: 30px;
border: 2px solid transparent; border: 2px solid transparent;
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
margin: 0 auto; margin: 0 auto;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
transition: all .3s; transition: all .3s;
&:hover { &:hover {
background: rgba($main-color, .1); background: rgba($main-color, .1);
transition: all .3s; transition: all .3s;
} }
} }
} }
.record-mark { .record-mark {
color: $main-color; color: $main-color;
span { span {
border-color: $main-color; border-color: $main-color;
} }
} }
.active { .active {
color: white; color: white;
span { span {
color: white; color: white;
border-color: $main-color; border-color: $main-color;
background: $main-color; background: $main-color;
&:hover { &:hover {
background: rgba($main-color, .8); background: rgba($main-color, .8);
} }
} }
} }
} }
} }
} }
.record-box { .record-box {
width: 100%; width: 100%;
height: calc(100% - 170px); height: calc(100% - 170px);
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
.record-item { .record-item {
position: relative; position: relative;
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 10px 20px; padding: 10px 20px;
transition: all .6s; transition: all .6s;
&:hover { &:hover {
background: rgba($main-color, .1); background: rgba($main-color, .1);
transition: all .6s; transition: all .6s;
} }
.icon-box { .icon-box {
flex-shrink: 0; flex-shrink: 0;
width: 50px; width: 50px;
height: 50px; height: 50px;
border-radius: 8px; border-radius: 8px;
background: rgba($main-color, .1); background: rgba($main-color, .1);
color: $main-color; color: $main-color;
font-size: 32px; font-size: 32px;
text-align: center; text-align: center;
line-height: 50px; line-height: 50px;
margin-right: 15px; margin-right: 15px;
} }
.remove-icon { .remove-icon {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
font-size: 20px; font-size: 20px;
top: calc(50% - 10px); top: calc(50% - 10px);
right: 20px; right: 20px;
color: $text3-color; color: $text3-color;
} }
} }
} }
} }
</style> </style>

View File

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

View File

@ -8,120 +8,120 @@
</el-select> </el-select>
</div> </div>
<img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png"> <img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png">
<div v-if="!isShowRegister" class="login-block move_2"> <div v-if="!isShowRegister" class="login-block move_2">
<div class="login-way"> <div class="login-way">
<span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span> <span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span>
<span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span> <span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span>
</div> </div>
<el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small"> <el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small">
<div class="login-form password-login" v-if="passwordLogin"> <div class="login-form password-login" v-if="passwordLogin">
<el-form-item prop="account"> <el-form-item prop="account">
<el-input v-model="loginParams.account" placeholder="请输入用户名"> <el-input v-model="loginParams.account" placeholder="请输入用户名">
<template #prepend> <template #prepend>
<el-icon> <el-icon>
<User/> <User/>
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码"> <el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码">
<template #prepend> <template #prepend>
<el-icon> <el-icon>
<Lock/> <Lock/>
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button> <el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button>
<span class="register-btn" @click="getCaptchaCode()">注册账号</span> <span class="register-btn" @click="getCaptchaCode()">注册账号</span>
</div> </div>
<div class="login-form code-login" v-else> <div class="login-form code-login" v-else>
<el-form-item prop="phone"> <el-form-item prop="phone">
<el-input v-model="loginParams.phone" placeholder="请输入手机号"> <el-input v-model="loginParams.phone" placeholder="请输入手机号">
<template #prepend> <template #prepend>
<div @click.stop style="display: flex;align-items: center;"> <div @click.stop style="display: flex;align-items: center;">
<el-dropdown @command="selectPhoneArea"> <el-dropdown @command="selectPhoneArea">
<span style="color: #909399;">{{ loginParams.phoneArea }}<el-icon> <span style="color: #909399;">{{ loginParams.phoneArea }}<el-icon>
<DCaret/> <DCaret/>
</el-icon></span> </el-icon></span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item v-for="item in phoneAreas" :command="item">{{ <el-dropdown-item v-for="item in phoneAreas" :command="item">{{
item item
}} }}
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
</div> </div>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="code"> <el-form-item prop="code">
<el-input v-model="loginParams.code" placeholder="请输入6位短信验证码"> <el-input v-model="loginParams.code" placeholder="请输入6位短信验证码">
<template #append> <template #append>
<span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span> <span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-button class="login-btn" type="primary" @click="login('code')">登录</el-button> <el-button class="login-btn" type="primary" @click="login('code')">登录</el-button>
</div> </div>
</el-form> </el-form>
</div> </div>
<div v-else class="register-block move_2"> <div v-else class="register-block move_2">
<div class="header-box"> <div class="header-box">
<span class="title">新用户申请</span> <span class="title">新用户申请</span>
<el-icon @click="isShowRegister = false"> <el-icon @click="isShowRegister = false">
<Close/> <Close/>
</el-icon> </el-icon>
</div> </div>
<el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100"> <el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100">
<el-form-item label="用户名" prop="username"> <el-form-item label="用户名" prop="username">
<el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input> <el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="密码" prop="password"> <el-form-item label="密码" prop="password">
<el-input v-model="registerParams.password" type="password" show-password <el-input v-model="registerParams.password" type="password" show-password
placeholder="请输入密码"></el-input> placeholder="请输入密码"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="姓名" prop="name"> <el-form-item label="姓名" prop="name">
<el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input> <el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="手机号" prop="phone"> <el-form-item label="手机号" prop="phone">
<el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input> <el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="医院" prop="hospital"> <el-form-item label="医院" prop="hospital">
<el-select v-model="registerParams.hospital" style="width: 100%;"> <el-select v-model="registerParams.hospital" style="width: 100%;">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name" <el-option v-for="item in hospitals" :key="item.id" :label="item.name"
:value="item.id"/> :value="item.id"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="性别" prop="sex"> <el-form-item label="性别" prop="sex">
<el-radio-group v-model="registerParams.sex"> <el-radio-group v-model="registerParams.sex">
<el-radio label="男"/> <el-radio label="男"/>
<el-radio label="女"/> <el-radio label="女"/>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="验证码" prop="code"> <el-form-item label="验证码" prop="code">
<el-input v-model="registerParams.code" placeholder="请输入验证码" <el-input v-model="registerParams.code" placeholder="请输入验证码"
style="width: calc(100% - 110px);"></el-input> style="width: calc(100% - 110px);"></el-input>
<img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/> <img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/>
<a class="change_img" @click="refreshImg" href="#">看不清</a> <a class="change_img" @click="refreshImg" href="#">看不清</a>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="footer-box"> <div class="footer-box">
<el-button type="primary" @click="register"> </el-button> <el-button type="primary" @click="register"> </el-button>
<span @click="isShowRegister = false">已有账号?</span> <span @click="isShowRegister = false">已有账号?</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl" <SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl"
:height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify> :height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
@ -313,21 +313,20 @@ const sendCode = () => {
}, 1000); }, 1000);
} }
const login = async (type: string) => { const login = async (type: string) => {
//: //:
loading.value=true; loading.value = true;
const obj = loginParams.value /*if (!currentHospital.value) {
if (!currentHospital.value) { ElMessage.warning('请在右上角选择院区')
ElMessage.warning('请在右上角选择院区') return
return }*/
} //:
//: loading.value = true;
loading.value = true; //
// await loginFormRef.value.validate((valid: any, fields: any) => {
await loginFormRef.value.validate((valid: any, fields: any) => { if (valid) {
if (valid) { sliderVConf.value.isShowSelf = true;
sliderVConf.value.isShowSelf = true; }
} })
})
} }
@ -353,50 +352,28 @@ function sliderSuccess() {
loading.value = false loading.value = false
} else { } else {
// token // token
Session.set('token', data.access_token); console.log(data)
Session.set('refresh_token', data.refresh_token); ElNotification({
console.log(data) type: 'success',
toHome() message: '欢迎回来',
} title: `HI,${getTime()}`
}) });
loginPost(data)
router.push('/home')
}
})
} }
function sliderClose() { function sliderClose() {
loading.value = false loading.value = false
} }
const toHome = () => { const loginPost = (data: any) => {
Session.set('token', data.access_token);
ElNotification({ Session.set('refresh_token', data.refresh_token);
type: 'success', useLoginStore().setlogin('account', data.username)
message: '欢迎回来', console.log(data)
title: `HI,${getTime()}` useLoginStore().setlogin('name', data.user_info.name || '暂未设置姓名')
});
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')
} }
</script> </script>

View File

@ -1,197 +1,181 @@
<template> <template>
<div class="chart-dom-box"> <div class="chart-dom-box">
<div ref="chartDom" style="width: 100%; height: 100%"></div> <div ref="chartDom" style="width: 100%; height: 100%"></div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from 'vue'; import {onMounted, ref} from 'vue';
import * as echarts from 'echarts'; 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 chartDom = ref();
const props = withDefaults(defineProps<{ names?: string[] }>(), {
interface Props { names: ['CH1', 'CH2']
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();
}); });
defineExpose({ defineExpose({
updateChart, updateChartData
chartSet
}); });
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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.chart-dom-box { .chart-dom-box {
position: relative; position: relative;
.chart-rate { .chart-rate {
position: absolute; position: absolute;
top: 5px; top: 5px;
left: 30px; left: 30px;
color: #285e7d; color: #285e7d;
font-size: 16px; font-size: 16px;
line-height: 30px; line-height: 30px;
font-weight: 600; font-weight: 600;
} }
} }
</style> </style>

View File

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

View File

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

View File

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

View File

@ -1,73 +1,101 @@
<template> <template>
<el-dialog class="header-none" v-model="dialogVisible" :width="700" :show-close="false"> <el-dialog class="header-none" v-model="dialogVisible" :width="700" :show-close="false">
<div class="content-box"> <div class="content-box">
<img src="@/assets/imgs/remote/remote_bck.png"> <img src="@/assets/imgs/remote/remote_bck.png">
<div class="info"> <div class="info">
<h3>连接云服务器</h3> <h3>连接云服务器</h3>
<br> <br>
<p><strong>云服务器连接状态{{ patientInfo.isRemote ? '已连接' : '未连接' }}</strong></p> <p>云服务器连接状态{{ patientInfo.isRemote ? '已连接' : '未连接' }}</p>
<p>输入用户名{{ patientInfo.serverUser }}</p> <!-- <p>输入用户名{{ patientInfo.serverun }}</p>
<p>密码*********</p> <p>密码*********</p>
<br> <br>-->
<p class="input-box"><span>输入病人姓名</span><el-input v-model="patientInfo.patientName"></el-input></p> <p class="input-box"><span>输入病人姓名</span>
<p class="input-box"><span>输入病人住院号</span><el-input v-model="patientInfo.patientCode"></el-input></p> <el-input v-model="patientInfo.patient"></el-input>
</p>
</div> <p class="input-box"><span>输入病人身份证号</span>
</div> <el-input v-model="patientInfo.patientId"></el-input>
<div class="btn-box"> </p>
<el-button class="f18" type="primary" @click="confirmRemote">确定连接</el-button> <p class="input-box"><span>请选择手术时间</span>
<!-- <el-button class="f18" @click="breakRemote">断开连接</el-button> --> <el-date-picker
<el-button class="f18" style="margin-left: 50px;" @click="dialogVisible = false">返回</el-button> v-model="patientInfo.date"
</div> type="date"
</el-dialog> 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> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {ref} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import {ElMessage} from 'element-plus'
import { useRouter } from 'vue-router' import {useRemoteWsStore} from "@/stores/remote-ws-store";
import { useRemoteStore } from '@/stores/remote-info-store'; import {dateFormater} from "@/utils/date-util";
import type { RemoteItem } from '@/utils/public-interface';
const router = useRouter()
const emit = defineEmits(['confirmRemote', 'errorRemote', 'breakRemote']) const emit = defineEmits(['confirmRemote', 'errorRemote', 'breakRemote'])
const dialogVisible = ref(false) const dialogVisible = ref(false)
const patientInfo = ref({} as RemoteItem) const patientInfo = ref({} as any)
const remoteWsStore = useRemoteWsStore();
defineExpose({ defineExpose({
open, open,
close, close,
})
onMounted(() => {
}) })
function open(e: RemoteItem) { function open(e: number) {
patientInfo.value = JSON.parse(JSON.stringify(e)) patientInfo.value = remoteWsStore.remoteTasks[e]
dialogVisible.value = true dialogVisible.value = true
} }
function close() { function close() {
dialogVisible.value = false dialogVisible.value = false
} }
const confirmRemote = () => { const confirmRemote = () => {
if(patientInfo.value.patientCode) { if (patientInfo.value.patientId && patientInfo.value.patient) {
ElMessage.success('连接成功!') ElMessage.success('连接成功!')
patientInfo.value.isRemote = true patientInfo.value.isRemote = true
patientInfo.value.title = '远程控制' + (patientInfo.value.index + 1) patientInfo.value.taskName = '远程控制' + (patientInfo.value.index + 1)
emit('confirmRemote', patientInfo.value) patientInfo.value.date = dateFormater("yyyy-MM-dd", patientInfo.value.date)
close() unsubscribeLastTask();
}else{ remoteWsStore.$patch({currentTaskIndex: patientInfo.value.index})
ElMessage.error('连接失败!') remoteWsStore.setRemoteLog({
emit('errorRemote', patientInfo.value) 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 = () => { const breakRemote = () => {
ElMessage.info('连接已断开!') ElMessage.info('连接已断开!')
emit('breakRemote', patientInfo.value) emit('breakRemote', patientInfo.value)
close() close()
}
const unsubscribeLastTask = () => {
const lastTaskIndex = remoteWsStore.currentTaskIndex;
const lastTask: any = remoteWsStore.remoteTasks[lastTaskIndex];
if (lastTask) {
remoteWsStore.unsubscribeVital(lastTask.patient, lastTask.patientId, lastTask.date);
}
} }
</script> </script>
@ -116,6 +144,7 @@ const breakRemote = () => {
} }
} }
} }
.btn-box { .btn-box {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

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

View File

@ -1,377 +1,415 @@
<template> <template>
<div class="remote-part"> <div class="remote-part">
<div class="title"> <div class="title">
<span>{{ remoteItem?.title || '远程控制' }}</span> <span>{{ remoteItem?.taskName || '远程控制' }}</span>
<el-button v-if="remoteItem" class="break-btn" @click="breakRemote">断开连接</el-button> <el-button v-if="remoteItem?.taskName" class="break-btn" @click="breakRemote">断开连接</el-button>
</div> </div>
<!-- 小分辨率 --> <!-- 小分辨率 -->
<div v-if="mediaMini800" class="content mini" :class="{'is-total': remoteItem?.isRemote}"> <div v-if="mediaMini800" class="content mini" :class="{'is-total': remoteItem?.isRemote}">
<div class="left-box"> <div class="left-box">
<div class="info-box"> <div class="info-box">
<div class="row-item"> <div class="row-item">
<span class="label">病人名称</span> <span class="label">病人名称</span>
<span class="input-value">{{ patientInfo.name }}</span> <span class="input-value">{{ remoteItem.patient }}</span>
</div> </div>
<div class="row-item"> <div class="row-item">
<span class="label">住院号</span> <span class="label">住院号</span>
<span class="input-value">{{ patientInfo.code }}</span> <span class="input-value">{{ remoteItem.patientId }}</span>
</div> </div>
<div class="row-item"> <div class="row-item">
<span class="label">手术时间</span> <span class="label">手术时间</span>
<span class="input-value">{{ patientInfo.time && dateFormater('yyyy-MM-dd HH:mm:ss', patientInfo.time) }}</span> <span class="input-value">{{
</div> remoteItem.date
<div class="row-item"> }}</span>
<span class="label">手术状态</span> </div>
<span class="tag-value" :class="{'normal': !patientInfo.state}">正常</span> <div class="row-item">
<span class="tag-value" :class="{'alarm': patientInfo.state}">异常</span> <span class="label">手术状态</span>
</div> <span class="tag-value" :class="{'normal': !patientInfo.state}">正常</span>
</div> <span class="tag-value" :class="{'alarm': patientInfo.state}">异常</span>
<div class="row-item" :class="{'alarm': patientInfo.BIS < 40 || patientInfo.BIS > 60}"> </div>
<span class="label">BIS</span> </div>
<span class="value">{{ patientInfo.BIS }}</span> <div class="row-item" :class="{'alarm': patientInfo.BIS_except}">
</div> <span class="label">BIS</span>
<div class="row-item" :class="{'alarm': patientInfo.SBP < 90 || patientInfo.SBP > 120}"> <span class="value">{{ patientInfo.BIS }}</span>
<span class="label">SBP</span> </div>
<span class="value">{{ patientInfo.SBP }}<span class="unit">mmHg</span></span> <div class="row-item" :class="{'alarm': patientInfo.SBP_except}">
</div> <span class="label">SBP</span>
<div class="row-item"> <span class="value">{{ patientInfo.SBP }}<span class="unit">mmHg</span></span>
<span class="label">SPO2</span> </div>
<span class="value">{{ patientInfo.SPO2 }}</span> <div class="row-item">
</div> <span class="label">SPO2</span>
<div class="row-item yellow" :class="{'alarm': patientInfo.DBP < 60 || patientInfo.DBP > 90}"> <span class="value">{{ patientInfo.SPO2 }}</span>
<span class="label">DBP</span> </div>
<span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span> <div class="row-item yellow" :class="{'alarm': patientInfo.DBP_except}">
</div> <span class="label">DBP</span>
<div class="row-item yellow" :class="{'alarm': patientInfo.HR < 50 || patientInfo.HR > 80}"> <span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span>
<span class="label">HR</span> </div>
<span class="value">{{ patientInfo.HR }}<span class="unit">/</span></span> <div class="row-item yellow" :class="{'alarm': patientInfo.HR_except}">
</div> <span class="label">HR</span>
<div class="row-item yellow"> <span class="value">{{ patientInfo.HR }}<span class="unit">/</span></span>
<span class="label">TEMP</span> </div>
<span class="value">{{ patientInfo.TEMP }}</span> <div class="row-item yellow">
</div> <span class="label">TEMP</span>
</div> <span class="value">{{ patientInfo.TEMP }}</span>
<div class="center-box"> </div>
<img src="@/assets/imgs/main_body_intact.png"> </div>
</div> <div class="center-box">
</div> <img src="@/assets/imgs/main_body_intact.png">
<div v-else class="content" :class="{'is-total': remoteItem?.isRemote}"> </div>
<div class="left-box"> </div>
<div class="info-box"> <div v-else class="content" :class="{'is-total': remoteItem?.isRemote}">
<div class="row-item"> <div class="left-box">
<span class="label">病人名称</span> <div class="info-box">
<span class="input-value">{{ patientInfo.name }}</span> <div class="row-item">
</div> <span class="label">病人名称</span>
<div class="row-item"> <span class="input-value">{{ remoteItem.patient }}</span>
<span class="label">住院号</span> </div>
<span class="input-value">{{ patientInfo.code }}</span> <div class="row-item">
</div> <span class="label">住院号</span>
</div> <span class="input-value">{{ remoteItem.patientId }}</span>
<div class="row-item" :class="{'alarm': patientInfo.BIS < 40 || patientInfo.BIS > 60}"> </div>
<span class="label">BIS</span> </div>
<span class="value">{{ patientInfo.BIS }}</span> <div class="row-item" :class="{'alarm': patientInfo.BIS_except}">
</div> <span class="label">BIS</span>
<div class="row-item" :class="{'alarm': patientInfo.SBP < 90 || patientInfo.SBP > 120}"> <span class="value">{{ patientInfo.BIS }}</span>
<span class="label">SBP</span> </div>
<span class="value">{{ patientInfo.SBP }}<span class="unit">mmHg</span></span> <div class="row-item" :class="{'alarm': patientInfo.SBP_except}">
</div> <span class="label">SBP</span>
<div class="row-item"> <span class="value">{{ patientInfo.SBP }}<span class="unit">mmHg</span></span>
<span class="label">SPO2</span> </div>
<span class="value">{{ patientInfo.SPO2 }}</span> <div class="row-item">
</div> <span class="label">SPO2</span>
</div> <span class="value">{{ patientInfo.SPO2 }}</span>
<div class="center-box"> </div>
<img src="@/assets/imgs/main_body_intact.png"> </div>
</div> <div class="center-box">
<div class="right-box"> <img src="@/assets/imgs/main_body_intact.png">
<div class="info-box"> </div>
<div class="row-item"> <div class="right-box">
<span class="label">手术时间</span> <div class="info-box">
<span class="input-value">{{ patientInfo.time && dateFormater('yyyy-MM-dd HH:mm:ss', patientInfo.time) }}</span> <div class="row-item">
</div> <span class="label">手术时间</span>
<div class="row-item"> <span class="input-value">{{
<span class="label">手术状态</span> remoteItem.date
<span class="tag-value" :class="{'normal': !patientInfo.state}">正常</span> }}</span>
<span class="tag-value" :class="{'alarm': patientInfo.state}">异常</span> </div>
</div> <div class="row-item">
</div> <span class="label">手术状态</span>
<div class="row-item" :class="{'alarm': patientInfo.DBP < 60 || patientInfo.DBP > 90}"> <span class="tag-value" :class="{'normal': !patientInfo.state}">正常</span>
<span class="label">DBP</span> <span class="tag-value" :class="{'alarm': patientInfo.state}">异常</span>
<span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span> </div>
</div> </div>
<div class="row-item" :class="{'alarm': patientInfo.HR < 50 || patientInfo.HR > 80}"> <div class="row-item" :class="{'alarm': patientInfo.DBP_except}">
<span class="label">HR</span> <span class="label">DBP</span>
<span class="value">{{ patientInfo.HR }}<span class="unit">/</span></span> <span class="value">{{ patientInfo.DBP }}<span class="unit">mmHg</span></span>
</div> </div>
<div class="row-item"> <div class="row-item" :class="{'alarm': patientInfo.HR_except}">
<span class="label">TEMP</span> <span class="label">HR</span>
<span class="value">{{ patientInfo.TEMP }}</span> <span class="value">{{ patientInfo.HR }}<span class="unit">/</span></span>
</div> </div>
</div> <div class="row-item">
</div> <span class="label">TEMP</span>
</div> <span class="value">{{ patientInfo.TEMP }}</span>
</div>
</div>
</div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, onBeforeUnmount, reactive, ref, toRefs, watch } from 'vue' import {onUnmounted, ref} from 'vue'
import { dateFormater } from '@/utils/date-util' import {useRemoteWsStore} from "@/stores/remote-ws-store";
import { useRemoteStore } from '@/stores/remote-info-store';
import type { RemoteItem, PatientInfoItem } from '@/utils/public-interface'
import { setRemoteLog } from '@/static-data/core'
const emit = defineEmits(['addLogAfter', 'breakRemote']) const emit = defineEmits(['addLogAfter', 'breakRemote'])
const remoteStore = useRemoteStore()
let timer = 0
const mediaMini800 = ref(false) const mediaMini800 = ref(false)
const remoteItem = ref<RemoteItem>({} as RemoteItem) const remoteItem = ref({} as any)
const patientInfo = ref({} as PatientInfoItem) const patientInfo = ref({} as any)
const remoteWsStore = useRemoteWsStore()
initData(remoteStore.currentRemote)
defineExpose({ defineExpose({
initData initData, showData
})
onBeforeUnmount(() => {
//
clearInterval(timer)
})
window.addEventListener('resize', () => {
mediaMini800.value = Boolean(window.innerWidth < 801)
}); });
function initData(e?: RemoteItem) { window.addEventListener('resize', () => {
const obj = e || {} as RemoteItem mediaMini800.value = Boolean(window.innerWidth < 801)
remoteItem.value = obj });
patientInfo.value.state = obj.dataAlarm
patientInfo.value.name = obj.patientName || '' onUnmounted(() => {
patientInfo.value.code = 'XXXXXX' remoteWsStore.unsubscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date);
clearInterval(timer) })
if(!patientInfo.value.name) return
timer = setInterval(() => { function showData(i: number) {
getData() const lastTaskIndex = remoteWsStore.currentTaskIndex;
}, 2000) 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() { function getData() {
remoteItem.value.dataAlarm = false remoteWsStore.unsubscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date);
const obj = { remoteWsStore.subscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date, (res: any) => {
state: false, if (res && res.data) {
BIS: Math.ceil(Math.random() * 100), const data = JSON.parse(res.data);
SBP: Math.ceil(Math.random() * 100), if (data.vitalSignsList && data.vitalSignsList.length > 0) {
SPO2: Math.ceil(Math.random() * 100), Object.assign(patientInfo.value, data.vitalSignsList[0]);
DBP: Math.ceil(Math.random() * 100), patientInfo.value.state = (patientInfo.value.BIS_except || patientInfo.value.SBP_except ||
HR: Math.ceil(Math.random() * 100), patientInfo.value.DBP_except || patientInfo.value.HR_except);
TEMP: Math.ceil(Math.random() * 100), setLog(patientInfo.value)
} as PatientInfoItem emit('addLogAfter')
patientInfo.value.time = new Date() }
setRemoteLog(obj, (title: string, size: string) => { }
obj.state = true })
remoteItem.value.dataAlarm = true }
remoteStore.setRemoteLog({
time: new Date(), function setLog(data: any) {
title, remoteWsStore.exceptionType.forEach((item: any) => {
state: '异常' if (data[item]) {
}, remoteItem.value.index) const msg: any = remoteWsStore.exceptionMsg[item];
}) remoteWsStore.setRemoteLog({
remoteStore.setRemoteDataAlarm(remoteItem.value.dataAlarm, remoteItem.value.index) state: msg,
remoteStore.$patch({currentRemote: remoteStore.remoteTasks[remoteItem.value.index]}) taskName: remoteItem.value.taskName,
Object.assign(patientInfo.value, obj) time: new Date(),
emit('addLogAfter') type: "exception"
}, remoteWsStore.currentTaskIndex);
}
})
} }
const breakRemote = () => { const breakRemote = () => {
remoteItem.value.isRemote = false remoteWsStore.disconnect(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date)
emit('breakRemote', remoteItem.value) remoteWsStore.resetRemoteTask(remoteWsStore.currentTaskIndex)
if (remoteWsStore.getActiveRemoteTask()) {
showData(remoteWsStore.getActiveRemoteTask())
}
emit('breakRemote')
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.remote-part { .remote-part {
width: 100%; width: 100%;
height: 100%; height: 100%;
border: 1px solid $border-color; border: 1px solid $border-color;
.title { .title {
position: relative; position: relative;
width: 100%; width: 100%;
height: 40px; height: 40px;
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
line-height: 40px; line-height: 40px;
font-weight: 600; font-weight: 600;
color: white; color: white;
background: $main-color; background: $main-color;
.break-btn {
position: absolute;
top: 4px;
right: 20px;
}
}
.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 { .break-btn {
background: $main-color; position: absolute;
} top: 4px;
} right: 20px;
.center-box { }
@extend .common-box; }
img {
max-width: 100%;
max-height: 100%;
}
}
.right-box {
@extend .common-box;
.label {
background: $main-color;
}
}
.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: $main-color;
border-color: $main-color;
}
.row-item.alarm {
.label {
background: red !important;
}
.value {
color: red !important;
border-color: red !important;
}
}
.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;
}
}
}
}
}
&.mini {
padding: 20px;
.left-box {
width: 240px;
}
.center-box {
width: calc(100% - 250px);
}
&.is-total {
.left-box {
.info-box {
display: block;
flex-shrink: 0;
}
.row-item.yellow {
.label {
background: $main-color;
}
.value {
color:$main-color;
border-color: $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: $main-color;
}
}
.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: $main-color;
border-color: $main-color;
}
.row-item.alarm {
.label {
background: red !important;
}
.value {
color: red !important;
border-color: red !important;
}
}
.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;
}
}
}
}
}
&.mini {
padding: 20px;
.left-box {
width: 240px;
}
.center-box {
width: calc(100% - 250px);
}
&.is-total {
.left-box {
.info-box {
display: block;
flex-shrink: 0;
}
.row-item.yellow {
.label {
background: $main-color;
}
.value {
color: $main-color;
border-color: $main-color;
}
}
}
}
}
}
} }
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,5 @@
<template> <template>
<div class="remote-manage-page"> <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="header-box">
<div class="thumbnail" @click="viewThumbnail"> <div class="thumbnail" @click="viewThumbnail">
<el-icon> <el-icon>
@ -14,9 +8,9 @@
<span>缩略图</span> <span>缩略图</span>
</div> </div>
<div class="task-btn-item" v-for="(item, index) in remoteTask" :key="'task-' + index" <div class="task-btn-item" v-for="(item, index) in remoteTask" :key="'task-' + index"
:class="{ 'connecting': item.patientName || item.patientCode, 'alarm': item.dataAlarm }" :class="{ 'connecting': item.patient || item.patientId, 'alarm': item.isException }"
@click="editTask(item, index)" @dblclick="toRemoteControl(item, index)"> @click="editTask(item)" @dblclick="toRemoteControl(item)">
<span>{{ item.title || ('新建任务' + (index + 1)) }}</span> <span>{{ item.taskName || ('新建任务' + (index + 1)) }}</span>
</div> </div>
</div> </div>
<div class="content-box"> <div class="content-box">
@ -32,268 +26,72 @@
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import {ref} from 'vue' import {onMounted, ref} from 'vue'
import {useRouter} from 'vue-router' 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 RemoteDialog from './part/remote-dialog.vue'
import RemotePart from './part/remote-part.vue' import RemotePart from './part/remote-part.vue'
import MessagePart from './part/message-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 router = useRouter()
const remoteStore = useRemoteStore()
const remotePartRef = ref() const remotePartRef = ref()
const messagePartRef = ref() const messagePartRef = ref()
const remoteDialogRef = ref() const remoteDialogRef = ref()
const remoteTask = ref([] as Array<RemoteItem>) const remoteTask = ref([] as Array<any>)
const remoteWsStore = useRemoteWsStore();
initRemoteTask() onMounted(() => {
initRemoteTask()
function resetRemoteTaskItem(e: RemoteItem) { })
Object.assign(remoteTask.value[e.index], {
isRemote: false,
dataAlarm: false,
title: '',
serverUser: '',
patientName: '',
patientCode: '',
index: e.index,
})
}
function initRemoteTask() { function initRemoteTask() {
remoteTask.value = remoteStore.remoteTasks remoteTask.value = remoteWsStore.initRemoteTask()
if (remoteTask.value.length < 1) { remotePartRef.value.showData(remoteWsStore.currentTaskIndex);
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]})
}
}
} }
const viewThumbnail = () => { const viewThumbnail = () => {
router.push({ router.push({
path: '/remote-manage/remote-thumbnail' path: '/remote-manage/remote-thumbnail',
query: {
}
}) })
} }
// //
const editTask = (item: RemoteItem, index: number) => { const editTask = (item: any) => {
item.index = index
// content // content
if (item.isRemote) { if (item.isRemote) {
confirmRemote(item) remotePartRef.value.showData(item.index)
} else { } else {
remoteDialogRef.value.open(item) remoteDialogRef.value.open(item.index)
} }
} }
// //
const toRemoteControl = (item: RemoteItem, index: number) => { const toRemoteControl = (item: any) => {
// //
if (item.isRemote) { if (item.isRemote) {
router.push('/remote-manage/remote-control') router.push('/remote-manage/remote-control')
} else { } else {
editTask(item, index) remoteDialogRef.value.open(item.index)
} }
} }
// //
const confirmRemote = (e: RemoteItem) => { const confirmRemote = () => {
messagePartRef.value.setData({ messagePartRef.value.scrollToBottom()
time: new Date(), //
title: e.title, remotePartRef.value.initData()
state: '连接成功'
}, e.index)
remoteTask.value[e.index] = e //
remotePartRef.value.initData(e)
console.log(e);
getSurgeryData();
} }
// //
const errorRemote = (e: RemoteItem) => { const errorRemote = () => {
messagePartRef.value.setData({ messagePartRef.value.scrollToBottom()
time: new Date(),
title: e.title,
state: '连接失败'
}, e.index)
} }
// //
const breakRemote = (e: RemoteItem) => { const breakRemote = () => {
resetRemoteTaskItem(e) messagePartRef.value.scrollToBottom()
remotePartRef.value.initData()
messagePartRef.value.setData({
time: new Date(),
title: e.title,
state: '断开连接'
}, e.index)
// disconnectSurgeryData("", "1")
} }
const addLogAfter = () => { const addLogAfter = () => {
messagePartRef.value.scrollToBottom() 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> </script>
<style lang='scss' scoped> <style lang='scss' scoped>

View File

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