lrf 1 år sedan
incheckning
3b1dcb9e07
100 ändrade filer med 6436 tillägg och 0 borttagningar
  1. 2 0
      .env
  2. 33 0
      .eslintrc.js
  3. 24 0
      .gitignore
  4. 0 0
      README.md
  5. 3 0
      babel.config.js
  6. 67 0
      package.json
  7. BIN
      public/favicon.ico
  8. 59 0
      public/index.html
  9. 39 0
      src/App.vue
  10. BIN
      src/assets/babs.png
  11. BIN
      src/assets/census_two.jpg
  12. BIN
      src/assets/ewm.png
  13. BIN
      src/assets/icon/3-5.png
  14. BIN
      src/assets/icon/guardian.png
  15. BIN
      src/assets/icon/less-3.png
  16. BIN
      src/assets/icon/more-5.png
  17. BIN
      src/assets/icon/p1.png
  18. BIN
      src/assets/icon/p2.png
  19. BIN
      src/assets/icon/p3.png
  20. BIN
      src/assets/icon/p4.png
  21. BIN
      src/assets/icon/p5.png
  22. BIN
      src/assets/icon/p6.png
  23. BIN
      src/assets/icon/warning.png
  24. BIN
      src/assets/jh1.png
  25. BIN
      src/assets/lb.jpg
  26. BIN
      src/assets/login-background.jpg
  27. BIN
      src/assets/logo.png
  28. BIN
      src/assets/oneLeft.png
  29. BIN
      src/assets/oneRight.png
  30. BIN
      src/assets/test2.png
  31. BIN
      src/assets/test3.png
  32. BIN
      src/assets/test4.png
  33. BIN
      src/assets/tg/alarmbg.png
  34. BIN
      src/assets/tg/all-statistics-bg.png
  35. BIN
      src/assets/tg/bottom-bg.png
  36. BIN
      src/assets/tg/l-topbg.png
  37. BIN
      src/assets/tg/map-light.png
  38. BIN
      src/assets/tg/new-alarm-title-bg.png
  39. BIN
      src/assets/tg/recent-charts-bg.png
  40. BIN
      src/assets/tg/room-list-bg.png
  41. BIN
      src/assets/tg/room-overview.png
  42. BIN
      src/assets/tg/room-ovewview-infobg.png
  43. BIN
      src/assets/tg/time-bg.png
  44. BIN
      src/assets/yzm.gif
  45. 88 0
      src/components/HelloWorld.vue
  46. 258 0
      src/components/fence.vue
  47. 198 0
      src/components/list/list-page.vue
  48. 37 0
      src/components/list/search.vue
  49. 65 0
      src/components/list/tabs.vue
  50. 44 0
      src/main.js
  51. 24 0
      src/plugins/amap.js
  52. 19 0
      src/plugins/axios.js
  53. 39 0
      src/plugins/check-res.js
  54. 17 0
      src/plugins/components.js
  55. 5 0
      src/plugins/element.js
  56. 6 0
      src/plugins/filters.js
  57. 27 0
      src/plugins/loading.js
  58. 4 0
      src/plugins/meta.js
  59. 33 0
      src/plugins/methods.js
  60. 21 0
      src/plugins/setting.js
  61. 65 0
      src/plugins/stomp.js
  62. 25 0
      src/plugins/var.js
  63. 301 0
      src/router/index.js
  64. 83 0
      src/store/index.js
  65. 90 0
      src/unit/htmlToPdf.js
  66. 83 0
      src/unit/htmlToPdfJQ.js
  67. 117 0
      src/util/axios-wrapper.js
  68. 381 0
      src/util/draw.js
  69. 1 0
      src/util/fence-prop.js
  70. 10 0
      src/util/filters.js
  71. 21 0
      src/util/map.js
  72. 50 0
      src/util/methods-util.js
  73. 163 0
      src/util/print.js
  74. 69 0
      src/util/user-util.js
  75. 53 0
      src/views/adminCenter/homeIndex/index.vue
  76. 38 0
      src/views/adminCenter/index.vue
  77. 2 0
      src/views/census/eventBus.js
  78. 204 0
      src/views/census/index.vue
  79. 169 0
      src/views/census/parts/center-1.vue
  80. 151 0
      src/views/census/parts/left-1.vue
  81. 170 0
      src/views/census/parts/left-2.vue
  82. 157 0
      src/views/census/parts/left-3.vue
  83. 277 0
      src/views/census/parts/map-1.vue
  84. 185 0
      src/views/census/parts/right-1.vue
  85. 182 0
      src/views/census/parts/right-2.vue
  86. 136 0
      src/views/census_two/index copy.vue
  87. 154 0
      src/views/census_two/index.vue
  88. 128 0
      src/views/census_two/parts/echarts-1.vue
  89. 122 0
      src/views/census_two/parts/echarts-10.vue
  90. 124 0
      src/views/census_two/parts/echarts-11.vue
  91. 121 0
      src/views/census_two/parts/echarts-2.vue
  92. 160 0
      src/views/census_two/parts/echarts-3.vue
  93. 134 0
      src/views/census_two/parts/echarts-4.vue
  94. 208 0
      src/views/census_two/parts/echarts-5.vue
  95. 135 0
      src/views/census_two/parts/echarts-6.vue
  96. 133 0
      src/views/census_two/parts/echarts-7.vue
  97. 141 0
      src/views/census_two/parts/echarts-8.vue
  98. 230 0
      src/views/census_two/parts/echarts-9.vue
  99. 351 0
      src/views/census_two/parts/map.vue
  100. 0 0
      src/views/fake_list/index.vue

+ 2 - 0
.env

@@ -0,0 +1,2 @@
+VUE_APP_AXIOS_BASE_URL = ''
+VUE_APP_ROUTER="sps"

+ 33 - 0
.eslintrc.js

@@ -0,0 +1,33 @@
+// https://eslint.org/docs/user-guide/configuring
+
+module.exports = {
+  root: true,
+  env: {
+    node: true,
+  },
+  extends: ["plugin:vue/essential", "@vue/prettier"],
+  plugins: ["vue"],
+  rules: {
+    "max-len": [
+      "warn",
+      {
+        code: 10000,
+      },
+    ],
+    "no-unused-vars": "off",
+    "no-console": "off",
+    "prettier/prettier": [
+      "warn",
+      {
+        singleQuote: true,
+        trailingComma: "es5",
+        bracketSpacing: true,
+        jsxBracketSameLine: true,
+        printWidth: 160,
+      },
+    ],
+  },
+  parserOptions: {
+    parser: "babel-eslint",
+  },
+};

+ 24 - 0
.gitignore

@@ -0,0 +1,24 @@
+.DS_Store
+node_modules
+package-lock.json
+/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?

+ 0 - 0
README.md


+ 3 - 0
babel.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  presets: ["@vue/cli-plugin-babel/preset"],
+};

+ 67 - 0
package.json

@@ -0,0 +1,67 @@
+{
+  "name": "study-cms",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@stomp/stompjs": "^6.1.0",
+    "animate.css": "^4.1.1",
+    "axios": "^0.21.1",
+    "babel-polyfill": "^6.26.0",
+    "core-js": "^3.6.5",
+    "echarts": "^5.1.0",
+    "element-ui": "^2.15.6",
+    "html2canvas": "^1.4.1",
+    "jsonwebtoken": "^8.5.1",
+    "jspdf": "^2.5.1",
+    "lodash": "^4.17.21",
+    "moment": "^2.29.1",
+    "naf-core": "^0.1.2",
+    "vue": "^2.6.11",
+    "vue-i18n": "^8.24.4",
+    "vue-meta": "^2.4.0",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0",
+    "wangeditor": "3.1.1"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~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",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-prettier": "^3.3.1",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "prettier": "^2.2.1",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended",
+      "@vue/prettier"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

BIN
public/favicon.ico


+ 59 - 0
public/index.html

@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html lang="">
+
+<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="<%= BASE_URL %>favicon.ico">
+  <title>加载中...</title>
+  <style>
+    div::-webkit-scrollbar {
+      width: 8px;
+      height: 8px;
+      /**/
+    }
+
+    div::-webkit-scrollbar-track {
+      background: rgb(239, 239, 239);
+      border-radius: 2px;
+    }
+
+    div::-webkit-scrollbar-thumb {
+      background: #bfbfbf;
+      border-radius: 5px;
+    }
+
+    div::-webkit-scrollbar-thumb:hover {
+      background: #333;
+    }
+
+    div::-webkit-scrollbar-corner {
+      background: #179a16;
+    }
+
+    body {
+      overflow: auto !important;
+    }
+  </style>
+</head>
+
+<body>
+  <script type="text/javascript">
+    window._AMapSecurityConfig = {
+      securityJsCode: 'ac773516846f5fff7ca6a1a10ae695cb',
+    }
+  </script>
+  <!-- <script
+    src="https://webapi.amap.com/maps?v=2.0&key=aad60badbcbc4d90b68337ee0ef27204&plugin=AMap.Scale,AMap.ToolBar,AMap.MouseTool"></script> -->
+    <script type="text/javascript"
+    src="https://webapi.amap.com/loca?v=2.0.0&key=aad60badbcbc4d90b68337ee0ef27204"></script>
+  <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 -->
+</body>
+
+</html>

+ 39 - 0
src/App.vue

@@ -0,0 +1,39 @@
+<template>
+  <div id="App">
+    <router-view></router-view>
+  </div>
+</template>
+
+<script>
+export default {
+  metaInfo: { title: 'App' },
+  name: 'App',
+  props: {},
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {},
+};
+</script>
+
+<style>
+body {
+  margin: 0;
+}
+.w_1200 {
+  width: 1200px;
+  margin: 0 auto;
+}
+p {
+  margin: 0;
+  padding: 0;
+}
+.textOver {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+</style>

BIN
src/assets/babs.png


BIN
src/assets/census_two.jpg


BIN
src/assets/ewm.png


BIN
src/assets/icon/3-5.png


BIN
src/assets/icon/guardian.png


BIN
src/assets/icon/less-3.png


BIN
src/assets/icon/more-5.png


BIN
src/assets/icon/p1.png


BIN
src/assets/icon/p2.png


BIN
src/assets/icon/p3.png


BIN
src/assets/icon/p4.png


BIN
src/assets/icon/p5.png


BIN
src/assets/icon/p6.png


BIN
src/assets/icon/warning.png


BIN
src/assets/jh1.png


BIN
src/assets/lb.jpg


BIN
src/assets/login-background.jpg


BIN
src/assets/logo.png


BIN
src/assets/oneLeft.png


BIN
src/assets/oneRight.png


BIN
src/assets/test2.png


BIN
src/assets/test3.png


BIN
src/assets/test4.png


BIN
src/assets/tg/alarmbg.png


BIN
src/assets/tg/all-statistics-bg.png


BIN
src/assets/tg/bottom-bg.png


BIN
src/assets/tg/l-topbg.png


BIN
src/assets/tg/map-light.png


BIN
src/assets/tg/new-alarm-title-bg.png


BIN
src/assets/tg/recent-charts-bg.png


BIN
src/assets/tg/room-list-bg.png


BIN
src/assets/tg/room-overview.png


BIN
src/assets/tg/room-ovewview-infobg.png


BIN
src/assets/tg/time-bg.png


BIN
src/assets/yzm.gif


+ 88 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,88 @@
+<template>
+  <div class="hello">
+    <h1>{{ msg }}</h1>
+    <p>
+      For a guide and recipes on how to configure / customize this project,<br />
+      check out the
+      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
+    </p>
+    <h3>Installed CLI Plugins</h3>
+    <ul>
+      <li>
+        <a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a>
+      </li>
+      <li>
+        <a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a>
+      </li>
+      <li>
+        <a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a>
+      </li>
+      <li>
+        <a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a>
+      </li>
+    </ul>
+    <h3>Essential Links</h3>
+    <ul>
+      <li>
+        <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
+      </li>
+      <li>
+        <a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a>
+      </li>
+      <li>
+        <a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a>
+      </li>
+      <li>
+        <a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a>
+      </li>
+      <li>
+        <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
+      </li>
+    </ul>
+    <h3>Ecosystem</h3>
+    <ul>
+      <li>
+        <a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a>
+      </li>
+      <li>
+        <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
+      </li>
+      <li>
+        <a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a>
+      </li>
+      <li>
+        <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a>
+      </li>
+      <li>
+        <a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a>
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'HelloWorld',
+  props: {
+    msg: String,
+  },
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="less">
+h3 {
+  margin: 40px 0 0;
+}
+ul {
+  list-style-type: none;
+  padding: 0;
+}
+li {
+  display: inline-block;
+  margin: 0 10px;
+}
+a {
+  color: #42b983;
+}
+</style>

+ 258 - 0
src/components/fence.vue

@@ -0,0 +1,258 @@
+<template>
+  <div id="fence">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="3" style="margin-bottom: 10px">
+          <slot name="back"></slot>
+        </el-col>
+        <template v-if="type === 'draw'">
+          <el-col :span="6">
+            <el-button size="small" @click="drawPolygon" v-if="!isDraw()">绘制多边形</el-button>
+            <el-button size="small" @click="drawRectangle" v-if="!isDraw()">绘制矩形</el-button>
+            <el-button size="small" @click="clearDraw" v-if="isDraw()">重新绘制</el-button>
+            <el-button size="small" @click="returnToDraw" v-if="isDraw()">重新选择绘制图形</el-button>
+            <el-button size="small" type="primary" @click="toSave" v-if="isDraw()">保存</el-button>
+          </el-col>
+          <el-col :span="8">
+            <span style="color: red" v-if="isDraw() === 'polygon'">您处于绘制多边形状态.双击最后的位置结束绘制</span>
+            <span style="color: red" v-if="isDraw() === 'rectangle'">您处于绘制矩形状态.点击后进行拖拽,松开结束绘制</span>
+          </el-col>
+        </template>
+        <template v-if="type === 'edit'">
+          <el-col :span="6">
+            <el-button size="small" type="primary" @click="toStart" v-if="!editing">编辑</el-button>
+            <el-button size="small" type="primary" @click="toEnd" v-if="editing">保存</el-button>
+            <el-button size="small" type="primary" @click="reDraw">重新绘制</el-button>
+          </el-col>
+        </template>
+        <el-col :span="6">
+          <el-input v-model="keyword" size="small" id="input" placeholder="请输入要查询的地点">
+            <template #append>
+              <el-button type="primary" @click="mapSearch">查询</el-button>
+            </template>
+          </el-input>
+        </el-col>
+
+        <el-col :span="24" class="one">
+          <div id="container"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import drawTools from '@/util/draw';
+import MapLoader from '@/plugins/amap';
+export default {
+  name: 'fence',
+  props: {
+    form: { type: Object, default: () => {} },
+    drawList: { type: Array },
+  },
+  model: {
+    prop: 'form',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      map: undefined,
+      center: [125.324667, 43.883476],
+      mapStyle: 'amap://styles/387f96e0666b7d5aec6e11cffa97c91a',
+      // 绘制
+      mouseTool: undefined,
+      drawForm: {},
+      dialog: false,
+      levelList: drawTools.levelList,
+      editor: undefined,
+      editing: false,
+      type: 'draw', // 类型模式:draw--画;edit--改
+      keyword: undefined,
+      searchPlugins: undefined,
+    };
+  },
+  created() {},
+  mounted() {
+    this.init();
+  },
+  methods: {
+    async toSave() {
+      const fence = _.cloneDeep(this.drawForm);
+      this.$emit('save', fence);
+    },
+    async init() {
+      if (!_.get(window, 'AMap')) await MapLoader();
+      if (this.map) this.map.destroy();
+      let that = this;
+      let map = new AMap.Map('container', {
+        zoom: '11.5',
+        resizeEnable: true,
+        viewMode: '2D',
+        center: this.center,
+        // mapStyle: this.mapStyle,
+      });
+      await this.initMapSearch();
+      await drawTools.initSearchAutoComplete('input');
+      // 无围栏信息,画
+      AMap.plugin(['AMap.MouseTool'], function () {
+        that.mouseTool = new AMap.MouseTool(map);
+      });
+      map.on('complete', () => {
+        this.map = map;
+        this.mouseTool.on('draw', this.drawFinish);
+        if (_.get(this.form, 'fence.type')) {
+          // 有围栏信息,复现,改
+          this.initGraphic();
+          this.type = 'edit';
+        }
+        this.drawInMap(this.drawList);
+      });
+    },
+    drawInMap(list = []) {
+      if (!_.isArray(list)) return;
+      for (const i of list) {
+        const { type } = i;
+        let obj;
+        if (type === 'polygon') obj = drawTools.initPolygon(i);
+        else obj = drawTools.initRectangle(i);
+        this.map.add(obj);
+      }
+    },
+    async initMapSearch() {
+      this.searchPlugins = await drawTools.initSearch({ city: '长春' });
+    },
+    mapSearch() {
+      // 根据关键字进行搜索
+      this.searchPlugins.search(this.keyword, (status, result) => {
+        // 先做简单的.只拿第一个,然后将中心点定过去
+        if (result.info !== 'OK') return;
+        const list = _.get(result, 'poiList.pois');
+        const poi = _.head(list);
+        const point = [_.get(poi, 'location.lng'), _.get(poi, 'location.lat')];
+        this.map.setCenter(point, true, 0);
+        const mark = drawTools.initMark({ position: point });
+        this.map.add(mark);
+      });
+    },
+    // 改
+    async initGraphic() {
+      const data = _.get(this.form, 'fence');
+      if (!data) return;
+      const { type } = data;
+      let obj;
+      // 生成画过的图形
+      if (type === 'polygon') obj = drawTools.initPolygon(data);
+      else obj = drawTools.initRectangle(data);
+      // 加入地图
+      this.map.add(obj);
+      // 加载插件
+      let editor;
+      if (type === 'polygon') {
+        this.drawForm.type = 'polygon';
+        editor = new AMap.PolyEditor(this.map, obj);
+        editor.on('end', (e) => {
+          this.editDrawFinish(e);
+          this.toSave();
+        });
+      } else {
+        this.drawForm.type = 'rectangle';
+        editor = new AMap.RectangleEditor(this.map, obj);
+        editor.on('end', (e) => {
+          this.editDrawFinish(e);
+          this.toSave();
+        });
+      }
+      this.editor = editor;
+    },
+    toStart() {
+      this.editor.open();
+      this.editing = true;
+    },
+    toEnd() {
+      this.editor.close();
+      this.editing = false;
+    },
+
+    // 画
+    // 结束绘制事件触发
+    clearDraw() {
+      this.mouseTool.close(true);
+      const type = _.get(this.drawForm, 'type');
+      if (type === 'polygon') this.drawPolygon();
+      else this.drawRectangle();
+    },
+    returnToDraw() {
+      this.mouseTool.close(true);
+      this.$set(this, 'drawForm', {});
+    },
+    // 结束绘制数据处理部分
+    drawFinish(e) {
+      let path;
+      if (_.get(this.drawForm, 'type') === 'polygon') {
+        path = _.get(e, 'obj._opts.path');
+        if (!path) {
+          this.$message.error('未获取到绘制图形的坐标');
+          return false;
+        }
+      } else if (_.get(this.drawForm, 'type') === 'rectangle') {
+        path = _.chunk(_.flattenDeep(_.get(e, 'obj.aE')), 2);
+      }
+      this.drawForm.range = path;
+    },
+    // 结束绘制数据处理部分
+    editDrawFinish(e) {
+      let path;
+      if (_.get(this.drawForm, 'type') === 'polygon') {
+        path = _.get(e, 'target._opts.path');
+        if (!path) {
+          this.$message.error('未获取到绘制图形的坐标');
+          return false;
+        }
+      } else if (_.get(this.drawForm, 'type') === 'rectangle') {
+        path = _.chunk(_.flattenDeep(_.get(e, 'target.aE')), 2);
+        if (!path) {
+          this.$message.error('未获取到绘制图形的坐标');
+          return false;
+        }
+      }
+      this.drawForm.range = path;
+    },
+    // 画多边形
+    drawPolygon() {
+      drawTools.drawPolygon(this.mouseTool);
+      this.$set(this.drawForm, 'type', 'polygon');
+    },
+    // 画矩形
+    drawRectangle() {
+      drawTools.drawRectangle(this.mouseTool);
+      this.$set(this.drawForm, 'type', 'rectangle');
+    },
+    isDraw() {
+      const r = _.get(this.drawForm, 'type');
+      return r;
+    },
+    // 重新绘制
+    reDraw() {
+      this.type = 'draw';
+      this.map.clearMap();
+      this.drawForm = {};
+      this.form.fencen = {};
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  beforeDestroy() {
+    this.map.destroy();
+  },
+};
+</script>
+
+<style lang="less" scoped>
+#container {
+  width: 100%;
+  height: 750px;
+  overflow: hidden;
+}
+</style>

+ 198 - 0
src/components/list/list-page.vue

@@ -0,0 +1,198 @@
+<template>
+  <div id="list-page">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <el-col :span="3" class="left">
+            <span>|</span> <span>{{ title }}</span>
+          </el-col>
+          <el-col :span="21" class="right">
+            <el-row type="flex" justify="end">
+              <el-col :span="12" class="tabs" v-if="useTab">
+                <tabs :displayList="displayList" :dropList="dropList" @toSearch="change"></tabs>
+              </el-col>
+              <el-col :span="12" class="search" v-if="useSearch">
+                <search @toSearch="toSearch"></search>
+              </el-col>
+            </el-row>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="down">
+          <slot></slot>
+          <!-- <el-col :span="24" class="list" v-for="(item, index) in list" :key="index">
+            <el-col :span="21" class="name" @click.native="clickDetail(item.id)">
+              {{ item.p1 }}
+            </el-col>
+            <el-col :span="3" class="date">
+              {{ getDate(item.p2) }}
+            </el-col>
+            <el-col :span="24" class="brief"> 成果简介:{{ item.p3 || '暂无' }} </el-col>
+          </el-col> -->
+        </el-col>
+        <el-col :span="24" class="page" v-if="usePage">
+          <el-pagination @current-change="search" :current-page="currentPage" layout="total, prev, pager, next, jumper" :total="total" :page-size="pageSize">
+          </el-pagination>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import tabs from './tabs.vue';
+import search from './search.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list-page',
+  props: {
+    useTab: { type: Boolean, default: false },
+    useSearch: { type: Boolean, default: true },
+    displayList: { type: Array, default: () => [] },
+    dropList: { type: Array, default: () => [] },
+    list: { type: Array, default: () => [] },
+    searchModel: { type: String, default: 'name' },
+    title: { type: String },
+    total: { type: Number, default: 0 },
+    pageSize: { type: Number, default: 5 },
+    usePage: { type: Boolean, default: true },
+  },
+  components: { tabs, search },
+  data: function () {
+    return {
+      searchInfo: undefined,
+      currentPage: 1,
+      condition: {},
+    };
+  },
+  created() {},
+  methods: {
+    search(page = 1) {
+      this.currentPage = page;
+      const skip = (this.currentPage - 1) * this.pageSize;
+      let condition = { skip, limit: this.pageSize, ...this.condition };
+      if (this.searchInfo && this.searchInfo !== '') condition[this.searchModel] = this.searchInfo;
+      this.$emit('toSearch', condition);
+    },
+    toSearch(condition) {
+      if (condition) {
+        this.$set(this, `searchInfo`, condition);
+      } else {
+        this.$set(this, `searchInfo`, undefined);
+      }
+      this.currentPage = 1;
+      this.search();
+    },
+    change(condition) {
+      this.$set(this, `condition`, condition);
+      this.currentPage = 1;
+      this.search();
+      // this.$emit('toChangeTab', condition);
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 49px;
+    border-bottom: 1px solid #ccc;
+    padding: 5px 0 0 0;
+    .left {
+      text-align: left;
+      span:first-child {
+        color: #22529a;
+        font-weight: bold;
+        font-size: 25px;
+      }
+      span:last-child {
+        color: #22529a;
+        font-size: 20px;
+        font-weight: bold;
+      }
+    }
+    .right {
+      .tabs {
+        span {
+          font-size: 16px;
+          padding: 8px 10px;
+          display: inline-block;
+          font-weight: bold;
+        }
+        span:hover {
+          cursor: pointer;
+          color: #409eff;
+        }
+        .btn {
+          padding: 0px 0 0 0;
+          position: relative;
+          top: 1px;
+          i {
+            font-size: 20px;
+            font-weight: bold;
+          }
+        }
+      }
+      .search {
+        /deep/.el-input__inner {
+          height: 35px;
+          line-height: 35px;
+        }
+      }
+    }
+  }
+  .down {
+    height: 500px;
+    overflow: hidden;
+    .list {
+      padding: 10px 0;
+      .name {
+        font-size: 18px;
+        font-weight: bold;
+      }
+      .date {
+        font-size: 16px;
+        text-align: center;
+      }
+      .brief {
+        font-size: 16px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        -webkit-line-clamp: 2;
+        word-break: break-all;
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        margin: 10px 0 0 0;
+        max-height: 42px;
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        -webkit-transform: translateY(-3px);
+        -ms-transform: translateY(-3px);
+        transform: translateY(-3px);
+        -webkit-box-shadow: 0 0 6px #999;
+        box-shadow: 0 0 6px #999;
+        -webkit-transition: all 0.5s ease-out;
+        transition: all 0.5s ease-out;
+        color: #0085d2;
+      }
+    }
+  }
+  .page {
+    text-align: center;
+    height: 30px;
+    overflow: hidden;
+  }
+}
+</style>

+ 37 - 0
src/components/list/search.vue

@@ -0,0 +1,37 @@
+<template>
+  <div id="search">
+    <el-input placeholder="请输入名称" v-model="input" class="input-with-select" clearable>
+      <el-button slot="append" icon="el-icon-search" @click="searchData()"></el-button>
+    </el-input>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'search',
+  components: {},
+  data: function () {
+    return {
+      input: undefined,
+    };
+  },
+  created() {},
+  methods: {
+    searchData() {
+      this.$emit('toSearch', !this.input ? undefined : this.input);
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 65 - 0
src/components/list/tabs.vue

@@ -0,0 +1,65 @@
+<template>
+  <div id="tabs">
+    <!-- 主要成果单位 -->
+    <span v-for="(item, index) in displayList" :key="index" @click="change(item.name)">{{ item.name }}</span>
+    <!-- 其他 -->
+    <el-dropdown trigger="click" @command="change">
+      <span class="el-dropdown-link btn"><i class="el-icon-d-arrow-right"></i> </span>
+      <el-dropdown-menu slot="dropdown">
+        <el-dropdown-item v-for="(item, index) in dropList" :key="index" :command="item.name">{{ item.name }}</el-dropdown-item>
+      </el-dropdown-menu>
+    </el-dropdown>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'tabs',
+  props: {
+    displayList: { type: Array, default: () => [] },
+    dropList: { type: Array, default: () => [] },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    change(data) {
+      this.$emit('toSearch', { company: data });
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+span {
+  font-size: 16px;
+  padding: 8px 10px;
+  display: inline-block;
+  font-weight: bold;
+}
+span:hover {
+  cursor: pointer;
+  color: #409eff;
+}
+.btn {
+  padding: 0px 0 0 0;
+  position: relative;
+  top: 1px;
+  i {
+    font-size: 20px;
+    font-weight: bold;
+  }
+}
+</style>

+ 44 - 0
src/main.js

@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import App from './App.vue';
+import router from './router';
+import store from './store';
+import '@/plugins/element.js';
+import '@/plugins/axios';
+import '@/plugins/check-res';
+import '@/plugins/meta';
+import '@/plugins/filters';
+import '@/plugins/loading';
+import '@/plugins/var';
+import '@/plugins/methods';
+import '@/plugins/setting';
+import '@/plugins/components';
+import '@common/src/assets/icon/iconfont.css';
+import 'animate.css';
+// 管理中心页面效果布局所需插件
+import ElementUI from 'element-ui';
+import VueI18n from 'vue-i18n';
+import 'babel-polyfill';
+import { messages } from '@common/src/components/admin-frame/i18n';
+import '@common/src/assets/css/main.css';
+// 默认样式
+import '@common/src/assets/css/color-dark.css';
+// element默认主题
+// import '@common/src/assets/css/theme-ele/index.css';
+// import '@common/src/assets/css/theme-ele/color-ele.css';
+// 浅绿色
+// import '@common/src/assets/css/theme-green/index.css';
+// import '@common/src/assets/css/theme-green/color-green.css';
+// 红色
+// import '@common/src/assets/css/theme-red/index.css';
+// import '@common/src/assets/css/theme-red/color-red.css';
+// 粉色
+// import '@common/src/assets/css/theme-pink/index.css';
+// import '@common/src/assets/css/theme-pink/color-pink.css';
+
+Vue.config.productionTip = false;
+
+Vue.use(VueI18n);
+Vue.use(ElementUI, { size: 'small' });
+const i18n = new VueI18n({ locale: 'zh', messages });
+new Vue({ router, store, i18n, render: (h) => h(App) }).$mount('#app');
+window.vm = new Vue({ router });

+ 24 - 0
src/plugins/amap.js

@@ -0,0 +1,24 @@
+export default function MapLoader() {
+  // <-- 原作者这里使用的是module.exports
+  return new Promise((resolve, reject) => {
+    if (window.AMap) {
+      resolve(window.AMap);
+    } else {
+      let script = document.createElement('script');
+      script.type = 'text/javascript';
+      script.async = true;
+      script.src =
+        'http://webapi.amap.com/maps?v=2.0&callback=initAMap&key=aad60badbcbc4d90b68337ee0ef27204&plugin=AMap.Scale,AMap.ToolBar,AMap.MouseTool,AMap.PolyEditor,AMap.RectangleEditor,AMap.AutoComplete,AMap.PlaceSearch';
+      script.onerror = reject;
+      document.head.appendChild(script);
+      // let localScript = document.createElement('script');
+      // localScript.type = 'text/javascript';
+      // localScript.src = 'https://webapi.amap.com/loca?v=2.0.0&key=aad60badbcbc4d90b68337ee0ef27204';
+      // localScript.onerror = reject;
+      // document.head.appendChild(localScript);
+    }
+    window.initAMap = () => {
+      resolve(window.AMap);
+    };
+  });
+}

+ 19 - 0
src/plugins/axios.js

@@ -0,0 +1,19 @@
+import Vue from 'vue';
+import AxiosWrapper from '@/util/axios-wrapper';
+
+const Plugin = {
+  install(vue, options) {
+    // 3. 注入组件
+    vue.mixin({
+      created() {
+        if (this.$store && !this.$store.$axios) {
+          this.$store.$axios = this.$axios;
+        }
+      },
+    });
+    // 4. 添加实例方法
+    vue.prototype.$axios = new AxiosWrapper(options);
+  },
+};
+
+Vue.use(Plugin, { baseUrl: process.env.VUE_APP_AXIOS_BASE_URL });

+ 39 - 0
src/plugins/check-res.js

@@ -0,0 +1,39 @@
+/* eslint-disable no-underscore-dangle */
+/* eslint-disable no-param-reassign */
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-shadow */
+import Vue from 'vue';
+import _ from 'lodash';
+import { Message } from 'element-ui';
+
+const vm = new Vue({});
+const Plugin = {
+  install(Vue, options) {
+    // 4. 添加实例方法
+    Vue.prototype.$checkRes = (res, okText, errText) => {
+      let _okText = okText;
+      let _errText = errText;
+      if (!_.isFunction(okText) && _.isObject(okText) && okText != null) {
+        ({ okText: _okText, errText: _errText } = okText);
+      }
+      const { errcode = 0, errmsg } = res || {};
+      if (errcode === 0) {
+        if (_.isFunction(_okText)) {
+          return _okText();
+        }
+        if (_okText) {
+          Message.success(_okText);
+        }
+        return true;
+      }
+      if (_.isFunction(_errText)) {
+        return _errText();
+      }
+      Message.error(_errText || errmsg);
+      // Message({ message: _errText || errmsg, duration: 60000 });
+      return false;
+    };
+  },
+};
+
+Vue.use(Plugin);

+ 17 - 0
src/plugins/components.js

@@ -0,0 +1,17 @@
+import Vue from 'vue';
+import dataTable from '@common/src/components/frame/filter-page-table.vue';
+import dataForm from '@common/src/components/frame/form.vue';
+import eUpload from '@common/src/components/frame/e-upload.vue';
+import sUpload from '@common/src/components/frame/s-upload.vue';
+import eDialog from '@common/src/components/frame/e-dialog.vue';
+
+const Plugin = (vue) => {
+  vue.prototype.$dev_mode = process.env.NODE_ENV === 'development';
+  vue.component('data-table', dataTable);
+  vue.component('data-form', dataForm);
+  vue.component('eUpload', eUpload);
+  vue.component('sUpload', sUpload);
+  vue.component('eDialog', eDialog);
+};
+
+Vue.use(Plugin);

+ 5 - 0
src/plugins/element.js

@@ -0,0 +1,5 @@
+import Vue from 'vue';
+import Element from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+
+Vue.use(Element);

+ 6 - 0
src/plugins/filters.js

@@ -0,0 +1,6 @@
+import Vue from 'vue';
+import filters from '@/util/filters';
+
+for (const method in filters) {
+  Vue.filter(method, filters[method]);
+}

+ 27 - 0
src/plugins/loading.js

@@ -0,0 +1,27 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import Vue from 'vue';
+
+const Plugin = {
+  // eslint-disable-next-line no-unused-vars
+  install(vue, options) {
+    // 3. 注入组件
+    vue.mixin({
+      created() {
+        // eslint-disable-next-line no-underscore-dangle
+        const isRoot = this.constructor === Vue;
+        // console.log(`rootId:${rootVue_uid}; thisId:${this._uid}`);
+        // if (rootVue_uid !== 3) {
+        //   console.log(this);
+        // }
+        if (isRoot) {
+          const el = document.getElementById('loading');
+          if (el) el.style.display = 'none';
+        }
+      },
+    });
+  },
+};
+
+Vue.use(Plugin, { baseUrl: process.env.VUE_APP_AXIOS_BASE_URL });

+ 4 - 0
src/plugins/meta.js

@@ -0,0 +1,4 @@
+import Vue from 'vue';
+import Meta from 'vue-meta';
+
+Vue.use(Meta);

+ 33 - 0
src/plugins/methods.js

@@ -0,0 +1,33 @@
+import Vue from 'vue';
+import _ from 'lodash';
+const Plugin = {
+  install(Vue, options) {
+    // 3. 注入组件
+    Vue.mixin({
+      created() {
+        if (this.$store && !this.$store.$toUndefined) {
+          this.$store.$toUndefined = this.$toUndefined;
+        }
+      },
+    });
+    // 4. 添加实例方法
+    Vue.prototype.$toUndefined = (object) => {
+      let keys = Object.keys(object);
+      keys.map((item) => {
+        object[item] = object[item] === '' ? (object[item] = undefined) : object[item];
+      });
+      return object;
+    };
+    Vue.prototype.$turnTo = (item) => {
+      if (item.info_type == 1) {
+        window.open(item.url);
+      } else {
+        let router = window.vm.$router;
+        let route = window.vm.$route.path;
+        router.push({ path: `/info/detail?id=${item.id}` });
+      }
+    };
+  },
+};
+
+Vue.use(Plugin);

+ 21 - 0
src/plugins/setting.js

@@ -0,0 +1,21 @@
+import Vue from 'vue';
+
+Vue.config.weixin = {
+  // baseUrl: process.env.BASE_URL + 'weixin',
+  baseUrl: `http://${location.host}`,
+};
+
+Vue.config.stomp = {
+  // brokerURL: 'ws://192.168.1.118/ws',
+  brokerURL: '/ws', // ws://${location.host}/ws
+  // brokerURL: 'ws://127.0.0.1:8000/ws',
+  connectHeaders: {
+    host: 'platform',
+    login: 'visit', //visit
+    passcode: 'visit', //visit123
+  },
+  // debug: true,
+  reconnectDelay: 5000,
+  heartbeatIncoming: 4000,
+  heartbeatOutgoing: 4000,
+};

+ 65 - 0
src/plugins/stomp.js

@@ -0,0 +1,65 @@
+/**
+ * 基于WebStomp的消息处理插件
+ */
+
+import Vue from 'vue';
+import _ from 'lodash';
+import assert from 'assert';
+import { Client } from '@stomp/stompjs/esm5/client';
+
+const Plugin = {
+  install(Vue, options) {
+    assert(_.isObject(options));
+    if (options.debug && !_.isFunction(options.debug)) {
+      options.debug = (str) => {
+        console.log(str);
+      };
+    }
+    assert(_.isString(options.brokerURL));
+    if (!options.brokerURL.startsWith('ws://')) {
+      options.brokerURL = `ws://${location.host}${options.brokerURL}`;
+    }
+
+    // 3. 注入组件
+    Vue.mixin({
+      beforeDestroy: function () {
+        if (this.$stompClient) {
+          this.$stompClient.deactivate();
+          delete this.$stompClient;
+        }
+      },
+    });
+
+    // 4. 添加实例方法
+    Vue.prototype.$stomp = function (subscribes = {}) {
+      // connect to mq
+      const client = new Client(options);
+      client.onConnect = (frame) => {
+        // Do something, all subscribes must be done is this callback
+        // This is needed because this will be executed after a (re)connect
+        console.log('[stomp] connected');
+        Object.keys(subscribes)
+          .filter((p) => _.isFunction(subscribes[p]))
+          .forEach((key) => {
+            client.subscribe(key, subscribes[key]);
+          });
+      };
+
+      client.onStompError = (frame) => {
+        // Will be invoked in case of error encountered at Broker
+        // Bad login/passcode typically will cause an error
+        // Complaint brokers will set `message` header with a brief message. Body may contain details.
+        // Compliant brokers will terminate the connection after any error
+        console.log('Broker reported error: ' + frame.headers['message']);
+        console.log('Additional details: ' + frame.body);
+      };
+
+      client.activate();
+
+      this.$stompClient = client;
+    };
+  },
+};
+export default () => {
+  Vue.use(Plugin, Vue.config.stomp);
+};

+ 25 - 0
src/plugins/var.js

@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import _ from 'lodash';
+
+const getSiteId = () => {
+  let host = `${window.location.hostname}`; //`999991.smart.jilinjobswx.cn ${window.location.hostname}`
+  let schId;
+  host = host.replace('http://', '');
+  let arr = host.split('.');
+  if (arr.length > 0) {
+    schId = arr[0];
+    if (schId === 'smart') schId = 'master';
+    else `${schId}`.includes('localhost') || `${schId}`.includes('127.0.0.1') ? (schId = '99991') : '';
+    sessionStorage.setItem('schId', `${schId}`.includes('localhost') || `${schId}`.includes('127.0.0.1') ? '99991' : schId);
+  }
+  return schId;
+};
+const Plugin = {
+  install(vue, options) {
+    // 4. 添加实例方法
+    vue.prototype.$limit = 10;
+    vue.prototype.$site = getSiteId();
+  },
+};
+
+Vue.use(Plugin);

+ 301 - 0
src/router/index.js

@@ -0,0 +1,301 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import store from '@/store/index';
+const jwt = require('jsonwebtoken');
+const originalPush = VueRouter.prototype.push;
+VueRouter.prototype.push = function push(location) {
+  return originalPush.call(this, location).catch((err) => err);
+};
+Vue.use(VueRouter);
+
+const web = [
+  {
+    path: '/',
+    redirect: '/adminCenter/homeIndex',
+  },
+  // 管理登录
+  {
+    path: '/login',
+    name: 'login',
+    meta: { title: '精神障碍患者管理系统' },
+    component: () => import('../views/login.vue'),
+  },
+  {
+    path: '/map',
+    name: 'map',
+    meta: { title: '精神障碍患者管理系统' },
+    component: () => import('../views/census_two/parts/map.vue'),
+  },
+  {
+    path: '/census',
+    name: 'census',
+    meta: { title: '精神障碍患者管理系统' },
+    component: () => import('../views/census/index.vue'),
+  },
+  {
+    path: '/census_two',
+    meta: { title: '精神障碍患者管理系统' },
+    component: () => import('../views/census_two/index.vue'),
+  },
+  // 弹出监控患者页面
+  {
+    path: '/watch/warning',
+    meta: { title: '警情查看' },
+    component: () => import('../views/new-page/warning.vue'),
+  },
+  {
+    path: '/watch/ward/:id',
+    meta: { title: '精神障碍患者管实时监控' },
+    component: () => import('../views/new-page/ward-watch.vue'),
+  },
+
+  // 管理中心
+  {
+    path: '/adminCenter/homeIndex',
+    name: 'adminCenter',
+    component: () => import('@common/src/components/admin-frame/Home.vue'),
+    children: [
+      {
+        path: '/adminCenter/homeIndex',
+        name: 'admin_homeIndex',
+        meta: { title: '首页' },
+        component: () => import('../views/adminCenter/homeIndex/index.vue'),
+      },
+      {
+        path: '/police/dept',
+        meta: { title: '部门管理' },
+        component: () => import('../views/police/dept/index.vue'),
+      },
+      {
+        path: '/police/role',
+        meta: { title: '角色管理' },
+        component: () => import('../views/police/role/index.vue'),
+      },
+      {
+        path: '/police/account',
+        meta: { title: '账号管理' },
+        component: () => import('../views/police/account/index.vue'),
+      },
+      {
+        path: '/hospital/account',
+        meta: { title: '医院账号管理' },
+        component: () => import('../views/hospital/account/index.vue'),
+      },
+      {
+        path: '/hospital/account/range',
+        meta: { title: '管理范围' },
+        component: () => import('../views/hospital/account/range.vue'),
+      },
+      {
+        path: '/hospital/doctor',
+        meta: { title: '随访医生管理' },
+        component: () => import('../views/hospital/doctor/index.vue'),
+      },
+      {
+        path: '/guardian/account',
+        meta: { title: '账号管理' },
+        component: () => import('../views/guardian/account/index.vue'),
+      },
+      {
+        path: '/guardian/patient',
+        meta: { title: '病人管理' },
+        component: () => import('../views/guardian/patient/index.vue'),
+      },
+      {
+        path: '/guardian/import',
+        meta: { title: '病人信息导入' },
+        component: () => import('../views/guardian/import/index.vue'),
+      },
+      {
+        path: '/guardian/patient/detail',
+        meta: { title: '病人信息管理' },
+        component: () => import('../views/guardian/patient/detail.vue'),
+      },
+      {
+        path: '/guardian/patient/info',
+        meta: { title: 'pdf患者信息预览' },
+        component: () => import('../views/guardian/patient/info.vue'),
+      },
+      {
+        path: '/guardian/manual',
+        meta: { title: '健康管理手册' },
+        component: () => import('../views/guardian/manual/index.vue'),
+      },
+
+      {
+        path: '/fence/apply',
+        meta: { title: '围栏变更申请' },
+        component: () => import('../views/fence/apply/index.vue'),
+      },
+      {
+        path: '/fence/apply/check',
+        meta: { title: '围栏变更审核' },
+        component: () => import('../views/fence/apply/check.vue'),
+      },
+      {
+        path: '/fence/set',
+        meta: { title: '围栏设置' },
+        component: () => import('../views/fence/set/index.vue'),
+      },
+      {
+        path: '/fence/add',
+        meta: { title: '围栏添加' },
+        component: () => import('../views/fence/set/add.vue'),
+      },
+      {
+        path: '/fence/edit',
+        meta: { title: '围栏编辑' },
+        component: () => import('../views/fence/set/edit.vue'),
+      },
+      {
+        path: '/fence/track',
+        meta: { title: '患者行动轨迹查询' },
+        component: () => import('../views/fence/track/index.vue'),
+      },
+      {
+        path: '/fence/ward',
+        meta: { title: '患者围栏管理' },
+        component: () => import('../views/fence/ward/index.vue'),
+      },
+      {
+        path: '/fence/ward/fence',
+        meta: { title: '患者围栏编辑' },
+        component: () => import('../views/fence/ward/fence.vue'),
+      },
+      {
+        path: '/fence/view',
+        meta: { title: '全部围栏查看' },
+        component: () => import('../views/fence/set/view.vue'),
+      },
+      {
+        path: '/warning',
+        meta: { title: '报警信息处理' },
+        component: () => import('../views/warning/index.vue'),
+      },
+      // 信息录入
+      {
+        path: '/infoCreate',
+        meta: { title: '信息录入' },
+        component: () => import('../views/infoCreate/index.vue'),
+      },
+      {
+        path: '/system/updatepd',
+        meta: { title: '修改密码' },
+        component: () => import('../views/system/updatepd/index.vue'),
+      },
+      {
+        path: '/system/level',
+        meta: { title: '患者等级设置' },
+        component: () => import('../views/system/level/index.vue'),
+      },
+      {
+        path: '/system/basic',
+        meta: { title: '基本设置' },
+        component: () => import('../views/system/basic/index.vue'),
+      },
+      {
+        path: '/sendcase',
+        meta: { title: '发案管理' },
+        component: () => import('../views/sendcase/index.vue'),
+      },
+      {
+        path: '/judge',
+        meta: { title: '研判中心管理' },
+        component: () => import('../views/judge/index.vue'),
+      },
+
+      //三长管理
+      {
+        path: '/three/grid',
+        meta: { title: '网格长管理' },
+        component: () => import('../views/three/grid/index.vue'),
+      },
+      {
+        path: '/three/building',
+        meta: { title: '楼道长管理' },
+        component: () => import('../views/three/building/index.vue'),
+      },
+      {
+        path: '/three/unit',
+        meta: { title: '单元长管理' },
+        component: () => import('../views/three/unit/index.vue'),
+      },
+      {
+        path: '/law',
+        meta: { title: '政法委账号管理' },
+        component: () => import('../views/law/index.vue'),
+      },
+      {
+        path: '/sheriff',
+        meta: { title: '警长账号管理' },
+        component: () => import('../views/sheriff/index.vue'),
+      },
+      // 全省统计情况,
+      {
+        path: '/jlcensus/region',
+        meta: { title: '地域分布情况' },
+        component: () => import('../views/jlcensus/region/index.vue'),
+      },
+      {
+        path: '/jlcensus/row',
+        meta: { title: '患者列划管控情况' },
+        component: () => import('../views/jlcensus/row/index.vue'),
+      },
+      {
+        path: '/jlcensus/level',
+        meta: { title: '等级评估分布情况' },
+        component: () => import('../views/jlcensus/level/index.vue'),
+      },
+      // kpi考核页
+      {
+        path: '/kpi/mjkpi',
+        meta: { title: '民警日常工作统计' },
+        component: () => import('../views/kpi/mjkpi/index.vue'),
+      },
+      {
+        path: '/kpi/jhrkpi',
+        meta: { title: '监护人日常工作统计' },
+        component: () => import('../views/kpi/jhrkpi/index.vue'),
+      },
+      {
+        path: '/equipment/index',
+        meta: { title: '手环管理' },
+        component: () => import('../views/guardian/equipment/index.vue'),
+      },
+      // 假数据
+      {
+        path: '/accountFake/:type',
+        meta: { title: '账号管理' },
+        component: () => import('../views/fake_list/index.vue'),
+      },
+    ],
+  },
+];
+const routes = [...web];
+const router = new VueRouter({
+  mode: 'history',
+  base: process.env.VUE_APP_ROUTER,
+  routes,
+});
+const whiteList = ['/census', '/watch/ward', '/watch/warning'];
+router.beforeEach((to, from, next) => {
+  document.title = `${to.meta.title} `;
+  const token = sessionStorage.getItem('token');
+  if (to.path === '/login') {
+    next();
+  } else {
+    const r = whiteList.find((f) => to.path.includes(f));
+    //白名单放过
+    if (r) next();
+    // 没token退出去登陆
+    else if (!token) next('/login');
+    else {
+      // 有token转换
+      let user = jwt.decode(token);
+      store.commit('setUser', user, { root: true });
+      next();
+    }
+  }
+});
+
+export default router;

+ 83 - 0
src/store/index.js

@@ -0,0 +1,83 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as ustate from '@common/src/store/user/state';
+import * as umutations from '@common/src/store/user/mutations';
+import * as window from '@common/src/store/user/window';
+
+// 部门管理
+import dept from '@common/src/store/dept';
+// 角色管理
+import role from '@common/src/store/role';
+// 公安端账号
+import police from '@common/src/store/police';
+// 医院账号管理
+import hospital from '@common/src/store/hospital';
+// 监护人信息
+import guardian from '@common/src/store/guardian';
+// 病人信息
+import ward from '@common/src/store/ward';
+// 围栏变更
+import fence from '@common/src/store/fence';
+// 管理员登陆
+import login from '@common/src/store/login';
+// 报警信息处理
+import warning from '@common/src/store/warning';
+// 统计
+import statistics from '@common/src/store/statistics';
+// 发案表
+import sendcase from '@common/src/store/sendcase';
+// 研判中心
+import judge from '@common/src/store/judge';
+// 围栏范围
+import range from '@common/src/store/range';
+// 定位
+import position from '@common/src/store/position';
+// 政法委账号管理
+import law from '@common/src/store/law';
+// 三长管理
+// 网格长
+import grid from '@common/src/store/grid';
+// 楼道长
+import building from '@common/src/store/building';
+// 单位长
+import unit from '@common/src/store/unit';
+// 警长账号管理
+import sheriff from '@common/src/store/sheriff';
+// 等级设置
+import level from '@common/src/store/level';
+// 系统基本设置
+import config from '@common/src/store/config';
+// 随访医生账号管理
+import doctor from '@common/src/store/doctor';
+
+Vue.use(Vuex);
+
+export default new Vuex.Store({
+  state: { ...ustate, ...window },
+  mutations: { ...umutations },
+  actions: {},
+  modules: {
+    dept,
+    role,
+    police,
+    hospital,
+    guardian,
+    ward,
+    fence,
+    login,
+    warning,
+    sendcase,
+    judge,
+    statistics,
+    range,
+    position,
+    law,
+    grid,
+    building,
+    unit,
+    sheriff,
+    level,
+    config,
+    doctor,
+  },
+});

+ 90 - 0
src/unit/htmlToPdf.js

@@ -0,0 +1,90 @@
+//不使用JQuery版的
+
+import html2canvas from 'html2canvas';
+import JsPDF from 'jspdf';
+
+/**
+ * @param  ele          要生成 pdf 的DOM元素(容器)
+ * @param  padfName     PDF文件生成后的文件名字
+ * */
+
+function downloadPDF(ele, pdfName) {
+  let eleW = ele.offsetWidth; // 获得该容器的宽
+  let eleH = ele.offsetHeight; // 获得该容器的高
+
+  let eleOffsetTop = ele.offsetTop; // 获得该容器到文档顶部的距离
+  let eleOffsetLeft = ele.offsetLeft; // 获得该容器到文档最左的距离
+
+  var canvas = document.createElement('canvas');
+  var abs = 0;
+
+  let win_in = document.documentElement.clientWidth || document.body.clientWidth; // 获得当前可视窗口的宽度(不包含滚动条)
+  let win_out = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
+
+  if (win_out > win_in) {
+    // abs = (win_o - win_i)/2;    // 获得滚动条长度的一半
+    abs = (win_out - win_in) / 2; // 获得滚动条宽度的一半
+    // console.log(a, '新abs');
+  }
+
+  canvas.width = eleW * 2; // 将画布宽&&高放大两倍
+  canvas.height = eleH * 2;
+
+  var context = canvas.getContext('2d');
+
+  context.scale(2, 2);
+
+  context.translate(-eleOffsetLeft - abs, -eleOffsetTop);
+  // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
+  // translate的时候,要把这个差值去掉
+
+  // html2canvas(element).then( (canvas)=>{ //报错
+  // html2canvas(element[0]).then( (canvas)=>{
+  html2canvas(ele, {
+    dpi: 300,
+    // allowTaint: true,  //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
+    useCORS: true, //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
+  }).then((canvas) => {
+    var contentWidth = canvas.width;
+    var contentHeight = canvas.height;
+    //一页pdf显示html页面生成的canvas高度;
+    var pageHeight = (contentWidth / 592.28) * 841.89;
+    //未生成pdf的html页面高度
+    var leftHeight = contentHeight;
+    //页面偏移
+    var position = 0;
+    //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
+    var imgWidth = 595.28;
+    var imgHeight = (595.28 / contentWidth) * contentHeight;
+
+    var pageData = canvas.toDataURL('image/jpeg', 1.0);
+
+    var pdf = new JsPDF('', 'pt', 'a4');
+
+    //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
+    //当内容未超过pdf一页显示的范围,无需分页
+    if (leftHeight < pageHeight) {
+      //在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
+      pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
+      // pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);
+    } else {
+      // 分页
+      while (leftHeight > 0) {
+        pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
+        leftHeight -= pageHeight;
+        position -= 841.89;
+        //避免添加空白页
+        if (leftHeight > 0) {
+          pdf.addPage();
+        }
+      }
+    }
+
+    //可动态生成
+    pdf.save(pdfName);
+  });
+}
+
+export default {
+  downloadPDF,
+};

+ 83 - 0
src/unit/htmlToPdfJQ.js

@@ -0,0 +1,83 @@
+//使用JQuery方式写的。
+
+import html2canvas from 'html2canvas';
+import JsPDF from 'jspdf';
+import $ from 'jquery';
+
+// console.log($, '这是什么什么');
+
+function download(ele) {
+  var element = $('#demo'); // 这个dom元素是要导出pdf的div容器
+  console.log(element, '1212122');
+
+  // var element = ele;    // 这个dom元素是要导出pdf的div容器
+
+  var w = element.width(); // 获得该容器的宽
+  var h = element.height(); // 获得该容器的高
+
+  var offsetTop = element.offset().top; // 获得该容器到文档顶部的距离
+  var offsetLeft = element.offset().left; // 获得该容器到文档最左的距离
+
+  console.log(offsetTop, '------', offsetLeft);
+
+  var canvas = document.createElement('canvas');
+  var abs = 0;
+  var win_i = $(window).width(); // 获得当前可视窗口的宽度(不包含滚动条)
+  var win_o = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
+
+  console.log(canvas, abs, win_i, win_o);
+
+  if (win_o > win_i) {
+    abs = (win_o - win_i) / 2; // 获得滚动条长度的一半
+  }
+
+  canvas.width = w * 2; // 将画布宽&&高放大两倍
+  canvas.height = h * 2;
+  var context = canvas.getContext('2d');
+  context.scale(2, 2);
+  context.translate(-offsetLeft - abs, -offsetTop);
+  // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
+  // translate的时候,要把这个差值去掉
+
+  // html2canvas(element).then( (canvas)=>{ //报错
+  html2canvas(element[0]).then((canvas) => {
+    var contentWidth = canvas.width;
+    var contentHeight = canvas.height;
+    //一页pdf显示html页面生成的canvas高度;
+    var pageHeight = (contentWidth / 592.28) * 841.89;
+    //未生成pdf的html页面高度
+    var leftHeight = contentHeight;
+    //页面偏移
+    var position = 0;
+    //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
+    var imgWidth = 595.28;
+    var imgHeight = (592.28 / contentWidth) * contentHeight;
+
+    var pageData = canvas.toDataURL('image/jpeg', 1.0);
+
+    var pdf = new JsPDF('', 'pt', 'a4');
+
+    //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
+    //当内容未超过pdf一页显示的范围,无需分页
+    if (leftHeight < pageHeight) {
+      pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
+    } else {
+      // 分页
+      while (leftHeight > 0) {
+        pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
+        leftHeight -= pageHeight;
+        position -= 841.89;
+        //避免添加空白页
+        if (leftHeight > 0) {
+          pdf.addPage();
+        }
+      }
+    }
+
+    pdf.save('我的简历.pdf');
+  });
+}
+
+export default {
+  download,
+};

+ 117 - 0
src/util/axios-wrapper.js

@@ -0,0 +1,117 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import _ from 'lodash';
+import Axios from 'axios';
+import { Util, Error } from 'naf-core';
+// import { Indicator } from 'mint-ui';
+import util from './user-util';
+
+const { trimData, isNullOrUndefined } = Util;
+const { ErrorCode } = Error;
+
+let currentRequests = 0;
+
+export default class AxiosWrapper {
+  constructor({ baseUrl = '', unwrap = true } = {}) {
+    this.baseUrl = baseUrl;
+    this.unwrap = unwrap;
+  }
+
+  // 替换uri中的参数变量
+  static merge(uri, query = {}) {
+    if (!uri.includes(':')) {
+      return uri;
+    }
+    const keys = [];
+    const regexp = /\/:([a-z0-9_]+)/gi;
+    let res;
+    // eslint-disable-next-line no-cond-assign
+    while ((res = regexp.exec(uri)) != null) {
+      keys.push(res[1]);
+    }
+    keys.forEach((key) => {
+      if (!isNullOrUndefined(query[key])) {
+        uri = uri.replace(`:${key}`, query[key]);
+      }
+    });
+    return uri;
+  }
+
+  $get(uri, query, options) {
+    return this.$request(uri, null, query, options);
+  }
+
+  $post(uri, data = {}, query, options) {
+    return this.$request(uri, data, query, options);
+  }
+  $delete(uri, data = {}, router, query, options = {}) {
+    options = { ...options, method: 'delete' };
+    return this.$request(uri, data, query, options, router);
+  }
+  async $request(uri, data, query, options) {
+    // TODO: 合并query和options
+    if (_.isObject(query) && _.isObject(options)) {
+      options = { ...options, params: query, method: 'get' };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    if (!options) options = {};
+    if (options.params) options.params = trimData(options.params);
+    const url = AxiosWrapper.merge(uri, options.params);
+    currentRequests += 1;
+    // Indicator.open({
+    //   spinnerType: 'fading-circle',
+    // });
+
+    try {
+      const axios = Axios.create({
+        baseURL: this.baseUrl,
+      });
+      axios.defaults.headers.common.Authorization = util.token;
+      let res = await axios.request({
+        method: isNullOrUndefined(data) ? 'get' : 'post',
+        url,
+        data,
+        responseType: 'json',
+        ...options,
+      });
+      res = res.data;
+      const { errcode, errmsg, details } = res;
+      if (errcode) {
+        console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`);
+        return res;
+      }
+      // unwrap data
+      if (this.unwrap) {
+        res = _.omit(res, ['errmsg', 'details']);
+        const keys = Object.keys(res);
+        if (keys.length === 1 && keys.includes('data')) {
+          res = res.data;
+        }
+      }
+      return res;
+    } catch (err) {
+      let errmsg = '接口请求失败,请稍后重试';
+      if (err.response) {
+        const { status } = err.response;
+        if (status === 401) errmsg = '用户认证失败,请重新登录';
+        if (status === 403) errmsg = '当前用户不允许执行该操作';
+      }
+      console.error(
+        `[AxiosWrapper] 接口请求失败: ${err.config && err.config.url} - 
+        ${err.message}`
+      );
+      return { errcode: ErrorCode.SERVICE_FAULT, errmsg, details: err.message };
+    } finally {
+      /* eslint-disable */
+      currentRequests -= 1;
+      if (currentRequests <= 0) {
+        currentRequests = 0;
+        // Indicator.close();
+      }
+    }
+  }
+}

+ 381 - 0
src/util/draw.js

@@ -0,0 +1,381 @@
+const _ = require('lodash');
+import { Message } from 'element-ui';
+const isDrawingColor = '#171d4f';
+const levelList = [
+  { label: '1', color: '#409eff' },
+  { label: '2', color: '#B5C334' },
+  { label: '3', color: '#E87C25' },
+  { label: '4', color: '#FCCE10' },
+  { label: '5', color: '#C1232B' },
+];
+
+// 绘制多边形
+const drawPolygon = (mouseTool) => {
+  if (!mouseTool) {
+    Message.error('鼠标工具初始化失败,无法进行绘制');
+    return false;
+  }
+  mouseTool.polygon({
+    strokeColor: isDrawingColor,
+    strokeOpacity: 1,
+    strokeWeight: 6,
+    strokeOpacity: 0.2,
+    fillColor: isDrawingColor,
+    fillOpacity: 0.4,
+    // 线样式还支持 'dashed'
+    strokeStyle: 'solid',
+    // strokeStyle是dashed时有效
+    // strokeDasharray: [30,10],
+  });
+};
+// 绘制矩形
+const drawRectangle = (mouseTool) => {
+  if (!mouseTool) {
+    Message.error('鼠标工具初始化失败,无法进行绘制');
+    return false;
+  }
+  mouseTool.rectangle({
+    fillColor: isDrawingColor,
+    strokeColor: isDrawingColor,
+    strokeOpacity: 1,
+    strokeWeight: 6,
+    strokeOpacity: 0.2,
+    fillOpacity: 0.4,
+    strokeStyle: 'solid',
+  });
+};
+// 生成多边形
+const initPolygon = (data) => {
+  const { range: path, color = isDrawingColor } = data;
+  let drawColor = color;
+  if (_.get(data, 'drawType') === 'fence') {
+    drawColor = '#C1232B';
+  } else if (_.get(data, 'drawType') === 'ward') {
+    drawColor = '#FCCE10';
+  }
+  let object = new AMap.Polygon({
+    //围栏样式
+    path,
+    strokeColor: drawColor,
+    strokeWeight: 3,
+    strokeOpacity: 0.2,
+    fillOpacity: 0.4,
+    fillColor: drawColor,
+    // zIndex: 50,
+    extData: data,
+  });
+  return object;
+};
+// 生成矩形
+const initRectangle = (data) => {
+  const { range: path, color = isDrawingColor } = data;
+  const bounds = new AMap.Bounds(path[0], path[2]);
+  let drawColor = color;
+  if (_.get(data, 'drawType') === 'fence') {
+    drawColor = '#C1232B';
+  } else if (_.get(data, 'drawType') === 'ward') {
+    drawColor = '#FCCE10';
+  }
+  let object = new AMap.Rectangle({
+    bounds,
+    strokeColor: drawColor,
+    strokeOpacity: 1,
+    strokeWeight: 3,
+    strokeDasharray: [30, 10],
+    // strokeStyle还支持 solid
+    strokeStyle: 'solid',
+    fillColor: drawColor,
+    fillOpacity: 0.5,
+    // cursor: 'pointer',
+    // zIndex: 50,
+    extData: data,
+  });
+  return object;
+};
+// 初始化鼠标工具
+const initMouseTool = async (map) => {
+  return new Promise((resolve, reject) => {
+    AMap.plugin(['AMap.MouseTool'], () => {
+      let plugin = new AMap.MouseTool(map);
+      resolve(plugin);
+    });
+    reject('error');
+  });
+};
+// 查询功能
+const initSearch = async (options = {}) => {
+  return new Promise((resolve, reject) => {
+    AMap.plugin(['AMap.PlaceSearch'], () => {
+      let plugin = new AMap.PlaceSearch(options);
+      resolve(plugin);
+    });
+    reject('error');
+  });
+};
+// 查询提示
+const initSearchAutoComplete = (id) => {
+  return new Promise((resolve, reject) => {
+    AMap.plugin('AMap.AutoComplete', function () {
+      // 实例化AutoComplete
+      let autoOptions = {
+        // input 为绑定输入提示功能的input的DOM ID
+        input: id,
+      };
+      let autoComplete = new AMap.AutoComplete(autoOptions);
+      // 无需再手动执行search方法,autoComplete会根据传入input对应的DOM动态触发search
+      resolve();
+    });
+    reject();
+  });
+};
+
+/**
+ * 生成标记
+ * @param {Object} data 标记数据
+ * @property {Array} position 经纬度数组 [lng,lat]
+ * @property {Boolean} clickable 是否可以点击,默认为false
+ * @property {Array} functionList 事件数组[{key:mouseover,func:(e)=>{}}]
+ * @property {String} markLabel 标记的标签(显示的字)
+ * @property {String} icon 标记的图标
+ * @property {Object} extData 除了上面的属性外,其他的所有属性都放这里
+ */
+const initMark = (data) => {
+  const { position, clickable = false, functionList = [], markLabel, icon, ...extData } = data;
+  const object = {
+    anchor: 'bottom-center',
+    position,
+    clickable,
+    extData,
+  };
+  if (markLabel) object.label = markLabel;
+  if (icon) object.icon = icon;
+  let mark = new AMap.Marker(object);
+  // 注册事件
+  for (const i of functionList) {
+    const { key, func } = i;
+    mark.on(key, func);
+  }
+  return mark;
+};
+
+/**
+ * 生成海量点类
+ * @param {Object} data 数据
+ */
+const initMassMark = (data) => {
+  // 海量点样式(有图片)
+  const styleArray = [
+    {
+      url: require('@/assets/icon/p1.png'), // 0级 0
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/p2.png'), // 1级 1
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/p3.png'), // 2级 2
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/p4.png'), // 3级 3
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/p5.png'), // 4级 4
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/p6.png'), // 5级 5
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/warning.png'), // 报警 6
+      size: new AMap.Size(30, 30), // 图标大小
+      anchor: new AMap.Pixel(10, 10), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/guardian.png'), // 监护人  7
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/less-3.png'), // 发病次数小于3 8
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/3-5.png'), // 发病次数3-5 9
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+    {
+      url: require('@/assets/icon/more-5.png'), // 发病次数大于5 10
+      size: new AMap.Size(20, 20), // 图标大小
+      anchor: new AMap.Pixel(5, 5), // 图标显示位置偏移量,基准点为图标左上角
+    },
+  ];
+  let massMarks = new AMap.MassMarks(data, {
+    zIndex: 999, // 海量点图层叠加的顺序
+    zooms: [3, 24], // 在指定地图缩放级别范围内展示海量点图层
+    style: styleArray, // 设置样式对象
+  });
+  return massMarks;
+};
+const initMassMarkData = (data) => {
+  let { position, latitude, longitude, name, ...info } = data;
+  let style = 0;
+  if (info.type === 'ward') {
+    // style 是上面图标列表的索引
+    if (info.level === 'warning') style = 6;
+    else if (info.level === '<3') style = 8;
+    else if (info.level === '3-5') style = 9;
+    else if (info.level === '>5') style = 10;
+    else style = parseInt(info.level);
+  } else style = 7;
+  if (!_.isArray(position)) {
+    position = [longitude, latitude];
+  }
+  if (!_.isArray(position)) return false;
+  position = position.map((i) => parseFloat(i));
+  const obj = {
+    lnglat: position,
+    name,
+    ...info,
+    style, // 该数据的样式取值styleObjectArr对应的样式索引
+  };
+  return obj;
+};
+/**
+ * 初始化loca
+ * @param {Object} map 地图对象
+ */
+const initLoca = (map) => {
+  let loca = new Loca.Container({
+    map,
+  });
+  loca.animate.start();
+  return loca;
+};
+
+/**
+ * 初始化脉冲图
+ */
+const initPulseLine = () => {
+  const pulseLineColor = ['#7F3CFF', '#4CC19B', '#0B5D74', '#E06AC4', '#223F9B', '#F15C1A', '#7A0FA6', '#EFBB51'];
+  let layer = new Loca.PulseLineLayer({
+    zIndex: 50,
+    opacity: 1,
+    visible: true,
+    zooms: [2, 22],
+  });
+  // 脉冲图层样式设置
+  layer.setStyle({
+    altitude: 0,
+    lineWidth: 3,
+    // 脉冲头颜色
+    headColor: (p, feature) => {
+      let color = pulseLineColor[0];
+      if (_.get(feature, 'properties.color')) color = _.get(feature, 'properties.color');
+      else if (_.get(feature, 'properties.colorIndex') > -1) color = pulseLineColor[_.get(feature, 'properties.colorIndex')];
+      return color;
+    },
+    // 脉冲尾颜色
+    trailColor: 'rgba(128, 128, 128, 0.5)',
+    // 脉冲长度,0.25 表示一段脉冲占整条路的 1/4
+    interval: 0.2,
+    // 脉冲线的速度,几秒钟跑完整段路
+    duration: 10000,
+  });
+  return layer;
+};
+
+/**
+ * 坐标数据初始化,返回实例
+ * @param {Array} data 经纬度数组
+ */
+const initGeoData = (data) => {
+  let geo = new Loca.GeoJSONSource({
+    data,
+  });
+  return geo;
+};
+/**
+ * 初始化脉冲线路数据,直接转换成地理数据;颜色优先使用color
+ * @param {Array} points 一组点的相关数据
+ * @param {String} color hex具体颜色
+ * @param {Number} colorIndex 默认设置的颜色索引
+ */
+const initPulseLineData = (points, color, colorIndex) => {
+  const pointsList = points.map((i) => {
+    if (_.isArray(i.position)) return i.position;
+    else if (_.get(i, 'longitude') && _.get(i, 'latitude')) return [i.longitude, i.latitude];
+  });
+  const data = {
+    type: 'Feature',
+    geometry: {
+      type: 'LineString',
+      // 点越多,越细致
+      coordinates: pointsList, //经纬坐标
+    },
+    properties: { color, colorIndex }, // 该点的属性,在设置中可以输出
+  };
+  let geoData = { type: 'FeatureCollection', features: [data] };
+  return geoData;
+};
+/**
+ * 移除脉冲图层
+ * @param {Object} pulse 脉冲图层
+ * @param {Object} loca 可视化类
+ */
+const removePulse = (pulse, loca) => {
+  if (pulse) {
+    loca.remove(pulse);
+    return true;
+  }
+};
+
+export default {
+  // 初始化查询
+  initSearch,
+  // 初始化海量点类
+  initMassMark,
+  // 初始化鼠标工具类
+  initMouseTool,
+  // 初始化关联查询(默认样式)
+  initSearchAutoComplete,
+  // 初始化视图可视化
+  initLoca,
+  // 初始化脉冲图图层
+  initPulseLine,
+
+  // 移除脉冲图
+  removePulse,
+
+  // 格式化海量点数据
+  initMassMarkData,
+  // 格式化为地理数据
+  initGeoData,
+  // 格式化脉冲图数据
+  initPulseLineData,
+
+  // 手动绘制多边形
+  drawPolygon,
+  // 手动绘制矩形
+  drawRectangle,
+  // 绘制多边形区域
+  initPolygon,
+  // 绘制矩形区域
+  initRectangle,
+  // 绘制标记
+  initMark,
+
+  // 等级对应颜色变量(应该是没用了)
+  levelList,
+};

+ 1 - 0
src/util/fence-prop.js

@@ -0,0 +1 @@
+export const categoryList = ['政府机关', '教育机构', '金融机构', '公共交通', '重点场所', '加油站'];

+ 10 - 0
src/util/filters.js

@@ -0,0 +1,10 @@
+import _ from 'lodash';
+
+const filters = {
+  getName(object) {
+    const { data, searchItem } = object;
+    return _.get(data, searchItem) === undefined ? '' : _.get(data, searchItem);
+  },
+};
+
+export default filters;

+ 21 - 0
src/util/map.js

@@ -0,0 +1,21 @@
+const _ = require('lodash');
+import { Message } from 'element-ui';
+const initEvent = (map, geo) => {
+  if (!map) return false;
+  map.on('click', (e) => {
+    // 获得点击位置
+    const pos = [_.get(e, 'lnglat.lng'), _.get(e, 'lnglat.lat')];
+    map.setCity('长春市');
+    geo.getAddress(pos, (status, result) => {
+      // if (!(status === 'complete' && result.info === 'OK')) return;
+      // const province = _.get(result, 'regeocode.addressComponent.province');
+      // if (province === '吉林省') {
+      // map.setCity('长春市');
+      // } else {
+      //   Message.warning('暂未开通其他城市的下潜');
+      // }
+    });
+  });
+};
+
+export default { initEvent };

+ 50 - 0
src/util/methods-util.js

@@ -0,0 +1,50 @@
+import { Util } from 'naf-core';
+
+const { isNullOrUndefined } = Util;
+
+export default {
+  //判断信息是否过期
+  isDateOff(dataDate) {
+    const now = new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
+    dataDate = new Date(dataDate);
+    return now.getTime() <= dataDate.getTime();
+  },
+  //判断企业是否可以执行此动作/显示
+  checkCorp(data) {
+    const { role, unit, selfUnit, status, displayType, userid } = data;
+    if (!isNullOrUndefined(selfUnit) && !isNullOrUndefined(status)) {
+      return role === 'corp' && selfUnit === unit && status === '0';
+    } else if (!isNullOrUndefined(displayType)) {
+      if (role === 'corp') {
+        return role === displayType;
+      } else {
+        return role === displayType && !isNullOrUndefined(userid);
+      }
+    }
+  },
+  //获取url的参数params
+  getParams() {
+    let str = location.href;
+    let num = str.indexOf('?');
+    const param = {};
+    str = str.substr(num + 1);
+    let num2 = str.indexOf('#');
+    let str2 = '';
+    if (num2 > 0) {
+      str2 = str.substr(0, num2);
+    } else {
+      num2 = str.indexOf('/');
+      str2 = str.substr(0, num2);
+    }
+    const arr = str2.split('&');
+    for (let i = 0; i < arr.length; i++) {
+      num = arr[i].indexOf('=');
+      if (num > 0) {
+        const name = arr[i].substring(0, num);
+        const value = arr[i].substr(num + 1);
+        param[name] = decodeURI(value);
+      }
+    }
+    return param;
+  },
+};

+ 163 - 0
src/util/print.js

@@ -0,0 +1,163 @@
+// 打印类属性、方法定义
+/* eslint-disable */
+const Print = function (dom, options) {
+  if (!(this instanceof Print)) return new Print(dom, options);
+
+  this.options = this.extend({
+    'noPrint': '.no-print'
+  }, options);
+
+  if ((typeof dom) === "string") {
+    this.dom = document.querySelector(dom);
+  } else {
+    this.isDOM(dom)
+    this.dom = this.isDOM(dom) ? dom : dom.$el;
+  }
+
+  this.init();
+};
+Print.prototype = {
+  init: function () {
+    var content = this.getStyle() + this.getHtml();
+    this.writeIframe(content);
+  },
+  extend: function (obj, obj2) {
+    for (var k in obj2) {
+      obj[k] = obj2[k];
+    }
+    return obj;
+  },
+
+  getStyle: function () {
+    var str = "",
+      styles = document.querySelectorAll('style,link');
+    for (var i = 0; i < styles.length; i++) {
+      str += styles[i].outerHTML;
+    }
+    str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
+
+    return str;
+  },
+
+  getHtml: function () {
+    var inputs = document.querySelectorAll('input');
+    var textareas = document.querySelectorAll('textarea');
+    var selects = document.querySelectorAll('select');
+
+    for (var k = 0; k < inputs.length; k++) {
+      if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
+        if (inputs[k].checked == true) {
+          inputs[k].setAttribute('checked', "checked")
+        } else {
+          inputs[k].removeAttribute('checked')
+        }
+      } else if (inputs[k].type == "text") {
+        inputs[k].setAttribute('value', inputs[k].value)
+      } else {
+        inputs[k].setAttribute('value', inputs[k].value)
+      }
+    }
+
+    for (var k2 = 0; k2 < textareas.length; k2++) {
+      if (textareas[k2].type == 'textarea') {
+        textareas[k2].innerHTML = textareas[k2].value
+      }
+    }
+
+    for (var k3 = 0; k3 < selects.length; k3++) {
+      if (selects[k3].type == 'select-one') {
+        var child = selects[k3].children;
+        for (var i in child) {
+          if (child[i].tagName == 'OPTION') {
+            if (child[i].selected == true) {
+              child[i].setAttribute('selected', "selected")
+            } else {
+              child[i].removeAttribute('selected')
+            }
+          }
+        }
+      }
+    }
+    // 包裹要打印的元素
+    // fix: https://github.com/xyl66/vuePlugs_printjs/issues/36
+    let outerHTML = this.wrapperRefDom(this.dom).outerHTML
+    return outerHTML;
+  },
+  // 向父级元素循环,包裹当前需要打印的元素
+  // 防止根级别开头的 css 选择器不生效
+  wrapperRefDom: function (refDom) {
+    let prevDom = null
+    let currDom = refDom
+    // 判断当前元素是否在 body 中,不在文档中则直接返回该节点
+    if (!this.isInBody(currDom)) return currDom
+
+    while (currDom) {
+      if (prevDom) {
+        let element = currDom.cloneNode(false)
+        element.appendChild(prevDom)
+        prevDom = element
+      } else {
+        prevDom = currDom.cloneNode(true)
+      }
+
+      currDom = currDom.parentElement
+    }
+
+    return prevDom
+  },
+
+  writeIframe: function (content) {
+    var w, doc, iframe = document.createElement('iframe'),
+      f = document.body.appendChild(iframe);
+    iframe.id = "myIframe";
+    //iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
+    iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
+    w = f.contentWindow || f.contentDocument;
+    doc = f.contentDocument || f.contentWindow.document;
+    doc.open();
+    doc.write(content);
+    doc.close();
+    var _this = this
+    iframe.onload = function(){
+      _this.toPrint(w);
+      setTimeout(function () {
+        document.body.removeChild(iframe)
+      }, 100)
+    }
+  },
+
+  toPrint: function (frameWindow) {
+    try {
+      setTimeout(function () {
+        frameWindow.focus();
+        try {
+          if (!frameWindow.document.execCommand('print', false, null)) {
+            frameWindow.print();
+          }
+        } catch (e) {
+          frameWindow.print();
+        }
+        frameWindow.close();
+      }, 10);
+    } catch (err) {
+      console.log('err', err);
+    }
+  },
+  // 检查一个元素是否是 body 元素的后代元素且非 body 元素本身
+  isInBody: function (node) {
+    return (node === document.body) ? false : document.body.contains(node);
+  },
+  isDOM: (typeof HTMLElement === 'object') ?
+    function (obj) {
+      return obj instanceof HTMLElement;
+    } :
+    function (obj) {
+      return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+    }
+};
+const MyPlugin = {}
+MyPlugin.install = function (Vue, options) {
+  // 4. 添加实例方法
+  Vue.prototype.$print = Print
+}
+export default MyPlugin

+ 69 - 0
src/util/user-util.js

@@ -0,0 +1,69 @@
+/* eslint-disable no-console */
+export default {
+  get user() {
+    const val = sessionStorage.getItem('user');
+    try {
+      if (val) return JSON.parse(val);
+    } catch (err) {
+      console.error(err);
+    }
+    return null;
+  },
+  set user(userinfo) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+  },
+  get token() {
+    return sessionStorage.getItem('token');
+  },
+  set token(token) {
+    sessionStorage.setItem('token', token);
+  },
+  get openid() {
+    return sessionStorage.getItem('openid');
+  },
+  set openid(openid) {
+    sessionStorage.setItem('openid', openid);
+  },
+  get isGuest() {
+    return !this.user || this.user.role === 'guest';
+  },
+  save({ userinfo, token }) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+    sessionStorage.setItem('token', token);
+  },
+
+  get corpInfo() {
+    const val = sessionStorage.getItem('corpInfo');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set corpInfo(corpInfo) {
+    sessionStorage.setItem('corpInfo', JSON.stringify(corpInfo));
+  },
+  saveCorpInfo(corpInfo) {
+    sessionStorage.setItem('corpInfo', JSON.stringify(corpInfo));
+  },
+
+  get unit() {
+    const val = sessionStorage.getItem('unit');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set unit(unitList) {
+    sessionStorage.setItem('unit', JSON.stringify(unitList));
+  },
+  saveUnit(unitList) {
+    sessionStorage.setItem('unit', JSON.stringify(unitList));
+  },
+  get userInfo() {
+    const val = sessionStorage.getItem('userInfo');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set userInfo(userInfo) {
+    sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
+  },
+  saveUserInfo(userInfo) {
+    sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
+  },
+};

+ 53 - 0
src/views/adminCenter/homeIndex/index.vue

@@ -0,0 +1,53 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight"> 精神障碍患者管理系统 </el-col>
+
+      <el-col :span="24">
+        <!-- <el-select v-model="value" clearable filterable placeholder="请选择">
+          <el-option-group v-for="group in options" :key="group.label" :label="group.label">
+            <el-option v-for="item in group.options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
+          </el-option-group>
+        </el-select> -->
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const { jlsq } = require('@common/src/layout/deploy/dict');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      options: jlsq,
+      value: '',
+    };
+  },
+  created() {
+    // console.log(this.win);
+    let array = [1, 2, 3, 4];
+    let evens = _.remove(array, 2);
+    console.log(evens);
+  },
+  methods: {},
+  computed: {
+    ...mapState(['user', 'win']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 38 - 0
src/views/adminCenter/index.vue

@@ -0,0 +1,38 @@
+<template>
+  <div id="index">
+    <admin-frame></admin-frame>
+  </div>
+</template>
+
+<script>
+import adminFrame from '@common/src/components/adminCommon/frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const _ = require('lodash');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    adminFrame,
+  },
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 2 - 0
src/views/census/eventBus.js

@@ -0,0 +1,2 @@
+import Vue from 'vue';
+export const EventBus = new Vue();

+ 204 - 0
src/views/census/index.vue

@@ -0,0 +1,204 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one animate__animated animate__bounceIn">
+          <el-col :span="8" class="one_1">
+            <span>{{ time }}</span>
+            <el-button type="primary" size="small" @click="back()">系统中心</el-button>
+          </el-col>
+          <el-col :span="8" class="one_2"> {{ census.title }} </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col :span="24" class="map">
+            <map-1></map-1>
+          </el-col>
+          <el-col :span="8" class="info_1">
+            <el-col :span="24" class="info_1one">
+              <left-1></left-1>
+            </el-col>
+            <el-col :span="24" class="info_1one animate__animated animate__fadeInLeft">
+              <left-2></left-2>
+            </el-col>
+            <el-col :span="24" class="info_1one animate__animated animate__fadeInUp">
+              <left-3></left-3>
+            </el-col>
+          </el-col>
+          <el-col :span="8" class="info_2">
+            <el-col :span="24" class="info_2one animate__animated animate__zoomIn">
+              <center-1></center-1>
+            </el-col>
+          </el-col>
+          <el-col :span="8" class="info_3">
+            <el-col :span="24" class="info_3one animate__animated animate__fadeInTopRight">
+              <right-1></right-1>
+            </el-col>
+            <el-col :span="24" class="info_3one animate__animated animate__fadeInBottomRight">
+              <right-2></right-2>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const { census } = require('@common/src/layout/deploy/dict');
+import map1 from './parts/map-1.vue';
+import left1 from './parts/left-1.vue';
+import left2 from './parts/left-2.vue';
+import left3 from './parts/left-3.vue';
+import center1 from './parts/center-1.vue';
+import right1 from './parts/right-1.vue';
+import right2 from './parts/right-2.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const moment = require('moment');
+export default {
+  name: 'index',
+  props: {},
+  components: { map1, left1, left2, left3, center1, right1, right2 },
+  data: function () {
+    return {
+      census: census,
+      // 当前时间
+      time: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
+    };
+  },
+  created() {},
+  methods: {
+    // 获取时间
+    getTime() {
+      this.time = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
+    },
+    // 返回
+    back() {
+      history.go(-1);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  mounted() {
+    this.timer = setInterval(this.getTime, 1000);
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background-color: #11145c !important;
+  background: url('~@/assets/tg/bottom-bg.png');
+  background-size: contain;
+  background-repeat: no-repeat;
+  background-position: bottom;
+  height: 100vh;
+  overflow: hidden;
+  .one {
+    background: url('~@/assets/tg/l-topbg.png');
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    -webkit-transition: all 0.5s;
+    transition: all 0.5s;
+    height: 5.36vw;
+    z-index: 3;
+    .one_1 {
+      height: 5.36vw;
+      span {
+        display: inline-block;
+        font-size: 3vmin;
+        font-family: cursive;
+        line-height: 5.36vw;
+        padding: 0 0 0 30px;
+        color: #31dafb;
+        font-weight: bold;
+      }
+      .el-button {
+        float: right;
+        margin: 40px 90px 0 0;
+        background-color: transparent;
+        color: #31dafb;
+      }
+      .el-button:hover {
+        color: #ffffff;
+      }
+    }
+    .one_2 {
+      text-align: center;
+      font-family: fzzuhjt;
+      font-size: 3.5vmin;
+      line-height: 4.6875vw;
+      overflow: hidden;
+      color: #ffffff;
+      text-shadow: 0 3px 3px #1872ec;
+    }
+    .one_3 {
+      height: 5.36vw;
+      .el-button {
+        margin: 40px 0 0 90px;
+        background-color: transparent;
+        color: #31dafb;
+      }
+      .el-button:hover {
+        color: #ffffff;
+      }
+    }
+  }
+  .two {
+    position: relative;
+    .info_1 {
+      position: absolute;
+      width: 22%;
+      .info_1one {
+        height: 13.6vw;
+        background: url('~@/assets/tg/room-overview.png');
+        background-repeat: no-repeat;
+        background-size: 100% 100%;
+        padding: 0 1.5625vw 1.5625vw 1.5625vw;
+        margin-bottom: 1.04vw;
+      }
+      .info_1one:last-child {
+        margin: 0px !important;
+      }
+    }
+    .info_2 {
+      position: absolute;
+      left: 23%;
+      width: 51.9%;
+      display: inline-block;
+      vertical-align: top;
+      margin: 0.04vw 1.04vw 0 1.04vw;
+      .info_2one {
+        height: 160px;
+        overflow: hidden;
+      }
+    }
+    .info_3 {
+      position: absolute;
+      right: 0;
+      width: 22%;
+      .info_3one {
+        height: 21vw;
+        background: url('~@/assets/tg/room-overview.png');
+        background-repeat: no-repeat;
+        background-size: 100% 100%;
+        padding: 0 1.5625vw 1.5625vw 1.5625vw;
+        margin-bottom: 1.04vw;
+      }
+      .info_3one:last-child {
+        margin: 0px !important;
+      }
+    }
+  }
+}
+</style>

+ 169 - 0
src/views/census/parts/center-1.vue

@@ -0,0 +1,169 @@
+<template>
+  <div id="center-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <ul>
+            <li class="list" v-for="(i, index) in list" :key="index" :style="{ width: width + '%' }">
+              <h5>{{ i.name }}</h5>
+              <p :title="i.num">
+                <span>{{ i.num }}</span> {{ i.type }}
+              </p>
+            </li>
+          </ul>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'center-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [],
+      width: '',
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...mapActions(['centerCount']),
+    async search() {
+      const res = await this.centerCount();
+      if (this.$checkRes(res)) {
+        const { d1, d2, d3, d4, d5, d6 } = res.data;
+        let data = [
+          { name: '精神障碍患者', num: d1, type: '人' },
+          { name: '患者发案率', num: d2, type: '%' },
+          { name: '监管医院', num: d3, type: '家' },
+          { name: '在院治疗患者', num: d4, type: '人' },
+          { name: '设备在线', num: d5, type: '个' },
+          { name: '警情中心', num: d6, type: '个' },
+        ];
+        this.$set(this, `list`, data);
+        this.countWidth(data.length);
+      }
+    },
+    // 计算宽度
+    countWidth(length) {
+      if (length == 4) this.$set(this, `width`, '23.1');
+      else if (length == 5) this.$set(this, `width`, '19');
+      else if (length == 6) this.$set(this, `width`, '15.4');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    typeInfo: {
+      deep: true,
+      // immediate: true,
+      handler(val) {
+        if (val && val.purpose_id) this.search({ rank: '2' });
+      },
+    },
+    companyInfo: {
+      deep: true,
+      // immediate: true,
+      handler(val) {
+        if (val && val.id) this.search({ rank: '3' });
+      },
+    },
+    rank: {
+      handler(val) {
+        if (val === '1') this.search();
+      },
+    },
+    serviceInfo: {
+      deep: true,
+      handler(val, oval) {
+        const keys = Object.keys(val);
+        const okeys = Object.keys(oval);
+        if (keys.length === 0 && okeys.length > 0) {
+          // 新值没有,旧值有值:返回,查询
+          this.search();
+        } else if (keys.length > 0 && okeys.length === 0) {
+          // 新值有值,旧值没值:查询某个服务对象
+          this.search();
+        } else if (keys.length > 0 && okeys.length > 0) {
+          // 都有值, 不是一个对象就重新查
+          const id = val.id;
+          const oid = oval.id;
+          if (!_.isEqual(id, oid)) this.search();
+        }
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    ul {
+      margin-top: 2.04vw;
+      height: 6.51vw;
+      text-align: center;
+      display: -webkit-flex;
+      display: flex;
+      -webkit-flex-flow: row;
+      flex-flow: row;
+      flex-wrap: wrap;
+      align-content: center;
+      justify-content: space-between;
+      li {
+        float: left;
+        height: 6.51vw;
+        margin-right: 0.5vw;
+        background: url('~@/assets/tg/all-statistics-bg.png');
+        background-repeat: no-repeat;
+        background-size: 100% 100%;
+        text-align: center;
+        list-style-type: none;
+        h5 {
+          font-size: 1vw;
+          color: #2bfdff;
+          font-style: italic;
+          padding-top: 1vw;
+          font-weight: 700;
+          font-family: fzzuhjt;
+          padding-bottom: 0.52vw;
+        }
+        p {
+          margin-top: 0.4vw;
+          color: #fff;
+          padding: 0 15px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          -webkit-line-clamp: 2;
+          word-break: break-all;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          span {
+            color: #f4fd50;
+            font-size: 1vw;
+            font-family: fantasy;
+            margin-right: 0.364vw;
+          }
+        }
+        p:hover {
+          cursor: pointer;
+        }
+      }
+      li:last-child {
+        margin: 0;
+      }
+    }
+  }
+}
+</style>

+ 151 - 0
src/views/census/parts/left-1.vue

@@ -0,0 +1,151 @@
+<template>
+  <div id="left-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__fadeInDown">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="one_1" @click.native="toPath()"> 各医院在院人数 </el-col>
+          <el-col :span="24" class="one_2">
+            <div id="echarts1" class="canvas" style="width: 100%; height: 9.8vw"></div>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { EventBus } from '../eventBus';
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'left-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [
+        { name: '测试医院1', value: 1 },
+        { name: '测试医院2', value: 2 },
+        { name: '测试医院3', value: 3 },
+        { name: '测试医院4', value: 4 },
+        { name: '测试医院5', value: 5 },
+        { name: '测试医院6', value: 6 },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['left1']),
+    async search() {
+      const res = await this.left1();
+      if (this.$checkRes(res)) {
+        let value = res.data.d3;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let option;
+      option = {
+        legend: { show: false },
+        toolbox: {},
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        series: [
+          {
+            name: '医院名称',
+            type: 'pie',
+            radius: [10, 70],
+            center: ['50%', '50%'],
+            roseType: '',
+            itemStyle: { borderRadius: 8 },
+            label: { color: 'rgba(255,255,255)', fontSize: '12', show: false },
+            data,
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts1');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {},
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .one_1 {
+      color: #000000;
+      font-size: 3vmin;
+      font-weight: 700;
+      position: relative;
+      border-bottom: 2px solid #2441a9;
+      line-height: 2.96875vw;
+      text-align: left;
+    }
+    .one_1::before {
+      background: #2441a9;
+      border-radius: 50%;
+      content: '';
+      width: 6px;
+      height: 6px;
+      position: absolute;
+      right: -2px;
+      bottom: -4px;
+      z-index: 1;
+      visibility: visible;
+    }
+    .one_2 {
+      background: #2441a9;
+    }
+  }
+}
+.canvas {
+  /deep/canvas {
+    width: 19vw !important;
+    // min-height: 5vw !important;
+    max-height: 9vw !important;
+  }
+}
+</style>

+ 170 - 0
src/views/census/parts/left-2.vue

@@ -0,0 +1,170 @@
+<template>
+  <div id="left-2">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__fadeInDown">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="one_1" @click.native="toPath()"> 精神障碍患者统计 </el-col>
+          <el-col :span="24" class="one_2">
+            <div id="echarts4" class="canvas" style="width: 100%; height: 10vw"></div>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { EventBus } from '../eventBus';
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'left-2',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [
+        { name: '2017', value: 20 },
+        { name: '2018', value: 70 },
+        { name: '2019', value: 150 },
+        { name: '2020', value: 360 },
+        { name: '2021', value: 15 },
+        { name: '2022', value: 251 },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['right1']),
+    async search() {
+      const res = await this.right1();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.name);
+      let thr = data.map((i) => i.value);
+      let option;
+      option = {
+        tooltip: {},
+        xAxis: {
+          type: 'category',
+          data: two,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series: [
+          {
+            data: thr,
+            type: 'line',
+            symbol: 'triangle',
+            symbolSize: 20,
+            lineStyle: { color: '#5470C6', width: 4, type: 'dashed' },
+            itemStyle: { borderWidth: 3, borderColor: '#EE6666', color: 'yellow' },
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts4');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .one_1 {
+      color: #000000;
+      font-size: 3vmin;
+      font-weight: 700;
+      position: relative;
+      border-bottom: 2px solid #2441a9;
+      line-height: 2.96875vw;
+      text-align: left;
+    }
+    .one_1::before {
+      background: #2441a9;
+      border-radius: 50%;
+      content: '';
+      width: 6px;
+      height: 6px;
+      position: absolute;
+      right: -2px;
+      bottom: -4px;
+      z-index: 1;
+      visibility: visible;
+    }
+    .one_1:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .one_2 {
+      background: #2441a9;
+    }
+  }
+}
+.canvas {
+  /deep/canvas {
+    width: 18vw !important;
+    // min-height: 5vw !important;
+    max-height: 10vw !important;
+  }
+}
+</style>

+ 157 - 0
src/views/census/parts/left-3.vue

@@ -0,0 +1,157 @@
+<template>
+  <div id="left-3">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__fadeInDown">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="one_1" @click.native="toPath()"> 精神障碍患者区域分布 </el-col>
+          <el-col :span="24" class="one_2">
+            <div id="echarts3" class="canvas" style="width: 100%; height: 9.8vw"></div>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { EventBus } from '../eventBus';
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'left-3',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [
+        { name: '数据1', value: 1 },
+        { name: '数据2', value: 2 },
+        { name: '数据3', value: 3 },
+        { name: '数据4', value: 4 },
+        { name: '数据5', value: 5 },
+        { name: '数据6', value: 6 },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['centerLeft1']),
+    async search() {
+      const res = await this.centerLeft1();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let option;
+      option = {
+        legend: { show: false },
+        toolbox: {},
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        series: [
+          {
+            name: '分布名称',
+            type: 'pie',
+            radius: [10, 70],
+            center: ['50%', '50%'],
+            roseType: '',
+            itemStyle: { borderRadius: 8 },
+            label: { color: 'rgba(255,255,255)', fontSize: '12', show: false },
+            data,
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts3');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .one_1 {
+      color: #000000;
+      font-size: 3vmin;
+      font-weight: 700;
+      position: relative;
+      border-bottom: 2px solid #2441a9;
+      line-height: 2.96875vw;
+      text-align: left;
+    }
+    .one_1::before {
+      background: #2441a9;
+      border-radius: 50%;
+      content: '';
+      width: 6px;
+      height: 6px;
+      position: absolute;
+      right: -2px;
+      bottom: -4px;
+      z-index: 1;
+      visibility: visible;
+    }
+    .one_1:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .one_2 {
+      background: #2441a9;
+    }
+  }
+}
+.canvas {
+  /deep/canvas {
+    width: 19vw !important;
+    // min-height: 5vw !important;
+    max-height: 9vw !important;
+  }
+}
+</style>

+ 277 - 0
src/views/census/parts/map-1.vue

@@ -0,0 +1,277 @@
+<template>
+  <div id="map-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <div id="container"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog :visible.sync="dialog" title="患者信息" :destroy-on-close="true">
+      <el-row>
+        <el-col :span="8">
+          <el-form>
+            <el-form-item v-for="(i, index) in infoFields1" :key="`if${index}`" :label="i.label">{{ getProp(i.data, i.prop) }}</el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="8">
+          <el-form>
+            <el-form-item v-for="(i, index) in infoFields2" :key="`if${index}`" :label="i.label">{{ getProp(i.data, i.prop) }}</el-form-item>
+          </el-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+/**
+ * 1.初始化地图
+ * 2.初始化围栏
+ * 3.查询患者及监护人坐标
+ * 4.初始化警告,修改患者是否未被处理状态
+ */
+import MapLoader from '@/plugins/amap';
+import drawTools from '@/util/draw';
+import mapFunction from '@/util/map';
+// import border from '@/util/map-border'
+const _ = require('lodash');
+import { EventBus } from '../eventBus';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: position } = createNamespacedHelpers('position');
+const { mapActions: range } = createNamespacedHelpers('range');
+const { mapActions: sendcase } = createNamespacedHelpers('sendcase');
+export default {
+  name: 'map-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      zoom: '10',
+      center: [125.324667, 43.911535], //初始定位到中心
+      mapStyle: 'amap://styles/32e687510f26553e59dfd896c133cafc',
+      map: undefined,
+      geocoder: undefined, // 地理查询
+      allPoints: [], // 所有监控的点
+      warningList: [],
+      fence: [], //围栏信息
+      fenceGraphic: [], // 地图围栏数据
+      info: {}, // 病人信息
+      infoFields1: [
+        { label: '姓名', data: 'info', prop: 'ward.name' },
+        { label: '性别', data: 'info', prop: 'ward.gender' },
+        { label: '身份证号', data: 'info', prop: 'ward.card' },
+        { label: '病例', data: 'info', prop: 'ward.case' },
+        { label: '重点人联系方式', data: 'info', prop: 'ward.important_phone' },
+        { label: '重点人微信号', data: 'info', prop: 'ward.important_wx' },
+        { label: '重点人工作单位', data: 'info', prop: 'ward.important_compan' },
+        { label: '户籍地址', data: 'info', prop: 'ward.hj_address' },
+        { label: '实际住址', data: 'info', prop: 'ward.address' },
+        { label: '预警等级', data: 'info', prop: 'ward.level' },
+        { label: '登记年份', data: 'info', prop: 'ward.year' },
+      ],
+      infoFields2: [
+        { label: '监护人姓名', data: 'info', prop: 'guardian.name' },
+        { label: '监护人身份证号', data: 'info', prop: 'guardian.card' },
+        { label: '监护人联系方式', data: 'info', prop: 'guardian.phone' },
+        { label: '监护人单位', data: 'info', prop: 'guardian.unit' },
+        { label: '监护人地址', data: 'info', prop: 'guardian.address' },
+        { label: '管辖民警', data: 'info', prop: 'ward.police' },
+        { label: '管辖民警联系电话', data: 'info', prop: 'ward.police_phone' },
+      ],
+      dialog: false,
+      // 地图类
+      massMark: undefined,
+
+      timer: undefined,
+    };
+  },
+  created() {},
+  async mounted() {
+    this.init();
+  },
+  methods: {
+    ...position(['mapPos', 'mapWard']),
+    ...range({ getFences: 'query' }),
+    ...sendcase({ getWarning: 'query' }),
+    async init() {
+      await MapLoader();
+      let that = this;
+      let map = new AMap.Map('container', {
+        zoom: this.zoom,
+        resizeEnable: true,
+        viewMode: '2D',
+        center: this.center,
+        mapStyle: this.mapStyle,
+      });
+      // 隐藏长春以外的地方
+      AMap.plugin('AMap.DistrictSearch', function () {
+        new AMap.DistrictSearch({
+          extensions: 'all',
+          level: 'province',
+          subdistrict: 0,
+        }).search('中国', function (status, result) {
+          // 外多边形坐标数组和内多边形坐标数组
+          let outer = [new AMap.LngLat(-360, 90, true), new AMap.LngLat(-360, -90, true), new AMap.LngLat(360, -90, true), new AMap.LngLat(360, 90, true)];
+          let holes = result.districtList[0].boundaries;
+          let pathArray = [outer];
+          pathArray.push.apply(pathArray, holes);
+          console.log(pathArray);
+          let polygon = new AMap.Polygon({
+            pathL: pathArray,
+            strokeColor: 'red', //城市边界颜色
+            strokeWeight: 3,
+            fillColor: '#171d4f', // 遮罩背景色黑色
+            fillOpacity: 1,
+          });
+          polygon.setPath(pathArray);
+          map.add(polygon);
+        });
+      });
+      AMap.plugin('AMap.Geocoder', function () {
+        that.geocoder = new AMap.Geocoder({ city: '全国' });
+      });
+
+      map.on('complete', () => {
+        this.map = map;
+        mapFunction.initEvent(this.map, this.geocoder);
+        this.searchFence();
+        this.initWarning();
+      });
+    },
+
+    async search() {
+      const res = await this.mapPos();
+      if (this.$checkRes(res)) {
+        let data = res.data;
+        data = data.map((i) => {
+          i.position = [i.longitude, i.latitude];
+          return i;
+        });
+        for (const i of data) {
+          const { fence } = i;
+          if (fence) {
+            let obj;
+            const { type } = fence;
+            if (type === 'polygon') obj = drawTools.initPolygon({ ...fence, drawType: 'ward' });
+            else obj = drawTools.initRectangle({ ...fence, drawType: 'ward' });
+            this.map.add(obj);
+          }
+        }
+        this.$set(this, `allPoints`, data);
+      }
+    },
+    // 初始化海量点
+    initMassMark(pointsList = this.allPoints) {
+      const points = [];
+      for (const i of pointsList) {
+        // TODO 处理数据,查看这个人是否报警了
+        const { type, user_id } = i;
+        if (type === 'ward') {
+          const r = this.warningList.find((f) => f.w_id === user_id);
+          if (r) i.level = 'warning';
+        }
+        const point = drawTools.initMassMarkData(i);
+        if (point) points.push(point);
+      }
+      //为海量点显示label提示的点
+      let marker;
+      if (!this.massMark) {
+        this.massMark = drawTools.initMassMark(points);
+        this.massMark.on('mouseover', (e) => {
+          marker = new AMap.Marker({ content: ' ', map: this.map });
+          const d = _.get(e, 'data');
+          marker.setPosition(d.lnglat);
+          marker.setLabel({ content: d.name, offset: [-20, -10] });
+        });
+        this.massMark.on('mouseout', (e) => {
+          this.map.remove(marker);
+        });
+        this.massMark.on('click', (e) => {
+          // 查看这是患者还是监护人,监护人没有事件
+          const d = _.get(e, 'data');
+          if (d.type !== 'ward') return;
+          this.getWardInfo(d.user_id);
+        });
+        this.massMark.setMap(this.map);
+      } else this.massMark.setData(points);
+    },
+    // 获取病人信息
+    async getWardInfo(id) {
+      const res = await this.mapWard(id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+        console.log(res.data);
+        this.dialog = true;
+      }
+    },
+    // 获取围栏
+    async searchFence() {
+      const res = await this.getFences({ status: '0' });
+      if (this.$checkRes(res)) {
+        const arr = [];
+        for (const i of res.data) {
+          const { range, ...info } = i;
+          const obj = { ...info, ...range };
+          arr.push(obj);
+        }
+        this.$set(this, 'fence', arr);
+        this.drawFence();
+      }
+    },
+    // 画围栏
+    drawFence() {
+      const arr = [];
+      for (const f of this.fence) {
+        const { type } = f;
+        let obj;
+        if (type === 'polygon') obj = drawTools.initPolygon({ ...f, drawType: 'fance' });
+        else obj = drawTools.initRectangle({ ...f, drawType: 'fance' });
+        this.map.add(obj);
+        arr.push(obj);
+      }
+      this.$set(this, `fenceGraphic`, arr);
+    },
+    // 获取属性(深层)
+    getProp(data, prop) {
+      return _.get(this[data], prop, '暂无');
+    },
+    // 初始化警情未处理事件
+    async initWarning() {
+      await this.search();
+      await this.searchWarning('init');
+      setInterval(async () => {
+        await this.search();
+        await this.searchWarning();
+      }, 5000);
+    },
+    async searchWarning() {
+      const res = await this.getWarning({ status: '0' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `warningList`, res.data);
+        // 查询渲染海量点
+        this.initMassMark();
+      }
+    },
+  },
+  beforeDestroy() {
+    if (this.timer) clearInterval(this.timer);
+    if (this.map) this.map.destroy();
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    #container {
+      width: 100%;
+      height: 89vh;
+      overflow: hidden;
+    }
+  }
+}
+</style>

+ 185 - 0
src/views/census/parts/right-1.vue

@@ -0,0 +1,185 @@
+<template>
+  <div id="left-2">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__fadeInDown">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="one_1" @click.native="toPath()"> 精神障碍患者等级 </el-col>
+          <el-col :span="24" class="one_2">
+            <div id="echarts2" class="canvas" style="width: 100%; height: 16.8vw"></div>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { EventBus } from '../eventBus';
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'left-2',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [
+        { grade: '等级0', num: 1 },
+        { grade: '等级1', num: 2 },
+        { grade: '等级2', num: 3 },
+        { grade: '等级3', num: 4 },
+        { grade: '等级4', num: 5 },
+        { grade: '等级5', num: 6 },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['centerRight1']),
+    async search() {
+      const res = await this.centerRight1();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.name);
+      let thr = data.map((i) => i.value);
+      let option;
+      option = {
+        title: {},
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        grid: {
+          y2: 30,
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: [0, 0.01],
+          data: two,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+          axisTick: {
+            // 坐标轴 刻度
+            show: true, // 是否显示
+            inside: true, // 是否朝内
+            length: 3, // 长度
+            lineStyle: { color: 'red', width: 1, type: 'solid' },
+          },
+        },
+        yAxis: {
+          axisLabel: {
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series: [
+          {
+            name: '职业等级',
+            label: { show: true, position: 'top' },
+            type: 'bar',
+            itemStyle: {
+              normal: {
+                color: function (params) {
+                  var colorList = ['#C1232B', '#B5C334', '#FCCE10', '#E87C25', '#E87C68', '#409eff'];
+                  return colorList[params.dataIndex];
+                },
+              },
+            },
+            data: thr,
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      if (this.list) {
+        var chartDom = document.getElementById('echarts2');
+        var myChart = echarts.init(chartDom);
+        this.chart = myChart;
+        this.search();
+      }
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .one_1 {
+      color: #000000;
+      font-size: 3vmin;
+      font-weight: 700;
+      position: relative;
+      border-bottom: 2px solid #2441a9;
+      line-height: 2.96875vw;
+      text-align: left;
+    }
+    .one_1::before {
+      background: #2441a9;
+      border-radius: 50%;
+      content: '';
+      width: 6px;
+      height: 6px;
+      position: absolute;
+      right: -2px;
+      bottom: -4px;
+      z-index: 1;
+      visibility: visible;
+    }
+    .one_1:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .one_2 {
+      background: #2441a9;
+    }
+  }
+}
+.canvas {
+  /deep/canvas {
+    width: 19vw !important;
+    // min-height: 5vw !important;
+    max-height: 16.8vw !important;
+  }
+}
+</style>

+ 182 - 0
src/views/census/parts/right-2.vue

@@ -0,0 +1,182 @@
+<template>
+  <div id="right-2">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__fadeInDown">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="one_1" @click.native="toPath()"> 精神障碍患者发案率统计 </el-col>
+          <el-col :span="24" class="one_2">
+            <div id="echarts5" class="canvas" style="width: 100%; height: 16.8vw"></div>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { EventBus } from '../eventBus';
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'right-2',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [],
+      chart: undefined,
+      series: [
+        { name: '3级', type: 'line', color: '#E87C25', stack: 'Total', data: [5, 6, 7, 8, 6, 1, 3] },
+        { name: '4级', type: 'line', color: '#E87C68', stack: 'Total', data: [5, 6, 7, 8, 6, 7, 6] },
+        { name: '5级', type: 'line', color: '#409eff', stack: 'Total', data: [3, 5, 2, 3, 4, 7, 6] },
+      ],
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['right2']),
+    async search() {
+      const res = await this.right2();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 处理数据
+    formatData(value) {
+      // x轴
+      const xZ = _.reverse(_.uniq(value.map((i) => i.name)));
+      const series = JSON.parse(JSON.stringify(this.series));
+      const d3 = value.filter((f) => f.level === '3').map((i) => i.value);
+      const d4 = value.filter((f) => f.level === '4').map((i) => i.value);
+      const d5 = value.filter((f) => f.level === '5').map((i) => i.value);
+      series[0].data = d3;
+      series[1].data = d4;
+      series[2].data = d5;
+      return { xZ, series };
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      const { xZ, series } = this.formatData(data);
+      let option;
+      option = {
+        tooltip: {
+          trigger: 'axis',
+        },
+        legend: {
+          data: ['3级', '4级', '5级'],
+          textStyle: {
+            color: '#ffffff',
+          },
+        },
+        grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
+        toolbox: {},
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: xZ,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series,
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts5');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .one_1 {
+      color: #000000;
+      font-size: 3vmin;
+      font-weight: 700;
+      position: relative;
+      border-bottom: 2px solid #2441a9;
+      line-height: 2.96875vw;
+      text-align: left;
+    }
+    .one_1::before {
+      background: #2441a9;
+      border-radius: 50%;
+      content: '';
+      width: 6px;
+      height: 6px;
+      position: absolute;
+      right: -2px;
+      bottom: -4px;
+      z-index: 1;
+      visibility: visible;
+    }
+    .one_1:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .one_2 {
+      background: #2441a9;
+    }
+  }
+}
+.canvas {
+  /deep/canvas {
+    width: 19vw !important;
+    // min-height: 5vw !important;
+    max-height: 16.8vw !important;
+  }
+}
+</style>

+ 136 - 0
src/views/census_two/index copy.vue

@@ -0,0 +1,136 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one animate__animated animate__bounce">
+          <el-col :span="9" class="img"><el-image :src="oneLeft"></el-image></el-col>
+          <el-col :span="6" class="txt">{{ census.title }}</el-col>
+          <el-col :span="9" class="img"><el-image :src="oneRight"></el-image></el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col :span="24" class="two_1">
+            <el-col :span="6" class="two_1_l animate__animated animate__heartBeat">
+              <el-col :span="24" class="two_1_l_1">
+                <el-col :span="12"><echarts-1></echarts-1></el-col>
+                <el-col :span="12"> <echarts-2></echarts-2></el-col>
+              </el-col>
+              <el-col :span="24" class="two_1_l_2"><echarts-3></echarts-3></el-col>
+            </el-col>
+            <el-col :span="12" class="two_1_c">
+              <maps></maps>
+            </el-col>
+            <el-col :span="6" class="two_1_r animate__animated animate__heartBeat">
+              <el-col :span="24" class="two_1_r_1">
+                <echarts-4></echarts-4>
+              </el-col>
+              <el-col :span="24" class="two_1_r_2">
+                <echarts-5></echarts-5>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two_2 animate__animated animate__heartBeat">
+            <el-col :span="12" class="two_2_l">
+              <echarts-6></echarts-6>
+            </el-col>
+            <el-col :span="12" class="two_2_r">
+              <echarts-7></echarts-7>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two_3">
+            <el-col :span="12" class="two_3_l animate__animated animate__heartBeat">
+              <el-col :span="12" class="two_3_l"><echarts-8></echarts-8> </el-col>
+              <el-col :span="12" class="two_3_l"><echarts-9></echarts-9> </el-col>
+            </el-col>
+            <el-col :span="12" class="two_3_r animate__animated animate__heartBeat">
+              <el-col :span="12"><echarts-10></echarts-10></el-col>
+              <el-col :span="12"><echarts-11></echarts-11></el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import maps from './parts/map.vue';
+import echarts1 from './parts/echarts-1.vue';
+import echarts2 from './parts/echarts-2.vue';
+import echarts3 from './parts/echarts-3.vue';
+import echarts4 from './parts/echarts-4.vue';
+import echarts5 from './parts/echarts-5.vue';
+import echarts6 from './parts/echarts-6.vue';
+import echarts7 from './parts/echarts-7.vue';
+import echarts8 from './parts/echarts-8.vue';
+import echarts9 from './parts/echarts-9.vue';
+import echarts10 from './parts/echarts-10.vue';
+import echarts11 from './parts/echarts-11.vue';
+const { census } = require('@common/src/layout/deploy/dict');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: { echarts1, echarts2, echarts3, echarts4, echarts5, echarts6, echarts7, echarts8, echarts9, echarts10, echarts11, maps },
+  data: function () {
+    return {
+      census: census,
+      oneLeft: require('@a/oneLeft.png'),
+      oneRight: require('@a/oneRight.png'),
+    };
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background: url('~@/assets/census_two.jpg');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  height: 100%;
+  overflow: auto;
+  .one {
+    padding: 10px 0;
+    .txt {
+      text-align: center;
+      font-family: fzzuhjt;
+      font-size: 3.5vmin;
+      line-height: 4.6875vw;
+      overflow: hidden;
+      color: #ffffff;
+      text-shadow: 0 3px 3px #1872ec;
+    }
+  }
+  .two {
+    color: #ffffff;
+    .two_1 {
+      height: 425px;
+      overflow: hidden;
+      margin: 0 0 10px 0;
+    }
+    .two_2 {
+      height: 190px;
+      overflow: hidden;
+      margin: 0 0 10px 0;
+    }
+    .two_3 {
+      height: 175px;
+      overflow: hidden;
+    }
+  }
+}
+</style>

+ 154 - 0
src/views/census_two/index.vue

@@ -0,0 +1,154 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one animate__animated animate__bounce">
+          <el-col :span="9" class="img"><el-image :src="oneLeft"></el-image></el-col>
+          <el-col :span="6" class="txt">{{ census.title }}</el-col>
+          <el-col :span="9" class="img"><el-image :src="oneRight"></el-image></el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col :span="24" class="two_1">
+            <el-col :span="6" class="two_1_l animate__animated animate__heartBeat">
+              <el-col :span="24" class="two_1_l_1">
+                <el-col :span="12"><echarts-1></echarts-1></el-col>
+                <el-col :span="12"> <echarts-2></echarts-2></el-col>
+              </el-col>
+              <el-col :span="24" class="two_1_l_2"><echarts-3></echarts-3></el-col>
+            </el-col>
+            <el-col :span="12" class="two_1_c">
+              <maps v-if="initFinish" :windowInfo="windowInfo"></maps>
+            </el-col>
+            <el-col :span="6" class="two_1_r animate__animated animate__heartBeat">
+              <el-col :span="24" class="two_1_r_1">
+                <echarts-4></echarts-4>
+              </el-col>
+              <el-col :span="24" class="two_1_r_2">
+                <echarts-5></echarts-5>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two_2">
+            <el-col :span="24" class="two_2 animate__animated animate__heartBeat">
+              <el-col :span="12" class="two_2_l">
+                <echarts-6></echarts-6>
+              </el-col>
+              <el-col :span="12" class="two_2_r">
+                <echarts-7></echarts-7>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two_3">
+            <el-col :span="12" class="two_3_l animate__animated animate__heartBeat">
+              <el-col :span="12" class="two_3_l"><echarts-8></echarts-8> </el-col>
+              <el-col :span="12" class="two_3_l"><echarts-9></echarts-9> </el-col>
+            </el-col>
+            <el-col :span="12" class="two_3_r animate__animated animate__heartBeat">
+              <el-col :span="12"><echarts-10></echarts-10></el-col>
+              <el-col :span="12"><echarts-11></echarts-11></el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import echarts1 from './parts/echarts-1.vue';
+import echarts2 from './parts/echarts-2.vue';
+import echarts3 from './parts/echarts-3.vue';
+import echarts4 from './parts/echarts-4.vue';
+import echarts5 from './parts/echarts-5.vue';
+import echarts6 from './parts/echarts-6.vue';
+import echarts7 from './parts/echarts-7.vue';
+import echarts8 from './parts/echarts-8.vue';
+import echarts9 from './parts/echarts-9.vue';
+import echarts10 from './parts/echarts-10.vue';
+import echarts11 from './parts/echarts-11.vue';
+const { census } = require('@common/src/layout/deploy/dict');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    echarts1,
+    echarts2,
+    echarts3,
+    echarts4,
+    echarts5,
+    echarts6,
+    echarts7,
+    echarts8,
+    echarts9,
+    echarts10,
+    echarts11,
+    maps: () => import('./parts/map.vue'),
+  },
+  data: function () {
+    return {
+      initFinish: false,
+      census: census,
+      oneLeft: require('@a/oneLeft.png'),
+      oneRight: require('@a/oneRight.png'),
+      windowInfo: {},
+    };
+  },
+  created() {},
+  methods: {
+    searchWin() {},
+  },
+  mounted() {
+    this.initFinish = true;
+    this.$set(this, `windowInfo`, { wid: window.screen.width, hei: window.screen.height });
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.w_1200 {
+  width: 1200px;
+  margin: 0 auto;
+}
+.main {
+  background: url('~@/assets/census_two.jpg');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  height: 100vh;
+  overflow: auto;
+  .one {
+    padding: 10px 0;
+    .txt {
+      text-align: center;
+      font-family: fzzuhjt;
+      font-size: 3.5vmin;
+      line-height: 4.6875vw;
+      overflow: hidden;
+      color: #ffffff;
+      text-shadow: 0 3px 3px #1872ec;
+    }
+  }
+  .two {
+    color: #ffffff;
+    .two_1 {
+      margin: 0 0 10px 0;
+    }
+    .two_2 {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 128 - 0
src/views/census_two/parts/echarts-1.vue

@@ -0,0 +1,128 @@
+<template>
+  <div id="echarts-1">
+    <el-row>
+      <el-col :span="24" class="main" @click.native="toPth()">
+        <div id="echarts1" class="canvas" style="width: 100%; height: 10vw"></div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      gaugeData: [
+        {
+          value: 20,
+          name: '精神障碍患者',
+          title: { offsetCenter: ['0%', '20'] },
+          detail: { valueAnimation: true, offsetCenter: ['0%', '-15%'] },
+        },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {},
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['left1']),
+    async search() {
+      const res = await this.left1();
+      if (this.$checkRes(res)) {
+        // let value = res.data.d1;
+        let value = 2356;
+        if (value) value = this.formatData(value);
+        this.changeData(value);
+      }
+    },
+    // 格式化数据
+    formatData(data) {
+      const obj = [
+        {
+          value: data,
+          name: '精神障碍患者',
+          title: { offsetCenter: ['0%', '20%'] },
+          detail: { valueAnimation: true, offsetCenter: ['0%', '-15%'] },
+        },
+      ];
+      return obj;
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数, 格式化图表设置
+    getOption(data) {
+      let option;
+      option = {
+        series: [
+          {
+            type: 'gauge',
+            startAngle: 90,
+            endAngle: -270,
+            pointer: { show: false },
+            progress: { show: true },
+            splitLine: { show: false },
+            axisTick: { show: false },
+            axisLabel: { show: false },
+            data,
+            title: { fontSize: 14, color: '#ffffff' },
+            detail: {
+              fontSize: 14,
+              color: '#ffffff',
+              formatter: '{value}',
+            },
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts1');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    // 跳转指定页面
+    toPth() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 122 - 0
src/views/census_two/parts/echarts-10.vue

@@ -0,0 +1,122 @@
+<template>
+  <div id="echarts-10">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="12" class="txt" @click.native="toPath()">研判中心</el-col>
+          <el-col :span="12" class="search">
+            <el-input size="mini" placeholder="请输入内容" v-model="value">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="search()"></i>
+            </el-input>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" border style="width: 100%">
+            <el-table-column prop="w_name" label="姓名" align="center" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="send_time" label="发生时间" align="center" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="content" label="内容" align="center" show-overflow-tooltip> </el-table-column>
+          </el-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: judge } = createNamespacedHelpers('judge');
+export default {
+  name: 'echarts-10',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      // 研判中心
+      list: [],
+      // 查询
+      value: '',
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...judge(['query']),
+    async search({ skip = 0, limit = 3, ...info } = {}) {
+      if (this.value) info.w_name = this.value;
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+      }
+    },
+
+    toPath() {
+      this.$router.push('/judge');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    height: 38px;
+    line-height: 38px;
+    background-color: transparent;
+    border: 1px solid #f1f1f1;
+    .txt {
+      text-align: center;
+      padding: 0 10px;
+    }
+    .txt:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .search {
+      padding: 0 5px;
+      /deep/.el-input__inner {
+        background-color: transparent;
+        color: #fff;
+      }
+      /deep/.el-input__icon {
+        font-weight: bold;
+      }
+    }
+  }
+  .two {
+    /deep/.el-table {
+      background-color: transparent !important;
+    }
+    /deep/.el-table th {
+      padding: 5px 0;
+      color: #fff;
+      background-color: #04a2bb7f !important;
+    }
+    /deep/.el-table td {
+      padding: 5px 0;
+      color: #fff;
+      background-color: transparent !important;
+    }
+    /deep/.el-table tr {
+      background-color: transparent !important;
+    }
+    /deep/.el-table tr:hover {
+      cursor: pointer;
+      background-color: #04a2bb7f !important;
+    }
+  }
+}
+</style>

+ 124 - 0
src/views/census_two/parts/echarts-11.vue

@@ -0,0 +1,124 @@
+<template>
+  <div id="echarts-11">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="12" class="txt" @click.native="toPath()">警情中心</el-col>
+          <el-col :span="12" class="search">
+            <el-input size="mini" placeholder="请输入内容" v-model="value">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="openSearch()"></i>
+            </el-input>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" border style="width: 100%">
+            <el-table-column prop="w_name" label="姓名" align="center" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="send_time" label="发案时间" align="center" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="reason" label="内容" align="center" show-overflow-tooltip> </el-table-column>
+          </el-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: sendcase } = createNamespacedHelpers('sendcase');
+export default {
+  name: 'echarts-11',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      // 警情中心
+      list: [],
+      value: '',
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...sendcase(['query']),
+    async search({ skip = 0, limit = 3, ...info } = {}) {
+      if (this.value) info.w_name = this.value;
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+      }
+    },
+    openSearch() {
+      window.open(`/sps/watch/warning?name=${this.value}`);
+    },
+
+    toPath() {
+      this.$router.push('/warning');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    height: 38px;
+    line-height: 38px;
+    background-color: transparent;
+    border: 1px solid #f1f1f1;
+    .txt {
+      text-align: center;
+      padding: 0 10px;
+    }
+    .txt:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .search {
+      padding: 0 5px;
+      /deep/.el-input__inner {
+        background-color: transparent;
+        color: #fff;
+      }
+      /deep/.el-input__icon {
+        font-weight: bold;
+      }
+    }
+  }
+  .two {
+    /deep/.el-table {
+      background-color: transparent !important;
+    }
+    /deep/.el-table th {
+      padding: 5px 0;
+      color: #fff;
+      background-color: #04a2bb7f !important;
+    }
+    /deep/.el-table td {
+      padding: 5px 0;
+      color: #fff;
+      background-color: transparent !important;
+    }
+    /deep/.el-table tr {
+      background-color: transparent !important;
+    }
+    /deep/.el-table tr:hover {
+      cursor: pointer;
+      background-color: #04a2bb7f !important;
+    }
+  }
+}
+</style>

+ 121 - 0
src/views/census_two/parts/echarts-2.vue

@@ -0,0 +1,121 @@
+<template>
+  <div id="echarts-2">
+    <el-row>
+      <el-col :span="24" class="main" @click.native="toPth()">
+        <div id="echarts2" class="canvas" style="width: 100%; height: 10vw"></div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-2',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      chart: undefined,
+    };
+  },
+  created() {},
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['left1']),
+    async search() {
+      const res = await this.left1();
+      if (this.$checkRes(res)) {
+        let value = res.data.d2;
+        if (value) value = this.formatData(value);
+        value[0].value = 14;
+        // this.changeData(value);
+        this.changeData(value);
+      }
+    },
+    // 格式化数据
+    formatData(data) {
+      const obj = [
+        {
+          value: data,
+          name: '医院总数',
+          title: { offsetCenter: ['0%', '20%'] },
+          detail: { valueAnimation: true, offsetCenter: ['0%', '-15%'] },
+        },
+      ];
+      return obj;
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数, 格式化图表设置
+    getOption(data) {
+      let option;
+      option = {
+        series: [
+          {
+            type: 'gauge',
+            startAngle: 90,
+            endAngle: -270,
+            pointer: { show: false },
+            progress: { show: true },
+            splitLine: { show: false },
+            axisTick: { show: false },
+            axisLabel: { show: false },
+            data,
+            title: { fontSize: 14, color: '#ffffff' },
+            detail: {
+              fontSize: 14,
+              color: '#ffffff',
+              formatter: '{value}',
+            },
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts2');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    // 跳转指定页面
+    toPth() {
+      this.$router.push('/hospital');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 160 - 0
src/views/census_two/parts/echarts-3.vue

@@ -0,0 +1,160 @@
+<template>
+  <div id="echarts-3">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">在院人数</el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts3" class="canvas" style="height: 11vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-3',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      chart: undefined,
+      timer: undefined,
+      dataIndex: 0,
+      list: [
+        { name: '长春市第六医院', value: 0 },
+        { name: '长春博远康复医院有限公司', value: 0 },
+        { name: '长春民安医院', value: 0 },
+        { name: '长春康林心理医院有限公司', value: 0 },
+        { name: '经开康爱精神心理医院', value: 0 },
+        { name: '九台康宁精神病医院', value: 0 },
+        { name: '宝华康复医院', value: 0 },
+        { name: '榆树康鹤心理医院', value: 0 },
+        { name: '榆树蓝兴精神康复医院', value: 0 },
+        { name: '吉林省公安厅安康医院', value: 0 },
+        { name: '公主岭静馨精神病医院', value: 0 },
+        { name: '长春安宁精神康复医院', value: 0 },
+        { name: '长春市康宁医院', value: 0 },
+        { name: '农安好大夫心理医院', value: 0 },
+      ],
+    };
+  },
+  created() {},
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['left1']),
+    async search() {
+      const res = await this.left1();
+      if (this.$checkRes(res)) {
+        let value = this.list;
+        // let value = res.data.d3;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+      if (this.timer) {
+        clearInterval(this.timer);
+        this.timer = undefined;
+      }
+      this.loopChart();
+      this.timer = setInterval(() => this.loopChart(), 3000);
+    },
+    // 组织chart的数据函数
+    getOption(value) {
+      let legendData = value.map((i) => i.name);
+      let seriesData = value;
+      let option;
+      option = {
+        title: {},
+        tooltip: { trigger: 'item' },
+        legend: {
+          type: 'scroll',
+          orient: 'vertical',
+          right: 10,
+          top: 20,
+          bottom: 20,
+          data: legendData,
+          textStyle: { color: '#ffffff', width: '92', overflow: 'truncate', ellipsis: '...' },
+          pageTextStyle: { color: '#ffffff' },
+        },
+        series: [
+          {
+            name: '在院人数',
+            type: 'pie',
+            radius: ['50%', '80%'],
+            center: ['40%', '50%'],
+            avoidLabelOverlap: false,
+            label: { show: false, position: 'center' },
+            emphasis: { label: { show: false, fontSize: '14', color: '#ffffff' } },
+            labelLine: { show: false },
+            data: seriesData,
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts3');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    loopChart() {
+      let num = this.dataIndex;
+      this.chart.dispatchAction({
+        type: 'downplay',
+      });
+      if (num > this.list.length) {
+        num = 0;
+      }
+      this.chart.dispatchAction({
+        type: 'highlight',
+        dataIndex: num,
+      });
+      this.dataIndex = num + 1;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    color: #ffffff;
+    font-weight: bold;
+  }
+}
+</style>

+ 134 - 0
src/views/census_two/parts/echarts-4.vue

@@ -0,0 +1,134 @@
+<template>
+  <div id="echarts-4">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <span @click="toPath()">精神障碍患者统计</span>
+          <el-button type="primary" size="mini" @click="back()">系统中心</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts4" class="canvas" style="width: 100%; height: 9.8vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-4',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      chart: undefined,
+    };
+  },
+  created() {},
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['right1']),
+    async search() {
+      const res = await this.right1();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        const data = [
+          { name: '2019', value: 865 },
+          { name: '2020', value: 1035 },
+          { name: '2021', value: 1253 },
+          { name: '2022', value: 2356 },
+        ];
+        this.changeData(data);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.name);
+      let thr = data.map((i) => i.value);
+      let option;
+      option = {
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        grid: { top: '10%', height: 'auto' },
+        xAxis: {
+          type: 'category',
+          data: two,
+          axisLabel: { interval: 0, textStyle: { color: '#ffffff' } },
+        },
+        yAxis: {
+          axisLabel: { textStyle: { color: '#ffffff' } },
+        },
+        series: [{ data: thr, type: 'line' }],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts4');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    // 返回
+    back() {
+      history.go(-1);
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    span {
+      color: #ffffff;
+      font-weight: bold;
+    }
+    span:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+    .el-button {
+      float: right;
+      margin: 0 40px 0 0;
+      background-color: transparent;
+    }
+  }
+}
+</style>

+ 208 - 0
src/views/census_two/parts/echarts-5.vue

@@ -0,0 +1,208 @@
+<template>
+  <div id="echarts-5">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one"> <span @click="toPath()">精神障碍患者发案率统计</span> </el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts5" class="canvas" style="width: 100%; height: 9.8vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-5',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [],
+      chart: undefined,
+      series: [
+        {
+          name: '3级',
+          type: 'line',
+          color: '#E87C25',
+          stack: 'Total',
+          areaStyle: {},
+          emphasis: { focus: 'series' },
+        },
+        {
+          name: '4级',
+          type: 'line',
+          color: '#E87C68',
+          stack: 'Total',
+          areaStyle: {},
+          emphasis: { focus: 'series' },
+        },
+        {
+          name: '5级',
+          type: 'line',
+          color: '#409eff',
+          stack: 'Total',
+          // data: [0, 5, 2, 3, 4, 7, 6],
+          areaStyle: {},
+          emphasis: { focus: 'series' },
+        },
+      ],
+      tempList: [
+        { name: 2019, value: 10, level: '3' },
+        { name: 2019, value: 26, level: '4' },
+        { name: 2019, value: 198, level: '5' },
+
+        { name: 2020, value: 4, level: '3' },
+        { name: 2020, value: 3, level: '4' },
+        { name: 2020, value: 31, level: '5' },
+
+        { name: 2021, value: 9, level: '3' },
+        { name: 2021, value: 11, level: '4' },
+        { name: 2021, value: 267, level: '5' },
+
+        { name: 2022, value: 0, level: '3' },
+        { name: 2022, value: 0, level: '4' },
+        { name: 2022, value: 11, level: '5' },
+      ],
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['right2']),
+    async search() {
+      const res = await this.right2();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        // const list = this.computedPercent(this.tempList);
+        this.changeData(this.tempList);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 处理数据
+    formatData(value) {
+      // x轴
+      const xZ = _.uniq(_.orderBy(value, ['name'], ['asc']).map((i) => i.name));
+      const series = JSON.parse(JSON.stringify(this.series));
+      const d3 = value.filter((f) => f.level === '3').map((i) => i.value);
+      const d4 = value.filter((f) => f.level === '4').map((i) => i.value);
+      const d5 = value.filter((f) => f.level === '5').map((i) => i.value);
+      series[0].data = d3;
+      series[1].data = d4;
+      series[2].data = d5;
+      return { xZ, series };
+    },
+
+    // 组织chart的数据函数
+    getOption(data) {
+      const { xZ, series } = this.formatData(data);
+      let option;
+      option = {
+        tooltip: {
+          trigger: 'axis',
+        },
+        legend: {
+          data: ['3级', '4级', '5级'],
+          textStyle: { color: '#ffffff' },
+        },
+        grid: { top: '10%', height: 'auto' },
+        toolbox: {},
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: xZ,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series,
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts5');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+
+    // 计算发案率
+    computedPercent(list) {
+      const midObject = _.groupBy(list, 'name');
+      console.log(midObject);
+      const keys = Object.keys(midObject);
+      let arr = [];
+      for (const key of keys) {
+        const yl = midObject[key];
+        const max = yl.reduce((p, n) => p + n.value || 0, 0);
+        for (const i of yl) {
+          const { value } = i;
+          const percent = _.round(_.multiply(_.divide(value, max), 100), 2);
+          i.value = percent;
+          arr.push(i);
+        }
+      }
+      arr = _.orderBy(arr, ['name', 'level'], ['desc', 'asc']);
+      return arr;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    span:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+  }
+}
+</style>

+ 135 - 0
src/views/census_two/parts/echarts-6.vue

@@ -0,0 +1,135 @@
+<template>
+  <div id="echarts-6">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one"><span @click="toPath()">精神障碍患者区域分布</span></el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts6" class="canvas" style="width: 100%; height: 8.6vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-6',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [
+        { name: '区域1', value: 1 },
+        { name: '区域2', value: 2 },
+        { name: '区域3', value: 3 },
+        { name: '区域4', value: 4 },
+        { name: '区域5', value: 5 },
+        { name: '区域6', value: 6 },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['centerLeft1']),
+    async search() {
+      const res = await this.centerLeft1();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        this.changeData(value);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.name);
+      let thr = data.map((i) => i.value);
+      let option;
+      option = {
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        grid: { top: '10%', left: '5%', height: '80px' },
+        xAxis: {
+          type: 'category',
+          data: two,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff', fontSize: '12px' },
+            rotate: -30,
+          },
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            show: true,
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series: [{ data: thr, type: 'line', smooth: true }],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts6');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    span {
+      color: #ffffff;
+      font-weight: bold;
+    }
+    span:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+  }
+}
+</style>

+ 133 - 0
src/views/census_two/parts/echarts-7.vue

@@ -0,0 +1,133 @@
+<template>
+  <div id="echarts-7">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one"><span @click="toPath()">精神障碍患者等级</span></el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts7" class="canvas" style="width: 100%; height: 8.6vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('statistics');
+export default {
+  name: 'echarts-7',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      chart: undefined,
+      list: [
+        { name: '等级0', value: 0 },
+        { name: '等级1', value: 0 },
+        { name: '等级2', value: 0 },
+        { name: '等级3', value: 1985 },
+        { name: '等级4', value: 245 },
+        { name: '等级5', value: 125 },
+      ],
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...mapActions(['centerRight1']),
+    async search() {
+      const res = await this.centerRight1();
+      if (this.$checkRes(res)) {
+        let value = res.data;
+        this.changeData(this.list);
+      }
+    },
+    // 更换chart数据
+    changeData(value) {
+      if (!this.chart) return;
+      let option = this.getOption(value);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.name);
+      let thr = data.map((i) => i.value);
+      let option;
+      option = {
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        grid: { top: '10%', left: '5%', height: '88px' },
+        xAxis: {
+          type: 'category',
+          data: two,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series: [{ data: thr, type: 'line', smooth: true }],
+      };
+      return option;
+    },
+    init() {
+      var chartDom = document.getElementById('echarts7');
+      var myChart = echarts.init(chartDom);
+      myChart.on('click', (params) => {
+        console.log('1');
+      });
+      this.chart = myChart;
+      this.search();
+    },
+    toPath() {
+      this.$router.push('/guardian/patient');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    span {
+      color: #ffffff;
+      font-weight: bold;
+    }
+    span:hover {
+      cursor: pointer;
+      color: #66b1ff;
+    }
+  }
+}
+</style>

+ 141 - 0
src/views/census_two/parts/echarts-8.vue

@@ -0,0 +1,141 @@
+<template>
+  <div id="echarts-8">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one"> 设备在线数量统计 </el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts8" class="canvas" style="width: 100%; height: 9vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'echarts-8',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [
+        { time: '手表1', num: 1 },
+        { time: '手表2', num: 1 },
+        { time: '手表3', num: 1 },
+        { time: '手环', num: 1 },
+        { time: 'app', num: 1 },
+        // { time: '时间6', num: 6 },
+      ],
+      chart: undefined,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    search() {
+      // if (!this.chart) this.init();
+      // else this.changeData();
+    },
+    // 更换chart数据
+    changeData() {
+      if (!this.chart) return;
+      let option = this.getOption(this.list);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.time);
+      let thr = data.map((i) => i.num);
+      let option;
+      option = {
+        title: {},
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        grid: { top: '15%', height: '85px' },
+        xAxis: {
+          type: 'category',
+          boundaryGap: [0, 0.01],
+          data: two,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+          axisTick: {
+            // 坐标轴 刻度
+            show: true, // 是否显示
+            inside: true, // 是否朝内
+            length: 3, // 长度
+            lineStyle: { color: 'red', width: 1, type: 'solid' },
+          },
+        },
+        yAxis: {
+          axisLabel: {
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series: [
+          {
+            name: '设备在线数量统计',
+            label: { show: true, position: 'top' },
+            type: 'bar',
+            itemStyle: {
+              normal: {
+                color: function (params) {
+                  var colorList = ['#C1232B', '#B5C334', '#FCCE10', '#E87C25', '#E87C68', '#409eff'];
+                  return colorList[params.dataIndex];
+                },
+              },
+            },
+            data: thr,
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      if (this.list) {
+        var chartDom = document.getElementById('echarts8');
+        var myChart = echarts.init(chartDom);
+        let option = this.getOption(this.list);
+        option && myChart.setOption(option);
+        this.chart = myChart;
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    color: #ffffff;
+    font-weight: bold;
+  }
+}
+</style>

+ 230 - 0
src/views/census_two/parts/echarts-9.vue

@@ -0,0 +1,230 @@
+<template>
+  <div id="echarts-9">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one"> 心跳率 </el-col>
+        <el-col :span="24" class="two">
+          <div id="echarts9" class="canvas" style="width: 100%; height: 9vw"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+// 引入基本模板
+let echarts = require('echarts/lib/echarts');
+// 引入柱状图组件
+require('echarts/lib/chart/bar');
+// 引入提示框和title组件
+require('echarts/lib/component/tooltip');
+require('echarts/lib/component/title');
+echarts = require('echarts');
+const moment = require('moment');
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'echarts-9',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      // list: [{ time: '心率', num: 1 }],
+      list: [],
+      chart: undefined,
+      times: 1000, //1s
+      x: [],
+      refreshTimes: 50,
+    };
+  },
+  created() {
+    // this.search();
+  },
+  mounted() {
+    // this.init();
+    this.initHeartLine();
+  },
+  methods: {
+    search() {
+      // if (!this.chart) this.init();
+      // else this.changeData();
+    },
+    // 更换chart数据
+    changeData() {
+      if (!this.chart) return;
+      let option = this.getOption(this.list);
+      this.chart.setOption(option);
+    },
+    // 组织chart的数据函数
+    getOption(data) {
+      let two = data.map((i) => i.time);
+      let thr = data.map((i) => i.num);
+      let option;
+      option = {
+        title: {},
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        grid: { top: '15%', height: '85px' },
+        xAxis: {
+          type: 'category',
+          boundaryGap: [0, 0.01],
+          data: two,
+          axisLabel: {
+            interval: 0, //横轴信息全部显示
+            textStyle: { color: '#ffffff' },
+          },
+          axisTick: {
+            // 坐标轴 刻度
+            show: true, // 是否显示
+            inside: true, // 是否朝内
+            length: 3, // 长度
+            lineStyle: { color: 'red', width: 1, type: 'solid' },
+          },
+        },
+        yAxis: {
+          axisLabel: {
+            textStyle: { color: '#ffffff' },
+          },
+        },
+        series: [
+          {
+            name: '设备掉线,故障统计',
+            label: { show: true, position: 'top' },
+            type: 'bar',
+            itemStyle: {
+              normal: {
+                color: function (params) {
+                  var colorList = ['#409eff'];
+                  return colorList[params.dataIndex];
+                },
+              },
+            },
+            data: thr,
+          },
+        ],
+      };
+      return option;
+    },
+    init() {
+      if (this.list) {
+        var chartDom = document.getElementById('echarts9');
+        var myChart = echarts.init(chartDom);
+        let option = this.getOption(this.list);
+        option && myChart.setOption(option);
+        this.chart = myChart;
+      }
+    },
+    // 心电图逻辑
+    initHeartLine() {
+      var chartDom = document.getElementById('echarts9');
+      var myChart = echarts.init(chartDom);
+      this.getXTime(this.refreshTimes);
+      this.getYData(this.refreshTimes);
+      let option = this.heartLineOptions();
+      option && myChart.setOption(option);
+      this.chart = myChart;
+      this.setHeartInter();
+    },
+
+    heartLineOptions() {
+      let option = {
+        tooltip: { trigger: 'item', backgroundColor: 'rgba(0,0,0,0.7)', textStyle: { color: '#ffffff', fontFamily: 'sans-serif', fontSize: 12 } },
+        xAxis: {
+          type: 'category',
+          name: '时间',
+          splitLine: {
+            show: false,
+          },
+          data: this.x,
+        },
+        yAxis: {
+          type: 'value',
+          name: '速率',
+          boundaryGap: [0, '100%'],
+          splitLine: {
+            show: false,
+          },
+        },
+        series: [
+          {
+            type: 'line',
+            showSymbol: false,
+            data: this.list,
+            smooth: true,
+          },
+        ],
+      };
+      return option;
+    },
+    setHeartInter() {
+      setInterval(() => {
+        this.getXTime();
+        this.getYData();
+        this.chart.setOption({
+          xAxis: {
+            data: this.x,
+          },
+          series: [
+            {
+              data: this.list,
+            },
+          ],
+        });
+      }, this.times);
+    },
+
+    getXTime(number) {
+      if (_.isNumber(number)) {
+        const arr = [];
+        for (let i = 1; i <= number; i++) {
+          arr.unshift(
+            moment()
+              .subtract(i * (this.times / 1000), 'seconds')
+              .format('HH:mm:ss')
+          );
+        }
+        this.$set(this, 'x', arr);
+      } else {
+        const now = moment().format('HH:mm:ss');
+        this.x.shift();
+        this.x.push(now);
+      }
+    },
+    getYData(number) {
+      if (_.isNumber(number)) {
+        const arr = [];
+        for (let i = 1; i <= number; i++) {
+          arr.unshift(_.random(80, 150));
+        }
+        this.$set(this, 'list', arr);
+      } else {
+        const now = _.random(80, 150);
+        this.list.shift();
+        this.list.push(now);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    color: #ffffff;
+    font-weight: bold;
+  }
+}
+</style>

+ 351 - 0
src/views/census_two/parts/map.vue

@@ -0,0 +1,351 @@
+<template>
+  <div id="maps">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-form :model="searchForm" ref="searchForm">
+            <el-col :span="6">
+              <el-form-item>
+                <el-input size="mini" placeholder="姓名" v-model="searchForm.name">
+                  <i slot="suffix" class="el-input__icon el-icon-user-solid"></i>
+                </el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item>
+                <el-input size="mini" placeholder="身份证号" v-model="searchForm.card">
+                  <i slot="suffix" class="el-input__icon el-icon-orange"></i>
+                </el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12" class="btn">
+              <el-button type="primary" size="mini" @click="toSearch()">查询</el-button>
+            </el-col>
+          </el-form>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="container" :style="{ height: `${windowInfo && windowInfo.hei == 1080 ? '385px' : '290px'}` }"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog :visible.sync="dialog" title="患者信息" :destroy-on-close="true">
+      <el-row>
+        <el-col :span="8">
+          <el-form>
+            <el-form-item v-for="(i, index) in infoFields1" :key="`if${index}`" :label="i.label">{{ getProp(i.data, i.prop) }}</el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="8">
+          <el-form>
+            <el-form-item v-for="(i, index) in infoFields2" :key="`if${index}`" :label="i.label">{{ getProp(i.data, i.prop) }}</el-form-item>
+          </el-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+/**
+ * 1.初始化地图
+ * 2.初始化围栏
+ * 3.查询患者及监护人坐标
+ * 4.初始化警告,修改患者是否未被处理状态
+ */
+const _ = require('lodash');
+import MapLoader from '@/plugins/amap';
+import drawTools from '@/util/draw';
+import mapFunction from '@/util/map';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: ward } = createNamespacedHelpers('ward');
+const { mapActions: position } = createNamespacedHelpers('position');
+const { mapActions: range } = createNamespacedHelpers('range');
+const { mapActions: sendcase } = createNamespacedHelpers('sendcase');
+export default {
+  name: 'maps',
+  props: {
+    windowInfo: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      zoom: '3.5',
+      map: undefined,
+      geocoder: undefined, // 地理查询
+      center: [105.34, 36.312316],
+      ccCenter: [125.324667, 43.911535], //初始定位到中心
+      mapStyle: 'amap://styles/387f96e0666b7d5aec6e11cffa97c91a',
+      allPoints: [], // 所有监控的点
+      warningList: [],
+      fence: [], //围栏信息
+      fenceGraphic: [], // 地图围栏数据
+      info: {}, // 病人信息
+      infoFields1: [
+        { label: '姓名', data: 'info', prop: 'ward.name' },
+        { label: '性别', data: 'info', prop: 'ward.gender' },
+        { label: '身份证号', data: 'info', prop: 'ward.card' },
+        { label: '病例', data: 'info', prop: 'ward.case' },
+        { label: '重点人联系方式', data: 'info', prop: 'ward.important_phone' },
+        { label: '重点人微信号', data: 'info', prop: 'ward.important_wx' },
+        { label: '重点人工作单位', data: 'info', prop: 'ward.important_compan' },
+        { label: '户籍地址', data: 'info', prop: 'ward.hj_address' },
+        { label: '实际住址', data: 'info', prop: 'ward.address' },
+        { label: '预警等级', data: 'info', prop: 'ward.level' },
+        { label: '登记年份', data: 'info', prop: 'ward.year' },
+      ],
+      infoFields2: [
+        { label: '监护人姓名', data: 'info', prop: 'guardian.name' },
+        { label: '监护人身份证号', data: 'info', prop: 'guardian.card' },
+        { label: '监护人联系方式', data: 'info', prop: 'guardian.phone' },
+        { label: '监护人单位', data: 'info', prop: 'guardian.unit' },
+        { label: '监护人地址', data: 'info', prop: 'guardian.address' },
+        { label: '管辖民警', data: 'info', prop: 'ward.police' },
+        { label: '管辖民警联系电话', data: 'info', prop: 'ward.police_phone' },
+      ],
+      dialog: false,
+      // 地图类
+      massMark: undefined,
+      timer: undefined,
+
+      wardFence: undefined,
+
+      // 新增查询方式
+      searchForm: {},
+    };
+  },
+  created() {},
+  mounted() {
+    this.init();
+  },
+  methods: {
+    ...position(['mapPos', 'mapWard']),
+    ...range({ getFences: 'query' }),
+    ...sendcase({ getWarning: 'query' }),
+    ...ward({ findWard: 'query' }),
+    async init() {
+      await MapLoader();
+      let that = this;
+      let map = new AMap.Map('container', {
+        zoom: this.zoom,
+        resizeEnable: true,
+        viewMode: '2D',
+        center: this.center,
+        mapStyle: this.mapStyle,
+      });
+      if (process.env.NODE_ENV !== 'development') {
+        // 隐藏中国以外的地方
+        AMap.plugin('AMap.DistrictSearch', function () {
+          new AMap.DistrictSearch({
+            extensions: 'all',
+            level: 'province',
+            subdistrict: 0,
+          }).search('中国', function (status, result) {
+            // 外多边形坐标数组和内多边形坐标数组
+            let outer = [new AMap.LngLat(-360, 90, true), new AMap.LngLat(-360, -90, true), new AMap.LngLat(360, -90, true), new AMap.LngLat(360, 90, true)];
+            let holes = result.districtList[0].boundaries;
+            let pathArray = [outer];
+            pathArray.push.apply(pathArray, holes);
+            let polygon = new AMap.Polygon({
+              pathL: pathArray,
+              strokeColor: 'red', //城市边界颜色
+              strokeWeight: 3,
+              fillColor: '#171d4f', // 遮罩背景色黑色
+              fillOpacity: 1,
+            });
+            polygon.setPath(pathArray);
+            map.add(polygon);
+          });
+        });
+      }
+
+      AMap.plugin('AMap.Geocoder', function () {
+        that.geocoder = new AMap.Geocoder({ city: '全国' });
+      });
+
+      map.on('complete', () => {
+        this.map = map;
+        mapFunction.initEvent(this.map, this.geocoder);
+        this.searchFence();
+        this.initWarning();
+      });
+    },
+
+    async search() {
+      const res = await this.mapPos();
+      if (this.$checkRes(res)) {
+        let data = res.data;
+        data = data.map((i) => {
+          i.position = [i.longitude, i.latitude];
+          return i;
+        });
+        for (const i of data) {
+          const { fence } = i;
+          if (fence) {
+            let obj;
+            const { type } = fence;
+            if (type === 'polygon') obj = drawTools.initPolygon({ ...fence, drawType: 'ward' });
+            else obj = drawTools.initRectangle({ ...fence, drawType: 'ward' });
+            this.map.add(obj);
+          }
+        }
+        this.$set(this, `allPoints`, data);
+      }
+    },
+    // 初始化海量点
+    initMassMark(pointsList = this.allPoints) {
+      const points = [];
+      for (const i of pointsList) {
+        // TODO 处理数据,查看这个人是否报警了
+        const { type, user_id, case_number } = i;
+        if (type === 'ward') {
+          const r = this.warningList.find((f) => f.w_id === user_id);
+          if (r) i.level = 'warning';
+          // 没报警的话,查看是否超过分级,需要修改图标
+          else if (case_number) {
+            if (case_number < 3) i.level = '<3';
+            else if (3 <= case_number && case_number < 5) i.level = '3-5';
+            else if (case_number >= 5) i.level = '>5';
+          }
+        }
+        const point = drawTools.initMassMarkData(i);
+        if (point) points.push(point);
+      }
+      //为海量点显示label提示的点
+      let marker;
+      if (!this.massMark) {
+        this.massMark = drawTools.initMassMark(points);
+        this.massMark.on('mouseover', (e) => {
+          marker = new AMap.Marker({ content: ' ', map: this.map });
+          const d = _.get(e, 'data');
+          marker.setPosition(d.lnglat);
+          marker.setLabel({ content: d.name, offset: [-20, -10] });
+        });
+        this.massMark.on('mouseout', (e) => {
+          this.map.remove(marker);
+        });
+        this.massMark.on('click', (e) => {
+          // 查看这是患者还是监护人,监护人没有事件
+          const d = _.get(e, 'data');
+          if (d.type !== 'ward') return;
+          this.getWardInfo(d.user_id);
+        });
+        this.massMark.setMap(this.map);
+      } else this.massMark.setData(points);
+    },
+    // 获取病人信息
+    async getWardInfo(id) {
+      const res = await this.mapWard(id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+        this.dialog = true;
+        // const fence = _.get(res.data, 'ward.fence');
+        // if (fence) {
+        //   if (this.wardFence) this.map.remove(this.wardFence);
+        //   let obj;
+        //   const { type } = fence;
+        //   if (type === 'polygon') obj = drawTools.initPolygon({ ...fence, drawType: 'ward' });
+        //   else obj = drawTools.initRectangle({ ...fence, drawType: 'ward' });
+        //   this.map.add(obj);
+        //   this.wardFence = obj;
+        // }
+      }
+    },
+    // 获取围栏
+    async searchFence() {
+      const res = await this.getFences({ status: '0' });
+      if (this.$checkRes(res)) {
+        const arr = [];
+        for (const i of res.data) {
+          const { range, ...info } = i;
+          const obj = { ...info, ...range };
+          arr.push(obj);
+        }
+        this.$set(this, 'fence', arr);
+        this.drawFence();
+      }
+    },
+    // 画围栏
+    drawFence() {
+      const arr = [];
+      for (const f of this.fence) {
+        const { type } = f;
+        let obj;
+        if (type === 'polygon') obj = drawTools.initPolygon({ ...f, drawType: 'fence' });
+        else obj = drawTools.initRectangle({ ...f, drawType: 'fence' });
+        this.map.add(obj);
+        arr.push(obj);
+      }
+      this.$set(this, `fenceGraphic`, arr);
+    },
+    // 获取属性(深层)
+    getProp(data, prop) {
+      return _.get(this[data], prop, '暂无');
+    },
+    // 初始化警情未处理事件
+    async initWarning() {
+      await this.search();
+      await this.searchWarning('init');
+      setInterval(async () => {
+        await this.search();
+        await this.searchWarning();
+      }, 5000);
+    },
+    async searchWarning() {
+      const res = await this.getWarning({ status: '0' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `warningList`, res.data);
+        // 查询渲染海量点
+        this.initMassMark();
+      }
+    },
+    // 提交查询
+    async toSearch() {
+      const obj = _.cloneDeep(this.searchForm);
+      const res = await this.findWard(obj);
+      if (this.$checkRes(res)) {
+        const data = _.head(res.data);
+        if (_.get(data, '_id')) {
+          window.open(`/sps/watch/ward/${_.get(data, '_id')}`);
+        } else {
+          this.$message.warning('没有查询到相关人员的定位信息');
+        }
+      }
+    },
+  },
+  beforeDestroy() {
+    if (this.timer) clearInterval(this.timer);
+    if (this.map) this.map.destroy();
+  },
+};
+</script>
+
+<style lang="less" scoped>
+#container {
+  width: 100%;
+  overflow: hidden;
+  color: #000;
+}
+/deep/.el-dialog__body {
+  height: 50vh;
+  overflow: auto;
+}
+.main {
+  .one {
+    /deep/.el-form-item {
+      float: left;
+      width: 100%;
+      margin: 0;
+    }
+    /deep/.el-input__inner {
+      background-color: transparent;
+      color: #fff;
+    }
+    .btn {
+      text-align: right;
+      .el-button {
+        background-color: transparent;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/views/fake_list/index.vue


Vissa filer visades inte eftersom för många filer har ändrats