Browse Source

康复大屏

master
aBin 4 years ago
commit
8af87dd41e
  1. 3
      .browserslistrc
  2. 8
      .editorconfig
  3. 3
      .env
  4. 10
      .env.development
  5. 10
      .env.production
  6. 47
      .eslintrc.js
  7. 23
      .gitignore
  8. 13
      .prettierrc
  9. 24
      README.md
  10. 13
      babel.config.js
  11. 1
      commitlint.config.js
  12. 13755
      package-lock.json
  13. 51
      package.json
  14. BIN
      public/favicon.ico
  15. BIN
      public/img/icons/android-chrome-192x192.png
  16. BIN
      public/img/icons/android-chrome-512x512.png
  17. BIN
      public/img/icons/android-chrome-maskable-192x192.png
  18. BIN
      public/img/icons/android-chrome-maskable-512x512.png
  19. BIN
      public/img/icons/apple-touch-icon-120x120.png
  20. BIN
      public/img/icons/apple-touch-icon-152x152.png
  21. BIN
      public/img/icons/apple-touch-icon-180x180.png
  22. BIN
      public/img/icons/apple-touch-icon-60x60.png
  23. BIN
      public/img/icons/apple-touch-icon-76x76.png
  24. BIN
      public/img/icons/apple-touch-icon.png
  25. BIN
      public/img/icons/favicon-16x16.png
  26. BIN
      public/img/icons/favicon-32x32.png
  27. BIN
      public/img/icons/msapplication-icon-144x144.png
  28. BIN
      public/img/icons/mstile-150x150.png
  29. 3
      public/img/icons/safari-pinned-tab.svg
  30. 18
      public/index.html
  31. 2
      public/robots.txt
  32. 15
      rest/http-client.env.json
  33. 72
      rest/project.http
  34. 50
      src/App.vue
  35. BIN
      src/assets/3304e84039a79afb28ec854b2b215e92.png
  36. BIN
      src/assets/bg-top.png
  37. BIN
      src/assets/bt-lf01.png
  38. 21
      src/assets/icon/iconfont.css
  39. BIN
      src/assets/icon/iconfont.eot
  40. 29
      src/assets/icon/iconfont.svg
  41. BIN
      src/assets/icon/iconfont.ttf
  42. BIN
      src/assets/icon/iconfont.woff
  43. BIN
      src/assets/line.png
  44. BIN
      src/assets/title.png
  45. BIN
      src/assets/top-lf01.png
  46. BIN
      src/assets/top-rt.png
  47. BIN
      src/assets/康复-03.mp4
  48. 134
      src/common/index.styl
  49. 283
      src/common/portrait.styl
  50. 48
      src/components/Duration/Duration.js
  51. 52
      src/components/Duration/Duration.vue
  52. 166
      src/components/Info/Info.vue
  53. 38
      src/components/Statistics/Statistics.js
  54. 43
      src/components/Statistics/Statistics.vue
  55. 13
      src/config/api-user.js
  56. 21
      src/config/api.js
  57. 30
      src/config/setting.js
  58. 19
      src/config/user.js
  59. 25
      src/main.js
  60. 237
      src/mixins/socket.js
  61. 74
      src/plugins/ant-design-vue.js
  62. 77
      src/plugins/axios.js
  63. 34
      src/registerServiceWorker.js
  64. 22
      src/router/index.js
  65. 13
      src/store/index.js
  66. 28
      src/store/modules/home/actions.js
  67. 7
      src/store/modules/home/getters.js
  68. 6
      src/store/modules/home/index.js
  69. 24
      src/store/modules/home/mutations.js
  70. 6
      src/store/modules/home/state.js
  71. 7
      src/store/modules/messages/actions.js
  72. 3
      src/store/modules/messages/getters.js
  73. 11
      src/store/modules/messages/index.js
  74. 181
      src/store/modules/messages/mutations.js
  75. 16
      src/store/modules/messages/state.js
  76. 282
      src/views/Index/Index.vue
  77. 58
      src/views/Video/Video.vue
  78. 138
      vue.config.js
  79. 9343
      yarn.lock

3
.browserslistrc

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

8
.editorconfig

@ -0,0 +1,8 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 140
root = true

3
.env

@ -0,0 +1,3 @@
VUE_APP_MODE=production
VUE_APP_PREVIEW=false
VUE_APP_URL=http://www.tall.wiki/

10
.env.development

@ -0,0 +1,10 @@
VUE_APP_MODE=development
VUE_APP_NODE_ENV=development
VUE_APP_SCENE=wisdomcar
VUE_APP_BASE_URL=http://www.tall.wiki/
VUE_APP_API_URL=http://www.tall.wiki/wisdomcar
VUE_APP_PROXY_URL=/gateway
VUE_APP_PUBLIC_PATH=/wisdomcar
VUE_APP_MSG_URL=wss://www.tall.wiki/websocket/message/v4.0/ws
VUE_APP_TITLE=盐湖区人民医院数字看板
VUE_APP_DESCRIPTION=盐湖区人民医院数字看板

10
.env.production

@ -0,0 +1,10 @@
VUE_APP_MODE=production
VUE_APP_NODE_ENV=production
VUE_APP_SCENE=kangfu-screen/
VUE_APP_BASE_URL=http://www.tall.wiki/
VUE_APP_API_URL=http://www.tall.wiki/kangfu-screen
VUE_APP_PROXY_URL=/gateway
VUE_APP_PUBLIC_PATH=/kangfu-screen
VUE_APP_MSG_URL=wss://www.tall.wiki/websocket/message/v4.0/ws
VUE_APP_TITLE=盐湖区人民医院数字看板
VUE_APP_DESCRIPTION=盐湖区人民医院数字看板

47
.eslintrc.js

@ -0,0 +1,47 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
module.exports = {
root: true,
env: { browser: true, node: true },
extends: ['plugin:vue/recommended', 'plugin:vue/essential'],
rules: {
'vue/html-self-closing': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['state'] }],
'max-len': ['error', { code: 140, tabWidth: 2 }],
'object-curly-newline': ['error', { multiline: true }],
'arrow-parens': ['error', 'as-needed'],
'linebreak-style': 'off',
'vue/attributes-order': 'off',
'no-param-reassign': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/html-indent': 'off',
},
parserOptions: { parser: 'babel-eslint' },
overrides: [
{
files: ['**/__tests__/*.{j,t}s?(x)'],
env: { jest: true },
},
],
globals: {
Vue: true,
VueRouter: true,
Vuex: true,
axios: true,
_: true,
Vuetify: true,
vuetify: true,
},
};

23
.gitignore

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

13
.prettierrc

@ -0,0 +1,13 @@
{
"printWidth": 140,
"singleQuote": true,
"semi": true,
"trailingComma": "all",
"arrowParens": "avoid",
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"jsxBracketSameLine": false,
"proseWrap": "always",
"endOfLine": "lf"
}

24
README.md

@ -0,0 +1,24 @@
# 盐湖区人民医院数字看板
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Lints and fixes files
```
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

13
babel.config.js

@ -0,0 +1,13 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true
}
]
]
};

1
commitlint.config.js

@ -0,0 +1 @@
module.exports = {extends: ['./node_modules/vue-cli-plugin-commitlint/lib/lint']};

13755
package-lock.json

File diff suppressed because it is too large

51
package.json

@ -0,0 +1,51 @@
{
"name": "screen",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"ant-design-vue": "^1.2.4",
"compression-webpack-plugin": "^6.1.1",
"core-js": "^3.6.5",
"echarts": "^4.9.0",
"echarts-gl": "^1.1.1",
"moment": "^2.29.1",
"register-service-worker": "^1.7.1",
"stylus": "^0.54.8",
"vue": "^2.6.11",
"vue-dompurify-html": "^2.3.0",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-pwa": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-prettier": "^6.0.0",
"axios": "^0.18.0",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.11.0",
"css-loader": "^5.0.1",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^6.2.2",
"less": "^2.7.3",
"less-loader": "^4.1.0",
"prettier": "^1.19.1",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.2",
"svg-sprite-loader": "^5.0.0",
"vue-cli-plugin-ant-design": "^1.0.1",
"vue-cli-plugin-axios": "^0.0.4",
"vue-template-compiler": "^2.6.11"
}
}

BIN
public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
public/img/icons/android-chrome-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
public/img/icons/android-chrome-512x512.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
public/img/icons/android-chrome-maskable-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
public/img/icons/android-chrome-maskable-512x512.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/img/icons/apple-touch-icon-120x120.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
public/img/icons/apple-touch-icon-152x152.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/img/icons/apple-touch-icon-180x180.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
public/img/icons/apple-touch-icon-60x60.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/img/icons/apple-touch-icon-76x76.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
public/img/icons/apple-touch-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
public/img/icons/favicon-16x16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/img/icons/favicon-32x32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/img/icons/msapplication-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/img/icons/mstile-150x150.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

3
public/img/icons/safari-pinned-tab.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 215 B

18
public/index.html

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="./favicon.ico">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>脑卒中智慧远程康复诊疗服务云平台</title>
</head>
<body>
<noscript>
<strong>We're sorry but 脑卒中智慧远程康复诊疗服务云平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

2
public/robots.txt

@ -0,0 +1,2 @@
User-agent: *
Disallow:

15
rest/http-client.env.json

@ -0,0 +1,15 @@
{
"$shared": {
"version": "v1",
"identifier": "wally",
"credential": "111111"
},
"dev": {
"name": "dev",
"url": "http://192.168.0.99/gateway"
},
"local": {
"version": "v2",
"url": "http://192.168.0.99/gateway"
}
}

72
rest/project.http

@ -0,0 +1,72 @@
# @tall = {{url}}/tall/v1.0
@tall = http://www.tall.wiki/gateway/tall/v1.0
@greenvalley = http://www.sxwikionline.com/gateway/greenvalley
@record = https://www.tall.wiki/gateway/wisdomcar
@type = content-type: application/json;charset=utf-8
### login
# @name login
POST {{tall}}/users/signin
{{type}}
{
"client": 1,
"type": 3,
"data": {
"identifier": "song",
"credential": "999999"
}
}
### send code
GET {{tall}}/users/smscode?phone=16603418748
### phone login
# @name phonelogin
POST {{tall}}/users/signin
{{type}}
{
"client": 1,
"type": 1,
"data": {
"identifier": "16603418748",
"credential": "1111"
}
}
### 根据团队id查看研发团队相关信息
POST {{greenvalley}}/researchTeam/selectTeam
{{type}}
Authorization: Bearer {{login.response.body.$.data.token}}
{
"param": {
"company": "",
"researchDirection": "",
"teamId": 0,
"teamIntroduce": "",
"teamLeaderName": "",
"teamName": ""
}
}
### 根据团队id查看研发团队相关信息
POST {{record}}/debug/record
{{type}}
# Authorization: Bearer {{login.response.body.$.data.token}}
{
"param":{
"authId": "1",
"type": "2",
"value":"21",
"time":"1607937529000"
}
}

50
src/App.vue

@ -0,0 +1,50 @@
<template>
<a-config-provider :locale="zh_CN">
<div id="app">
<router-view></router-view>
</div>
</a-config-provider>
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import zh_CN from 'ant-design-vue/lib/locale-provider/zh_CN';
export default {
name: 'App',
data() {
return { zh_CN };
},
computed: mapState('home', ['anyringToken']),
created() {
// const userId = '1338747522436435968';
// const params = { userId };
// this.getUserId(params);
},
methods: mapActions('home', ['getUserId']),
};
</script>
<style>
html,
body,
#app {
min-height: 100%;
}
#app {
background: transparent;
}
body::-webkit-scrollbar {
width: 0;
}
</style>
<style lang="stylus">
@import './common/portrait.styl';
@import './common/index.styl';
</style>

BIN
src/assets/3304e84039a79afb28ec854b2b215e92.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
src/assets/bg-top.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/assets/bt-lf01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

21
src/assets/icon/iconfont.css

@ -0,0 +1,21 @@
@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1606814380789'); /* IE9 */
src: url('iconfont.eot?t=1606814380789#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALAAAsAAAAABnAAAAJ0AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp8gRABNgIkAwgLBgAEIAWEbQcvG7UFyJ6aPClS2/jAQpBlKUHgLEQQraGzf/cfBIUoGRWCjoqLMLFRrXRVrTH1bMRfztXeEwobfUDy1DOlP3OusGk5nTSH6gmFJ0tKIY+nBgQ4ZZ5fe/U+cbjXxvJA5jvvchlj0FiTJnUBxoEU0N4YbeEC+QD+h7ELXMJlAs2GJMUOR6aWoE1mzQrEm22q0JbzyzJLNQpVzcYsvio1Fp/FAXwJfx//IR9tFMrEqrh4HTag75dmZ6SPmhefIEBA20skLACZuKmNn2kUjNmoOd5kDOyrNPil1bVvE3v954mKVdwKBqDknqSu7Fb5C5DpzRiwMuoDpJaW1veXVeV5b+lxhVLteX355ZA+rS0ZjT+ex05fRr8/jR493lS0+Eefi/THEQbKv8zAm9u5cn11ob622gISIuUCqogn3i5OR1tKlzE/z2iuVkMfQC0tEYA/mX852tS7eVtLBj//5s/CKbVc+kDjvh3BP5L2bMm63LIWWZXWpgtjGs9d1awZddjd7Xusoe+G0qFR3205GwymSBpNEDN1AaUWi6g02kGzeaPbW/QQGkVuwpxNgNDpEoV235B0uiJm6hdK/f5R6YxGNLuLngNbTIXdcSBQlWgQrUZsnQfMscuOqHQBzZKniqw8ZCkoIjtEculsMTWKAYo5lkRlMy8lI0xwn4yA69DzOAkFd1CXaUvKsJDJsLo7pXXuQ4cDAlJJyEBoagibjgswv7PUUfr+AmQq8ahES1NNUIGEiN0/kZOW7UEc1QS9mu7llkiZKU+SGIIROB8xAsYhj4cjwvpxDqST0qwR0VBBxm7H+mrS6+v8r9sFzSxjEfaIpHzjuuoBAAA=') format('woff2'),
url('iconfont.woff?t=1606814380789') format('woff'),
url('iconfont.ttf?t=1606814380789') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1606814380789#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 14px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-local:before {
content: "\e662";
font-size: 20px;
}

BIN
src/assets/icon/iconfont.eot

Binary file not shown.

29
src/assets/icon/iconfont.svg

@ -0,0 +1,29 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="local" unicode="&#58978;" d="M720.0256 262.9504c115.168 115.5392 115.168 303.0336 0 418.5664-114.9376 115.3088-301.12 115.3088-416.0512 0-115.168-115.5328-115.168-303.0272 0-418.56L512 54.2464l208.0256 208.704z m-506.7072-90.3616c-164.96 165.4912-164.96 433.8048 0 599.296 164.96 165.4848 432.4032 165.4848 597.3632 0 164.96-165.4912 164.96-433.8048 0-599.296L512-127.0592l-298.6816 299.648zM512 345.6c-70.6944 0-128 57.3056-128 128s57.3056 128 128 128 128-57.3056 128-128-57.3056-128-128-128z" horiz-adv-x="1024" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 1018 B

BIN
src/assets/icon/iconfont.ttf

Binary file not shown.

BIN
src/assets/icon/iconfont.woff

Binary file not shown.

BIN
src/assets/line.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

BIN
src/assets/title.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
src/assets/top-lf01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
src/assets/top-rt.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
src/assets/康复-03.mp4

Binary file not shown.

134
src/common/index.styl

@ -0,0 +1,134 @@
.wrap{
position: absolute;
width: 100%;
height: 100%;
// color: #fff;
// background: url('assets/bg.jpg') no-repeat top;
background: #000A3B;
background-size: 100% 100%;
}
.wrap .bg-left{
position: absolute;
pointer-events: auto;
left: 10px;
top: 16px;
width: 12px;
height: 96%;
}
.wrap .bg-top{
position: absolute;
width: 97%;
margin: 0 auto;
height: 100.64px;
left: 1.5%;
top: 0;
z-index: 9;
}
.wrap .bg-top .animation{
position: absolute;
top: -1px;
left: 14%;
width: 72%;
height: 162px;
}
// .wrap .bg-top .animation video{
// width: 1346px;
// height: 162px;
// object-fit: fill;
// mix-blend-mode: screen;
// filter: saturate(200%);
// }
.wrap .bg-top .bg-title{
position: absolute;
left: 33%;
top: 1px;
width: 34%;
height: 66px;
line-height: 60px;
font-size: 30px;
color: #01F3FF;
text-align: center;
overflow: hidden;
cursor: pointer;
pointer-events: auto;
// transform: rotateX(0deg) rotateY(0deg) scaleX(1) scaleY(0.8) translate(0px, 0px);
text-shadow: #0196BD 0px 0px 8px;
}
@media (max-width: 1500px){
.wrap .bg-top .bg-title{
font-size: 38px;
}
}
.wrap .bg-right{
position: absolute;
pointer-events: auto;
right: 10px;
top: 16px;
width: 12px;
height: 96%;
}
.wrap .bg-bottom{
position: absolute;
pointer-events: auto;
left: 34px;
top: 96%;
width: 96%;
height: 13px;
}
.wrap .pic{
width: 100%;
height: 70%;
}
.content{
position: absolute;
top: 12%;
left: 2%;
width: 96%;
height: 87%;
}
.box-top{
width:100%;
height: 10px;
background: url('~assets/bg-top.png') no-repeat center;
background-size: 100% 100%;
text-align: center;
}
.box-top span{
display: inline-block;
position: relative;
top: -10px;
z-index: 999;
text-shadow: rgb(0, 117, 255) 0px 0px 8px;
font-family: SourceHanSansCN-Bold;
font-size: 1.2rem;
font-weight: bold;
text-align: center;
letter-spacing: 0px;
}
// .box-bottom{
// width:100%;
// background: url('assets/box-bottom.png') repeat fixed top;
// }
.s-pic{
width:191.85px;
height: 107.85px;
position: absolute;
top: 10px;
left: 10px;
border-radius: 6px;
overflow: hidden;
}

283
src/common/portrait.styl

@ -0,0 +1,283 @@
// padding
.pa-3 {
padding: 12px;
}
.px-2{
padding-left: 8px;
padding-right: 8px;
}
.px-3{
padding-left: 12px;
padding-right: 12px;
}
.px-10{
padding-left: 30px;
padding-right: 30px;
}
.pb-3 {
padding-bottom: 12px;
}
.pb-4 {
padding-bottom: 16px;
}
.pb-5 {
padding-bottom: 20px;
}
.pb-10 {
padding-bottom: 40px;
}
// margin
.ma-2 {
margin: 8px;
}
.ma-3 {
margin: 12px;
}
.mx-2{
margin-left: 8px;
margin-right: 8px;
}
.my-2{
margin-top: 8px;
margin-bottom: 8px;
}
.my-3{
margin-top: 12px;
margin-bottom: 12px;
}
.my-4{
margin-top: 16px;
margin-bottom: 16px;
}
.mt-1{
margin-top: 4px;
}
.mt-2{
margin-top: 8px;
}
.mt-3{
margin-top: 12px;
}
.mt-4{
margin-top: 16px;
}
.mb-1{
margin-bottom: 4px;
}
.mb-2{
margin-bottom: 8px;
}
.mb-3{
margin-bottom: 12px;
}
.mb-4{
margin-bottom: 16px;
}
.ml-2{
margin-left: 8px;
}
.ml-3{
margin-left: 12px;
}
.ml-4{
margin-left: 16px;
}
.ml-5{
margin-left: 20px;
}
.ml-6{
margin-left: 24px;
}
.ml-7{
margin-left: 28px;
}
.ml-8{
margin-left: 32px;
}
.mr-1{
margin-right: 4px;
}
.mr-2{
margin-right: 8px;
}
.mr-3{
margin-right: 12px;
}
.mr-4{
margin-right: 16px;
}
.mr-5{
margin-right: 20px;
}
.mr-6{
margin-right: 24px;
}
// background
.white {
background: white;
}
// flex
.d-flex{
display: flex;
}
.flex-wrap{
flex-wrap: wrap;
}
.flex-nowrap{
flex-wrap: nowrap;
}
.flex-column{
flex-direction: column;
}
.flex-column-reverse{
flex-direction: column-reverse;
}
.flex-row{
flex-direction: row;
}
.flex-row-reverse{
flex-direction: row-reverse;
}
.justify-center{
justify-content: center;
}
.justify-space-between{
justify-content: space-between;
}
.align-center{
align-items: center;
}
.flex-1{
display: flex;
flex: 1;
}
.flex-2{
display: flex;
flex: 2;
}
.flex-3{
display: flex;
flex: 3;
}
// other
.pointer{
cursor:pointer;
}
.fill-height{
height:100%;
}
// font
.font-bold-24{
font-size: 24px;
font-weight: bold;
}
.font-24{
font-size: 24px;
}
.font-bold-16{
font-size: 16px;
font-weight: bold;
}
.font-16{
font-size: 16px;
}
.font-bold-14{
font-size: 14px;
font-weight: bold;
}
.font-14{
font-size: 14px;
}
.icon-size{
font-size: 20px;
}
h2{
font-size: 24px;
font-weight: bold;
color: rgba(0,0,0,.85)
}
.textColor{
color: rgba(0,0,0,.65)
}
.baseColor{
color: #13ACC4
}
.bg{
background: #F5F5F5
}
.ant-btn-primary{
background-color: #13ACC4
border-color: #13ACC4;
}
.ant-btn-link:hover, .ant-btn-link:focus{
color: #13ACC4;
}
.fill-width{
width:100%;
}
.fill-height{
height:100%;
}

48
src/components/Duration/Duration.js

@ -0,0 +1,48 @@
const option = {
tooltip: { trigger: 'axis' },
legend: {
data: ['标准恢复状态', '历史恢复状态'],
icon: 'diamond',
bottom: 0,
textStyle: { color: '#01F3FF' },
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
axisLabel: { color: '#01F3FF' },
},
yAxis: {
type: 'value',
axisLabel: { color: '#01F3FF' },
splitLine: {
//分割线配置
show: true,
lineStyle: { color: '#333' },
},
},
series: [
{
name: '标准恢复状态',
type: 'line',
data: [10, 132, 101, 134, 90, 230, 210],
smooth: true,
color: '#FF1493',
},
{
name: '历史恢复状态',
type: 'line',
color: '#DAA520',
data: [20, 182, 191, 234, 290, 330, 310],
smooth: true,
lineStyle: { color: '#DAA520' },
},
],
};
export default option;

52
src/components/Duration/Duration.vue

@ -0,0 +1,52 @@
<template>
<!-- <div>数据统计组件</div> -->
<div :style="{ width: 'width', height: 'height' }" class="chart-box">
<div id="Duration" style="width: 100%; height: 160%"></div>
</div>
</template>
<script>
import option from './Duration.js';
export default {
name: 'Duration',
data() {
return {
// msg: 'Welcome to Your Vue.js App',
width: '',
height: '',
timer: null,
};
},
mounted() {
this.drawLine();
this.timer = setInterval(() => {
this.drawLine();
}, 10000);
let wh = window.innerWidth;
let hg = window.innerHeight;
this.width = wh + 'px';
this.height = hg + 'px';
console.log(this.height);
window.onresize = () => {
return (() => {
wh = window.innerWidth;
hg = window.innerHeight;
this.width = wh + 'px';
this.height = hg + 'px';
})();
};
},
destroyed() {
clearInterval(this.timer);
},
methods: {
drawLine() {
// domecharts
let myChart = this.$echarts.init(document.getElementById('Duration'));
//
myChart.setOption(option);
},
},
};
</script>
<style lang="stylus" scoped ></style>

166
src/components/Info/Info.vue

@ -0,0 +1,166 @@
<template>
<div class="info-box">
<span class="doctor-box">{{ str }}{{ doctor }}</span>
<div>
<img src="~assets/line.png" alt="" />
<div class="d-flex">
<div v-for="item in infoList" :key="item" class="flex-1 justify-center infoColor">{{ item }}</div>
</div>
</div>
<div>
<img src="~assets/line.png" alt="" />
<div class="d-flex">
<div v-for="item in conList" :key="item" class="flex-1 justify-center infoColor">{{ item }}</div>
</div>
</div>
<div>
<img src="~assets/line.png" alt="" />
</div>
<div class="con-box">
<div class="time-box" v-for="(item, index) in list" :key="index">
<div class="num-box">{{ index + 1 }}</div>
<div class="time">
{{ item.date }} <span style="margin-left: 10px"> {{ item.time }}</span>
</div>
<div v-if="item.tips" class="con-tips">
{{ item.tips }}
</div>
<div class="con-content">
{{ item.content }}
</div>
<div class="con-num">
{{ item.num }}
</div>
<div class="bder"></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Info',
data() {
return {
str: '主治医生:',
doctor: '李阳',
infoList: ['姓名', '出生日期', '病情', '目前状态', '治疗次数', '出院时间'],
conList: ['庞谷山', '1985-04-17', '关节中风', '较严重', '5次', '2020-12-04'],
list: [
{
date: '12-25',
time: '15:00',
tips: '训练处方',
num: '98分',
content: 'Bobath握手训练:每天5次,每次4组,每组10遍; 对指训练:每天4次,每次4组,每组10遍',
},
{
date: '12-20',
time: '09:00',
num: '89分',
content: 'Bobath握手训练:每天5次,每次4组,每组10遍; 对指训练:每天4次,每次4组,每组10遍',
},
{
date: '12-19',
time: '13:00',
num: '90分',
content: 'Bobath握手训练:每天5次,每次4组,每组10遍; 对指训练:每天4次,每次4组,每组10遍',
},
],
};
},
};
</script>
<style lang="stylus" scoped>
.info-box {
height: 100%;
width: 100%;
padding: 40px 40px;
z-index: 10;
}
.doctor-box {
border: 1px solid #006CC8;
color: #1C9043;
font-size: 14px;
padding: 1px 4px;
font-weight: bold;
}
.infoColor {
color: #70c5ff;
font-size: 14px;
font-weight: bold;
}
.con-box {
margin-top: 2%;
height: 74%;
}
.time-box {
height: 30%;
margin-bottom: 3%;
position: relative;
}
.bder {
position: absolute;
height: 80%;
width: 70%;
bottom: 0;
left: 6px;
border-left: 1px solid #1a224f;
border-bottom: 1px solid #1a224f;
}
.num-box {
position: absolute;
left: 0;
top: 0;
width: 14px;
height: 14px;
font-size: 12px;
color: #fff;
text-align: center;
line-height: 14px;
border-radius: 50%;
background: #006CC8;
}
.time {
position: absolute;
left: 20px;
height: 14px;
line-height: 14px;
top: 0;
color: #02D9FD;
}
.con-tips {
position: absolute;
top: 22%;
left: 4%;
color: red;
}
.con-content {
position: absolute;
top: 40%;
left: 4%;
width: 74%;
font-size: 14px;
color: #70C5FF;
}
.con-num {
position: absolute;
right: 8%;
color: #C20707;
font-size: 20px;
font-weight: bold;
top: 50%;
}
</style>

38
src/components/Statistics/Statistics.js

@ -0,0 +1,38 @@
const option = {
title: {
text: '总分:100分',
right: '10%',
top: '10%',
textStyle: {
color: '#01F3FF',
fontSize: '16px',
},
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisLabel: { color: '#01F3FF' },
},
yAxis: {
type: 'value',
axisLabel: { color: '#01F3FF' },
splitLine: {
//分割线配置
show: true,
lineStyle: { color: '#333' },
},
},
series: [
{
data: [34, 45, 20, 81, 70, 50, 40],
type: 'bar',
showBackground: true,
barWidth: '40%',
color: '#3451B0',
// color: '#F2704D',
backgroundStyle: { color: 'rgba(220, 220, 220, 0.8)' },
},
],
};
export default option;

43
src/components/Statistics/Statistics.vue

@ -0,0 +1,43 @@
<template>
<!-- <div>数据统计组件</div> -->
<div :style="{ width: 'width', height: 'height' }" style="padding-top: 10%" class="chart-box">
<div id="myChart" style="width: 100%; height: 220%"></div>
</div>
</template>
<script>
import option from './Statistics.js';
export default {
name: 'Statistics',
data() {
return {
width: '',
height: '',
};
},
mounted() {
this.drawLine();
let wh = window.innerWidth;
let hg = window.innerHeight;
this.width = wh + 'px';
this.height = hg + 'px';
window.onresize = () => {
return (() => {
wh = window.innerWidth;
hg = window.innerHeight;
this.width = wh + 'px';
this.height = hg + 'px';
})();
};
},
methods: {
drawLine() {
// domecharts
let myChart = this.$echarts.init(document.getElementById('myChart'));
//
myChart.setOption(option);
},
},
};
</script>
<style lang="stylus" scoped ></style>

13
src/config/api-user.js

@ -0,0 +1,13 @@
/*
* Copyright (c) 2020.
* author: wally
* email: 18603454788@163.com
*/
import axios from 'axios';
let { proxyUrl, msgUrl } = require('@/config/setting');
const tall = `${proxyUrl}/tall/v1.0`;
const users = `${tall}/users`;
// 查找用户详细信息
export const getUserId = params => axios.get(`${users}/userId`, params);

21
src/config/api.js

@ -0,0 +1,21 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
import axios from 'axios';
let { proxyUrl, msgUrl } = require('@/config/setting');
const wisdomcar = `${proxyUrl}/wisdomcar`; // 盐湖医院分路径
const statistics = `${wisdomcar}/statistics`; // 盐湖医院相关接口
// websocket基础地址
export const WS_BASE_URL = msgUrl;
// 按钮模拟信息发送
export const record = params => axios.post(`${wisdomcar}/debug/record`, params);
// 急救数量统计图数据
export const selResult = params => axios.post(`${statistics}/get/selResult`, params);
// 急救时长分析统计图数据
export const getPointTime = params => axios.post(`${statistics}/getPointTime`, params);

30
src/config/setting.js

@ -0,0 +1,30 @@
const title = process.env.VUE_APP_TITLE;
const description = process.env.VUE_APP_DESCRIPTION;
const baseUrl = process.env.VUE_APP_BASE_URL;
const apiUrl = process.env.VUE_APP_API_URL;
const proxyUrl = process.env.VUE_APP_PROXY_URL;
const publicPath = process.env.VUE_APP_PUBLIC_PATH;
const msgUrl = process.env.VUE_APP_MSG_URL;
module.exports = {
// 首页标题
title,
// 首页描述信息
description,
// 基础地址
baseUrl,
// api基础地址
apiUrl,
// 消息系统地址
msgUrl,
// api代理地址
proxyUrl,
// 生成文件目录 publicPath
publicPath,
};

19
src/config/user.js

@ -0,0 +1,19 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
// 用户登录client
export const SIGN_IN_CLIENTS = { mp: 0, h5: 1, android: 2, ios: 3 };
// 用户登录类型
export const SIGN_IN_TYPES = {
mp: 0,
phone: 1,
email: 2,
username: 3,
wx: 4,
wx_web: 5,
wb: 6,
};

25
src/main.js

@ -0,0 +1,25 @@
// @ts-ignore
import Vue from 'vue';
import './plugins/axios';
import App from './App.vue';
import './registerServiceWorker';
import router from './router';
import store from './store';
import './plugins/ant-design-vue.js';
import 'common/portrait.styl';
import echarts from 'echarts';
import 'echarts-gl';
import 'echarts/map/js/province/shanxi.js'; //对应的省份
// Vue.use(echarts);
Vue.prototype.$echarts = echarts;
// import './assets/icon/iconfont.css';
// import VueDOMPurifyHTML from 'vue-dompurify-html';
// import moment from 'moment'; //导入文件
// Vue.prototype.$moment = moment; //赋值使用
Vue.config.productionTip = false;
window.vm = new Vue({
router,
store,
render: h => h(App),
}).$mount('#app');

237
src/mixins/socket.js

@ -0,0 +1,237 @@
import { WS_BASE_URL } from 'config/api';
import { mapGetters, mapMutations } from 'vuex';
let connected = false; // socket 是否连接
let socket = null; // websocket 实例
let lockSocket = false;
let socketMsgQueue = []; // socket消息队列
let prevTimestamp = 0; // 上次收到消息的时间戳
let sendHeartTimer = null; // 💓的timer计时器
const mixin = {
// computed: mapGetters('home', ['projectId']),
mounted() {
socket ? socket.close() : this.initSocket();
},
methods: {
...mapMutations('messages', [
'messagesAdd',
'messagesAddWeight',
'setStartMessages',
'messagesAddRfid',
'messagesAddWeighSensor1',
'messagesAddWeighSensor2',
'messagesAddWeighSensor3',
'messagesAddWeighSensor4',
'messagesAddVibrationSensor',
'messagesAddThrombolyticDose',
'messagesAddBolusDose',
'messagesAddMaintenanceDose',
]),
// ...mapMutations('home', ['increaseProjectsRingNum']),
// 初始化websocket
initSocket() {
if (lockSocket) return;
lockSocket = true;
// const token = sessionStorage.getItem('anyringToken');
// if (!token) return;
if ('WebSocket' in window) {
socket = new WebSocket(WS_BASE_URL);
socket.onopen = this.websocketOpen;
socket.onmessage = this.websocketOnMessage;
socket.onclose = this.websocketClose;
socket.onerror = this.websocketError;
} else {
// @ts-ignore
this.$message.error('当前浏览器不支持 websocket');
}
lockSocket = false;
},
/**
* 处理收到的消息内容
* @param {object} item 单个消息体对象
*/
handleMessagesData(item) {
const data = JSON.parse(item.data);
switch (data.type) {
case 'ChannelStatus': // 认证消息
this.handleAuthMessage(data);
break;
case 'CarRecord': // 平车
// if (!data.data.type) return;
switch (data.data.type) {
case 0: // 开始
// 收到开始消息
this.setStartMessages(true);
this.messagesAddRfid(null);
break;
case 1: // 体重
// 收到同步消息
// 把消息添加到store 的消息栈中
this.messagesAddWeight(data.data.value);
break;
case 2: // RFID
this.messagesAddRfid(data.data);
console.log('data.data: ', data.data);
break;
case 3: // 称重传感器一
this.messagesAddWeighSensor1(data.data.value);
break;
case 4: // 称重传感器二
this.messagesAddWeighSensor2(data.data.value);
break;
case 5: // 称重传感器三
this.messagesAddWeighSensor3(data.data.value);
break;
case 6: // 称重传感器四
this.messagesAddWeighSensor4(data.data.value);
break;
case 7: // 震动传感器
this.messagesAddVibrationSensor(data.data);
break;
case 8: // 溶栓剂量(总量)
this.messagesAddThrombolyticDose(data.data.value);
break;
case 9: // 团注剂量
this.messagesAddBolusDose(data.data.value);
break;
case 10: // 维持剂量
this.messagesAddMaintenanceDose(data.data.value);
break;
default:
break;
}
break;
default:
break;
}
},
/**
*
* data:{
* data: {
* value: ''
* },
* type: '',
* }
*/
/**
* 收到ws 消息
* @param {object} res 收到的消息数据
*/
async websocketOnMessage(res) {
try {
prevTimestamp = Date.now();
// console.warn('message: ', res, new Date().toLocaleString());
if (res && res.data && JSON.parse(res.data)) {
const resData = JSON.parse(res.data);
const { messageSet, ackId } = resData;
// 处理消息体对象
messageSet.forEach(item => this.handleMessagesData(item));
// console.log('ackId', ackId);
// 有ackId 发送ack
ackId && this.sendSocketMessage({ type: 'Ack', data: { ackId } });
}
} catch (error) {
console.error('error: ', error);
}
},
// 打开socket
websocketOpen() {
// console.warn('socket 打开成功', new Date().toLocaleString());
connected = true;
prevTimestamp = Date.now();
this.auth();
for (let i = 0; i < socketMsgQueue.length; i += 1) {
this.sendSocketMessage(socketMsgQueue[i]);
}
socketMsgQueue = [];
},
// 发送消息
sendSocketMessage(data) {
// console.warn('send:', data, new Date().toLocaleString());
if (connected) {
if (socket.readyState === 1) {
socket.send(JSON.stringify({ toDomain: 'Server', data: JSON.stringify(data) }));
}
} else {
socketMsgQueue.push(data);
}
},
// 关闭socket
websocketClose(e) {
// console.warn(e);
connected = false;
if (sendHeartTimer) clearInterval(sendHeartTimer);
// console.warn('close:', connected, new Date().toLocaleString());
if (!e || e.code !== 1005) {
socket.close();
}
setTimeout(() => {
// connected 在这里的作用是:
// 在发生重连 但是还没连上之前 不要再次重连
this.initSocket();
}, 300);
},
// 连接失败
websocketError() {
console.warn('error = ', connected);
},
// websocket发送token进行认证
auth() {
// const token = sessionStorage.getItem('anyringToken');
// if (!token) return;
const userId = '1338747522436435968';
const data = { type: 'Auth', data: { userId }, major: 1, minor: 1 };
this.sendSocketMessage(data);
},
// 心跳检测
sendHeart() {
if (sendHeartTimer) clearInterval(sendHeartTimer);
sendHeartTimer = setInterval(() => {
if (Date.now() - prevTimestamp >= 15000) {
this.sendSocketMessage({ type: 'Ping' });
if (Date.now() - prevTimestamp > 20000) {
// console.warn('手动断开');
socket.close();
}
}
}, 5000);
},
/**
* 处理auth认证返回的ChannelStatus消息
* @param {object} data 消息内容对象
*/
handleAuthMessage(data) {
if (data.data.authed) {
// 认证成功
this.sendHeart();
} else {
this.$message.error('消息系统认证失败, 请重新登录');
// 清除掉本地无用的token
sessionStorage.removeItem('anyringToken');
socket = null;
setTimeout(() => {
this.$router.push('/user/login');
}, 1000);
}
},
},
};
export default mixin;

74
src/plugins/ant-design-vue.js

@ -0,0 +1,74 @@
import Vue from 'vue';
import {
Pagination,
Button,
Input,
message,
notification,
Modal,
Tag,
Table,
Tabs,
Icon,
Empty,
Form,
Select,
Upload,
Badge,
Popconfirm,
DatePicker,
Switch,
Radio,
Dropdown,
Menu,
Row,
Col,
Timeline,
Checkbox,
BackTop,
Progress,
carousel,
Spin,
} from 'ant-design-vue';
import { ConfigProvider } from 'ant-design-vue';
Vue.component(ConfigProvider.name, ConfigProvider);
Vue.use(Pagination);
Vue.use(Button);
Vue.use(Input);
Vue.use(Modal);
Vue.use(Tag);
Vue.use(Table);
Vue.use(Tabs);
Vue.use(Icon);
Vue.use(Empty);
Vue.use(Form);
Vue.use(Select);
Vue.use(Upload);
Vue.use(Badge);
Vue.use(Popconfirm);
Vue.use(DatePicker);
Vue.use(Switch);
Vue.use(Radio);
Vue.use(Dropdown);
Vue.use(Menu);
Vue.use(Row);
Vue.use(Col);
Vue.use(Timeline);
Vue.use(Checkbox);
Vue.use(BackTop);
Vue.use(Progress);
Vue.use(carousel);
Vue.use(Spin);
Vue.prototype.$message = message;
Vue.prototype.$notification = notification;
Vue.prototype.$info = Modal.info;
Vue.prototype.$success = Modal.success;
Vue.prototype.$error = Modal.error;
Vue.prototype.$warning = Modal.warning;
Vue.prototype.$confirm = Modal.confirm;
message.config({
duration: 3,
maxCount: 3,
});

77
src/plugins/axios.js

@ -0,0 +1,77 @@
'use strict';
import Vue from 'vue';
import axios from 'axios';
import router from '../router/index';
import store from '../store/index';
// Full config: https://github.com/axios/axios#request-config
// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
let config = {
// baseURL: process.env.baseURL || process.env.apiUrl || ""
timeout: 60 * 1000, // Timeout
// withCredentials: true, // Check cross-site Access-Control
};
const _axios = axios.create(config);
axios.interceptors.request.use(
function(config) {
let token = store.state.anyringToken || sessionStorage.getItem('anyringToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
function(error) {
// Do something with request error
return Promise.reject(error);
},
);
// Add a response interceptor
axios.interceptors.response.use(
function(response) {
if (response.data && response.data.code >= 400 && response.data.code < 500) {
store.commit('user/sign', '');
router.replace({
path: '/user/login',
query: { redirect: router.currentRoute.fullPath },
});
}
// Do something with response data
return response;
},
function(error) {
// Do something with response error
return Promise.reject(error);
},
);
Plugin.install = function(Vue) {
Vue.axios = _axios;
window.axios = _axios;
Object.defineProperties(Vue.prototype, {
axios: {
get() {
return _axios;
},
},
$axios: {
get() {
return _axios;
},
},
$http: {
get() {
return _axios;
},
},
});
};
Vue.use(Plugin);
export default Plugin;

34
src/registerServiceWorker.js

@ -0,0 +1,34 @@
/* eslint-disable no-console */
import { register } from "register-service-worker";
if (process.env.NODE_ENV === "production") {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log(
"App is being served from cache by a service worker.\n" +
"For more details, visit https://goo.gl/AFskqB"
);
},
registered() {
console.log("Service worker has been registered.");
},
cached() {
console.log("Content has been cached for offline use.");
},
updatefound() {
console.log("New content is downloading.");
},
updated() {
console.log("New content is available; please refresh.");
},
offline() {
console.log(
"No internet connection found. App is running in offline mode."
);
},
error(error) {
console.error("Error during service worker registration:", error);
}
});
}

22
src/router/index.js

@ -0,0 +1,22 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from 'views/Video/Video.vue';
Vue.use(VueRouter);
const routes = [
// 首页
{
path: '/',
name: 'Home',
component: Home,
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
export default router;

13
src/store/index.js

@ -0,0 +1,13 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
import Vue from 'vue';
import Vuex from 'vuex';
import home from './modules/home/index';
import messages from './modules/messages/index';
Vue.use(Vuex);
export default new Vuex.Store({ modules: { home, messages } });

28
src/store/modules/home/actions.js

@ -0,0 +1,28 @@
import axios from 'axios';
import { message } from 'ant-design-vue';
import { getUserId } from 'config/api-user';
const actions = {
/**
* 通过userId获取token
* @param {any} commit
* @param {object} params 提交的参数
*/
async getUserId({ commit }, params) {
try {
const res = await getUserId({ params });
const { code, msg, data } = res.data;
if (code === 200) {
commit('sign', data.token);
commit('setUser', data);
return data;
} else {
throw msg;
}
} catch (error) {
throw error || '获取个人信息失败';
}
},
};
export default actions;

7
src/store/modules/home/getters.js

@ -0,0 +1,7 @@
const getters = {};
// 域定制导航展示形式
// 0 -> 无特殊导航文字
// 1 -> 横向定制导航
// 2 -> 纵向定制导航
export default getters;

6
src/store/modules/home/index.js

@ -0,0 +1,6 @@
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
import state from './state';
export default { namespaced: true, state, getters, mutations, actions };

24
src/store/modules/home/mutations.js

@ -0,0 +1,24 @@
const mutations = {
/**
* 设置token
* @param { object } state
* @param { string } token
*/
sign(state, token) {
state.anyringToken = token;
sessionStorage.setItem('anyringToken', token);
},
/**
* 设置user用户信息
* @param {object} state
* @param {object} user {id, account, phone}
*/
setUser(state, user) {
if (!user) return;
state.user = { ...user };
sessionStorage.setItem('user', JSON.stringify(user));
},
};
export default mutations;

6
src/store/modules/home/state.js

@ -0,0 +1,6 @@
const state = {
anyringToken: '',
user: { id: '', phone: '', account: '' },
};
export default state;

7
src/store/modules/messages/actions.js

@ -0,0 +1,7 @@
import http from 'axios';
import { message } from 'ant-design-vue';
import {} from 'config/api';
const actions = {};
export default actions;

3
src/store/modules/messages/getters.js

@ -0,0 +1,3 @@
const getters = {};
export default getters;

11
src/store/modules/messages/index.js

@ -0,0 +1,11 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
import state from './state';
export default { namespaced: true, state, getters, mutations, actions };

181
src/store/modules/messages/mutations.js

@ -0,0 +1,181 @@
const mutations = {
/**
* 初始化消息栈
* @param {object} state
* @param {string} type
* type:
* syncMessages 同步消息栈
* checkMessages 交付物消息栈
* faultMessages 故障消息 未处理消息栈
* faults 所有的故障消息栈
*/
messagesInit(state, type) {
const messages = localStorage.getItem(type) ? JSON.parse(localStorage.getItem(type)) : [];
state[type] = messages;
},
/**
* 将新 消息添加到 消息栈 最前边
* @param { object } state
* @param { object } data
* data: message, type
* message 消息对象
* type:
* syncMessages 同步消息栈
* checkMessages 交付物消息栈
* faultMessages 故障消息 未处理消息栈
* faults 所有的故障消息栈
*
* cache: boolean true 本地存储 false 不存储
*/
messagesAdd(state, data) {
const messages = state[data.type];
if (messages.length > 0) {
const result = messages.find(msg => msg.id === data.message.id);
if (result) return;
}
messages.unshift(data.message);
// eslint-disable-next-line no-param-reassign
state[data.type] = messages;
if (data.cache) {
localStorage.setItem(data.type, JSON.stringify(messages));
}
},
/**
* 通过消息id移除指定 同步 消息
* @param { object } state
* @param { object } data
* data: messageId, type
* messageId: 要移除的消息的messageId
* type:
* syncMessages 同步消息栈
* checkMessages 交付物消息栈
* faultMessages 故障消息 未处理消息栈
* faults 所有的故障消息栈
* cache: boolean true 本地存储 false 不存储
*/
messagesRemoveById(state, data) {
const messages = state[data.type];
const index = messages.findIndex(msg => msg.id === data.messageId);
if (index < 0) return;
messages.splice(index, 1);
// eslint-disable-next-line no-param-reassign
state[data.type] = messages;
if (data.cache) {
localStorage.setItem(data.type, JSON.stringify(messages));
}
},
/**
* 清除指定type的消息
* @param {any} state
* @param {object} data
* data: type, cache
*/
messagesClear(state, data) {
state[data.type] = [];
if (data.cache) {
localStorage.removeItem(data.type);
}
},
/**
* 添加体重消息
* @param {*} state
* @param {*} data
*/
messagesAddWeight(state, data) {
state.weightMessage = data;
},
/**
* 添加RFID消息
* @param {*} state
* @param {*} data
*/
messagesAddRfid(state, data) {
state.rfidMessage = data;
},
/**
* 添加称重传感器一消息
* @param {*} state
* @param {*} data
*/
messagesAddWeighSensor1(state, data) {
state.weighSensor1 = data;
},
/**
* 添加称重传感器二消息
* @param {*} state
* @param {*} data
*/
messagesAddWeighSensor2(state, data) {
state.weighSensor2 = data;
},
/**
* 添加称重传感器三消息
* @param {*} state
* @param {*} data
*/
messagesAddWeighSensor3(state, data) {
state.weighSensor3 = data;
},
/**
* 添加称重传感器四消息
* @param {*} state
* @param {*} data
*/
messagesAddWeighSensor4(state, data) {
state.weighSensor4 = data;
},
/**
* 添加震动传感器消息
* @param {*} state
* @param {*} data
*/
messagesAddVibrationSensor(state, data) {
state.vibrationSensor = data;
},
/**
* 添加溶栓剂量总量消息
* @param {*} state
* @param {*} data
*/
messagesAddThrombolyticDose(state, data) {
state.thrombolyticDose = data;
},
/**
* 添加团注剂量消息
* @param {*} state
* @param {*} data
*/
messagesAddBolusDose(state, data) {
state.bolusDose = data;
},
/**
* 添加维持剂量消息
* @param {*} state
* @param {*} data
*/
messagesAddMaintenanceDose(state, data) {
state.maintenanceDose = data;
},
/**
* 重新开始
* @param {*} state
* @param {*} data
*/
setStartMessages(state, data) {
state.startMessages = data;
},
};
export default mutations;

16
src/store/modules/messages/state.js

@ -0,0 +1,16 @@
const state = {
startMessages: false, // 是否重新开始 true为开始
syncMessages: [], // 同步消息
weightMessage: 0, // 体重
rfidMessage: null, // RFID
weighSensor1: 0, // 称重传感器一
weighSensor2: 0, // 称重传感器二
weighSensor3: 0, // 称重传感器三
weighSensor4: 0, // 称重传感器四
vibrationSensor: null, // 震动传感器
thrombolyticDose: 0, // 溶栓剂量(总量)
bolusDose: 0, // 团注剂量
maintenanceDose: 0, // 维持剂量
};
export default state;

282
src/views/Index/Index.vue

@ -0,0 +1,282 @@
<template>
<div class="wrap">
<div v-if="!showVideo">
<div class="bg-top">
<img class="pic" src="~assets/bg-top.png" />
<span class="bg-title">脑卒中智慧远程康复诊疗服务云平台</span>
</div>
<div class="time">
<div class="time-content">目前有23人正在接受治疗共有127名在职医生全程服务于康复治疗病人当前已治愈有 {{ manNum }} 名病人</div>
</div>
<!--内容区-->
<div class="content flex-1">
<!-- 第一列 -->
<div class="flex-1 ma-2 flex-column">
<!-- 第一行 -->
<div class="d-flex flex-column flex-3" style="position: relative">
<img src="~assets/top-lf01.png" style="position: absolute; width: 96%; height: 94%; top: 20px; left: 2%" />
<img src="~assets/title.png" class="bg-img-title" />
<div class="bg-img-title title-style" style="line-height: 40px">病人信息</div>
<info />
</div>
<!-- 第二行 -->
<div class="d-flex flex-column flex-1" style="overflow: hidden; position: relative">
<img src="~assets/bt-lf01.png" style="position: absolute; width: 96%; height: 90%; bottom: 5px; left: 2%" />
<img src="~assets/title.png" class="bg-title1" />.
<div class="bg-img-title title-style" style="line-height: 24px">恢复状态对比</div>
<duration />
</div>
</div>
<!-- 第二列 -->
<div class="flex-2 ma-2 flex-column">
<!-- 第一行 -->
<div class="d-flex flex-column flex-2" style="position: relative">
<img src="~assets/top-rt.png" class="bg-img" style="width: 99%; top: 20px" />
<img src="~assets/title.png" class="bg-img-title" />
<div class="bg-img-title title-style" style="line-height: 40px">实时数据</div>
<div style="z-index: 100" class="video-box1">
<iframe
width="100%"
height="100%"
frameborder="0"
scrolling="no"
src="https://www.tall.wiki/zego/av/#/au?roomId=ccsens"
></iframe>
</div>
</div>
<!-- 第二行 -->
<div class="d-flex flex-1">
<!-- 打卡得分表 -->
<div class="d-flex fill-width flex-column flex-2" style="overflow: hidden; position: relative">
<img src="~assets/top-lf01.png" class="bg-img" style="width: 94%" />
<img src="~assets/title.png" class="bg-title1" />
<div class="bg-img-title title-style" style="line-height: 24px">打卡得分表</div>
<statistics style="margin-top: 16px" />
</div>
<!-- 病人视频1 -->
<div class="d-flex flex-column flex-3" style="position: relative">
<img src="~assets/top-lf01.png" class="bg-img" style="width: 96%" />
<img src="~assets/title.png" class="bg-title1" />
<div class="bg-img-title title-style" style="line-height: 24px">病人视频1</div>
<div style="z-index: 100" class="video-box">
<iframe
width="100%"
height="100%"
frameborder="0"
scrolling="no"
src="https://www.tall.wiki/kangfu-v1/?key=E83239936"
></iframe>
</div>
<div class="video-tips d-flex justify-space-between">
<span>地址运城市盐湖区中城跃伟诊所</span>
<span>{{ nowTime }}</span>
</div>
</div>
<!-- 病人视频2 -->
<div class="d-flex flex-column flex-3" style="position: relative">
<img src="~assets/top-lf01.png" class="bg-img" style="width: 97%" />
<img src="~assets/title.png" class="bg-title1" />
<div class="bg-img-title title-style" style="line-height: 24px">病人视频2</div>
<div style="z-index: 100" class="video-box">
<iframe
width="100%"
height="100%"
frameborder="0"
scrolling="no"
src="https://www.tall.wiki/kangfu-v1/?key=230659446"
></iframe>
</div>
<div class="video-tips d-flex justify-space-between">
<span>地址运城市盐湖区中城跃伟诊所</span>
<span>{{ nowTime }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else>
<!-- <img class="fill-width fill-height" src="~assets/aaa.png" /> -->
</div>
</div>
</template>
<script>
import socketMixin from '@/mixins/socket';
import Statistics from 'components/Statistics/Statistics.vue';
import Duration from 'components/Duration/Duration.vue';
import Info from 'components/Info/Info.vue';
// import Statistics from 'components/Statistics/Statistics.vue';
// import Duration from 'components/Duration/Duration.vue';
// import Sensor from 'components/Sensor/Sensor.vue';
// import LoadCells from 'components/LoadCells/LoadCells.vue';
// import RFID from 'components/RFID/RFID.vue';
// import FastEd from 'components/FastEd/FastEd.vue';
// import Panel from 'components/Panel/Panel.vue';
// import ShanxiMap from 'components/Map/Map.vue';
export default {
name: 'Index',
components: { Statistics, Duration, Info },
mixins: [socketMixin],
data() {
return {
nowTime: new Date(),
str: '',
showVideo: false,
manNum: 359,
timer: null,
};
},
mounted() {
this.nowTimes();
},
created() {
this.timer = setInterval(() => {
this.manNum += 5;
}, 30000);
},
beforeDestroy() {
clearInterval(this.timer);
this.timer = null;
},
methods: {
//
timeFormate(timeStamp) {
let data = new Date(timeStamp);
// let year = data.getFullYear();
// let month = data.getMonth() + 1 < 10 ? '0' + (data.getMonth() + 1) : data.getMonth() + 1;
// let date = data.getDate() < 10 ? '0' + data.getDate() : data.getDate();
let hh = data.getHours() < 10 ? '0' + data.getHours() : data.getHours();
let mm = data.getMinutes() < 10 ? '0' + data.getMinutes() : data.getMinutes();
let ss = data.getSeconds() < 10 ? '0' + data.getSeconds() : data.getSeconds();
this.nowTime = hh + ':' + mm + ':' + ss;
},
nowTimes() {
this.timeFormate(new Date());
setInterval(this.nowTimes, 1000);
this.clear();
},
clear() {
clearInterval(this.nowTimes);
this.nowTimes = null;
},
},
};
</script>
<style lang="stylus" scoped>
iframe {
border: none !important;
}
.sxmap {
position: absolute;
top: -4rem;
right: -2rem;
z-index: 9;
width: 19rem;
height: 25rem;
}
.time {
position: relative;
top: 80px;
left: 0;
z-index: 100;
width: 100%;
overflow: hidden;
background: #0067C1;
height: 42px;
line-height: 42px;
font-family: SourceHanSansCN-Medium;
font-size: 1.2rem;
color: #fff;
text-align: left;
// transform: rotateX(0deg) rotateY(0deg) scaleX(1) scaleY(0.8) translate(0px, 0px);
}
.time-content {
position: absolute;
padding: 0 20px;
width: 100%;
transform: translate3d(100%, 0, 0);
text-align: center;
animation: myfirst 15s infinite cubic-bezier(0, 0.24, 1, 0.79);
}
@keyframes myfirst {
from {
transform: translate3d(100%, 0, 0);
}
to {
transform: translate3d(-100%, 0, 0);
}
}
@media (max-width: 1500px) {
.time {
top: 80px;
left: 0;
font-size: 1.5rem;
}
}
.bg-img {
position: absolute;
height: 93%;
bottom: 5px;
}
.bg-img-title {
position: absolute;
width: 200px;
top: 4px;
height: 40px;
left: 50%;
margin-left: -100px;
}
.bg-title1 {
position: absolute;
width: 180px;
top: 0;
height: 34px;
left: 50%;
margin-left: -90px;
}
.title-style {
text-align: center;
font-size: 22px;
color: #02D9FD;
font-weight: bold;
}
.video-box {
margin-left: 0.5%;
height: 76%;
margin-top: 38px;
width: 95%;
}
.video-box1 {
margin-left: 0.5%;
height: 86%;
margin-top: 44px;
width: 98%;
}
.video-tips {
padding-left: 20px;
padding-right: 40px;
z-index: 10;
font-size: 14px;
color: #02D9FD;
font-weight: bold;
}
</style>

58
src/views/Video/Video.vue

@ -0,0 +1,58 @@
<!--
* @Author: wally
* @email: 18603454788@163.com
* @Date: 2021-04-01 10:38:34
* @LastEditors: wally
* @LastEditTime: 2021-04-01 11:11:25
-->
<template>
<div class="wrap">
<video class="videoDom" id="cideoPlay1" src="@/assets/康复-03.mp4" loop></video>
<a-button @click="startLook" class="btn" v-if="show">点击进入直播间</a-button>
</div>
</template>
<script>
export default {
data() {
return {
str: '',
show: true,
};
},
methods: {
startLook() {
console.log(23);
this.show = !this.show;
var video1 = document.getElementById('cideoPlay1');
video1.play();
},
},
};
</script>
<style scoped>
.videoDom {
width: 100%;
height: 100%;
object-fit: fill;
}
.btn {
position: absolute;
left: 50%;
margin-left: -100px;
width: 200px;
top: 50%;
margin-top: -30px;
height: 60px;
background: rgba(0, 0, 0, 0);
color: #2cb6fb;
font-size: 24px;
border: solid 1px #72c1eb;
}
.btn:hover {
background: rgba(255, 118, 8, 0.8);
color: #ccc;
border: solid 1px rgba(255, 118, 8, 0.8);
}
</style>

138
vue.config.js

@ -0,0 +1,138 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
const path = require('path');
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg|ttf|woff|woff2)(\?.*)?$/i;
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const resolve = dir => path.join(__dirname, dir);
const isPro = process.env.VUE_APP_NODE_ENV === 'production';
const publicPath = process.env.VUE_APP_PUBLIC_PATH;
const proxyUrl = process.env.VUE_APP_PROXY_URL;
const apiUrl = process.env.VUE_APP_API_URL;
const title = process.env.VUE_APP_TITLE;
console.log('proxyUrl: ', proxyUrl);
console.log('apiUrl: ', apiUrl);
// 本地环境是否需要使用cdn
const devNeedCdn = true;
// cdn 链接及配置
const cdn = {
css: [
'https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css',
'https://cdn.bootcdn.net/ajax/libs/ant-design-vue/1.6.5/antd.min.css',
],
js: [
isPro ? 'https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js' : 'https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js',
'https://cdn.bootcdn.net/ajax/libs/vue-router/3.4.3/vue-router.min.js',
'https://cdn.bootcdn.net/ajax/libs/vuex/3.5.1/vuex.min.js',
'https://cdn.bootcdn.net/ajax/libs/moment.js/2.9.0/moment.min.js',
'https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.min.js',
'https://cdn.bootcdn.net/ajax/libs/axios/0.20.0/axios.min.js',
'https://cdn.bootcdn.net/ajax/libs/ant-design-vue/1.6.5/antd.min.js',
],
// externals: {
// vue: 'Vue',
// vuex: 'Vuex',
// 'vue-router': 'VueRouter',
// moment: 'moment',
// axios: 'axios',
// 'ant-design-vue': 'antd',
// lodash: '_',
// },
};
module.exports = {
lintOnSave: true,
publicPath: isPro ? publicPath : '/',
devServer: {
open: true,
overlay: {
warnings: false,
errors: true,
},
proxy: {
[proxyUrl]: {
target: apiUrl, // 代理接口
changeOrigin: true,
pathRewrite: { [`^${proxyUrl}`]: '' },
},
},
},
productionSourceMap: false, // 去掉生产环境的sourcemap 加快构建速度
configureWebpack: {
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
name: title,
resolve: {
alias: {
'~': __dirname,
'@': resolve('src'),
assets: resolve('src/assets'),
views: resolve('src/views'),
components: resolve('src/components'),
common: resolve('src/common'),
config: resolve('src/config'),
router: resolve('src/router'),
store: resolve('src/store'),
util: resolve('src/util'),
request: resolve('src/request'),
},
},
plugins: isPro
? [
new CompressionWebpackPlugin({
test: productionGzipExtensions,
threshold: 10240,
deleteOriginalAssets: false,
}),
]
: [],
externals: isPro || devNeedCdn ? cdn.externals : {},
},
chainWebpack(config) {
if (isPro) {
config.optimization
.runtimeChunk('single')
.minimize(true)
.splitChunks({
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 20000, // 依赖包超过20000bit将被单独打包
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`;
},
},
},
});
}
// set svg-sprite-loader
// config.module
// .rule('svg')
// .exclude.add(resolve('src/icons'))
// .end();
// config.module
// .rule('icons')
// .test(/\.svg$/)
// .include.add(resolve('src/icons'))
// .end()
// .use('svg-sprite-loader')
// .loader('svg-sprite-loader')
// .options({ symbolId: 'icon-[name]' })
// .end();
},
};

9343
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save