项目初始化
|
@ -0,0 +1,29 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
/cypress/videos/
|
||||||
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
47
README.md
|
@ -1,39 +1,10 @@
|
||||||
# rax-medical
|
# rax-medical
|
||||||
|
```bash
|
||||||
#### 介绍
|
# vue安装启动
|
||||||
{**以下是 Gitee 平台说明,您可以替换此简介**
|
npm i
|
||||||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
|
npm run serve
|
||||||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
|
# node服务安装启动
|
||||||
|
cd node-server
|
||||||
#### 软件架构
|
npm i
|
||||||
软件架构说明
|
node index.js
|
||||||
|
```
|
||||||
|
|
||||||
#### 安装教程
|
|
||||||
|
|
||||||
1. xxxx
|
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### 使用说明
|
|
||||||
|
|
||||||
1. xxxx
|
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### 参与贡献
|
|
||||||
|
|
||||||
1. Fork 本仓库
|
|
||||||
2. 新建 Feat_xxx 分支
|
|
||||||
3. 提交代码
|
|
||||||
4. 新建 Pull Request
|
|
||||||
|
|
||||||
|
|
||||||
#### 特技
|
|
||||||
|
|
||||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
|
||||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
|
||||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
|
||||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
|
||||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
|
||||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,7 @@
|
||||||
|
# rax-medical
|
||||||
|
## node-server
|
||||||
|
123.57.147.184
|
||||||
|
Xg137839
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import common from "./common.js";
|
||||||
|
const app = common.app;
|
||||||
|
const connection = common.connection;
|
||||||
|
const m_get = common.m_get;
|
||||||
|
const nowTime = common.nowTime;
|
||||||
|
|
||||||
|
const getTable = () => app.post('/getaimedicine', function (req, res) {
|
||||||
|
const database = req.body.database;
|
||||||
|
const table = `AIMedicineTable`;
|
||||||
|
const order = `ID`;
|
||||||
|
const Clause = false;
|
||||||
|
const start = ~~req.body.start;
|
||||||
|
const end = ~~req.body.end;
|
||||||
|
connection(database).query(m_get(table, Clause, order, start, end), function (error, results, fields) {
|
||||||
|
if (error) {
|
||||||
|
console.log(`${nowTime()} 错误:${JSON.stringify(error)}`);
|
||||||
|
return res.status(500).send(error);
|
||||||
|
} else {
|
||||||
|
res.send(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getTable
|
||||||
|
};
|
|
@ -0,0 +1,78 @@
|
||||||
|
|
||||||
|
import express from "express";
|
||||||
|
import mysql from "mysql";
|
||||||
|
/**
|
||||||
|
* 401 需要跳转登录验证
|
||||||
|
* 500 接口错误
|
||||||
|
*/
|
||||||
|
const app = express();
|
||||||
|
// 连接 mysql 数据库
|
||||||
|
const connection = (database) => {
|
||||||
|
return mysql.createConnection({
|
||||||
|
host: '123.57.147.184',
|
||||||
|
port: '3306',
|
||||||
|
user: 'root',
|
||||||
|
password: 'Xg137839',
|
||||||
|
database: database || 'zhangxinhe'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据方法 SELECT * FROM table
|
||||||
|
const m_get = (table, Clause, order, start, end) => {
|
||||||
|
return `SELECT * FROM ${table} ${Clause ? 'WHERE ' + Clause : ``} ORDER BY ${order || `ID`} DESC ${!end ? `` : `LIMIT ` + start + `,` + end};`
|
||||||
|
}
|
||||||
|
// 插入数据方法 INSERT INTO table_name ( field1, field2,...fieldN ) VALUES ( value1, value2,...valueN );
|
||||||
|
const m_add = (table, field, value) => {
|
||||||
|
return `INSERT INTO ${table} ( ${field} ) VALUES ( ${value} );`
|
||||||
|
}
|
||||||
|
// 更新数据方法 UPDATE table_name SET field1=new-value1, field2=new-value2 [WHERE Clause]
|
||||||
|
const m_update = (table, data, Clause) => {
|
||||||
|
return `UPDATE ${table} SET ${data} WHERE ${Clause};`
|
||||||
|
}
|
||||||
|
// 删除数据方法 DELETE FROM table_name [WHERE Clause]
|
||||||
|
const m_delete = (table, Clause) => {
|
||||||
|
return `DELETE FROM ${table} WHERE ${Clause};`
|
||||||
|
}
|
||||||
|
|
||||||
|
const nowTime = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = now.getMonth();
|
||||||
|
const date = now.getDate() >= 10 ? now.getDate() : ('0' + now.getDate());
|
||||||
|
const hour = now.getHours() >= 10 ? now.getHours() : ('0' + now.getHours());
|
||||||
|
const miu = now.getMinutes() >= 10 ? now.getMinutes() : ('0' + now.getMinutes());
|
||||||
|
const sec = now.getSeconds() >= 10 ? now.getSeconds() : ('0' + now.getSeconds());
|
||||||
|
return +year + "-" + (month + 1) + "-" + date + " " + hour + ":" + miu + ":" + sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const dateFormater = (formater, time) => {
|
||||||
|
let date = time ? new Date(time) : new Date(),
|
||||||
|
Y = date.getFullYear() + '',
|
||||||
|
M = date.getMonth() + 1,
|
||||||
|
D = date.getDate(),
|
||||||
|
H = date.getHours(),
|
||||||
|
m = date.getMinutes(),
|
||||||
|
s = date.getSeconds();
|
||||||
|
return formater.replace(/YYYY|yyyy/g, Y)
|
||||||
|
.replace(/YY|yy/g, Y.substr(2, 2))
|
||||||
|
.replace(/MM/g, (M < 10 ? '0' : '') + M)
|
||||||
|
.replace(/DD|dd/g, (D < 10 ? '0' : '') + D)
|
||||||
|
.replace(/HH|hh/g, (H < 10 ? '0' : '') + H)
|
||||||
|
.replace(/mm/g, (m < 10 ? '0' : '') + m)
|
||||||
|
.replace(/ss/g, (s < 10 ? '0' : '') + s)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
app,
|
||||||
|
connection,
|
||||||
|
m_get,
|
||||||
|
m_add,
|
||||||
|
m_update,
|
||||||
|
m_delete,
|
||||||
|
nowTime,
|
||||||
|
dateFormater
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
import common from "./common.js";
|
||||||
|
const app = common.app;
|
||||||
|
const connection = common.connection;
|
||||||
|
const m_get = common.m_get;
|
||||||
|
const nowTime = common.nowTime;
|
||||||
|
|
||||||
|
const getTable = () => app.post('/getdoctormedicine', function (req, res) {
|
||||||
|
const database = req.body.database;
|
||||||
|
const table = `DoctorMedicineTable`;
|
||||||
|
const order = `ID`;
|
||||||
|
const Clause = false;
|
||||||
|
const start = ~~req.body.start;
|
||||||
|
const end = ~~req.body.end;
|
||||||
|
connection(database).query(m_get(table, Clause, order, start, end), function (error, results, fields) {
|
||||||
|
if (error) {
|
||||||
|
console.log(`${nowTime()} 错误:${JSON.stringify(error)}`);
|
||||||
|
return res.status(500).send(error);
|
||||||
|
} else {
|
||||||
|
res.send(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getTable
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
import common from "./common.js";
|
||||||
|
const app = common.app;
|
||||||
|
const connection = common.connection;
|
||||||
|
const m_get = common.m_get;
|
||||||
|
const nowTime = common.nowTime;
|
||||||
|
|
||||||
|
const getTable = () => app.post('/getfeature', function (req, res) {
|
||||||
|
const database = req.body.database;
|
||||||
|
const table = `FeatureTable`;
|
||||||
|
const order = `ID`;
|
||||||
|
const Clause = false;
|
||||||
|
const start = ~~req.body.start;
|
||||||
|
const end = ~~req.body.end;
|
||||||
|
connection(database).query(m_get(table, Clause, order, start, end), function (error, results, fields) {
|
||||||
|
if (error) {
|
||||||
|
console.log(`${nowTime()} 错误:${JSON.stringify(error)}`);
|
||||||
|
return res.status(500).send(error);
|
||||||
|
} else {
|
||||||
|
res.send(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getTable
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
import bodyParser from "body-parser";
|
||||||
|
// 解决跨域
|
||||||
|
import cors from "cors";
|
||||||
|
import common from "./core/common.js";
|
||||||
|
import featureTable from "./core/featureTable.js";
|
||||||
|
import AIMedicineTable from "./core/AIMedicineTable.js";
|
||||||
|
import doctorMedicineTable from "./core/doctorMedicineTable.js";
|
||||||
|
|
||||||
|
// root/Gao!8636
|
||||||
|
const app = common.app;
|
||||||
|
const connection = common.connection;
|
||||||
|
const nowTime = common.nowTime;
|
||||||
|
|
||||||
|
//配置ajax跨域请求
|
||||||
|
app.use(cors({
|
||||||
|
origin: "*",
|
||||||
|
credentials: true //每次登陆都验证跨域请求,要不会每次报跨域错误
|
||||||
|
}));
|
||||||
|
// 配置 bodyParser
|
||||||
|
app.use(bodyParser.urlencoded({ extended: false }));
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
app.listen(3001, () => console.log('服务启动! ' + nowTime()));
|
||||||
|
|
||||||
|
connection().connect();
|
||||||
|
|
||||||
|
featureTable.getTable();
|
||||||
|
AIMedicineTable.getTable();
|
||||||
|
doctorMedicineTable.getTable();
|
||||||
|
|
||||||
|
// MedicineFeadbackInfoTable
|
||||||
|
// TimingFeadbackInfoTable
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.20.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"mysql": "^2.18.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "rax-medical",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vite",
|
||||||
|
"build": "run-p type-check build-only",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"build-only": "vite build",
|
||||||
|
"type-check": "vue-tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.3.3",
|
||||||
|
"sass": "^1.58.3",
|
||||||
|
"echarts": "^5.4.1",
|
||||||
|
"element-plus": "2.3.1",
|
||||||
|
"vue": "^3.2.45",
|
||||||
|
"vue-router": "^4.1.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.11.12",
|
||||||
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
|
"@vue/tsconfig": "^0.1.3",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"typescript": "^5.0.2",
|
||||||
|
"vite": "^4.0.0",
|
||||||
|
"vue-tsc": "^1.0.12"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
$main-color: #006080;
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
span,
|
||||||
|
p {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
li {
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track-piece {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border: 0;
|
||||||
|
background-color: rgba($main-color, .5);
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
border: 0;
|
||||||
|
background-color: $main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 震动
|
||||||
|
.shake_1 {
|
||||||
|
animation: shake_1 .2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake_1 {
|
||||||
|
2% {
|
||||||
|
transform: translate(-.5px, .5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
4% {
|
||||||
|
transform: translate(2.5px, .5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
6% {
|
||||||
|
transform: translate(-.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
8% {
|
||||||
|
transform: translate(.5px, .5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
transform: translate(-.5px, -1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
12% {
|
||||||
|
transform: translate(.5px, -.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
14% {
|
||||||
|
transform: translate(1.5px, 2.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
transform: translate(-.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
18% {
|
||||||
|
transform: translate(2.5px, .5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
transform: translate(.5px, -1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
22% {
|
||||||
|
transform: translate(2.5px, 2.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
24% {
|
||||||
|
transform: translate(2.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
26% {
|
||||||
|
transform: translate(.5px, 1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
28% {
|
||||||
|
transform: translate(1.5px, .5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
30% {
|
||||||
|
transform: translate(-1.5px, 2.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
32% {
|
||||||
|
transform: translate(.5px, .5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
34% {
|
||||||
|
transform: translate(.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
36% {
|
||||||
|
transform: translate(2.5px, -.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
38% {
|
||||||
|
transform: translate(.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: translate(2.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
42% {
|
||||||
|
transform: translate(2.5px, -1.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
44% {
|
||||||
|
transform: translate(.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
46% {
|
||||||
|
transform: translate(1.5px, -1.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
48% {
|
||||||
|
transform: translate(-1.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(2.5px, -1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
52% {
|
||||||
|
transform: translate(.5px, 1.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
54% {
|
||||||
|
transform: translate(2.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
56% {
|
||||||
|
transform: translate(2.5px, 2.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
58% {
|
||||||
|
transform: translate(2.5px, 1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: translate(1.5px, 1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
62% {
|
||||||
|
transform: translate(-.5px, .5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
64% {
|
||||||
|
transform: translate(2.5px, 1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
66% {
|
||||||
|
transform: translate(-1.5px, .5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
68% {
|
||||||
|
transform: translate(1.5px, -1.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
transform: translate(.5px, .5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
72% {
|
||||||
|
transform: translate(-.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
74% {
|
||||||
|
transform: translate(-1.5px, 1.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
76% {
|
||||||
|
transform: translate(2.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
78% {
|
||||||
|
transform: translate(2.5px, 2.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
transform: translate(-1.5px, 2.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
82% {
|
||||||
|
transform: translate(-1.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
84% {
|
||||||
|
transform: translate(.5px, 1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
86% {
|
||||||
|
transform: translate(-.5px, 2.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
88% {
|
||||||
|
transform: translate(2.5px, 2.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
90% {
|
||||||
|
transform: translate(-.5px, -1.5px) rotate(-.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
92% {
|
||||||
|
transform: translate(1.5px, .5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
94% {
|
||||||
|
transform: translate(-.5px, -.5px) rotate(.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
96% {
|
||||||
|
transform: translate(1.5px, .5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
98% {
|
||||||
|
transform: translate(.5px, -.5px) rotate(1.5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translate(0, 0) rotate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item.selected {
|
||||||
|
color: #006080;
|
||||||
|
}
|
||||||
|
.el-select {
|
||||||
|
--el-select-input-focus-border-color: #006080;
|
||||||
|
}
|
||||||
|
.el-dialog {
|
||||||
|
.el-dialog__header {
|
||||||
|
.el-dialog__headerbtn:focus .el-dialog__close,
|
||||||
|
.el-dialog__headerbtn:hover .el-dialog__close {
|
||||||
|
color: #006080;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
.el-button {
|
||||||
|
--el-button-hover-text-color: #006080;
|
||||||
|
--el-button-hover-bg-color: rgba(0, 96, 128, .1);
|
||||||
|
--el-button-hover-border-color: rgba(0, 96, 128, .8);
|
||||||
|
--el-button-active-text-color: #006080;
|
||||||
|
--el-button-active-border-color: rgba(0, 96, 128, .8);
|
||||||
|
--el-button-active-bg-color: rgba(0, 96, 128, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button--primary {
|
||||||
|
--el-button-text-color: white;
|
||||||
|
--el-button-bg-color: #006080;
|
||||||
|
--el-button-border-color: #006080;
|
||||||
|
--el-button-outline-color: rgba(0, 96, 128, .5);
|
||||||
|
--el-button-active-color: rgba(0, 96, 128, .8);
|
||||||
|
--el-button-hover-text-color: white;
|
||||||
|
--el-button-hover-link-text-color: rgba(0, 96, 128, .5);
|
||||||
|
--el-button-hover-bg-color: rgba(0, 96, 128, .7);
|
||||||
|
--el-button-hover-border-color: rgba(0, 96, 128, .7);
|
||||||
|
--el-button-active-bg-color: rgba(0, 96, 128, .8);
|
||||||
|
--el-button-active-border-color: rgba(0, 96, 128, .8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 944 B |
After Width: | Height: | Size: 204 KiB |
After Width: | Height: | Size: 359 KiB |
|
@ -0,0 +1,17 @@
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
// const HOST = 'http://127.0.0.1:3001';
|
||||||
|
const HOST = 'http://123.57.183.183:3001';
|
||||||
|
|
||||||
|
export const get = (url, params, success) => {
|
||||||
|
axios.get(HOST + url, params)
|
||||||
|
.then(res => {
|
||||||
|
success(res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const post = (url, params, success) => {
|
||||||
|
axios.post(HOST + url, params)
|
||||||
|
.then(res => {
|
||||||
|
success(res);
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { createApp, defineComponent, ref, reactive } from 'vue'
|
||||||
|
|
||||||
|
import main from './main.vue'
|
||||||
|
import router from './router'
|
||||||
|
import ElementPlus from 'element-plus';
|
||||||
|
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
|
import './assets/css/global.scss';
|
||||||
|
|
||||||
|
const app = createApp(main)
|
||||||
|
|
||||||
|
app.use(router)
|
||||||
|
.use(ElementPlus) // ElementPlus 全局引入
|
||||||
|
|
||||||
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
|
app.component(key, component)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.mount('#app')
|
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<RouterView />
|
||||||
|
</template>
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: '远程管理',
|
||||||
|
component: () => import('@/views/remote-manage/remote-manage.vue'),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
|
@ -0,0 +1,197 @@
|
||||||
|
<template>
|
||||||
|
<div class="chart-dom-box">
|
||||||
|
<div ref="chartDom" style="width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { dateFormater } from './date-util';
|
||||||
|
|
||||||
|
const chartDom = ref();
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
names?: string[];
|
||||||
|
chartData: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
names: () => ['CH1', 'CH2'],
|
||||||
|
chartData: () => [] as any[],
|
||||||
|
});
|
||||||
|
|
||||||
|
// const emit = defineEmits(['updateData']);
|
||||||
|
|
||||||
|
let chart: any;
|
||||||
|
const names = props.names; // 类型名称
|
||||||
|
const color = ['#00AAB7', '#C77000'];
|
||||||
|
let xData = [] as any[]; // x时间轴
|
||||||
|
let series = [] as any[];
|
||||||
|
|
||||||
|
// 更新图表
|
||||||
|
function updateChart(num: number, time?: string) {
|
||||||
|
xData.shift();
|
||||||
|
xData.push(dateFormater('HH:mm:ss', time));
|
||||||
|
// const values = [] as number[];
|
||||||
|
series.forEach((item, index) => {
|
||||||
|
item.data.shift();
|
||||||
|
// item.data.push(index === 0 ? num - 0.2 : index === 2 ? num + 0.2 : num);
|
||||||
|
// item.data.push(index === 0 ? -Math.floor(Math.random() * 50 + 40) : Math.floor(Math.random() * 50 + 40));
|
||||||
|
item.data.push(Math.floor(Math.random() * 160 + -80));
|
||||||
|
// values.push(item.data[item.data.length - 1]);
|
||||||
|
});
|
||||||
|
// emit('updateData', values); // 传值
|
||||||
|
chart.setOption({
|
||||||
|
xAxis: {
|
||||||
|
data: xData,
|
||||||
|
},
|
||||||
|
series,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 格式化数据
|
||||||
|
function formatterData() {
|
||||||
|
xData = [];
|
||||||
|
series = [];
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
if (props.chartData[i]) xData.push(dateFormater('HH:mm:ss', props.chartData[i].Time || props.chartData[i].TIME));
|
||||||
|
else xData.unshift(0);
|
||||||
|
}
|
||||||
|
names.forEach((item, index) => {
|
||||||
|
const obj = {
|
||||||
|
name: item,
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: 'rgba(40,94,125,0)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 0.3,
|
||||||
|
color: color[index],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 0.5,
|
||||||
|
color: color[index],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 0.7,
|
||||||
|
color: color[index],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: 'rgba(40,94,125,0)',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
data: [] as number[],
|
||||||
|
};
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
if (props.chartData[i]) {
|
||||||
|
const num = props.chartData[i].ST;
|
||||||
|
// obj.data.push(index === 0 ? num - 0.2 : index === 2 ? num + 0.2 : num);
|
||||||
|
// obj.data.push(index === 0 ? -Math.floor(Math.random() * 50 + 40) : Math.floor(Math.random() * 50 + 40));
|
||||||
|
obj.data.push(Math.floor(Math.random() * 160 + -80));
|
||||||
|
} else obj.data.unshift(0);
|
||||||
|
}
|
||||||
|
series.push(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 渲染图表 父组件调用
|
||||||
|
function chartSet() {
|
||||||
|
formatterData();
|
||||||
|
if (chart) chart.setOption({
|
||||||
|
xAxis: {
|
||||||
|
data: xData,
|
||||||
|
},
|
||||||
|
series,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 图表初始化
|
||||||
|
function chartInit() {
|
||||||
|
chart = echarts.init(chartDom.value as HTMLElement);
|
||||||
|
chart.clear();
|
||||||
|
const option = {
|
||||||
|
color: color,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: (params: any) => {
|
||||||
|
let str = params[0].axisValue;
|
||||||
|
str += `<br>`;
|
||||||
|
names.forEach((item, index) => {
|
||||||
|
str += params[index].marker;
|
||||||
|
str += params[index].seriesName + ' ';
|
||||||
|
str += `${params[index].value} HZ`;
|
||||||
|
str += index === 0 ? '<br>' : '';
|
||||||
|
});
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 1,
|
||||||
|
right: 20,
|
||||||
|
bottom: 5,
|
||||||
|
top: 20,
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
show: true,
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLine: { show: false, lineStyle: { color: '#006080' } },
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLabel: { show: false },
|
||||||
|
splitLine: { show: true, lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } },
|
||||||
|
data: xData,
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
show: true,
|
||||||
|
type: 'value',
|
||||||
|
min: function (value: any) {
|
||||||
|
return value.min - 40
|
||||||
|
},
|
||||||
|
max: function (value: any) {
|
||||||
|
return value.max + 40
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
formatter: `{value} HZ`
|
||||||
|
},
|
||||||
|
axisLine: { show: false, lineStyle: { color: '#006080' } },
|
||||||
|
splitLine: { lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } },
|
||||||
|
},
|
||||||
|
series,
|
||||||
|
};
|
||||||
|
chart.setOption(option);
|
||||||
|
chart.resize();
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
chart.resize();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
chartInit();
|
||||||
|
});
|
||||||
|
defineExpose({
|
||||||
|
updateChart,
|
||||||
|
chartSet
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chart-dom-box {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.chart-rate {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 30px;
|
||||||
|
color: #285e7d;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,224 @@
|
||||||
|
<template>
|
||||||
|
<div class="chart-dom-box">
|
||||||
|
<div ref="chartDom" style="width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { dateFormater } from './date-util';
|
||||||
|
|
||||||
|
const chartDom = ref();
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
names: string[];
|
||||||
|
chartData: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
names: () => ['BIS', 'HR'],
|
||||||
|
chartData: () => [] as any[],
|
||||||
|
});
|
||||||
|
|
||||||
|
// const emit = defineEmits(['updateData']);
|
||||||
|
|
||||||
|
let chart: any;
|
||||||
|
const names = props.names; // 类型名称
|
||||||
|
const color = ['#00AAB7', '#C77000'];
|
||||||
|
let legendData = [] as any[];
|
||||||
|
let xData = [] as any[]; // x时间轴
|
||||||
|
let series = [] as any[];
|
||||||
|
|
||||||
|
|
||||||
|
// 更新图表
|
||||||
|
function updateChart(ary: number[], time?: string) {
|
||||||
|
xData.shift();
|
||||||
|
xData.push(dateFormater('HH:mm:ss', time));
|
||||||
|
// const values: number[] = [];
|
||||||
|
series.forEach((item, index) => {
|
||||||
|
item.data.shift();
|
||||||
|
item.data.push(ary[index]);
|
||||||
|
// values.push(item.data[item.data.length - 1]);
|
||||||
|
});
|
||||||
|
// emit('updateData', [values]); // 传值
|
||||||
|
chart.setOption({
|
||||||
|
xAxis: {
|
||||||
|
data: xData,
|
||||||
|
},
|
||||||
|
series,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 格式化数据
|
||||||
|
function formatterData() {
|
||||||
|
legendData = [];
|
||||||
|
xData = [];
|
||||||
|
series = [];
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
if (props.chartData[i]) xData.push(dateFormater('HH:mm:ss', props.chartData[i].Time || props.chartData[i].TIME));
|
||||||
|
else xData.unshift(0);
|
||||||
|
}
|
||||||
|
names.forEach((item, index) => {
|
||||||
|
const obj = {
|
||||||
|
name: item,
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'none',
|
||||||
|
smooth: true,
|
||||||
|
data: [] as number[],
|
||||||
|
};
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
if (props.chartData[i]) obj.data.push(props.chartData[i][item]);
|
||||||
|
else obj.data.unshift(0);
|
||||||
|
}
|
||||||
|
legendData.push({
|
||||||
|
name: item,
|
||||||
|
textStyle: { color: color[index] },
|
||||||
|
});
|
||||||
|
series.push(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 渲染图表 父组件调用
|
||||||
|
function chartSet() {
|
||||||
|
formatterData();
|
||||||
|
if (chart) chart.setOption({
|
||||||
|
xAxis: {
|
||||||
|
data: xData,
|
||||||
|
},
|
||||||
|
series,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 图表初始化
|
||||||
|
function chartInit() {
|
||||||
|
chart = echarts.init(chartDom.value as HTMLElement);
|
||||||
|
chart.clear();
|
||||||
|
formatterData();
|
||||||
|
const option : any = {
|
||||||
|
color,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: (params: any) => {
|
||||||
|
let str = '';
|
||||||
|
str += params[0].axisValue;
|
||||||
|
str += '<br>';
|
||||||
|
names.forEach((item, index) => {
|
||||||
|
str += params[index].marker;
|
||||||
|
str += params[index].seriesName + ' ';
|
||||||
|
switch (item) {
|
||||||
|
case 'BIS':
|
||||||
|
str += `脑电双频指数<麻醉深度>:${params[index].value}`;
|
||||||
|
break;
|
||||||
|
case 'HR':
|
||||||
|
str += `心率:${params[index].value} 次/分`;
|
||||||
|
break;
|
||||||
|
case 'SBP':
|
||||||
|
str += `收缩压:${params[index].value} mmHg`;
|
||||||
|
break;
|
||||||
|
case 'DBP':
|
||||||
|
str += `舒张压:${params[index].value} mmHg`;
|
||||||
|
break;
|
||||||
|
case 'SPO2':
|
||||||
|
str += `体温:${params[index].value}`;
|
||||||
|
break;
|
||||||
|
case 'TEMP':
|
||||||
|
str += `氧饱和度:${params[index].value}`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str += index === 0 ? '<br>' : '';
|
||||||
|
});
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'plain',
|
||||||
|
show: true,
|
||||||
|
top: 0,
|
||||||
|
right: 15,
|
||||||
|
itemGap: 30,
|
||||||
|
itemWidth: 20,
|
||||||
|
itemHeight: 3,
|
||||||
|
icon: 'rect',
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 600,
|
||||||
|
lineHeight: 30,
|
||||||
|
},
|
||||||
|
formatter: (params: string) => {
|
||||||
|
const index = names.findIndex((item) => item === params);
|
||||||
|
let str = params + ' ';
|
||||||
|
switch (params) {
|
||||||
|
case 'BIS':
|
||||||
|
str += `${series[index].data[series[index].data.length - 1]}`;
|
||||||
|
break;
|
||||||
|
case 'HR':
|
||||||
|
str += `${series[index].data[series[index].data.length - 1]} 次/分`;
|
||||||
|
break;
|
||||||
|
case 'SBP':
|
||||||
|
str += `${series[index].data[series[index].data.length - 1]} mmHg`;
|
||||||
|
break;
|
||||||
|
case 'DBP':
|
||||||
|
str += `${series[index].data[series[index].data.length - 1]} mmHg`;
|
||||||
|
break;
|
||||||
|
case 'SPO2':
|
||||||
|
str += `${series[index].data[series[index].data.length - 1]}`;
|
||||||
|
break;
|
||||||
|
case 'TEMP':
|
||||||
|
str += `${series[index].data[series[index].data.length - 1]}`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
data: legendData,
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 5,
|
||||||
|
right: 25,
|
||||||
|
bottom: 5,
|
||||||
|
top: 40,
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
show: true,
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: xData,
|
||||||
|
axisLine: { lineStyle: { color: '#006080' } }
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
show: true,
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: `{value} ${names[0] === 'BIS' ? '次/分' : names[0] === 'SBP' ? 'mmHg' : ''}`
|
||||||
|
},
|
||||||
|
axisLine: { show: true, lineStyle: { color: '#006080' } },
|
||||||
|
splitLine: { lineStyle: { color: '#C0C4CC', width: 1, type: 'dashed' } },
|
||||||
|
},
|
||||||
|
series,
|
||||||
|
};
|
||||||
|
if(names[0] !== 'BIS') {
|
||||||
|
option.yAxis.max = (value: any) => value.max + 20;
|
||||||
|
}
|
||||||
|
chart.setOption(option);
|
||||||
|
chart.resize();
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
chart.resize();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
chartInit();
|
||||||
|
});
|
||||||
|
defineExpose({
|
||||||
|
updateChart,
|
||||||
|
chartSet
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chart-dom-box {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,17 @@
|
||||||
|
export function dateFormater(formater: string, time?: any) {
|
||||||
|
let date = time ? new Date(time) : new Date(),
|
||||||
|
Y = date.getFullYear() + '',
|
||||||
|
M = date.getMonth() + 1,
|
||||||
|
D = date.getDate(),
|
||||||
|
H = date.getHours(),
|
||||||
|
m = date.getMinutes(),
|
||||||
|
s = date.getSeconds();
|
||||||
|
return formater
|
||||||
|
.replace(/YYYY|yyyy/g, Y)
|
||||||
|
.replace(/YY|yy/g, Y.substr(2, 2))
|
||||||
|
.replace(/MM/g, (M < 10 ? '0' : '') + M)
|
||||||
|
.replace(/DD|dd/g, (D < 10 ? '0' : '') + D)
|
||||||
|
.replace(/HH|hh/g, (H < 10 ? '0' : '') + H)
|
||||||
|
.replace(/mm/g, (m < 10 ? '0' : '') + m)
|
||||||
|
.replace(/ss/g, (s < 10 ? '0' : '') + s);
|
||||||
|
}
|
|
@ -0,0 +1,858 @@
|
||||||
|
<template>
|
||||||
|
<div class="remote-box" id="screenBox">
|
||||||
|
<div class="head-box">
|
||||||
|
<div class="logo-box">
|
||||||
|
<img src="@/assets/imgs/logo.png" />
|
||||||
|
</div>
|
||||||
|
<ul class="menu-box">
|
||||||
|
<li class="menu-item"><img src="@/assets/imgs/menu_1.png" /><span>首页</span></li>
|
||||||
|
<li class="menu-item"><img src="@/assets/imgs/menu_1.png" /><span>权限管理</span></li>
|
||||||
|
<li class="menu-item"><img src="@/assets/imgs/menu_1.png" /><span>患者管理</span></li>
|
||||||
|
<li class="menu-item active"><img src="@/assets/imgs/menu_1.png" /><span>远程管理</span></li>
|
||||||
|
<li class="menu-item"><img src="@/assets/imgs/menu_1.png" /><span>后台管理</span></li>
|
||||||
|
<li class="menu-item"><img src="@/assets/imgs/menu_1.png" /><span>系统管理</span></li>
|
||||||
|
<li class="area">北京第一医院</li>
|
||||||
|
</ul>
|
||||||
|
<div class="user-box">
|
||||||
|
<el-button text>
|
||||||
|
<el-icon>
|
||||||
|
<Search />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-button text>
|
||||||
|
<el-badge is-dot :hidden="!messageSum">
|
||||||
|
<el-icon>
|
||||||
|
<Bell />
|
||||||
|
</el-icon>
|
||||||
|
</el-badge>
|
||||||
|
</el-button>
|
||||||
|
<el-button text @click="toggleFullscreen">
|
||||||
|
<el-icon>
|
||||||
|
<FullScreen />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<span class="el-dropdown-link">
|
||||||
|
{{ userName }}
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<arrow-down />
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item>设置</el-dropdown-item>
|
||||||
|
<el-dropdown-item>退出</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main-box">
|
||||||
|
<div class="left-box">
|
||||||
|
<h3>远程控制 1</h3>
|
||||||
|
<chart-line ref="chartDom1" class="chart-line" :names="['BIS', 'HR']"
|
||||||
|
:chartData="featureTable"></chart-line>
|
||||||
|
<chart-line ref="chartDom2" class="chart-line" :names="['SBP', 'DBP']"
|
||||||
|
:chartData="featureTable"></chart-line>
|
||||||
|
<chart-line ref="chartDom3" class="chart-line" :names="['SPO2', 'TEMP']"
|
||||||
|
:chartData="featureTable"></chart-line>
|
||||||
|
<chart-ecg ref="chartDom4" class="chart-ecg" :chartData="featureTable"></chart-ecg>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="center-box">
|
||||||
|
<div class="body-box">
|
||||||
|
<div class="body-img">
|
||||||
|
<img src="@/assets/imgs/main_body.png" style="width: 100%;height: 100%;" />
|
||||||
|
<img class="lung-img" :class="{ 'shake_1': lungAlarm }" :src="lungAlarm ? imgLungAlarm : imgLung">
|
||||||
|
<img class="heart-img" :class="{ 'shake_1': heartAlarm }"
|
||||||
|
:src="heartAlarm ? imgHeartAlarm : imgHeart">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="btn-box">
|
||||||
|
<el-button class="start-btn" color="#F80000" @click="getTableData(!isStart)">{{ isStart ? '终止' : '开始'
|
||||||
|
}}</el-button>
|
||||||
|
<div class="right-btn-box">
|
||||||
|
<el-button :class="{ 'active': isAIDose }" size="small" @click="getTableData(true)">AI给药</el-button>
|
||||||
|
<el-button :class="{ 'active': !isAIDose }" size="small"
|
||||||
|
@click="getTableData(false)">人工给药</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-box">
|
||||||
|
<div class="top-btn-box">
|
||||||
|
<div class="top-left-btn-box">
|
||||||
|
<el-select v-model="database" filterable placeholder="Select" style="width: 100%;" @change="selectDatabase">
|
||||||
|
<el-option v-for="item in databaseOptions" :key="item.value" :label="item.label"
|
||||||
|
:value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
<el-button color="#C77000">患者信息</el-button>
|
||||||
|
<el-button color="#C77000">已连接</el-button>
|
||||||
|
<el-button color="#C77000">机器人运行正常</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button color="#e0e0e0"><el-icon>
|
||||||
|
<Back />
|
||||||
|
</el-icon> 返回</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="video-box" @click="playPause">
|
||||||
|
<div class="icon-box">
|
||||||
|
<el-icon v-if="isVideoPlay">
|
||||||
|
<VideoPause />
|
||||||
|
</el-icon>
|
||||||
|
<el-icon v-else>
|
||||||
|
<VideoPlay />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<video ref="liveVideo" poster="@/assets/imgs/video_bck.png">
|
||||||
|
<source src="@/assets/medical.mp4" type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
<div class="message-box">
|
||||||
|
<ul ref="msgLog" class="message-log">
|
||||||
|
<li v-for="(item, index) in mssageList" :key="'msg-log-' + index"
|
||||||
|
:class="{ 'align-right': item.user === userName }">
|
||||||
|
<span>{{ item.msg }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="send-box">
|
||||||
|
<el-input v-model="msgVal" placeholder="请输入消息" />
|
||||||
|
<el-button color="#006080" @click="sendMsg">发送消息</el-button>
|
||||||
|
</div>
|
||||||
|
<ul ref="unusualMsg" class="unusual-box">
|
||||||
|
<li v-for="item in unusual" :key="item">{{ item }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="table-box">
|
||||||
|
<el-table :data="tableData" height="100%" style="width: 100%">
|
||||||
|
<el-table-column prop="num" label="票号" width="40" align="center" />
|
||||||
|
<el-table-column prop="name" label="药物名称" align="center" />
|
||||||
|
<el-table-column prop="speed" label="速度(ml/h)" width="100" />
|
||||||
|
<el-table-column prop="total" label="累计药量(ml)" width="100" />
|
||||||
|
<el-table-column prop="state" label="工作状态" width="70" align="center" />
|
||||||
|
<el-table-column label="特殊情况人为干预" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="table-btn-box">
|
||||||
|
<el-button size="small" color="#006080" @click="tableItemPlus(scope)"><el-icon>
|
||||||
|
<Plus />
|
||||||
|
</el-icon></el-button>
|
||||||
|
<el-button size="small" color="#006080" :disabled="scope.row.speed <= 0"
|
||||||
|
@click="tableItemMinus(scope)"><el-icon>
|
||||||
|
<Minus />
|
||||||
|
</el-icon></el-button>
|
||||||
|
<el-button size="small" color="#006080" @click="tableItemConfirm(scope)"
|
||||||
|
:disabled="tableDataStore[scope.$index].speed === scope.row.speed">确定</el-button>
|
||||||
|
<el-button size="small" color="#006080" @click="tableItemCancel(scope)"
|
||||||
|
:disabled="tableDataStore[scope.$index].speed === scope.row.speed">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="setDatabaseDialog" title="请选择需要查询的病人" width="300px" align-center>
|
||||||
|
<el-select v-model="database" filterable placeholder="Select" style="width: 100%;">
|
||||||
|
<el-option v-for="item in databaseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="setDatabaseDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="setDatabase">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref, reactive } from 'vue';
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
import { dateFormater } from './date-util';
|
||||||
|
import { post } from "@/axios/index";
|
||||||
|
import chartLine from './chart-line.vue';
|
||||||
|
import chartEcg from './chart-ecg.vue';
|
||||||
|
import imgLung from '@/assets/imgs/lung.png';
|
||||||
|
import imgHeart from '@/assets/imgs/heart.png';
|
||||||
|
import imgLungAlarm from '@/assets/imgs/lung_alarm.png';
|
||||||
|
import imgHeartAlarm from '@/assets/imgs/heart_alarm.png';
|
||||||
|
|
||||||
|
const chartDom1 = ref(),
|
||||||
|
chartDom2 = ref(),
|
||||||
|
chartDom3 = ref(),
|
||||||
|
chartDom4 = ref(),
|
||||||
|
liveVideo = ref(),
|
||||||
|
msgLog = ref(),
|
||||||
|
unusualMsg = ref();
|
||||||
|
|
||||||
|
const databaseOptions: { value: string, label: string }[] = [
|
||||||
|
{ value: 'zhangxinhe', label: 'zhangxinhe' },
|
||||||
|
{ value: '数据模拟20231109185403', label: '模拟数据库' }
|
||||||
|
];
|
||||||
|
const medicineCustom: any[] = [
|
||||||
|
{ name: '丙泊酚', plus: 0.5 },
|
||||||
|
{ name: '舒芬太尼', plus: 1 },
|
||||||
|
{ name: '瑞芬太尼', plus: 0.05 },
|
||||||
|
{ name: '顺阿曲库胺', plus: 0.02 },
|
||||||
|
{ name: '尼卡地平', plus: 1 },
|
||||||
|
{ name: '艾司洛尔', plus: 1 },
|
||||||
|
{ name: '麻黄素', plus: 1 },
|
||||||
|
{ name: '阿托品', plus: 1 },
|
||||||
|
{ name: '罗库溴铵', plus: 0.1 }
|
||||||
|
];
|
||||||
|
const database = ref('数据模拟20231109185403');
|
||||||
|
const messageSum = ref(10);
|
||||||
|
const userName = ref('admin');
|
||||||
|
const setDatabaseDialog = ref(false);
|
||||||
|
const featureTable = ref([] as any[]);
|
||||||
|
let chartNowData = reactive({ ID: 0 });
|
||||||
|
const lungAlarm = ref(false); // 肺部警告
|
||||||
|
const heartAlarm = ref(false); // 心脏警告
|
||||||
|
const isStart = ref(false); // 是否开始
|
||||||
|
const isAIDose = ref(false); // 是否AI给药
|
||||||
|
const isVideoPlay = ref(false); // 视频是否播放
|
||||||
|
const videoSrc = ref('https://www.runoob.com/try/demo_source/mov_bbb.mp4');
|
||||||
|
const mssageList = ref([] as any);
|
||||||
|
const msgVal = ref('');
|
||||||
|
const unusual = ref([] as any);
|
||||||
|
const tableData = ref([] as any[]);
|
||||||
|
const tableDataStore = ref([] as any[]);
|
||||||
|
|
||||||
|
function initData() {
|
||||||
|
lungAlarm.value = false;
|
||||||
|
heartAlarm.value = false;
|
||||||
|
isStart.value = false;
|
||||||
|
isAIDose.value = false;
|
||||||
|
unusual.value = [];
|
||||||
|
mssageList.value = [];
|
||||||
|
getFeatureTable();
|
||||||
|
getMssageLog();
|
||||||
|
getTableData(isAIDose.value);
|
||||||
|
try {
|
||||||
|
msgLogScrollBottom();
|
||||||
|
} catch (error) { }
|
||||||
|
|
||||||
|
}
|
||||||
|
function getFeatureTable() {
|
||||||
|
featureTable.value = [];
|
||||||
|
post('/getfeature', { database: database.value, start: 1, end: 100 }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
featureTable.value = res.data.reverse();
|
||||||
|
setTimeout(() => {
|
||||||
|
chartDom1.value.chartSet();
|
||||||
|
chartDom2.value.chartSet();
|
||||||
|
chartDom3.value.chartSet();
|
||||||
|
chartDom4.value.chartSet();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getChartData() {
|
||||||
|
let isThrottle = true; // 节流
|
||||||
|
throttle(2000);
|
||||||
|
getEEG();
|
||||||
|
function throttle(speed: number) {
|
||||||
|
if (isThrottle) {
|
||||||
|
isThrottle = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
getData(() => {
|
||||||
|
isThrottle = true;
|
||||||
|
throttle(speed);
|
||||||
|
});
|
||||||
|
}, speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 脑电图随机数据
|
||||||
|
function getEEG() {
|
||||||
|
setTimeout(() => {
|
||||||
|
// if (isStart.value) {
|
||||||
|
chartDom4.value.updateChart(0, new Date());
|
||||||
|
// }
|
||||||
|
getEEG();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getData(callback: () => void) {
|
||||||
|
// if (isStart.value) {
|
||||||
|
post('/getfeature', { database: database.value, start: 0, end: 1 }, (res: any) => {
|
||||||
|
const obj = res.data[0] || {};
|
||||||
|
if (obj.ID !== chartNowData.ID) {
|
||||||
|
chartNowData = obj;
|
||||||
|
const isHR = obj.HR >= 50 && obj.HR <= 80;
|
||||||
|
const isSBP = obj.SBP >= 90 && obj.SBP <= 120;
|
||||||
|
const isDBP = obj.DBP >= 60 && obj.DBP <= 90;
|
||||||
|
// const isST = obj.ST >= -0.2 && obj.ST <= 0.2;
|
||||||
|
if (!isHR) unusualUpDate('心率异常');
|
||||||
|
if (!isSBP) unusualUpDate('收缩压异常');
|
||||||
|
if (!isDBP) unusualUpDate('舒张异常');
|
||||||
|
// if (!isST) unusualUpDate('心电图ST段变异度异常');
|
||||||
|
lungAlarm.value = Boolean(!isSBP || !isDBP);
|
||||||
|
// heartAlarm.value = Boolean(!isHR || !isST);
|
||||||
|
heartAlarm.value = Boolean(!isHR);
|
||||||
|
chartDom1.value.updateChart([obj.BIS, obj.HR], obj.Time || obj.TIME);
|
||||||
|
chartDom2.value.updateChart([obj.SBP, obj.DBP], obj.Time || obj.TIME);
|
||||||
|
chartDom3.value.updateChart([obj.SPO2, obj.TEMP], obj.Time || obj.TIME);
|
||||||
|
// chartDom4.value.updateChart(obj.ST, obj.Time || obj.TIME);
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
})
|
||||||
|
// } else {
|
||||||
|
// callback();
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function msgLogScrollBottom() {
|
||||||
|
msgLog.value.scrollTo({
|
||||||
|
top: msgLog.value.scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function unusualUpDate(msg: string) {
|
||||||
|
unusual.value.push(dateFormater('HH:mm:ss') + msg);
|
||||||
|
setTimeout(() => {
|
||||||
|
unusualMsg.value.scrollTo({
|
||||||
|
top: unusualMsg.value.scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getMssageLog() {
|
||||||
|
mssageList.value.push({ user: 'admin', msg: '请您把治疗单和药品给我' });
|
||||||
|
mssageList.value.push({ user: 'nurse', msg: '好的' });
|
||||||
|
mssageList.value.push({ user: 'admin', msg: '请您把治疗单和药品给我' });
|
||||||
|
mssageList.value.push({ user: 'nurse', msg: '好的' });
|
||||||
|
}
|
||||||
|
function getTableData(e: boolean) {
|
||||||
|
isStart.value = e;
|
||||||
|
isAIDose.value = e;
|
||||||
|
const url = e ? '/getaimedicine' : '/getdoctormedicine';
|
||||||
|
tableData.value = [];
|
||||||
|
post(url, { database: database.value, start: 0, end: 1 }, (res: any) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
let i = 0;
|
||||||
|
for (let key in res.data[0]) {
|
||||||
|
if (key !== 'ID' && key !== 'Phase' && key !== 'Time' && key !== 'TIME') {
|
||||||
|
i++;
|
||||||
|
tableData.value.push({ num: i, name: key, speed: res.data[0][key], total: Number(res.data[0][key]), state: '正常' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const defaultMedicine: string[] = ['丙泊酚', '舒芬太尼', '瑞芬太尼', '顺阿曲库胺', '尼卡地平', '艾司洛尔', '麻黄素', '阿托品'];
|
||||||
|
defaultMedicine.forEach((item, index) => {
|
||||||
|
tableData.value.push({ num: index + 1, name: item, speed: 0, total: 0, state: '正常' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tableDataStore.value = JSON.parse(JSON.stringify(tableData.value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function keepFit(designWidth: number, designHeight: number, renderDomId: string) {
|
||||||
|
let width = designWidth || 1920,
|
||||||
|
height = designHeight || 1080;
|
||||||
|
let clientHeight = document.documentElement.clientHeight;
|
||||||
|
let clientWidth = document.documentElement.clientWidth;
|
||||||
|
let scale = 1;
|
||||||
|
scale = clientHeight / height;
|
||||||
|
const renderDom = document.getElementById(renderDomId);
|
||||||
|
if (renderDom) {
|
||||||
|
renderDom.style.height = clientHeight / scale + 'px';
|
||||||
|
renderDom.style.width = clientWidth / scale + 'px';
|
||||||
|
renderDom.style.transform = 'scale(' + scale + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function initScale() {
|
||||||
|
let w = 1920,
|
||||||
|
h = 1080;
|
||||||
|
keepFit(w, h, 'screenBox');
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
keepFit(w, h, 'screenBox');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectDatabase = (value: any) => {
|
||||||
|
initData();
|
||||||
|
};
|
||||||
|
const setDatabase = () => {
|
||||||
|
initData();
|
||||||
|
setDatabaseDialog.value = false;
|
||||||
|
};
|
||||||
|
const toggleFullscreen = () => {
|
||||||
|
if (document.fullscreenElement) {
|
||||||
|
document.exitFullscreen();
|
||||||
|
} else {
|
||||||
|
document.documentElement.requestFullscreen();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const playPause = () => {
|
||||||
|
if (liveVideo.value.paused) {
|
||||||
|
liveVideo.value.play(); // 播放视频
|
||||||
|
isVideoPlay.value = true;
|
||||||
|
} else {
|
||||||
|
liveVideo.value.pause(); // 暂停视频
|
||||||
|
isVideoPlay.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sendMsg = () => {
|
||||||
|
if (msgVal.value.trim() == '') return;
|
||||||
|
mssageList.value.push({ user: userName.value, msg: msgVal.value });
|
||||||
|
msgVal.value = '';
|
||||||
|
setTimeout(() => {
|
||||||
|
msgLogScrollBottom()
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
const tableItemPlus = (e: any) => {
|
||||||
|
const obj = medicineCustom.find(item => item.name === e.row.name) || { plus: 1 };
|
||||||
|
e.row.speed += obj.plus;
|
||||||
|
e.row.speed = Number(e.row.speed.toFixed(2));
|
||||||
|
};
|
||||||
|
const tableItemMinus = (e: any) => {
|
||||||
|
const obj = medicineCustom.find(item => item.name === e.row.name) || { plus: 1 };
|
||||||
|
if(!isAIDose.value && e.row.speed - obj.plus <= 0) return;
|
||||||
|
e.row.speed -= obj.plus;
|
||||||
|
if (e.row.speed < 0) e.row.speed = 0;
|
||||||
|
else e.row.speed = Number(e.row.speed.toFixed(2));
|
||||||
|
};
|
||||||
|
const tableItemConfirm = (e: any) => {
|
||||||
|
tableDataStore.value[e.$index].speed = e.row.speed;
|
||||||
|
};
|
||||||
|
const tableItemCancel = (e: any) => {
|
||||||
|
e.row.speed = tableDataStore.value[e.$index].speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
initData();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
msgLogScrollBottom();
|
||||||
|
getChartData();
|
||||||
|
initScale();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.remote-box {
|
||||||
|
$main-color: #006080;
|
||||||
|
width: 1920px;
|
||||||
|
height: 1080px;
|
||||||
|
background: #f1f3f5;
|
||||||
|
transform-origin: top left;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.head-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0 24px;
|
||||||
|
background: white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.logo-box {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $main-color;
|
||||||
|
line-height: 50px;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin: 0 10px;
|
||||||
|
transition: all .3s;
|
||||||
|
-webkit-transition: all .3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #F5F7FA;
|
||||||
|
transition: all .3s;
|
||||||
|
-webkit-transition: all .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: rgba($main-color, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.area {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $main-color;
|
||||||
|
line-height: 1.6;
|
||||||
|
padding: 0 20px;
|
||||||
|
border: 1px solid #8c9094;
|
||||||
|
border-radius: 7px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&>.el-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>.el-dropdown {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-box {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
// min-height: 1080px;
|
||||||
|
margin-top: 10px;
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left-box {
|
||||||
|
width: 670px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&>h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: $main-color;
|
||||||
|
line-height: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-line {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(25% - 15px - 12.5px);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background: #e8f5f8;
|
||||||
|
border-top-left-radius: 20px;
|
||||||
|
border-top-right-radius: 20px;
|
||||||
|
// overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-ecg {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(25% - 15px - 12.5px);
|
||||||
|
border-left: 1px solid #92b3c1;
|
||||||
|
border-bottom: 1px solid #92b3c1;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 0;
|
||||||
|
left: -5px;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
border-bottom: 15px solid #285e7d;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
bottom: -5px;
|
||||||
|
right: 0;
|
||||||
|
border-left: 15px solid #285e7d;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 5px solid transparent;
|
||||||
|
border-top: 5px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-box {
|
||||||
|
width: calc(100% - 1500px);
|
||||||
|
min-width: 500px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.body-box {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 110px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.body-img {
|
||||||
|
position: relative;
|
||||||
|
// width: 400px;
|
||||||
|
// height: 650px;
|
||||||
|
width: 500px;
|
||||||
|
height: 812.5px;
|
||||||
|
min-height: 650px;
|
||||||
|
|
||||||
|
.lung-img {
|
||||||
|
position: absolute;
|
||||||
|
width: 500px;
|
||||||
|
height: auto;
|
||||||
|
top: 240px;
|
||||||
|
left: 0;
|
||||||
|
transition: all 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart-img {
|
||||||
|
position: absolute;
|
||||||
|
width: 500px;
|
||||||
|
height: auto;
|
||||||
|
top: 420px;
|
||||||
|
left: 0;
|
||||||
|
transition: all 2s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-box {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 110px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.start-btn {
|
||||||
|
width: 230px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 20px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-btn-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 70px;
|
||||||
|
height: 62px;
|
||||||
|
top: calc(50% - 31px);
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
height: 25px;
|
||||||
|
line-height: 22px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
color: #616161;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: $main-color;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-box {
|
||||||
|
width: 670px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.top-btn-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 34px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.top-left-btn-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.el-select {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-button {
|
||||||
|
border-radius: 16px;
|
||||||
|
height: 31px;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #c77000;
|
||||||
|
}
|
||||||
|
&>.el-button {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: $main-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-box {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
background: $main-color;
|
||||||
|
/* background: url(@/assets/imgs/video_bck.png);
|
||||||
|
background-size: 100% 100%; */
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.icon-box {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-box {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
font-size: 60px;
|
||||||
|
color: white;
|
||||||
|
background: rgba(black, .3);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 260px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.message-log {
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #c8c8c8;
|
||||||
|
background: #f8f8f8;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
li {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 5px 0;
|
||||||
|
|
||||||
|
&.align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 80%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
background: $main-color;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 46px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
width: calc(100% - 110px);
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
background-color: #F2F3F5;
|
||||||
|
border-color: #C1C1C1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
padding: 0;
|
||||||
|
width: 100px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unusual-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
background: #F8F8F8;
|
||||||
|
border: 1px solid #C1C1C1;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
li {
|
||||||
|
color: #F80000;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-box {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 604px);
|
||||||
|
|
||||||
|
:deep(.el-table__inner-wrapper) {
|
||||||
|
.el-table__cell {
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table__header-wrapper {
|
||||||
|
tr {
|
||||||
|
background-color: $main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.el-table__cell {
|
||||||
|
color: white;
|
||||||
|
background-color: $main-color;
|
||||||
|
padding: 8px 0;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-btn-box {
|
||||||
|
.el-button {
|
||||||
|
padding: 0 7px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||||
|
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"types": ["node"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||||
|
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"ignoreDeprecations": "5.0",
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
},
|
||||||
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.config.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
base: '/medical/',
|
||||||
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
css:{
|
||||||
|
preprocessorOptions:{
|
||||||
|
scss:{
|
||||||
|
// additionalData: '@import "./src/assets/css/global.scss";' //引入scss文件
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|