Browse Source

机构管理

master
aBin 4 years ago
commit
76a4239e06
  1. 3
      .browserslistrc
  2. 8
      .editorconfig
  3. 3
      .env
  4. 10
      .env.development
  5. 3
      .env.mock
  6. 10
      .env.production
  7. 47
      .eslintrc.js
  8. 23
      .gitignore
  9. 13
      .prettierrc
  10. 24
      README.md
  11. 13
      babel.config.js
  12. 1
      commitlint.config.js
  13. 30269
      package-lock.json
  14. 54
      package.json
  15. BIN
      public/favicon.ico
  16. BIN
      public/img/icons/Chevron left-Outlined_好压看图.png
  17. BIN
      public/img/icons/android-chrome-192x192.png
  18. BIN
      public/img/icons/android-chrome-512x512.png
  19. BIN
      public/img/icons/android-chrome-maskable-192x192.png
  20. BIN
      public/img/icons/android-chrome-maskable-512x512.png
  21. BIN
      public/img/icons/apple-touch-icon-120x120.png
  22. BIN
      public/img/icons/apple-touch-icon-152x152.png
  23. BIN
      public/img/icons/apple-touch-icon-180x180.png
  24. BIN
      public/img/icons/apple-touch-icon-60x60.png
  25. BIN
      public/img/icons/apple-touch-icon-76x76.png
  26. BIN
      public/img/icons/apple-touch-icon.png
  27. BIN
      public/img/icons/favicon-16x16.png
  28. BIN
      public/img/icons/favicon-32x32.png
  29. BIN
      public/img/icons/msapplication-icon-144x144.png
  30. BIN
      public/img/icons/mstile-150x150.png
  31. 3
      public/img/icons/safari-pinned-tab.svg
  32. 19
      public/index.html
  33. 2
      public/robots.txt
  34. 99
      public/sdk.js
  35. 15
      rest/http-client.env.json
  36. 56
      rest/project.http
  37. 54
      src/App.vue
  38. 521
      src/common/portrait.styl
  39. 101
      src/components/AddHospital/AddHospital.vue
  40. 192
      src/components/LeftList/LeftList.vue
  41. 186
      src/components/RightPage/RightPage.vue
  42. 202
      src/components/RightPage/TreeNode.vue
  43. 20
      src/config/api-user.js
  44. 21
      src/config/api.js
  45. 30
      src/config/setting.js
  46. 19
      src/config/user.js
  47. 36
      src/main.js
  48. 102
      src/plugins/ant-design-vue.js
  49. 83
      src/plugins/axios.js
  50. 3
      src/plugins/vue-quill-editor.js
  51. 34
      src/registerServiceWorker.js
  52. 38
      src/router/index.js
  53. 7
      src/store/index.js
  54. 29
      src/store/modules/home/actions.js
  55. 26
      src/store/modules/home/getters.js
  56. 6
      src/store/modules/home/index.js
  57. 54
      src/store/modules/home/mutations.js
  58. 7
      src/store/modules/home/state.js
  59. 40
      src/views/Index/Index.vue
  60. 139
      vue.config.js
  61. 10011
      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=https://www.tall.wiki/

10
.env.development

@ -0,0 +1,10 @@
VUE_APP_MODE=development
VUE_APP_NODE_ENV=development
VUE_APP_SCENE=flat-car
VUE_APP_BASE_URL=http://101.201.226.163
VUE_APP_API_URL=http://101.201.226.163
VUE_APP_PROXY_URL=http://101.201.226.163
VUE_APP_PUBLIC_PATH=/carbasics
VUE_APP_MSG_URL=ws://101.201.226.163/websocket/message/v4.0/ws
VUE_APP_TITLE=暴风眼Typhoneye机构管理
VUE_APP_DESCRIPTION=暴风眼Typhoneye机构管理

3
.env.mock

@ -0,0 +1,3 @@
VUE_APP_BASE_URL=http://127.0.0.1:3000
VUE_APP_API_URL=http://127.0.0.1:3000
VUE_APP_PROXY_URL=

10
.env.production

@ -0,0 +1,10 @@
VUE_APP_MODE=production
VUE_APP_NODE_ENV=production
VUE_APP_SCENE=flat-car
VUE_APP_BASE_URL=https://www.tall.wiki/
VUE_APP_API_URL=https://www.tall.wiki
VUE_APP_PROXY_URL=https://www.tall.wiki
VUE_APP_PUBLIC_PATH=/carbasics
VUE_APP_MSG_URL=wss://www.tall.wiki/websocket/message/v4.0/ws
VUE_APP_TITLE=暴风眼Typhoneye机构管理
VUE_APP_DESCRIPTION=暴风眼Typhoneye机构管理

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']};

30269
package-lock.json

File diff suppressed because it is too large

54
package.json

@ -0,0 +1,54 @@
{
"name": "wisdom-mobile",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"serve-mock": "vue-cli-service serve --mode mock",
"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.8.0",
"echarts-gl": "^1.1.1",
"moment": "^2.29.1",
"register-service-worker": "^1.7.1",
"stylus": "^0.54.8",
"vconsole": "^3.9.1",
"vue": "^2.6.11",
"vue-dompurify-html": "^2.3.0",
"vue-quill-editor": "^3.0.6",
"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/Chevron left-Outlined_好压看图.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 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

19
public/index.html

@ -0,0 +1,19 @@
<!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><%= webpackConfig.name %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="./sdk.js"></script>
</body>
</html>

2
public/robots.txt

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

99
public/sdk.js

@ -0,0 +1,99 @@
/*
* @Author: aBin
* @email: binbin0314@126.com
* @Date: 2021-04-19 10:23:19
* @LastEditors: aBin
* @LastEditTime: 2021-06-09 09:50:31
*/
/**
* ccsens tall sdk.js
* v1.0.0
* 父组件调用 TallPlugin.init()即可
* 监听message消息, 如果是created消息 就把tall的参数传递过来
*/
(function(window) {
// 单例局部变量
var _instance = null;
// 对外暴露TallPlugin类
window.TallPlugin = function(config) {
this.config = config;
this.props = null;
this.parent = '*';
};
// 初始化并保证是单例
TallPlugin.init = function(callback, config) {
if (!_instance) {
_instance = new TallPlugin(config);
_instance.config = config;
_instance.parent = window.parent.origin;
// DOM加载完成
window.addEventListener('DOMContentLoaded', _instance.mounted, false);
// window onload
window.addEventListener('load', _instance.loaded, false);
// destroy
window.addEventListener('unload', _instance.destroy, false);
// error
window.addEventListener('error', _instance.error, false);
_instance.onMessage(callback);
}
return _instance;
};
TallPlugin.prototype.onMessage = function(callback) {
var _this = this;
window.addEventListener(
'message',
function(event) {
try {
if (_this.parent === event.origin) {
// 是父窗体传来的消息
console.log('event.data:', event.data);
var data = JSON.parse(event.data);
_this.props = data || null;
callback && typeof callback === 'function' && callback.call(_this, data);
} else {
_this.props = null;
}
} catch (e) {
// console.error(`TallPlugin warn: ${e}`)
_this.props = null;
}
},
false,
);
return this;
};
// DOMContentLoaded DOM加载完成触发
TallPlugin.prototype.mounted = function(callback) {
var _this = this;
window.postMessage('created', _this.parent);
callback && typeof callback === 'function' && callback.call(this);
return this;
};
// load window onload触发
TallPlugin.prototype.loaded = function(callback) {
var _this = this;
window.postMessage('loaded', _this.parent);
callback && typeof callback === 'function' && callback.call(this);
return this;
};
// 子窗体销毁触发
TallPlugin.prototype.destroy = function(callback) {
var _this = this;
window.postMessage('destroy', _this.parent);
callback && typeof callback === 'function' && callback.call(this);
return this;
};
// error触发
TallPlugin.prototype.error = function(callback) {
var _this = this;
window.postMessage('error', _this.parent);
callback && typeof callback === 'function' && callback.call(this);
return this;
};
})(window);

15
rest/http-client.env.json

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

56
rest/project.http

@ -0,0 +1,56 @@
# @tall = {{url}}/tall3/v3.0
@tall = https://www.tall.wiki/gateway/tall3/v3.0
@tcm = https://www.tall.wiki/gateway/tcm
@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 {{tcm}}/patient/selSearchCriteriaList
{{type}}
Authorization: Bearer {{login.response.body.$.data.token}}
# {
# "param": {
# "company": "",
# "researchDirection": "",
# "teamId": 0,
# "teamIntroduce": "",
# "teamLeaderName": "",
# "teamName": ""
# }
# }

54
src/App.vue

@ -0,0 +1,54 @@
<template>
<a-config-provider :locale="zh_CN">
<div v-if="anyringToken" class="d-flex flex-column flex-wrap pt-46" id="app">
<router-view class="flex-1 bg fill-width"></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']),
mounted() {
window.addEventListener('unload', this.saveState);
},
async created() {
const userId = '1462629589099614208';
const params = { userId };
await this.getUserId(params);
await this.getToken();
},
methods: {
...mapActions('home', ['getUserId']),
...mapMutations('home', ['getToken', 'setHistoryNum']),
},
};
</script>
<style>
html,
body,
#app {
min-height: 100%;
}
#app {
background: transparent;
}
body::-webkit-scrollbar {
width: 0;
}
/* .pt-46 {
padding-top: 46px;
} */
</style>
<style lang="stylus">
@import './common/portrait.styl';
</style>

521
src/common/portrait.styl

@ -0,0 +1,521 @@
// padding
.p-4{
padding: 16px;
}
.pa-3 {
padding: 12px;
}
.pl-1{
padding-left: 4px;
}
.pl-2{
padding-left: 8px;
}
.pl-3{
padding-left: 12px;
}
.pl-4{
padding-left: 16px;
}
.pl-5{
padding-left: 20px;
}
.pr-1{
padding-right: 4px;
}
.pr-2{
padding-right: 8px;
}
.pr-3{
padding-right: 12px;
}
.pr-4{
padding-right: 16px;
}
.pr-5{
padding-right: 20px;
}
.px-1{
padding-left: 4px;
padding-right: 4px;
}
.px-2{
padding-left: 8px;
padding-right: 8px;
}
.px-3{
padding-left: 12px;
padding-right: 12px;
}
.px-4{
padding-left: 16px;
padding-right: 16px;
}
.px-10{
padding-left: 30px;
padding-right: 30px;
}
.py-1{
padding-top: 4px;
padding-bottom: 4px;
}
.py-2{
padding-top: 8px;
padding-bottom: 8px;
}
.py-3{
padding-top: 12px;
padding-bottom: 12px;
}
.pt-3 {
padding-top: 12px;
}
.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;
}
.mx-3{
margin-left: 12px;
margin-right: 12px;
}
.my-0{
margin-top: 0px;
margin-bottom: 0px;
}
.my-1{
margin-top: 4px;
margin-bottom: 4px;
}
.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-0{
margin-bottom: 0px;
}
.mb-1{
margin-bottom: 4px;
}
.mb-2{
margin-bottom: 8px;
}
.mb-3{
margin-bottom: 12px;
}
.mb-4{
margin-bottom: 16px;
}
.mb-10{
margin-bottom: 40px;
}
.ml-1{
margin-left: 4px;
}
.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;
}
.ml-9{
margin-left: 36px;
}
.ml-10{
margin-left: 40px;
}
.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;
}
.green{
background: #4CAF50;
}
.blue{
background: #1890ff;
}
.gray{
background: #CCCCCC;
}
.white--text{
color: #fff;
width: 100px;
margin: 0 auto
}
.bot-right-btn{
position: fixed;
height: 40px;
right: 6px;
bottom: 20px;
}
.bot-right-tips {
position: fixed;
height: 40px;
font-size: 14px;
right: 18px;
top: 0;
}
// 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-evenly{
justify-content: space-evenly;
}
.justify-space-between{
justify-content: space-between;
}
.justify-flex-end{
justify-content: flex-end;
}
.align-center{
align-items: center;
}
.align-left{
align-items: start;
}
.flex-1{
display: flex;
flex: 1;
}
.flex-2{
display: flex;
flex: 2;
}
// other
.pointer{
cursor:pointer;
}
.pointerEdit {
font-size: 16px;
margin-right: 20px;
}
.fill-height{
height:100%;
}
// font
.font-bold{
font-weight: bold;
}
.font-bold-24{
font-size: 24px;
font-weight: bold;
}
.font-24{
font-size: 24px;
}
.font-bold-18{
font-size: 18px;
font-weight: bold;
}
.font-18{
font-size: 18px;
}
.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;
}
.font-12{
font-size: 12px;
}
.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)
}
.text-white{
color: #fff
}
.text-red{
color: #EB3527
}
.gray-text{
color: #bbb
}
.baseColor{
color: #1890ff
}
.bg{
background: #EDEDED;
}
.fill-width{
width:100%;
}
.fill-height{
height:100%;
}
// .ant-form-item-label {
// text-align: left;
// }
// .ant-form-item-control {
// width:100%
// }
.ant-form-item-children(:only-child) {
display: flex;
flex-wrap: nowrap;
}
.ant-card-head-title {
font-weight: 600 !important;
font-size: 18px !important;
}
.ant-card-bordered {
border-radius: 10px;
}
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
position: fixed;
top: 50%;
left: 50%;
margin: -10px;
}
.ant-list-bordered {
border: none;
border-radius: 4px
}
.ant-collapse {
background-color: none;
border: none
}
.w-screen{
width: 100vw;
}
.h-screen{
height: 100vh;
}
.text-center{
text-align: center;
}
.bg-white {
background-color:white;
}
.ant-list-item {
min-height: 54px;
}
.ant-list-bordered .ant-list-item {
padding-right: 16px;
padding-left: 16px;
border-bottom: 1px solid #e8e8e8;
}
.ant-list {
color: #3B3B3B;
}
.ant-list-empty-text {
display: none;
}
.ant-calendar {
margin: auto !important;
}

101
src/components/AddHospital/AddHospital.vue

@ -0,0 +1,101 @@
<template>
<div>
<a-modal title="增加医院" :visible="visible" @ok="handleOk" @cancel="handleCancel" :width="800">
<a-form :form="form" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
<a-form-item label="省">
<a-select default-value="1">
<a-select-option value="1"> 山西省 </a-select-option>
</a-select>
</a-form-item>
<a-form-item label="市/区">
<a-cascader
:field-names="{ label: 'name', value: 'id', children: 'child' }"
:options="options"
placeholder="市/区"
@change="changeArea"
/>
</a-form-item>
<a-form-item label="医院等级">
<a-select placeholder="医院等级" allow-clear @change="changeProvince">
<a-select-option v-for="(item, index) in levelList" :value="item.levelId" :key="index"> {{ item.name }} </a-select-option>
</a-select>
</a-form-item>
<a-form-item label="医院名称">
<a-input v-model="hospitalName" placeholder="医院名称" />
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { addHospital } from 'config/api';
export default {
props: {
visible: {
default: true,
type: Boolean,
},
options: {
default: () => [],
type: Array,
},
levelList: {
default: () => [],
type: Array,
},
},
data() {
return {
formLayout: 'horizontal',
form: this.$form.createForm(this, { name: 'coordinated' }),
hospitalName: '', //
cityId: '', // id
countyId: '', // id
levelId: '', // id
};
},
methods: {
//
handleCancel() {
this.$emit('showModal');
},
//
async handleOk() {
try {
const params = {
param: {
cityId: this.cityId,
countyId: this.countyId,
levelId: this.levelId,
name: this.hospitalName,
provinceId: '140000',
},
};
const res = await addHospital(params);
const { code, msg, data } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.$emit('showModal');
this.$emit('getHosList');
} else {
this.$message.warning(msg);
}
} catch (error) {
this.$message.warning(error);
}
},
//
changeArea(e) {
this.cityId = e[0];
this.countyId = e[1];
},
//
changeProvince(e) {
this.levelId = e;
},
},
};
</script>
<style scoped>
</style>

192
src/components/LeftList/LeftList.vue

@ -0,0 +1,192 @@
<template>
<div class="d-flex flex-column left-box white">
<div class="shadow-box">
<div class="px-4 d-flex justify-space-between mt-4">
<a-select default-value="1" style="width: 120px">
<a-select-option value="1"> 山西省 </a-select-option>
</a-select>
<a-cascader
:field-names="{ label: 'name', value: 'id', children: 'child' }"
:options="options"
style="width: 120px"
placeholder="市/区"
@change="changeArea"
/>
<a-select placeholder="医院等级" allow-clear style="width: 120px" @change="changeProvince">
<a-select-option v-for="(item, index) in levalList" :value="item.levelId" :key="index"> {{ item.name }} </a-select-option>
</a-select>
</div>
<div class="d-flex px-4 mt-4">
<a-input-search placeholder="请输入医院名称" style="width: 100%" @search="onSearch" />
<a-button class="ml-8" type="primary" icon="plus" @click="showAdd">增加</a-button>
</div>
</div>
<div class="flex-1 hospital-box" @scroll="scrollY">
<a-list bordered :data-source="list" class="fill-width">
<a-list-item :class="hospitalInfo.id === item.id ? 'active' : ''" slot="renderItem" slot-scope="item" @click="chooseHospital(item)">
{{ item.name }}
</a-list-item>
</a-list>
</div>
<div class="go-top d-flex justify-center align-center flex-column" @click="gotTop" v-if="showToTop">
<a-icon type="up" style="font-size: 24px" />
<div>回到顶部</div>
</div>
</div>
</template>
<script>
import { queryLevel, queryArea, queryHospitalList } from 'config/api';
import { mapMutations, mapState } from 'vuex';
export default {
name: 'HospitalList',
data() {
return {
levalList: [{ levelId: '4', name: '特等' }],
list: [],
options: [],
showToTop: false,
cityId: '',
countyId: '',
levelId: '',
name: '',
};
},
computed: { ...mapState('home', ['hospitalInfo']) },
created() {
this.getArea();
this.getLevel();
this.getHospitalList();
},
methods: {
...mapMutations('home', ['setHospitalInfo']),
//
chooseHospital(info) {
this.setHospitalInfo(info);
},
//
changeArea(e) {
this.cityId = e[0];
this.countyId = e[1];
this.getHospitalList();
},
changeProvince(e) {
this.levelId = e;
this.getHospitalList();
},
onSearch(e) {
this.name = e;
this.getHospitalList();
},
//
gotTop() {
var dom = document.getElementsByClassName('hospital-box')[0];
dom.scrollTo(0, 0);
},
//
scrollY() {
var dom = document.getElementsByClassName('hospital-box')[0];
this.showToTop = dom.scrollTop > 200;
},
//
showAdd() {
this.$emit('showModal', this.options, this.levalList);
},
//
async getArea() {
try {
const params = { param: { id: 140000 } };
const res = await queryArea(params);
const { code, data, msg } = res.data;
if (code === 200) {
this.options = data;
} else {
console.error(msg);
}
} catch (error) {
this.$message.error('查询地区信息错误:', error);
}
},
//
async getLevel() {
try {
const params = { param: {} };
const res = await queryLevel(params);
const { code, data, msg } = res.data;
if (code === 200) {
this.levalList = data;
} else {
console.error(msg);
}
} catch (error) {
this.$message.error('查询医院等级错误:', error);
}
},
//
async getHospitalList() {
try {
const params = {
param: {
cityId: this.cityId,
countyId: this.countyId,
levelId: this.levelId,
name: this.name,
provinceId: '',
},
};
const res = await queryHospitalList(params);
const { code, data, msg } = res.data;
if (code === 200) {
this.list = data;
} else {
console.error(msg);
}
} catch (error) {
this.$message.error('获取医院列表失败:', error);
}
},
},
};
</script>
<style scoped>
.active {
background: rgba(64, 169, 255, 0.3) !important;
font-weight: bold;
}
/deep/ .ant-list-item {
cursor: pointer;
font-size: 16px;
}
/deep/ .ant-list-item:hover {
background: rgba(64, 169, 255, 0.1);
}
.go-top {
height: 60px;
width: 60px;
border-radius: 8px;
position: absolute;
bottom: 40px;
right: 16px;
background: #40a9ff;
font-size: 12px;
color: #fff;
cursor: pointer;
}
.left-box {
position: relative;
width: 460px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
max-height: 100vh;
}
.shadow-box {
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1);
padding-bottom: 16px;
}
.hospital-box {
overflow-y: scroll;
}
.hospital-box::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
</style>

186
src/components/RightPage/RightPage.vue

@ -0,0 +1,186 @@
<template>
<div class="d-flex flex-column p-4" style="max-height: 100vh">
<div class="hos-name hos-shadow white mb-2">{{ hospitalInfo.name }}</div>
<div class="d-flex justify-space-between tree-title white">
<div class="d-flex">
<!-- <div class="mr-4 cursor-pointer">
<a-checkbox @change="changeChooseAll"> 全选 </a-checkbox>
</div> -->
<div class="mr-4 cursor-pointer d-flex align-center" @click="fold"><a-icon class="mr-2" type="menu-unfold" />全部折叠</div>
<div class="cursor-pointer d-flex align-center" @click="open"><a-icon class="mr-2" type="menu-fold" />全部展开</div>
</div>
<div class="d-flex align-center">
<a-input-search style="width: 260px" class="mr-4" placeholder="搜索部门/职位/角色" @change="onChange" />
<a-button type="primary" icon="plus">新建部门</a-button>
</div>
</div>
<div class="right-box flex-1 hos-box hos-shadow white">
<TreeNode
ref="tree-node"
class="fill-width"
v-if="treeData.length"
:tree-data="treeData"
@showAddItem="showAddItem"
@showEditItem="showEditItem"
@showAddMember="showAddMember"
@showEditMember="showEditMember"
/>
</div>
<a-modal :visible="visible" title="添加部门/职位" @cancel="visible = false" @ok="handleOk">
添加部门/职位
{{ addId }}
</a-modal>
<a-modal :visible="visible2" title="修改部门信息" @cancel="visible2 = false" @ok="handleOk"> 修改部门信息 </a-modal>
<a-modal :visible="visible1" title="添加成员" @cancel="visible1 = false" @ok="handleOk">
添加成员
{{ addId }}
</a-modal>
<a-modal :visible="visible3" title="修改成员信息" @cancel="visible3 = false" @ok="handleOk"> 修改成员信息 </a-modal>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { queryHospitalInfo } from 'config/api';
import TreeNode from './TreeNode.vue';
export default {
components: { TreeNode },
data() {
return {
treeData: [],
isSelect: '',
visible: false,
visible1: false,
visible2: false,
visible3: false,
addId: '',
};
},
computed: { ...mapState('home', ['hospitalInfo']) },
watch: {
hospitalInfo() {
this.getHospitalInfo();
},
},
created() {
this.getHospitalInfo();
},
methods: {
//
changeChooseAll(e) {
// console.log(e.target.checked);
var child = this.$refs['tree-node'];
child.chooseAll(e.target.checked);
},
//
fold() {
var child = this.$refs['tree-node'];
child.foldAll();
},
//
open() {
var child = this.$refs['tree-node'];
child.openAll();
},
//
async getHospitalInfo() {
try {
this.treeData = [];
const params = { param: { id: this.hospitalInfo.id } };
const res = await queryHospitalInfo(params);
const { code, msg, data } = res.data;
if (code === 200) {
console.log(data);
this.treeData = data;
} else {
console.error(msg);
}
} catch (error) {
this.$message.error('医院详情查询失败:', error);
}
},
// /
handleOk() {
this.visible = false;
},
// /modal
showAddItem(id) {
this.addId = id;
this.visible = true;
},
// /modal
showEditItem(item) {
console.log('item: ', item);
this.visible2 = true;
},
// modal
showAddMember(id) {
this.addId = id;
this.visible1 = true;
},
// modal
showEditMember(item) {
console.log('item: ', item);
this.visible3 = true;
},
// //
onChange(e) {
const value = e.target.value;
const expandedKeys = dataList
.map(item => {
if (item.title.indexOf(value) > -1) {
return getParentKey(item.key, gData);
}
return null;
})
.filter((item, i, self) => item && self.indexOf(item) === i);
Object.assign(this, {
expandedKeys,
searchValue: value,
autoExpandParent: true,
});
},
},
};
</script>
<style lang="less" scoped>
.right-box {
overflow-y: scroll;
}
.right-box::-webkit-scrollbar {
width: 0;
}
/deep/.ant-tree li span.ant-tree-switcher,
.ant-tree li span.ant-tree-iconEle {
margin-top: 8px !important;
}
/deep/.ant-tree li {
min-height: 54px;
line-height: 40px;
}
/deep/.ant-tree li .ant-tree-node-content-wrapper {
min-height: 40px;
line-height: 40px;
}
.hos-name {
font-size: 20px;
font-weight: bold;
color: rgba(0, 0, 0, 0.85);
}
.hos-shadow {
border-radius: 4px;
padding: 8px 16px;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.15);
}
.tree-title {
border-radius: 4px;
padding: 16px;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.15);
color: rgba(0, 0, 0, 0.5);
font-size: 16px;
font-weight: bold;
}
.cursor-pointer {
cursor: pointer;
}
</style>

202
src/components/RightPage/TreeNode.vue

@ -0,0 +1,202 @@
<template>
<div>
<a-tree
v-model="checkedKeys"
:expanded-keys="expandedKeys"
@expand="onExpand"
:auto-expand-parent="autoExpandParent"
class="fill-width"
:block-node="true"
@select="onSelect"
:checkable="false"
>
<a-tree-node v-for="item in treeData" :key="item.did">
<a-tree-node v-for="itemA in item.positionInfoList" :key="item.did + itemA.pid">
<a-tree-node v-for="itemB in itemA.memberInfoList" :key="itemA.pid + itemB.mid">
<div class="d-flex flex-row justify-space-between align-center" slot="title">
<div>{{ itemB.mname }}{{ itemB.phone }}</div>
</div>
</a-tree-node>
<div class="d-flex flex-row justify-space-between align-center" slot="title">
<div>
{{ itemA.pname }}
<a-tag color="blue" class="ml-2" v-for="tag in itemA.roleList" :key="tag.rid">
{{ tag.rname }}
</a-tag>
</div>
<div>
<a-icon
class="mr-2"
:style="{ fontSize: '20px' }"
v-if="isSelect === item.did + itemA.pid"
type="plus"
@click="showAddMember(itemA.did)"
></a-icon>
<a-icon
class="mr-2"
:style="{ fontSize: '20px' }"
v-if="isSelect === item.did + itemA.pid"
type="more"
@click="showEditMember(itemA)"
/>
</div>
</div>
</a-tree-node>
<div class="d-flex flex-row justify-space-between align-center" slot="title">
<div>
{{ item.departmentName }}
<a-tag color="#87d068" class="ml-2" style="border-radius: 10px">
{{ (item.positionInfoList ? item.positionInfoList.length : 0) + (item.sonDepartment ? item.sonDepartment.length : 0) }}
</a-tag>
</div>
<div>
<a-icon
class="mr-2"
:style="{ fontSize: '20px' }"
v-if="isSelect === item.did"
type="plus"
@click="showAddItem(item.did)"
></a-icon>
<a-icon class="mr-2" :style="{ fontSize: '20px' }" v-if="isSelect === item.did" type="more" @click="showEditItem(item)" />
</div>
</div>
<TreeNode
ref="tree-node"
v-if="item.sonDepartment"
:tree-data="item.sonDepartment"
@showAddItem="showAddItem"
@showEditItem="showEditItem"
@showAddMember="showAddMember"
@showEditMember="showEditMember"
/>
</a-tree-node>
</a-tree>
</div>
</template>
<script>
import TreeNode from './TreeNode.vue';
export default {
isTreeNode: true,
components: { TreeNode },
props: {
treeData: {
default: () => [],
type: Array,
},
},
data() {
return {
isSelect: '',
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
};
},
watch: {
treeData: {
handler() {
this.expandedKeys = [];
if (this.treeData.length) {
for (let i = 0; i < this.treeData.length; i++) {
this.expandedKeys.push(this.treeData[i].did);
}
}
},
deep: true,
},
},
created() {
this.expandedKeys = [];
if (this.treeData.length) {
for (let i = 0; i < this.treeData.length; i++) {
this.expandedKeys.push(this.treeData[i].did);
}
}
},
methods: {
onSelect(selectedKeys, info) {
console.log('selected', selectedKeys, info);
this.isSelect = selectedKeys[0];
},
showAddItem(id) {
this.$emit('showAddItem', id);
},
showEditItem(item) {
this.$emit('showEditItem', item);
},
showAddMember(id) {
this.$emit('showAddMember', id);
},
showEditMember(item) {
this.$emit('showEditMember', item);
},
onExpand(expandedKeys) {
this.expandedKeys = expandedKeys;
this.autoExpandParent = false;
},
//
foldAll() {
this.expandedKeys = [];
},
//
openAll() {
var expandedKeys = [];
if (this.treeData.length) {
for (let i = 0; i < this.treeData.length; i++) {
const item = this.treeData[i];
expandedKeys.push(item.did);
for (let j = 0; j < item.positionInfoList.length; j++) {
const itemA = item.positionInfoList[j];
expandedKeys.push(item.did + itemA.pid);
}
}
}
this.expandedKeys = expandedKeys;
var child = this.$refs['tree-node'];
console.log('child: ', child);
if (child) {
child.foldAll();
}
},
// /
chooseAll(isTrue) {
if (isTrue) {
var checkedKeys = [];
if (this.treeData.length) {
for (let i = 0; i < this.treeData.length; i++) {
const item = this.treeData[i];
checkedKeys.push(item.did);
for (let j = 0; j < item.positionInfoList.length; j++) {
const itemA = item.positionInfoList[j];
checkedKeys.push(item.did + itemA.pid);
}
}
}
this.checkedKeys = checkedKeys;
var child = this.$refs['tree-node'];
if (child) {
child.foldAll();
}
} else {
this.checkedKeys = [];
}
},
},
};
</script>
<style lang="less" scoped>
/deep/.ant-tree li span.ant-tree-switcher,
.ant-tree li span.ant-tree-iconEle {
margin-top: 8px !important;
}
/deep/.ant-tree li {
min-height: 54px;
line-height: 40px;
font-size: 16px;
}
/deep/.ant-tree li .ant-tree-node-content-wrapper {
min-height: 40px;
line-height: 40px;
}
</style>

20
src/config/api-user.js

@ -0,0 +1,20 @@
/*
* @Author: aBin
* @email: binbin0314@126.com
* @Date: 2021-05-31 17:25:39
* @LastEditors: aBin
* @LastEditTime: 2021-06-02 15:27:56
*/
/*
* Copyright (c) 2020.
* author: wally
* email: 18603454788@163.com
*/
import axios from 'axios';
let { proxyUrl } = require('@/config/setting');
const tall = `${proxyUrl}/gateway/tall3/v3.0`;
const users = `${tall}/users`;
// 查找用户详细信息
export const getUserId = params => axios.get(`${users}/userId`, params);

21
src/config/api.js

@ -0,0 +1,21 @@
import axios from 'axios';
let { proxyUrl } = require('@/config/setting');
const qcp = `${proxyUrl}/gateway/carbasics/v4.0`;
const management = `${qcp}/management`; // 机构管理相关接口
const questionnaire = `${qcp}/questionnaire`; // 查询问卷相关接口
// 查询医院列表
export const queryHospitalList = params => axios.post(`${management}/queryHospitalList`, params);
// 查询医院等级列表
export const queryLevel = params => axios.post(`${management}/queryLevel`, params);
// 查询地区
export const queryArea = params => axios.post(`${questionnaire}/area`, params);
// 添加医院
export const addHospital = params => axios.post(`${management}/addHospital`, params);
// 查询机构管理的医院详情
export const queryHospitalInfo = params => axios.post(`${management}/queryHospitalInfo`, 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,
};

36
src/main.js

@ -0,0 +1,36 @@
/*
* @Author: wally
* @email: 18603454788@163.com
* @Date: 2021-01-29 11:16:27
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-29 09:51:17
*/
// @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'; //对应的省份
import './plugins/vue-quill-editor.js';
// import VueDOMPurifyHTML from 'vue-dompurify-html';
// import VConsole from 'vconsole';
// const vConsole = new VConsole();
// console.log('Hello world');
// vConsole.destroy();
Vue.prototype.$echarts = echarts;
import moment from 'moment'; //导入文件
Vue.prototype.$moment = moment; //赋值使用
Vue.config.productionTip = false;
window.vm = new Vue({
router,
store,
render: h => h(App),
}).$mount('#app');

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

@ -0,0 +1,102 @@
/*
* @Author: wally
* @email: 18603454788@163.com
* @Date: 2021-01-29 11:16:27
* @LastEditors: aBin
* @LastEditTime: 2021-06-02 10:10:30
*/
import Vue from 'vue';
import {
Pagination,
Button,
Input,
InputNumber,
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,
Card,
List,
Collapse,
Cascader,
TimePicker,
Divider,
Tooltip,
Affix,
Drawer,
Tree,
} from 'ant-design-vue';
import { ConfigProvider } from 'ant-design-vue';
Vue.component(ConfigProvider.name, ConfigProvider);
Vue.use(Pagination);
Vue.use(Tooltip);
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.use(Card);
Vue.use(List);
Vue.use(Collapse);
Vue.use(Cascader);
Vue.use(InputNumber);
Vue.use(TimePicker);
Vue.use(Divider);
Vue.use(Affix);
Vue.use(Drawer);
Vue.use(Tree);
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,
});

83
src/plugins/axios.js

@ -0,0 +1,83 @@
/*
* @Author: wally
* @email: 18603454788@163.com
* @Date: 2021-04-19 10:23:19
* @LastEditors: wally
* @LastEditTime: 2021-05-06 11:42:20
*/
'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;

3
src/plugins/vue-quill-editor.js

@ -0,0 +1,3 @@
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';

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);
}
});
}

38
src/router/index.js

@ -0,0 +1,38 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from 'views/Index/Index.vue';
Vue.use(VueRouter);
const routes = [
// 首页数据统计
{
path: '/',
name: 'Home',
component: Home,
},
// // 基本信息界面
// {
// path: '/info',
// name: 'Info',
// component: () => import('@/views/Info/Info.vue'),
// meta: { title: '基本信息' },
// },
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
router.beforeEach((to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title;
} else {
document.title = '暴风眼Typhoneye机构管理';
}
next();
});
export default router;

7
src/store/index.js

@ -0,0 +1,7 @@
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 } });

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

@ -0,0 +1,29 @@
import axios from 'axios';
import { getUserId } from 'config/api-user';
import { message } from 'ant-design-vue';
import { aidRecord, queryAidRecord, getDetail } from 'config/api';
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;

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

@ -0,0 +1,26 @@
/*
* @Author: your name
* @Date: 2021-07-28 12:00:41
* @LastEditTime: 2021-07-29 10:07:25
* @LastEditors: your name
* @Description: In User Settings Edit
* @FilePath: \wisdomcar_mobile\src\store\modules\home\getters.js
*/
const getters = {
// 获取用户的id
userId({ user }) {
try {
if (!user) return '';
return user.id;
} catch (error) {
console.warn("user's getters 获取userId失败", error);
return '';
}
},
};
// 域定制导航展示形式
// 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 };

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

@ -0,0 +1,54 @@
/*
* @Author: aBin
* @email: binbin0314@126.com
* @Date: 2021-05-31 17:25:39
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-29 11:48:32
*/
const mutations = {
/**
* 设置token
* @param { object } state
* @param { string } token
*/
sign(state, token) {
state.anyringToken = token;
sessionStorage.setItem('anyringToken', token);
},
/**
* 设置token
* @param { object } state
* @param { string } token
*/
getToken(state, token) {
state.anyringToken = sessionStorage.getItem('anyringToken');
},
/**
* 设置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));
},
/**
* 设置user用户信息
* @param {object} state
* @param {Array} data
*/
setControlGroups(state, data) {
state.controlGroups = data;
},
/**
* 设置当前选择的医院信息
* @param {object} state
* @param {object} data
*/
setHospitalInfo(state, data) {
state.hospitalInfo = data;
},
};
export default mutations;

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

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

40
src/views/Index/Index.vue

@ -0,0 +1,40 @@
<template>
<div class="d-flex flex-row">
<LeftList ref="left-list" @showModal="showModal" />
<AddHospital @showModal="showModal" @getHosList="getHosList" :visible="isShow" :options="options" :level-list="levelList" />
<RightPage class="flex-1" v-if="hospitalInfo && hospitalInfo.name" />
</div>
</template>
<script>
import LeftList from 'components/LeftList/LeftList.vue';
import AddHospital from 'components/AddHospital/AddHospital.vue';
import RightPage from 'components/RightPage/RightPage.vue';
import { mapState } from 'vuex';
export default {
name: 'Index',
components: { LeftList, AddHospital, RightPage },
data() {
return {
isShow: false,
options: [],
levelList: [],
};
},
computed: { ...mapState('home', ['hospitalInfo']) },
methods: {
showModal(options, levelList) {
this.options = options;
this.levelList = levelList;
this.isShow = !this.isShow;
},
//
getHosList() {
const leftDom = this.$refs['left-list'];
leftDom.getHospitalList();
},
},
};
</script>
<style scoped>
</style>

139
vue.config.js

@ -0,0 +1,139 @@
/*
* 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}`]: '' },
},
},
https: false,
},
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();
},
};

10011
yarn.lock

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