Переглянути джерело

医院级空间结构开发

WenNingning 4 роки тому
батько
коміт
03bb6c888a
50 змінених файлів з 2550 додано та 525 видалено
  1. 1 1
      dist/index.html
  2. 0 1
      dist/static/css/app.848c2287.css
  3. 0 1
      dist/static/css/chunk-06faafad.c4469a3f.css
  4. 0 1
      dist/static/css/chunk-33c220b5.5e69ac7c.css
  5. 0 1
      dist/static/css/chunk-3e9c6b25.5f95877f.css
  6. 0 1
      dist/static/css/chunk-3fc04dc7.646ba2db.css
  7. 0 1
      dist/static/css/chunk-4decaba3.95168f18.css
  8. 0 1
      dist/static/css/chunk-536dc705.05e6c10a.css
  9. 0 1
      dist/static/css/chunk-537d7593.b22894e7.css
  10. 0 1
      dist/static/css/chunk-7c5298e1.516f9bb1.css
  11. 0 1
      dist/static/css/chunk-95ac90b6.3a7928f9.css
  12. 0 1
      dist/static/css/chunk-c4207b36.31192868.css
  13. 0 1
      dist/static/css/chunk-d5ed0cd6.5cbe9b13.css
  14. 0 1
      dist/static/css/chunk-libs.854468b4.css
  15. BIN
      dist/static/img/loginBg.238668d2.jpg
  16. 0 1
      dist/static/js/app.af067b6f.js
  17. 0 1
      dist/static/js/chunk-06faafad.2aab81cd.js
  18. 0 6
      dist/static/js/chunk-107fdb58.bb729d73.js
  19. 0 1
      dist/static/js/chunk-1d9ec8ab.c4d651da.js
  20. 0 1
      dist/static/js/chunk-2d0bdbb6.352c6034.js
  21. 0 1
      dist/static/js/chunk-2d0c8694.a3443a88.js
  22. 0 1
      dist/static/js/chunk-30ca8599.35aae577.js
  23. 0 1
      dist/static/js/chunk-33c220b5.07f68482.js
  24. 0 1
      dist/static/js/chunk-3e9c6b25.ae9262c2.js
  25. 0 1
      dist/static/js/chunk-3fc04dc7.2aa1b151.js
  26. 0 1
      dist/static/js/chunk-4decaba3.10847f33.js
  27. 0 1
      dist/static/js/chunk-536dc705.b9f9f39d.js
  28. 0 1
      dist/static/js/chunk-537d7593.5b70e487.js
  29. 0 1
      dist/static/js/chunk-5c92bfb9.7e52b7ae.js
  30. 0 1
      dist/static/js/chunk-5f4cdadc.aa7f35e8.js
  31. 0 1
      dist/static/js/chunk-665577f1.dd5b3358.js
  32. 0 1
      dist/static/js/chunk-7c5298e1.db0cc428.js
  33. 0 1
      dist/static/js/chunk-95ac90b6.33943a7d.js
  34. 0 1
      dist/static/js/chunk-c4207b36.3aa5951e.js
  35. 0 1
      dist/static/js/chunk-d5ed0cd6.d2eb0448.js
  36. 0 1
      dist/static/js/chunk-elementUI.d21c1ac9.js
  37. 0 457
      dist/static/js/chunk-libs.f11dcb7f.js
  38. 9 0
      src/api/ncs_customer.js
  39. 9 0
      src/api/ncs_device.js
  40. 1 1
      src/components/AgGridLayout/src/main.vue
  41. 16 0
      src/router/index.js
  42. 48 23
      src/store/modules/permission.js
  43. 1 1
      src/views/dashboard/calling/components/PanelGroup.vue
  44. 610 0
      src/views/hospital/ncs_customer/customerEdit.vue
  45. 495 0
      src/views/hospital/ncs_customer/list.vue
  46. 590 0
      src/views/hospital/ncs_device/deviceManager.vue
  47. 767 0
      src/views/hospital/ncs_frame/frameTreeView.vue
  48. 2 2
      src/views/hospitalFrame/frameTreeView.vue
  49. 1 0
      src/views/ncs-clerk/clerkList.vue
  50. 0 1
      src/views/ncs-device/components/deviceManager.vue

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/index.html


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/css/app.848c2287.css


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/css/chunk-06faafad.c4469a3f.css


+ 0 - 1
dist/static/css/chunk-33c220b5.5e69ac7c.css

@@ -1 +0,0 @@
-fieldset[data-v-c1a826a4]{border-style:solid;border-color:#dcdfe6;border-width:1px}.margin-top-sm[data-v-c1a826a4]{margin-top:20px}

+ 0 - 1
dist/static/css/chunk-3e9c6b25.5f95877f.css

@@ -1 +0,0 @@
-.el-drawer.rtl{overflow:scroll}

+ 0 - 1
dist/static/css/chunk-3fc04dc7.646ba2db.css

@@ -1 +0,0 @@
-[data-v-92eb0d7e] .avatar-uploader .el-upload{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-92eb0d7e]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-92eb0d7e]{font-size:28px;color:#8c939d;width:178px;height:178px;line-height:178px;text-align:center}.avatar[data-v-92eb0d7e]{width:178px;height:178px;display:block}.green-text[data-v-92eb0d7e]{color:green}.red-text[data-v-92eb0d7e]{color:red}

+ 0 - 1
dist/static/css/chunk-4decaba3.95168f18.css

@@ -1 +0,0 @@
-fieldset[data-v-023c7e3b]{border-style:solid;border-color:#dcdfe6;border-width:1px}.margin-top-sm[data-v-023c7e3b]{margin-top:20px}

Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/css/chunk-536dc705.05e6c10a.css


+ 0 - 1
dist/static/css/chunk-537d7593.b22894e7.css

@@ -1 +0,0 @@
-[data-v-34ab69ba] .avatar-uploader .el-upload{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-34ab69ba]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-34ab69ba]{font-size:28px;color:#8c939d;width:178px;height:178px;line-height:178px;text-align:center}.avatar[data-v-34ab69ba]{width:178px;height:178px;display:block}

+ 0 - 1
dist/static/css/chunk-7c5298e1.516f9bb1.css

@@ -1 +0,0 @@
-fieldset[data-v-c2106f28]{border-style:solid;border-color:#dcdfe6;border-width:1px}.margin-top-sm[data-v-c2106f28]{margin-top:20px}fieldset[data-v-8812c67a]{border-style:solid;border-color:#dcdfe6;border-width:1px}.margin-top-sm[data-v-8812c67a]{margin-top:20px}

+ 0 - 1
dist/static/css/chunk-95ac90b6.3a7928f9.css

@@ -1 +0,0 @@
-[data-v-7f6faf30] .colorBtn{width:80px!important;height:40px!important}[data-v-7f6faf30] .m-colorPicker .box.open{z-index:1000!important}

+ 0 - 1
dist/static/css/chunk-c4207b36.31192868.css

@@ -1 +0,0 @@
-[data-v-5dbb8868] .avatar-uploader .el-upload{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-5dbb8868]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-5dbb8868]{font-size:28px;color:#8c939d;width:178px;height:178px;line-height:178px;text-align:center}.avatar[data-v-5dbb8868]{width:178px;height:178px;display:block}.green-text[data-v-5dbb8868]{color:green}.red-text[data-v-5dbb8868]{color:red}

Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/css/chunk-d5ed0cd6.5cbe9b13.css


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/css/chunk-libs.854468b4.css


BIN
dist/static/img/loginBg.238668d2.jpg


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/app.af067b6f.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-06faafad.2aab81cd.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 6
dist/static/js/chunk-107fdb58.bb729d73.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-1d9ec8ab.c4d651da.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-2d0bdbb6.352c6034.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-2d0c8694.a3443a88.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-30ca8599.35aae577.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-33c220b5.07f68482.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-3e9c6b25.ae9262c2.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-3fc04dc7.2aa1b151.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-4decaba3.10847f33.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-536dc705.b9f9f39d.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-537d7593.5b70e487.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-5c92bfb9.7e52b7ae.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-5f4cdadc.aa7f35e8.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-665577f1.dd5b3358.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-7c5298e1.db0cc428.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-95ac90b6.33943a7d.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-c4207b36.3aa5951e.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-d5ed0cd6.d2eb0448.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
dist/static/js/chunk-elementUI.d21c1ac9.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 457
dist/static/js/chunk-libs.f11dcb7f.js


+ 9 - 0
src/api/ncs_customer.js

@@ -50,4 +50,13 @@ export function remove(id) {
     method: 'DELETE',
     loading: true
   })
+}
+export function customerListByHospital(params) {
+  return request({
+    url: '/ncs/customer/customerListByHospital',
+    method: 'POST',
+    loading: true,
+    data: params,
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
+  })
 }

+ 9 - 0
src/api/ncs_device.js

@@ -168,4 +168,13 @@ export function getFrameByDeviceId(id) {
     loading: false
   })
 }
+export function listByHospital(params) {
+  return request({
+    url: '/ncs/device/listByHospital',
+    method: 'POST',
+    loading: true,
+    data: params,
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
+  })
+}
 

+ 1 - 1
src/components/AgGridLayout/src/main.vue

@@ -81,7 +81,7 @@ export default {
   },
   watch: {
     rowData(value) {
-      console.log('rows', value)
+      // console.log('rows', value)
     }
   },
   methods: {

+ 16 - 0
src/router/index.js

@@ -337,6 +337,22 @@ export const partRoutes = [
   },
   { path: '*', redirect: '/404', hidden: true }
 ]
+export const hospitalRoutes = [
+  {
+    path: '/hospital/ncs_frame',
+    component: Layout,
+    redirect: '/ncs_frame/index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/hospital/ncs_frame/frameTreeView'),
+        name: 'hospital_frameTreeView',
+        meta: { title: '空间管理', icon: 'component', noCache: true }
+      }
+    ]
+  },
+  { path: '*', redirect: '/404', hidden: true }
+]
 export const adminRoutes = [
   {
     path: '/ncs-device',

+ 48 - 23
src/store/modules/permission.js

@@ -1,4 +1,4 @@
-import { constantRoutes, partRoutes, adminRoutes } from '@/router'
+import { constantRoutes, partRoutes, adminRoutes, hospitalRoutes } from '@/router'
 import store from '@/store'
 import { getUserRolesPermissions } from '@/api/user'
 /**
@@ -47,36 +47,61 @@ const mutations = {
   }
 }
 
+function getUserRoutes(role_id, routes) {
+  getUserRolesPermissions(role_id).then(response => {
+    return filterRoleRouter(routes, response)
+  })
+}
 const actions = {
   async generateRoutes({ commit }) {
     return new Promise(resolve => {
       const accessedRoutes = [] // asyncRoutes || []
       let lastRoutes = []
       const userInfo = store.getters.userInfo
-      if (userInfo && userInfo.founder === 1) { // 机构管理
-        if (userInfo.username === 'superadmin') { // 超级管理员
-          lastRoutes = accessedRoutes.concat(adminRoutes)
-        } else { // 普通机构管理员
-          lastRoutes = accessedRoutes.concat(partRoutes)
+      if (userInfo.username === 'superadmin') { // 超级管理员
+        lastRoutes = accessedRoutes.concat(adminRoutes)
+      } else {
+        const shopInfo = store.getters.organization // 机构信息
+        if (shopInfo.shop_type === '6') { // 为医院
+          if (userInfo && userInfo.founder === 1) { // 科室管理
+            lastRoutes = accessedRoutes.concat(hospitalRoutes)
+          } else {
+            lastRoutes = accessedRoutes.concat(getUserRoutes(userInfo.role_id, hospitalRoutes))
+          }
+        } else if (shopInfo.shop_type === '5') { // 为科室
+          if (userInfo && userInfo.founder === 1) { // 科室管理
+            lastRoutes = accessedRoutes.concat(partRoutes)
+          } else {
+            lastRoutes = accessedRoutes.concat(getUserRoutes(userInfo.role_id, partRoutes))
+          }
         }
-        commit('SET_ROUTES', lastRoutes)
-        resolve(lastRoutes)
-      } else if (userInfo) { // 普通医护人员
-        getUserRolesPermissions(userInfo.role_id).then(response => {
-          const filtered = filterRoleRouter(partRoutes, response)
-          console.log(filtered)
-          // 过滤路由之后,因为首页不会匹配,需要根据店铺类型加入不同首页
-          // let lastAccessedRouters = []
-          // if (shopt.getters.shopInfo.shop_type !== '3' && shopt.getters.shopInfo.shop_type !== '2') {
-          //   lastAccessedRouters = careIndexRouter.concat(accessedRouters)
-          // } else {
-          //   lastAccessedRouters = shopDashboardRouter.concat(accessedRouters)
-          // }
-          lastRoutes = accessedRoutes.concat(filtered)
-          commit('SET_ROUTES', lastRoutes)
-          resolve(lastRoutes)
-        })
       }
+      commit('SET_ROUTES', lastRoutes)
+      resolve(lastRoutes)
+      // if (userInfo && userInfo.founder === 1) { // 机构管理
+      //   if (userInfo.username === 'superadmin') { // 超级管理员
+      //     lastRoutes = accessedRoutes.concat(adminRoutes)
+      //   } else { // 普通机构管理员
+      //     lastRoutes = accessedRoutes.concat(partRoutes)
+      //   }
+      //   commit('SET_ROUTES', lastRoutes)
+      //   resolve(lastRoutes)
+      // } else if (userInfo) { // 普通医护人员
+      //   getUserRolesPermissions(userInfo.role_id).then(response => {
+      //     const filtered = filterRoleRouter(partRoutes, response)
+      //     console.log(filtered)
+      //     // 过滤路由之后,因为首页不会匹配,需要根据店铺类型加入不同首页
+      //     // let lastAccessedRouters = []
+      //     // if (shopt.getters.shopInfo.shop_type !== '3' && shopt.getters.shopInfo.shop_type !== '2') {
+      //     //   lastAccessedRouters = careIndexRouter.concat(accessedRouters)
+      //     // } else {
+      //     //   lastAccessedRouters = shopDashboardRouter.concat(accessedRouters)
+      //     // }
+      //     lastRoutes = accessedRoutes.concat(filtered)
+      //     commit('SET_ROUTES', lastRoutes)
+      //     resolve(lastRoutes)
+      //   })
+      // }
     })
   },
   /** 退出时清除 动态挂载的路由 */

+ 1 - 1
src/views/dashboard/calling/components/PanelGroup.vue

@@ -103,7 +103,7 @@ export default {
 
 <style lang="scss" title="style1" scoped>
   :root{
-    --icon-special-care:#f4516c;
+    --icon-special-care: #f3556f;
     --icon-primary-care:#34bfa3;
   }
 .panel-group {

+ 610 - 0
src/views/hospital/ncs_customer/customerEdit.vue

@@ -0,0 +1,610 @@
+<template>
+  <div class="formwrap">
+    <el-tabs v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="用户管理" name="customerEdit">
+        <el-form ref="editForm" :model="formmodel" :rules="rules" label-width="140px">
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="用户姓名" prop="named">
+                <el-input v-model="formmodel.named" clearable placeholder="请输入姓名" :maxlength="20" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="用户编号">
+                <el-input v-model="formmodel.card_no" clearable placeholder="请输入用户编号" :maxlength="20" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="年龄" prop="age">
+                <el-input v-model="formmodel.age" clearable :maxlength="4" placeholder="请输入年龄">
+                  <el-select slot="append" v-model="formmodel.age_unit" placeholder="请选择年龄单位">
+                    <el-option label="岁" value="岁" />
+                    <el-option label="月" value="月" />
+                    <el-option label="天" value="天" />
+                  </el-select>
+                </el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="性别" class="form-item-sex">
+                <el-radio v-model="formmodel.sex" :label="1">男</el-radio>
+                <el-radio v-model="formmodel.sex" :label="0">女</el-radio>
+                <el-radio v-model="formmodel.sex" :label="3">未知</el-radio>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="在院状态">
+                <el-radio v-model="formmodel.status" :label="0">在院</el-radio>
+                <el-radio v-model="formmodel.status" :label="1">已出院</el-radio>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="证件类型">
+                <el-radio v-model="formmodel.id_type" label="身份证">身份证</el-radio>
+                <el-radio v-model="formmodel.id_type" label="护照">护照</el-radio>
+                <el-radio v-model="formmodel.id_type" label="军人证">军人证</el-radio>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="证件号">
+                <el-input v-model="formmodel.id_no" clearable placeholder="请输入证件号" :maxlength="20" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="入院日期" prop="in_date">
+                <el-date-picker
+                  v-model="formmodel.in_date"
+                  type="date"
+                  :editable="false"
+                  value-format="timestamp"
+                  placeholder="选择入院日期"
+                  :picker-options="{disabledDate(time) { return time.getTime() > Date.now() }}"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="出院日期" prop="out_date">
+                <el-date-picker
+                  v-model="formmodel.out_date"
+                  type="date"
+                  :editable="false"
+                  value-format="timestamp"
+                  placeholder="选择出院日期"
+                  :picker-options="{disabledDate(time) { return time.getTime() < Date.now() }}"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="责任医生">
+                <el-select v-model="formmodel.doctor_id" placeholder="请选择医生" @change="doctorChange(1)">
+                  <el-option v-for="(item,index) in doctors" :key="index" :label="item.clerk_name" :value="item.clerk_id" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="责任护士">
+                <el-select v-model="formmodel.nurse_id" placeholder="请选择护士" @change="doctorChange(2)">
+                  <el-option v-for="(item,index) in nurses" :key="index" :label="item.clerk_name" :value="item.clerk_id" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="责任护工">
+                <el-select v-model="formmodel.worker_id" placeholder="请选择护工" @change="doctorChange(3)">
+                  <el-option v-for="(item,index) in workrs" :key="index" :label="item.clerk_name" :value="item.clerk_id" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row v-if="nurseData.length > 0">
+            <el-col v-for="(item, index) in nurseList" :key="index" :span="24 / nurseList.length">
+              <el-form-item :label="item[0]">
+                <el-select v-model="nurseData[index].nurse_level" :placeholder="'请选择'+item[0]" @change="changeNurseData(index)">
+                  <el-option v-for="(t,i) in item[1]" :key="i" :label="t.option_name" :value="t.id">
+                    <span style="float: left">{{ t.option_name }}</span>
+                    <span :style="'float: right; background-color: #'+t.color_rgb+';color: #'+t.color_rgb">颜色</span>
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="16">
+              <el-form-item label="病况描述">
+                <el-input
+                  v-model="formmodel.illness_desc"
+                  type="textarea"
+                  :autosize="{ minRows: 2, maxRows: 4}"
+                  :minlength="2"
+                  :maxlength="50"
+                  :placeholder="'请输入文本内容,长度2~50'"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-form-item style="margin-top:15px;">
+            <el-button type="primary" :disabled="isDisabled" class="save" @click="handlerSubmit('editForm')">保存修改</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-card v-if="this.customerId != 0" style="maring:15px">
+          <div>
+            <div style="float: left"><h4>用户备注</h4></div>
+            <div style="float: right">
+              <el-button type="success" @click="dialogAddVisible = true">添加备注</el-button>
+            </div>
+          </div>
+          <div style="clear:both">
+            <div>
+              <el-card v-for="(item, index) in tableData" :key="index">
+                <div>
+                  <span style="margin-left: 20px;font-weight:bold">备注内容:</span><span style="line-height:1.5">{{ item.content }}</span>
+                </div>
+                <div style="margin: 10px">
+                  <div style="float: left">
+                    <span v-if="item.file_name">
+                      <el-link :href="item.file_path" icon="el-icon-folder" type="success" target="_blank" :download="item.file_name">{{ item.file_name }}</el-link>
+                    </span>
+                  </div>
+                  <div style="float: right">
+                    <p>
+                      <span style="font-weight:bold">创建时间:</span>{{ forDate(item.create_time) }}
+                      <span style="font-weight:bold;margin-left: 10px;">创建人:</span>{{ item.create_name }}
+                    </p>
+                  </div>
+                </div>
+              </el-card>
+              <!--翻页-->
+              <el-pagination
+                v-if="pageData"
+                slot="pagination"
+                :current-page="pageData.page_no"
+                :page-sizes="[10, 30, 50, 100]"
+                :page-size="pageData.page_size"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="pageData.data_total"
+                @size-change="handlePageSizeChange"
+                @current-change="handlePageCurrentChange"
+              />
+            </div>
+          </div>
+        </el-card>
+        <el-dialog title="添加用户备注" :visible.sync="dialogAddVisible" :append-to-body="true" width="80%">
+          <el-form ref="editForm" :model="formmodel" :rules="rules" label-width="140px">
+            <el-form-item label="内容" prop="content">
+              <el-input
+                v-model="content"
+                type="textarea"
+                :autosize="{ minRows: 2, maxRows: 6}"
+                :minlength="2"
+                :maxlength="300"
+                show-word-limit
+                :placeholder="'请输入文本内容,长度300'"
+              />
+            </el-form-item>
+            <el-form-item label="附件">
+              <el-upload
+                v-if="!filePath"
+                class="avatar-uploader"
+                :action="`${uploadServer}?scene=avatar`"
+                :show-file-list="false"
+                :on-success="uploaded"
+                :before-upload="handleShopLogoBefore"
+              >
+                <i class="el-icon-plus avatar-uploader-icon" />
+              </el-upload>
+              <span v-if="filePath">{{ fileName }}</span>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="addRemark">立即添加</el-button>
+              <el-button @click="quxiao">取消</el-button>
+            </el-form-item>
+          </el-form>
+        </el-dialog>
+      </el-tab-pane>
+      <el-tab-pane v-if="customerId != 0" label="用户亲属" name="customer-relative">
+        <customer-relative :member-id="memberId" />
+      </el-tab-pane>
+    </el-tabs>
+
+  </div>
+
+</template>
+
+<script>
+import * as customer_API from '@/api/ncs_customer'
+import * as clerk_API from '@/api/ncs_clerk'
+import * as NurseConfig_API from '@/api/ncs_nurse_config'
+import * as remark_API from '@/api/ncs_remark'
+import * as RegExp from '@/utils/RegExp'
+import { unixToDate } from '@/utils/Foundation'
+import { serverUrl } from '@/utils/domain'
+import customerRelative from '@/views/customer/customer_relative'
+
+export default {
+  name: 'PatientInfoEdit',
+  components: { customerRelative },
+  props: {
+    customerId: {
+      type: Number,
+      default: 0
+    },
+    frameId: {
+      type: Number,
+      default: 0
+    }
+  },
+  data: function() {
+    return {
+      formmodel: {
+        sex: 1,
+        status: 0,
+        age_unit: '岁',
+        id_type: '身份证',
+        part_id: this.$store.getters.partId
+      },
+      nurseList: [],
+      nurseData: [],
+      nurseConfigDtos: [],
+      rules: {
+        named: [
+          this.MixinRequired('请输入真实姓名!'),
+          { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' },
+          {
+            validator: (rule, value, callback) => {
+              if (!RegExp.userName.test(value)) {
+                callback(new Error('只支持汉字、字母、数字、“-”、“_”的组合!'))
+              } else {
+                callback()
+              }
+            }
+          }
+        ],
+        age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
+        content: [{ required: true, message: '请输入备注内容', trigger: 'blur' }],
+        in_date: [{ required: true, message: '请选择入院日期', trigger: 'blur' }]
+      },
+      isDisabled: false,
+      doctors: [],
+      nurses: [],
+      workrs: [],
+      doctor_mapping_id: false,
+      nurse_Mapping_id: false,
+      worker_mapping_id: false,
+      params: {
+        page_size: 10,
+        page_no: 1,
+        sort: 'create_time',
+        dir: 'desc'
+      },
+      tableData: [],
+      pageData: [],
+      dialogAddVisible: false,
+      fileName: null,
+      filePath: null,
+      uploadServer: serverUrl + '/ncs/upload/uploadFile',
+      userInfo: this.$store.getters.userInfo,
+      content: null,
+      activeName: 'customerEdit',
+      memberId: null
+    }
+  },
+  watch: {
+    frameId: function(val, oldVal) {
+      this.getNurseConfigs()
+      this.hasCustomerId()
+    }
+  },
+  mounted() {
+    this.getEmployees()
+    if (this.nurseList.length === 0) {
+      this.getNurseConfigs()
+      this.hasCustomerId()
+    }
+  },
+
+  methods: {
+    getEmployees() {
+      const _this = this
+      clerk_API.listByPartRoleId({ partId: this.$store.getters.partId }).then(res => {
+        const groupBy = (arr, func) =>
+          arr.map(typeof func === 'function' ? func : val => val[func]).reduce((acc, val, i) => {
+            acc[val] = (acc[val] || []).concat(arr[i])
+            return acc
+          }, {})
+        const groupData = groupBy(res, item => item.role_name)
+        if (Object.entries(groupData).length > 0) {
+          Object.entries(groupData).forEach(item => {
+            if (item[0] === '医生') {
+              _this.doctors = item[1]
+            } else if (item[0] === '护士') {
+              _this.nurses = item[1]
+            } else if (item[0] === '护工') {
+              _this.workrs = item[1]
+            }
+          })
+        }
+      })
+    },
+    getNurseConfigs() {
+      this.nurseData = []
+      const _this = this
+      NurseConfig_API.listByPartId({ partId: this.$store.getters.partId }).then(res => {
+        const groupBy = (arr, func) =>
+          arr.map(typeof func === 'function' ? func : val => val[func]).reduce((acc, val, i) => {
+            acc[val] = (acc[val] || []).concat(arr[i])
+            return acc
+          }, {})
+          // 以参数名称来分组
+        const groupData = groupBy(res, item => item.config_name)
+        _this.nurseList = Object.entries(groupData)
+        if (_this.nurseList.length > 0) {
+          _this.nurseList.forEach((item, index) => {
+            _this.nurseData.push({ nurse_level: null, id: null, nurse_config: item[1][0].ncfg_id })
+          })
+        }
+      })
+    },
+    hasCustomerId() {
+      this.clearForm()
+      if (this.customerId !== 0) {
+        const _this = this
+        customer_API.getCustomerInfo(this.customerId).then(res => {
+          _this.formmodel = res
+          _this.doctor_mapping_id = res.doctor_mapping_id
+          _this.nurse_Mapping_id = res.nurse_Mapping_id
+          _this.worker_mapping_id = res.worker_mapping_id
+          _this.formmodel.doctor_mapping_id = null
+          _this.formmodel.nurse_Mapping_id = null
+          _this.formmodel.worker_mapping_id = null
+          if (_this.formmodel.in_date) {
+            _this.formmodel.in_date = _this.formmodel.in_date * 1000
+          }
+          if (_this.formmodel.out_date) {
+            _this.formmodel.out_date = _this.formmodel.out_date * 1000
+          }
+          console.log(_this.formmodel.in_date, _this.formmodel.out_date)
+          _this.getRemarks()
+          if (res.list !== null) {
+            _this.nurseData.forEach((item, index) => {
+              res.list.forEach((t, i) => { // 为护理项赋值
+                if (item.nurse_config === t.nurse_config) {
+                  item.nurse_level = t.nurse_level
+                  item.id = t.id
+                }
+              })
+            })
+          }
+        })
+      }
+    },
+    doctorChange(type) {
+      if (this.customerId !== 0) {
+        if (type === 1) {
+          if (this.doctor_mapping_id === null) {
+            this.formmodel.doctor_mapping_id = 0 // 为0则新增,// 其他值为修改
+          } else {
+            this.formmodel.doctor_mapping_id = this.doctor_mapping_id
+          }
+        } else if (type === 2) {
+          if (this.nurse_Mapping_id === null) {
+            this.formmodel.nurse_Mapping_id = 0 // 为0则新增,// 其他值为修改
+          } else {
+            this.formmodel.nurse_Mapping_id = this.nurse_Mapping_id
+          }
+        } else {
+          if (this.worker_mapping_id === null) {
+            this.formmodel.worker_mapping_id = 0 // 为0则新增,// 其他值为修改
+          } else {
+            this.formmodel.worker_mapping_id = this.worker_mapping_id
+          }
+        }
+      }
+    },
+    /** 保存按钮处理事件 */
+    handlerSubmit(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          this.isDisabled = true
+          if (this.formmodel.in_date) {
+            this.formmodel.in_date = this.formmodel.in_date / 1000
+          }
+          if (this.formmodel.out_date) {
+            this.formmodel.out_date = this.formmodel.out_date / 1000
+          }
+          if (this.customerId === 0) {
+            this.formmodel.frame_id = this.frameId
+            this.formmodel.list = this.nurseConfigDtos
+            customer_API.addAll(this.formmodel).then(res => {
+              this.$message.success('添加成功!')
+              this.clearForm()
+              this.$emit('saved')
+            }).catch(e => {
+              this.isDisabled = false
+            })
+          } else {
+            this.formmodel.list = this.nurseConfigDtos
+            customer_API.updateAll(this.formmodel).then(res => {
+              this.$message.success('修改成功!')
+              this.isDisabled = false
+              this.$emit('saved')
+            })
+          }
+        } else {
+          this.$message.error('表单填写有误,请检查!')
+          return false
+        }
+      })
+    },
+    clearForm() {
+      this.activeName = 'customerEdit'
+      this.formmodel = {
+        sex: 1,
+        status: 0,
+        age_unit: '岁',
+        id_type: '身份证',
+        part_id: this.$store.getters.partId,
+        named: null,
+        card_no: null,
+        id_no: null,
+        in_date: new Date(new Date().toLocaleDateString()).getTime(),
+        out_date: null,
+        doctor_id: null,
+        nurse_id: null,
+        worker_id: null,
+        illness_desc: null
+      }
+      this.isDisabled = false
+      this.nurseConfigDtos = []
+    },
+    // 选择了护理项
+    changeNurseData(index) {
+      const i = this.nurseConfigDtos.findIndex(item => {
+        return item.nurse_level === this.nurseData[index].nurse_level
+      })
+      if (i !== -1) {
+        this.nurseConfigDtos.splice(i, 1)
+      }
+      this.nurseConfigDtos.push(this.nurseData[index])
+    },
+    getRemarks() {
+      const _this = this
+      this.params.fixedCondition = ' part_id=' + this.$store.getters.partId + ' and type=1 and member_id = ' + this.formmodel.member_id
+      remark_API.getRemarks(this.params).then(res => {
+        _this.tableData = res.data
+        _this.pageData = {
+          page_no: res.page_no,
+          page_size: res.page_size,
+          data_total: res.data_total
+        }
+      })
+    },
+    /** 分页大小发生改变 */
+    handlePageSizeChange(size) {
+      this.params.page_size = size
+      this.getRemarks()
+    },
+    /** 分页页数发生改变 */
+    handlePageCurrentChange(page) {
+      this.params.page_no = page
+      this.getRemarks()
+    },
+    forDate(date) {
+      return unixToDate(date)
+    },
+    /** 上传成功后的钩子 更换图片 置空存储数组*/
+    uploaded(res) {
+      this.filePath = serverUrl + '/' + res
+    },
+    /** 图片上传之前的校验 */
+    handleShopLogoBefore(file) {
+      const _this = this
+      return new Promise((resolve, reject) => {
+        let hz = file.name
+        _this.fileName = hz
+        const index = hz.lastIndexOf('.')
+        hz = hz.substring(index + 1, hz.length)
+        const isImg = hz === 'jpeg' || hz === 'png' || hz === 'jpg' || hz === 'txt' || hz === 'doc' || hz === 'docx' || hz === 'xls' || hz === 'xlsx'
+        const isLt5M = file.size / 1024 / 1024 < 5
+        if (!isImg) {
+          _this.$message.error('上传附件只能是txt,doc,docx,xls,xlsx,jpg,png,jpeg格式!')
+          reject()
+        }
+        if (!isLt5M) {
+          _this.$message.error('上传附件大小不能超过 5MB!')
+          reject()
+        }
+        resolve()
+      })
+    },
+    addRemark() {
+      if (!this.content) {
+        this.$message.info('请输入内容!')
+        return
+      }
+      if (!this.filePath) {
+        this.fileName = null
+      }
+      const data = {
+        partId: this.$store.getters.partId,
+        type: 1,
+        memberId: this.formmodel.member_id,
+        createName: this.userInfo.username,
+        content: this.content,
+        filePath: this.filePath,
+        fileName: this.fileName
+      }
+      const _this = this
+      remark_API.save(data).then(res => {
+        _this.$message.success('添加成功!')
+        _this.getRemarks()
+        _this.quxiao()
+      })
+    },
+    quxiao() {
+      this.dialogAddVisible = false
+      this.content = null
+      this.fileName = null
+      this.filePath = null
+    },
+    handleClick(tab) {
+      this.memberId = this.formmodel.member_id
+    }
+  }
+}
+</script>
+
+<style type="text/scss" scoped>
+  .el-input .el-select {
+    width: 68px;
+  }
+  .el-select {
+    width: 100%;
+  }
+  .formwrap {
+    border: 1px solid #ebebeb;
+    border-radius: 3px;
+    background: #fff;
+    padding: 24px;
+    min-height: 500px;
+  }
+  /deep/ .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  /deep/ .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  /deep/ .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 100px;
+    height: 100px;
+    line-height: 100px;
+    text-align: center;
+  }
+
+  /deep/ .avatar {
+    width: 100px;
+    height: 100px;
+    display: block;
+  }
+
+</style>

+ 495 - 0
src/views/hospital/ncs_customer/list.vue

@@ -0,0 +1,495 @@
+<template>
+  <div>
+    <!--工具栏-->
+    <div class="toolbar" style="padding-left: 20px">
+      <el-form :inline="true" label-width="120px">
+        <el-form-item>
+          <el-input v-model="searchStr" placeholder="请输入用户姓名、编号、病床" clearable @clear="clickSearch" @keyup.native.enter="clickSearch">
+            <el-button slot="append" icon="el-icon-search" @click="clickSearch" />
+          </el-input>
+        </el-form-item>
+        <el-form-item label="用户状态">
+          <el-select v-model="callingType" placeholder="请选择用户状态" clearable @change="changeStatus">
+            <el-option label="在院" :value="0" />
+            <el-option label="已出院" :value="1" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="danger" @click="batchDelete">批量删除</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    <ag-grid-layout
+      :toolbar="false"
+      :table-height="tableHeight"
+      theme="ag-theme-alpine"
+      :column-defs="columnDefs"
+      :row-data="tableData"
+      :locale-text="localeText"
+      :grid-options="gridOptions"
+      :default-col-def="defaultColDef"
+      :animate-rows="true"
+      :row-selection="rowSelection"
+      @filterChanged="filterModifed"
+      @sortChanged="gridSortChange"
+    >
+      <el-pagination
+        v-if="pageData"
+        slot="pagination"
+        :current-page="pageData.page_no"
+        :page-sizes="[20, 50, 100, 200]"
+        :page-size="pageData.page_size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="pageData.data_total"
+        @size-change="handlePageSizeChange"
+        @current-change="handlePageCurrentChange"
+      />
+    </ag-grid-layout>
+    <el-dialog title="编辑用户信息" :visible.sync="dialogAddVisible" :append-to-body="true" width="85%">
+      <customer-edit :customer-id="customerId" :frame-id="frameId" @saved="handlePatientFinished" />
+    </el-dialog>
+
+    <el-dialog title="换床" :visible.sync="formshow" :append-to-body="true" width="80%">
+      <el-form ref="editForm" label-width="140px">
+        <el-form-item label="当前病床:"><svg-icon icon-class="bed" style="color: #9aaabf;margin-top: 5px" />{{ full_name }}</el-form-item>
+        <el-form-item label="可换病床:">
+          <el-radio-group v-model="changeFrameId">
+            <el-radio v-for="(item, index) in frameList" :key="index" :label="item.id">
+              <svg-icon icon-class="bed" style="color: #9aaabf;margin-top: 5px" />{{ item.full_name }}
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" @click="updateFrameId">确定换床</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import * as API_customer from '@/api/ncs_customer'
+import { unixToDate } from '@/utils/Foundation'
+import customerEdit from '@/views/customer/customerEdit'
+import * as API_hospitalFrame from '@/api/ncs_hospitalFrame'
+import { AG_GRID_LOCALE_CN } from '@/utils/AgGridVueLocaleCn'
+import ButtonCellRender from '@/components/AgGridCellRender/ButtonCellRender'
+import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
+
+export default {
+  name: 'CustomerList',
+  components: { customerEdit, ButtonCellRender, RadioFilter },
+  props: {
+    frame: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data: function() {
+    return {
+      /** 列表loading状态 */
+      loading: false,
+      /** 列表参数 */
+      params: {
+        page_size: 20,
+        page_no: 1,
+        sort: 'status,create_time',
+        dir: 'desc',
+        fixedCondition: ' 1 = 1',
+        hospital_id: this.$store.getters.partId,
+        alias: 'nc'
+      },
+      currentRow: {},
+      /** 列表数据 */
+      tableData: [],
+      pageData: [],
+      dialogAddVisible: false,
+      /** 选中行数据 */
+      multipleSelection: [],
+      lookForm: {},
+      formshow: false,
+      changeFrameId: null,
+      customerId: null,
+      frameId: null,
+      callingType: null,
+      frameList: [],
+      searchStr: null,
+      full_name: '',
+      columnDefs: null,
+      defaultColDef: null,
+      gridOptions: null,
+      gridApi: null,
+      columnApi: null,
+      localeText: AG_GRID_LOCALE_CN,
+      rowSelection: null,
+      sexTransfer: [
+        { key: '男', value: 1, color: 'green' },
+        { key: '女', value: 0, color: 'red' }
+      ],
+      statusTransfer: [
+        { key: '已出院', value: 1, color: 'orange' },
+        { key: '在院', value: 0, color: 'green' }
+      ]
+    }
+  },
+  computed: {
+    tableHeight() {
+      return this.mainAreaHeight - 130
+    }
+  },
+  watch: {
+    frame(val, oldvalue) {
+      if (val.type === 1) { // 医院
+        this.params.fixedCondition = '1=1'
+      } else if (val.type === 3) { // 科室
+        this.params.fixedCondition = ' part_id =' + this.frame.part_id
+      } else if (val.type === 4) { // 房间
+        const ids = []
+        this.frame.children.forEach(item => {
+          ids.push(item.id)
+        })
+        this.params.fixedCondition = ' frame_id in (' + ids + ')'
+      } else {
+        this.params.fixedCondition = ' frame_id = ' + this.frame.id
+      }
+      this.GET_List()
+    }
+  },
+  beforeMount() {
+    this.gridOptions = {
+    }
+    this.columnDefs = [
+      {
+        headerName: '#',
+        headerCheckboxSelection: true,
+        headerCheckboxSelectionFilteredOnly: true,
+        checkboxSelection: true,
+        sortable: false, filter: false,
+        width: 50,
+        resizable: false,
+        valueGetter: this.hashValueGetter
+      },
+      { headerName: '姓名', field: 'named', sortable: true, filter: 'agTextColumnFilter', minWidth: 160 },
+      { headerName: '用户编号', field: 'card_no', sortable: true, filter: true, width: 120 },
+      { headerName: '年龄', field: 'age', sortable: true, filter: 'agNumberColumnFilter', valueFormatter: this.formatterAge, width: 80 },
+      { headerName: '入驻病床', field: 'full_name', sortable: true, filter: true, minWidth: 160, valueFormatter: this.fullNameFormatter },
+      { headerName: '性别', field: 'sex', sortable: true, filter: true, cellRenderer: this.formatterSex, width: 80, filterFramework: 'RadioFilter',
+        filterParams: {
+          listData: this.sexTransfer
+        }
+      },
+      { headerName: '住院时间', field: 'in_date', valueFormatter: this.formatterDate, sortable: true, minWidth: 220, filter: 'agDateColumnFilter',
+        filterParams: {
+          comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
+            return 0
+          }
+        }
+      },
+      { headerName: '状态', field: 'status', sortable: true, filter: false, cellRenderer: this.formatterStatus, width: 100, filterFramework: 'RadioFilter',
+        filterParams: {
+          listData: this.statusTransfer
+        }
+      },
+      { headerName: '操作任务', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.handleAdd,
+            label: '编辑',
+            buttonType: 'primary',
+            buttonSize: 'mini'
+          }
+        },
+        filter: false,
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: false,
+        sortable: false },
+      { headerName: '换床', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.handlerEdit,
+            label: '换床',
+            buttonType: 'success',
+            buttonSize: 'mini',
+            show: !param.data['status']
+          }
+        },
+        filter: false,
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: false,
+        sortable: false },
+      { headerName: '出院', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.cy,
+            label: '出院',
+            buttonType: 'danger',
+            buttonSize: 'mini',
+            show: !param.data['status']
+          }
+        },
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: false,
+        filter: false,
+        sortable: false }
+    ]
+    this.defaultColDef = {
+      filter: 'agTextColumnFilter',
+      sortable: true,
+      resizable: true,
+      comparator: this.testComparator,
+      filterParams: {
+        debounceMs: 200,
+        newRowsAction: 'keep',
+        textCustomComparator: this.textCustomComparator,
+        comparator: this.testComparator
+      }
+    }
+    this.rowSelection = 'multiple'
+  },
+  mounted() {
+    this.gridApi = this.gridOptions.api
+    // this.GET_List()
+  },
+  methods: {
+    /** 选择行变化时,记录选中的行数据 */
+    selectFun(val) {
+      this.multipleSelection = val
+    },
+    /** 加载设备信息列表 */
+    GET_List() {
+      this.loading = true
+      this.gridApi.showLoadingOverlay()
+      this.gridApi.sizeColumnsToFit()
+      API_customer.customerListByHospital(this.params).then(res => {
+        this.loading = false
+        this.tableData = res.data
+        this.pageData = {
+          page_no: res.page_no,
+          page_size: res.page_size,
+          data_total: res.data_total
+        }
+      }).catch(() => {
+        this.loading = false
+      })
+    },
+    /** 处理搜索 **/
+    handlerSearch(keywords) {
+      this.params.query = keywords
+      this.GET_List()
+    },
+    changeStatus(value) {
+      delete this.params.fixedCondition
+      if (value) {
+        this.params.fixedCondition = ' part_id =' + this.$store.getters.partId + ' and status=' + value
+      } else {
+        this.params.fixedCondition = ' 1 = 1'
+      }
+      this.GET_List()
+    },
+    /** 单条数据删除处理 */
+    handlerDelete(ids) {
+      const test = '你确定要删除此用户信息?'
+      const _this = this
+      this.$confirm(test, '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        API_customer.remove(ids).then(
+          response => {
+            _this.GET_List()
+          }
+        ).catch(response => {
+          _this.$message({
+            type: 'info',
+            message: response.message
+          })
+        })
+      })
+    },
+    /** 批量数据删除处理(删除选中的行) */
+    batchDelete: function() {
+      const rows = this.gridApi.getSelectedRows()
+      if (rows.length === 0) {
+        this.$message({ type: 'info', message: '请先勾选需要删除的数据' })
+        return
+      }
+      const ids = []
+      rows.forEach(function(item) {
+        ids.push(item.id)
+      })
+      this.handlerDelete(ids.join(','), 'del')
+    },
+    /** 添加设备信息 */
+    handleAdd(row) {
+      this.dialogAddVisible = true
+      this.customerId = row.id
+      this.frameId = row.frame_id
+    },
+    handlerEdit(row) {
+      this.customerId = row.id
+      this.full_name = row.full_name
+      API_hospitalFrame.getSickbedByPartId(row.part_id).then(res => {
+        this.frameList = res
+      })
+      this.formshow = true
+    },
+    cy(row) {
+      this.customerId = row.id
+      const _this = this
+      this.$confirm('你确定要进行出院操作吗', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const data = {
+          out_date: new Date(new Date().toLocaleDateString()).getTime(),
+          status: 1
+        }
+        _this.updateSave(data)
+      })
+    },
+    /** 分页大小发生改变 */
+    handlePageSizeChange(size) {
+      this.params.page_size = size
+      this.GET_List()
+    },
+    /** 分页页数发生改变 */
+    handlePageCurrentChange(page) {
+      this.params.page_no = page
+      this.GET_List()
+    },
+    formatterAge(param) {
+      return param.data.age + param.data.age_unit
+    },
+    formatterStatus(params) {
+      if (params.value === null || params.value === undefined) return ''
+      const item = this.statusTransfer.filter(p => p.value === params.value)[0]
+      if (item) {
+        return '<span style="color:' + item.color + ';">' + item.key + '</span>'
+      } else {
+        return '未知'
+      }
+    },
+    fullNameFormatter(params) {
+      return params.data.shop_name + '-' + params.value
+    },
+    formatterDate(param) {
+      let date = unixToDate(param.data.in_date, 'yyyy-MM-dd')
+      if (param.data.out_date) {
+        date += '至' + unixToDate(param.data.out_date, 'yyyy-MM-dd')
+      } else {
+        if (param.data.in_date) {
+          date += '至今'
+        }
+      }
+      return date
+    },
+    handlePatientFinished() {
+      this.dialogAddVisible = false
+      this.GET_List()
+    },
+    updateFrameId() {
+      if (!this.changeFrameId) {
+        this.$message({
+          type: 'info',
+          message: '请选择病床'
+        })
+        return
+      }
+      const data = {
+        frame_id: this.changeFrameId
+      }
+      this.updateSave(data)
+    },
+    updateSave(data) {
+      API_customer.update(this.customerId, data).then(res => {
+        this.$message({
+          type: 'success',
+          message: '修改成功'
+        })
+        this.formshow = false
+        this.GET_List()
+      })
+    },
+    clickSearch(value) {
+      this.params.query = this.searchStr
+      this.GET_List()
+    },
+    /** 性别格式化 */
+    formatterSex(params) {
+      if (params.value === null || params.value === undefined) return ''
+      const item = this.sexTransfer.filter(p => p.value === params.value)[0]
+      if (item) {
+        return '<span style="color:' + item.color + ';">' + item.key + '</span>'
+      } else {
+        return '未知'
+      }
+    },
+    filterModifed(param) {
+      const model = param.api.getFilterModel()
+      this.params.filter = JSON.stringify(model)
+      this.GET_List()
+    },
+    gridSortChange(param) {
+      const columnState = param.columnApi.getColumnState()
+      // 排序状态
+      const sortState = columnState.filter(function(s) {
+        return s.sort != null
+      }).map(function(s) {
+        return {
+          colId: s.colId,
+          sort: s.sort,
+          sortIndex: s.sortIndex
+        }
+      }).sort(function(a, b) {
+        return a.sortIndex - b.sortIndex
+      })
+      if (sortState.length > 0) {
+        if (sortState.length === 1) {
+          this.params.sort = sortState[0].colId
+          this.params.dir = sortState[0].sort
+        } else {
+          let sortstring = ''
+          sortState.forEach(function(item) {
+            sortstring += item.colId + ' ' + item.sort + ','
+          })
+          this.params.sort = sortstring.substring(0, sortstring.length - 1)
+          this.params.dir = ' '
+        }
+      } else {
+        delete this.params.sort
+        delete this.params.dir
+      }
+      this.GET_List()
+    }
+  }
+}
+</script>
+
+<style type="text/scss" scoped>
+
+  /deep/ div.toolbar {
+    height: 70px;
+    padding: 20px 0;
+  }
+
+  /deep/ .el-table {
+    width: 100%;
+    overflow-x: scroll;
+
+    & td:not(.is-left) {
+      text-align: center;
+    }
+  }
+</style>

+ 590 - 0
src/views/hospital/ncs_device/deviceManager.vue

@@ -0,0 +1,590 @@
+<template>
+  <div>
+    <ag-grid-layout
+      toolbar
+      :table-height="tableHeight"
+      theme="ag-theme-alpine"
+      :column-defs="columnDefs"
+      :row-data="rowData"
+      :locale-text="localeText"
+      :grid-options="gridOptions"
+      :default-col-def="defaultColDef"
+      :animate-rows="true"
+      :row-selection="rowSelection"
+      :framework-components="frameworkComponents"
+      @filterChanged="filterModifed"
+      @sortChanged="gridSortChange"
+    >
+      <div slot="toolbar" class="inner-toolbar">
+        <div class="toolbar-search">
+          <en-table-search placeholder="请输入搜索关键字" @search="handlerSearch" />
+        </div>
+        <div v-if="hasAdd" class="toolbar-btns">
+          <el-button type="primary" size="mini" @click="handleAdd">新增设备</el-button>
+        </div>
+      </div>
+      <el-pagination
+        v-if="pageData"
+        slot="pagination"
+        :current-page="pageData.page_no"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="pageData.page_size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="pageData.data_total"
+        @size-change="handlePageSizeChange"
+        @current-change="handlePageCurrentChange"
+      />
+    </ag-grid-layout>
+
+    <!-- 设备编辑弹窗 -->
+    <el-dialog :title="deviceEditTitle" :visible.sync="deviceDialogVisible" width="60%">
+      <el-form ref="deviceEditForm" :rules="deviceRules" label-width="120px" :model="deviceModel">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="设备类型" prop="device_type">
+              <el-select v-model="deviceModel.device_type" placeholder="请选择设备类型" :disabled="deviceTypeDisabled" clearable @change="deviceTypeChange">
+                <el-option v-for="(item,index) in deviceTypeTransfer" :key="index" :label="item.key" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设备别名" prop="name">
+              <el-input v-model="deviceModel.name" clearable :maxlength="20" placeholder="请输入设备别名" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="出厂编号" prop="code">
+              <el-input v-model="deviceModel.code" clearable placeholder="请输入出厂编号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设备型号" prop="model">
+              <el-input v-model="deviceModel.model" clearable placeholder="请输入设备型号" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="有线物理地址" prop="eth_mac">
+              <el-input v-model="deviceModel.eth_mac" clearable placeholder="请输入物理MAC地址" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="有线IP地址" prop="eth_ip">
+              <el-input v-model="deviceModel.eth_ip" clearable placeholder="请输入IP地址" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="WIFI物理地址" prop="wifi_mac">
+              <el-input v-model="deviceModel.wifi_mac" clearable placeholder="请输入WIFI MAC地址" readonly />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="WIFIIP地址" prop="wifi_ip">
+              <el-input v-model="deviceModel.wifi_ip" clearable placeholder="请输入WIFI IP地址" readonly />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="软件版本" prop="soft_ver">
+              <el-input v-model="deviceModel.soft_ver" clearable placeholder="请输入软件版本号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="硬件版本" prop="hard_ver">
+              <el-input v-model="deviceModel.hard_ver" clearable placeholder="请输入硬件版本号" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="WIFI热点">
+              <el-input v-model="deviceModel.wifi_hostname" :readonly="true" clearable placeholder="请输入WIFI热点名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="WIFI密码">
+              <el-input v-model="deviceModel.wifi_password" :readonly="true" clearable placeholder="请输入WIFI热点密码" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="设备位置">
+              <span>{{ deviceModel.full_name }}</span>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="后备设备ID">
+              <el-input v-model="deviceModel.backup_id" clearable placeholder="" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="设备优先级">
+              <el-input-number v-model="deviceModel.priority" controls-position="right" :min="1" :max="99" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="是否启用">
+              <el-checkbox v-model="deviceModel.status" :true-label="1" :false-label="0">启用设备</el-checkbox>
+              <!--              <el-radio v-model="formmodel.status" :label="1">启用</el-radio>-->
+              <!--              <el-radio v-model="formmodel.status" :label="0">不启用</el-radio>-->
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="hasRoleId">
+          <el-col :span="12">
+            <el-form-item label="适用角色" prop="role_id">
+              <el-select v-model="deviceModel.role_id" placeholder="适用角色" clearable>
+                <el-option v-for="item in rolesOptions" :key="item.role_id" :label="item.role_name" :value="item.role_id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="handlerFormSubmit('deviceEditForm')">确 定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 设备编辑弹窗 -->
+  </div>
+</template>
+
+<script>
+import { AG_GRID_LOCALE_CN } from '@/utils/AgGridVueLocaleCn'
+import { unix2Date } from '@/utils/Foundation'
+import ButtonCellRender from '@/components/AgGridCellRender/ButtonCellRender'
+import ListFilter from '@/components/AgGridCustomFilter/ListFilter'
+import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
+import * as API_Device from '@/api/ncs_device'
+import * as clerk_API from '@/api/ncs_clerk'
+export default {
+  name: 'DeviceManager',
+  components: { ButtonCellRender, ListFilter, RadioFilter },
+  props: {
+    frame: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      /** ag-grid参数 **/
+      pageData: {}, // 翻页数据
+      errorId: null,
+      shopVisible: false,
+      columnDefs: null,
+      rowData: null,
+      defaultColDef: null,
+      gridOptions: null,
+      gridApi: null,
+      columnApi: null,
+      localeText: AG_GRID_LOCALE_CN,
+      filterState: null,
+      rowSelection: null,
+      frameworkComponents: null,
+      /** 列表参数 */
+      params: {
+        page_size: 20,
+        page_no: 1,
+        hospital_id: this.$store.getters.partId,
+        fixedCondition: '1=1'
+      },
+      /** device 弹窗 **/
+      deviceDialogVisible: false,
+      deviceEditTitle: '添加设备',
+      deviceModel: {},
+      deviceTypeDisabled: false,
+      deviceRules: {
+        name: [
+          this.MixinRequired('请输入设备别名!')
+        ],
+        device_type: [
+          { required: true, message: '请选择设备类型', trigger: 'blur' }
+        ],
+        code: [
+          { required: true, message: '请输入设备编码', trigger: 'blur' }
+        ],
+        model: [
+          { required: true, message: '请输入设备型号', trigger: 'blur' }
+        ],
+        eth_mac: [
+          { required: true, message: '请输入设备MAC地址', trigger: 'blur' },
+          { pattern: /^([0-9A-Fa-f]{2}:?){6}/gi, message: '请输入正确的MAC地址', trigger: 'blur' }
+        ],
+        frame_id: [
+          { required: Object.keys(this.frame).length === 0, message: '请选安装位置!', trigger: 'blur' } // 没有传入frame 属性,必须选择安装位置
+        ],
+        role_id: [
+          { required: true, message: '请选择适用人', trigger: 'blur' }
+        ]
+      },
+      /** 设备类型转换数组 **/
+      deviceTypeTransfer: [
+        { key: '护士主机', value: 1 },
+        { key: '医生主机', value: 2 },
+        { key: '门口机', value: 3 },
+        { key: '病床分机', value: 4 },
+        { key: 'LCD走廊屏', value: 5 },
+        { key: 'LED点阵屏', value: 6 },
+        { key: '移动设备', value: 7 },
+        // { key: '护工腕表', value: 8 },
+        { key: '病人腕表', value: 9 },
+        { key: '手机App', value: 10 },
+        { key: '总线转换盒', value: 11 },
+        { key: '模拟分机', value: 12 },
+        { key: '模拟紧急按钮', value: 13 },
+        { key: '模拟门灯', value: 14 },
+        { key: '遥控器', value: 15 },
+        { key: '信标', value: 16 },
+        { key: '看板', value: 17 }
+      ],
+      deviceStatusTransfer: [
+        { key: '启用', value: 1, color: 'green' },
+        { key: '未启用', value: 0, color: 'red' }
+      ],
+      rolesOptions: [],
+      hasRoleId: false,
+      hasAdd: true
+    }
+  },
+  computed: {
+    tableHeight() {
+      return Object.keys(this.frame).length === 0 ? this.mainAreaHeight - 130 : this.mainAreaHeight - 174
+    },
+    frameSelectabled() { return Object.keys(this.frame).length > 0 }
+  },
+  watch: {
+    frame(val, oldvalue) {
+      console.log('watch22', val)
+      if (val.type === 1) {
+        this.params.fixedCondition = '1=1'
+        this.hasAdd = false
+      } else {
+        this.params.fixedCondition = Object.keys(this.frame).length === 0 ? '1=1' : ' frame_id =' + this.frame.id
+        this.hasAdd = true
+      }
+      this.getList()
+    }
+  },
+  beforeMount() {
+    this.gridOptions = {
+    }
+    this.columnDefs = [
+      {
+        headerName: '#',
+        headerCheckboxSelection: true,
+        headerCheckboxSelectionFilteredOnly: true,
+        checkboxSelection: true,
+        sortable: false, filter: false,
+        width: 80,
+        resizable: false,
+        valueGetter: this.hashValueGetter
+      },
+      // { headerName: 'ID', field: 'id', sortable: true, filter: 'agNumberColumnFilter', width: 100 },
+      { headerName: '设备类型', field: 'device_type', sortable: true, filterFramework: 'ListFilter', width: 160,
+        filterParams: {
+          listData: this.deviceTypeTransfer
+        },
+        valueGetter: this.deviceTypeGetter
+      },
+      // lockPosition 锁定位置,会在第一列
+      // lockPinned = true 不能拖动然后固定
+      // resizeable 单元个大小是否可以调整
+      { headerName: '设备别名', field: 'name', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '设备状态', field: 'status', sortable: true, filterFramework: 'RadioFilter',
+        filterParams: {
+          listData: this.deviceStatusTransfer
+        },
+        cellRenderer: this.deviceStatusFormatter
+      },
+
+      { headerName: '部署位置', field: 'full_name', sortable: true, filter: 'agTextColumnFilter', valueFormatter: this.fullNameFormatter },
+      { headerName: '以太网MAC地址', field: 'eth_mac', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '以太网IP地址', field: 'eth_ip', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '通讯端口', field: 'eth_ip_port', sortable: true, filter: 'agNumberColumnFilter' },
+      { headerName: '设备型号', field: 'model', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '出厂编号', field: 'code', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '软件版本', field: 'soft_ver', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '硬件版本', field: 'hard_ver', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '无线MAC地址', field: 'wifi_mac', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '无线IP地址', field: 'wifi_ip', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: 'SIP账号', field: 'sip_id', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '更新时间', field: 'update_time', sortable: true, filter: 'agDateColumnFilter', valueFormatter: this.unixDateFormatter, filterParams: {
+        comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
+          return 0
+        }
+      }},
+      { headerName: '编辑', field: 'shop_id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: {
+          onClick: this.handleEdit,
+          label: '编辑',
+          buttonType: 'primary',
+          buttonSize: 'mini'
+        },
+        filter: false,
+        pinned: 'right',
+        lockPinned: true,
+        width: 90,
+        resizable: false,
+        sortable: false },
+      { headerName: '删除', field: 'shop_id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.deleteSingle,
+            label: '删除',
+            buttonType: 'danger',
+            buttonSize: 'mini',
+            disabled: param.data['member_name'] === 'superadmin'
+          }
+        },
+        pinned: 'right',
+        lockPinned: true,
+        width: 90,
+        resizable: false,
+        filter: false,
+        sortable: false }
+    ]
+    this.defaultColDef = {
+      // filter: 'agTextColumnFilter',
+      sortable: true,
+      resizable: true,
+      // comparator: this.dateCustomComparator,
+      filterParams: {
+        debounceMs: 500,
+        newRowsAction: 'keep',
+        textCustomComparator: this.textCustomComparator
+      }
+    }
+    this.rowSelection = 'multiple'
+  },
+  mounted() {
+    this.gridApi = this.gridOptions.api
+    this.gridColumnApi = this.gridOptions.columnApi
+    this.gridColumnApi.applyColumnState({
+      state: [
+        {
+          colId: 'status',
+          sort: 'asc'
+        }
+      ]
+    })
+  },
+  methods: {
+    /** 加载列表数据 */
+    getList() {
+      const param = this.MixinClone(this.params)
+      this.gridApi.showLoadingOverlay()
+      API_Device.listByHospital(param).then(response => {
+        this.rowData = [...response.data]
+        this.pageData = {
+          page_no: response.page_no,
+          page_size: response.page_size,
+          data_total: response.data_total
+        }
+      }).catch(err => {
+        this.$message.error(err)
+      })
+    },
+
+    /**
+     * 过滤状态发生变化,发送到服务器检索数据
+     */
+    filterModifed(param) {
+      var model = param.api.getFilterModel()
+      this.params.filter = JSON.stringify(model)
+      this.getList()
+    },
+    gridSortChange(param) {
+      console.log('sortparam', param)
+      const columnState = param.columnApi.getColumnState()
+      // 排序状态
+      const sortState = columnState.filter(function(s) {
+        return s.sort != null
+      }).map(function(s) {
+        return {
+          colId: s.colId,
+          sort: s.sort,
+          sortIndex: s.sortIndex
+        }
+      }).sort(function(a, b) {
+        return a.sortIndex - b.sortIndex
+      })
+      if (sortState.length > 0) {
+        if (sortState.length === 1) {
+          this.params.sort = sortState[0].colId
+          this.params.dir = sortState[0].sort
+        } else {
+          let sortstring = ''
+          sortState.forEach(function(item) {
+            sortstring += item.colId + ' ' + item.sort + ','
+          })
+          this.params.sort = sortstring.substring(0, sortstring.length - 1)
+          this.params.dir = ' '
+        }
+      } else {
+        delete this.params.sort
+        delete this.params.dir
+      }
+
+      this.getList()
+    },
+    /** 处理搜索 */
+    handlerSearch(keywords) {
+      this.params.query = keywords
+      this.getList()
+    },
+    /** 获取设备类型文字显示,从deviceTypeTransfer 中找出value值对应的key显示出来 */
+    deviceTypeGetter(params) {
+      const gridVal = params.data.device_type
+      return this.deviceTypeTransfer.filter(p => p.value === gridVal).map(p => p.key)
+    },
+    /** 格式化时间函数 */
+    unixDateFormatter(param) {
+      if (!param.value) return ''
+      return unix2Date(param.value * 1000)
+    },
+    /** 设备状态格式化 **/
+    deviceStatusFormatter(params) {
+      if (params.value === null || params.value === undefined) return ''
+      const item = this.deviceStatusTransfer.filter(p => p.value === params.value)[0]
+      if (item) {
+        return '<span style="color:' + item.color + ';">' + item.key + '</span>'
+      } else {
+        return ''
+      }
+    },
+    fullNameFormatter(params) {
+      if (params.data.type === 3) {
+        return params.value
+      } else {
+        return params.data.shop_name + '-' + params.value
+      }
+    },
+    /** 删除设备 **/
+    deleteSingle(row) {
+      this.handlerDelete(row.id)
+    },
+    /** 删除设备 **/
+    handlerDelete(id) {
+      this.$confirm('删除操作后数据不可复原,您确定要删除此数据?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        API_Device.remove(id).then(
+          response => {
+            this.getList()
+          }
+        ).catch(response => {
+          this.$message({
+            type: 'info',
+            message: response.message
+          })
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    /** 设备类型选中变化  **/
+    deviceTypeChange(val) {
+      this.deviceRules.eth_mac[0].required = !(val === 12 || val === 13 || val === 14)
+      this.hasRoleId = val === 7
+    },
+    /** 添加设备事件 **/
+    handleAdd() {
+      this.deviceModel = {
+        soft_ver: 'SV1.0',
+        hard_ver: 'HV1.0',
+        code: 'C' + parseInt(Math.random() * 100000),
+        model: 'M' + parseInt(Math.random() * 100000)
+      }
+      if (Object.keys(this.frame).length > 0) {
+        this.$set(this.deviceModel, 'frame_id', this.frame.id)
+      }
+      delete this.deviceModel.id
+      this.hasRoleId = false
+      this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
+      this.deviceEditTitle = '添加设备'
+      this.deviceDialogVisible = true
+      this.deviceTypeDisabled = false // 新增设备可以选择设备类型
+      this.deviceModel.full_name = this.frame.full_name
+    },
+    /** 修改设备  **/
+    handleEdit(params) {
+      this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
+      console.log('param', params)
+      this.hasRoleId = params.device_type === 7
+      this.deviceModel = {
+        ...params
+      }
+      this.deviceEditTitle = '修改设备'
+      this.deviceDialogVisible = true
+      this.deviceTypeDisabled = true // 修改设备时,不能改变设备类型
+    },
+    /** 新增 提交表单 */
+    handlerFormSubmit(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          /** 新增 */
+          if (!this.deviceModel.id) {
+            this.deviceModel.part_id = this.frame.part_id
+            this.deviceModel.frame_id = this.frame.id
+            API_Device.add(this.deviceModel).then(() => {
+              this.$message.success('保存成功!')
+              this.deviceDialogVisible = false
+              this.getList()
+            }).catch(err => {
+              this.$message.error(err)
+            })
+          } else {
+            /** 修改 */
+            API_Device.update(this.deviceModel.id, this.deviceModel).then(() => {
+              this.$message.success('修改成功!')
+              this.deviceDialogVisible = false
+              this.getList()
+            }).catch(error => {
+              this.$message.error(error)
+            })
+          }
+        }
+      })
+    },
+    /** 分页大小发生改变 */
+    handlePageSizeChange(size) {
+      this.params.page_size = size
+      this.getList()
+    },
+
+    /** 分页页数发生改变 */
+    handlePageCurrentChange(page) {
+      this.params.page_no = page
+      this.getList()
+    },
+    getRoles(param) {
+      // 获取角色
+      clerk_API.getRoles(param).then(response => {
+        this.rolesOptions = response.data
+      })
+    }
+
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 767 - 0
src/views/hospital/ncs_frame/frameTreeView.vue

@@ -0,0 +1,767 @@
+<template>
+  <div>
+    <el-container :style="{height: asideHeight+'px'}">
+      <el-aside width="280px" style="border-color: rgb(238, 241, 246)">
+        <div class="el-row--flex">
+          <el-input
+            v-model="filterText"
+            placeholder="输入关键字进行过滤"
+            clearable
+          />
+<!--          <el-button-->
+<!--            type="text"-->
+<!--            size="mini"-->
+<!--            style="margin-left: 10px;color: #67C23A"-->
+<!--            @click="quickCreateFrame"-->
+<!--          >快速创建-->
+<!--          </el-button>-->
+
+        </div>
+        <el-tree
+          ref="frameTree"
+          :data="treeData"
+          :show-checkbox="false"
+          node-key="id"
+          :default-expand-all="true"
+          :auto-expand-parent="true"
+          :expand-on-click-node="false"
+          :highlight-current="true"
+          :current-node-key="selectedNodeId"
+          draggable
+          :accordion="true"
+          :filter-node-method="filterNode"
+          @node-drag-start="nodeDragStart"
+          @node-drop="nodeDrop"
+          @node-click="nodeClick"
+        >
+          <span slot-scope="{ node, data }" class="custom-tree-node">
+            <span v-if="data.type === 3"><svg-icon
+              icon-class="area"
+            />{{ data.name }}</span>
+            <span v-else><svg-icon
+              :icon-class="data.type===4?'sickroom':data.type===5?'bed':'area'"
+            />{{ data.full_name }}</span>
+            <span>
+              <el-button
+                v-if="data.type!==5"
+                type="text"
+                size="mini"
+                icon="el-icon-plus"
+                @click.stop="() => append(data)"
+              />
+              <el-button
+                type="text"
+                size="mini"
+                icon="el-icon-edit"
+                @click.stop="() => edit(data)"
+              />
+              <el-button
+                type="text"
+                :disabled="data.id===1"
+                size="mini"
+                icon="el-icon-delete"
+                @click.stop="() => remove(data)"
+              />
+            </span>
+          </span>
+        </el-tree>
+      </el-aside>
+      <el-main>
+        <el-row :gutter="40" class="panel-group">
+          <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+            <div class="card-panel">
+              <div class="card-panel-icon-wrapper icon-people">
+                <svg-icon icon-class="peoples" class-name="card-panel-icon" />
+              </div>
+              <div class="card-panel-description">
+                <div class="card-panel-text">
+                  在院人数
+                </div>
+                <count-to :start-val="0" :end-val="zyrs" :duration="2600" class="card-panel-num" />
+              </div>
+            </div>
+          </el-col>
+          <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+            <div class="card-panel">
+              <div class="card-panel-icon-wrapper icon-message">
+                <svg-icon icon-class="sickbed" class-name="card-panel-icon" />
+              </div>
+              <div class="card-panel-description">
+                <div class="card-panel-text">
+                  空置病床
+                </div>
+                <count-to :start-val="0" :end-val="kzbc" :duration="2000" class="card-panel-num" />
+              </div>
+            </div>
+          </el-col>
+          <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+            <div class="card-panel">
+              <div class="card-panel-icon-wrapper icon-special-care">
+                <svg-icon icon-class="care" class-name="card-panel-icon" />
+              </div>
+              <div class="card-panel-description">
+                <div class="card-panel-text">
+                  病房
+                </div>
+                <count-to :start-val="0" :end-val="bf" :duration="1900" class="card-panel-num" />
+              </div>
+            </div>
+          </el-col>
+          <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+            <div class="card-panel">
+              <div class="card-panel-icon-wrapper icon-primary-care">
+                <svg-icon icon-class="care1" class-name="card-panel-icon" />
+              </div>
+              <div class="card-panel-description primary-care">
+                <div class="card-panel-text primary-care">
+                  在床人数
+                </div>
+                <count-to :start-val="0" :end-val="zcrs" :duration="1500" class="card-panel-num" />
+              </div>
+            </div>
+          </el-col>
+        </el-row>
+        <el-tabs v-model="activeName" style="margin:0;" type="border-card">
+          <el-tab-pane label="设备列表" name="deviceList">
+            <keep-alive>
+              <device-manager :frame="selectedNode" />
+            </keep-alive>
+          </el-tab-pane>
+          <el-tab-pane label="用户列表" name="frameInfo">
+            <keep-alive>
+              <customer-manager :frame="selectedNode" />
+            </keep-alive>
+          </el-tab-pane>
+        </el-tabs>
+      </el-main>
+    </el-container>
+
+    <!---添加空间结构弹窗 -->
+    <el-dialog :title="frameEditTitle" :visible.sync="frameDialogVisible" width="500px">
+      <el-form ref="editForm" :model="frameInfo" :rules="rules" label-width="110px">
+        <el-row>
+          <el-col :span="24">
+            <!--医院结构名称-->
+            <el-form-item label="名称" prop="name">
+              <el-input v-model="frameInfo.name" :maxlength="20">
+                <template slot="append">{{ frameInfo.type === 4?"房":"床" }}</template>
+              </el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <!--医院结构别名-->
+            <el-form-item label="别名" prop="alias">
+              <el-input v-model="frameInfo.alias" :maxlength="20" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row hidden>
+          <el-col :span="12">
+            <el-form-item label="类型">
+              <el-radio v-model="frameInfo.type" :label="1">病房</el-radio>
+              <el-radio v-model="frameInfo.type" :label="2">床位</el-radio>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-form-item>
+          <el-button type="primary" class="save" @click="handleFrameSubmit('editForm')">确定</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <!---添加空间结构弹窗 -->
+
+    <!---快速创建结构弹窗 -->
+    <el-dialog title="快速构建结构" :visible.sync="frameQuickCreateVisible" width="500px">
+      <el-form ref="createFrameForm" :model="createFrameModel" :rules="createFrameRules" label-width="110px">
+        <el-row>
+          <el-col :span="24">
+            <!--开始房间号-->
+            <el-form-item label="开始房间号" prop="start_no">
+              <el-input-number
+                v-model="createFrameModel.room_start_no"
+                :min="1"
+                @change="roomStartChange"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <!--结束房间号-->
+            <el-form-item label="结束房间号" prop="end_no">
+              <el-input-number
+                v-model="createFrameModel.room_end_no"
+                :min="createFrameModel.room_start_no"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <!--每房床位数-->
+            <el-form-item label="每房床位数" prop="beds_per_room">
+              <el-input-number v-model="createFrameModel.beds_per_room" :min="1" :max="20" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="18">
+            <!--每房床位数-->
+            <el-form-item label="房号显示位数" prop="room_num_bits">
+              <el-input-number
+                v-model="createFrameModel.room_num_bits"
+                :min="1"
+                :max="4"
+                @change="(val)=>{bitNumChange(val,'room')}"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <div class="el-form-item__label">
+              示例:{{ room_num_demo }}
+            </div>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="18">
+            <!--每房床位数-->
+            <el-form-item label="床号显示位数" prop="bed_num_bits">
+              <el-input-number
+                v-model="createFrameModel.bed_num_bits"
+                :min="1"
+                :max="4"
+                @change="(val)=>{bitNumChange(val,'bed')}"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <div class="el-form-item__label">
+              示例:{{ bed_num_demo }}
+            </div>
+          </el-col>
+        </el-row>
+
+        <el-form-item>
+          <el-button type="primary" class="save" @click="quickCreateSubmit()">确定</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <!---快速创建结构弹窗 -->
+
+    <!-- 新建科室弹窗 -->
+    <el-dialog :title.sync="formtitle" :visible.sync="formshow" width="50%">
+      <div>
+        <el-form ref="editform" :rules="rules" label-width="120px" :model="formmodel">
+          <el-form-item label="科室名称" prop="shop_name">
+            <el-input v-model="formmodel.shop_name" clearable :maxlength="100" placeholder="请输入科室名称" />
+          </el-form-item>
+          <el-form-item label="管理员账号" prop="member_name">
+            <el-input v-model="formmodel.member_name" clearable :maxlength="100" placeholder="请输入管理员账号" />
+          </el-form-item>
+          <el-form-item label="管理员密码" prop="member_password">
+            <el-input v-model="formmodel.member_password" type="password" clearable :maxlength="100" placeholder="请输入管理员密码" />
+          </el-form-item>
+        </el-form>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="formshow = false">取 消</el-button>
+        <el-button type="primary" @click="handlerFormSubmit('editform')">确 定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 新建科室弹窗结束 -->
+  </div>
+</template>
+
+<script>
+import * as HospitalFrame_API from '@/api/ncs_hospitalFrame'
+import * as API_FrameGroup from '@/api/ncs_frameGroup'
+import CustomerManager from '@/views/hospital/ncs_customer/list'
+import DeviceManager from '@/views/hospital/ncs_device/deviceManager'
+import CountTo from 'vue-count-to'
+import * as API_PartInfo from '@/api/ncs_partInfo'
+
+export default {
+  name: 'FrameTreeView',
+  components: { DeviceManager, CustomerManager, CountTo },
+  data() {
+    return {
+      treeData: [],
+      treeDataClone: [],
+      /** 当前选中的树节点 */
+      selectedNodeId: 0,
+      selectedNode: {},
+      filterText: '',
+      activeName: 'deviceList',
+      /** 上级机构数组 **/
+      parents: [],
+      /** frame 编辑弹窗 **/
+      frameEditTitle: '添加',
+      frameDialogVisible: false,
+      frameInfo: {},
+      rules: {
+        name: [
+          this.MixinRequired('请输入结构名称!'),
+          { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
+        ],
+        alias: [
+          { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
+        ],
+        shop_name: [
+          { required: true, message: '组织名称必须选择', trigger: 'blur' }
+        ],
+        member_name: [
+          { required: true, message: '管理员账号必须填写', trigger: 'blur' }
+        ],
+        member_password: [
+          { required: true, message: '管理员密码必须填写', trigger: 'blur' }
+        ]
+      },
+      /** 快速创建空间结构弹窗 **/
+      frameQuickCreateVisible: false,
+      createFrameModel: {
+        room_start_no: 1,
+        room_end_no: 2,
+        beds_per_room: 4,
+        room_num_bits: 2,
+        bed_num_bits: 2
+      },
+      bed_num_demo: '01',
+      room_num_demo: '01',
+      createFrameRules: {},
+      zyrs: 1232,
+      zcrs: 632,
+      bf: 82,
+      kzbc: 56,
+      /** 新建组织弹出参数 **/
+      formtitle: '新建组织',
+      formshow: false,
+      formmodel: {}
+    }
+  },
+  computed: {
+    asideHeight() {
+      return this.mainAreaHeight
+    }
+  },
+  watch: {
+    selectedNodeId(newval, old) {
+      console.log('watch', newval)
+      this.selectedNode = this.findNodeById(this.treeData, newval)
+      console.log(this.selectedNode)
+    },
+    filterText(val) {
+      this.$refs.frameTree.filter(val)
+    }
+  },
+  mounted() {
+    this.getFrameTree().then(() => {
+      if (this.treeData.length > 0) {
+        this.selectedNodeId = this.treeData[0].id
+        this.$refs.frameTree.setCurrentKey(this.selectedNodeId)
+      }
+    }).catch(err => {
+      this.$message.error(err)
+    })
+  },
+  methods: {
+    /**
+     * 获取空间结构树形数据
+     * */
+    getFrameTree() {
+      return new Promise((resolve, reject) => {
+        API_FrameGroup.getframestruct(this.$store.getters.partId, 1).then(res => {
+          this.treeData = [...res]
+          resolve()
+        }).catch(err => {
+          reject(err)
+        })
+      })
+    },
+
+    append(data) {
+      if (data.type === 1) {
+        this.formmodel = {}
+        this.formmodel.parent_id = data.hospital_id
+        this.formmodel.frame_parent_id = data.id
+        this.formmodel.full_name = data.name
+        console.log('this.formmodel.parent_id=', this.formmodel.parent_id)
+        this.formshow = true
+      } else {
+        if (data.type === 4) {
+          this.frameEditTitle = '【' + data.full_name + '】添加床位'
+        } else {
+          this.frameEditTitle = '【' + data.full_name + '】添加房间'
+        }
+        this.frameInfo = {
+          parent_id: data.id,
+          type: data.type === 4 ? 5 : 4,
+          parent_name: data.name,
+          name: '',
+          alias: ''
+        }
+        this.frameDialogVisible = true
+        console.log('append', data)
+      }
+    },
+    edit(data, e) {
+      if (data.type === 3 || data.type === 1) {
+        console.log('暂未开发')
+        return
+      }
+      const parentNode = this.findNodeById(this.treeData, data.parent_id)
+      this.frameInfo = {
+        ...data,
+        parent_name: parentNode === null ? '' : parentNode.name
+      }
+      this.frameEditTitle = '编辑节点'
+      this.frameDialogVisible = true
+    },
+    remove(data) {
+      let warning = ''
+      if (data.type === 4) {
+        warning = '确定要删除【' + data.full_name + '】及其中的所有床位吗?'
+      } else {
+        warning = '确定删除床位【' + data.full_name + '】吗?'
+      }
+      this.$confirm(warning, '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        HospitalFrame_API.deleteHospitalFrame(data.id).then(response => {
+          this.$message({
+            type: 'success',
+            message: '已删除!'
+          })
+          this.getFrameTree().then(() => {
+            // 判断选中节点是否被删除,如果被删除需要重新选择根节点
+            const selectNode = this.findNodeById(this.treeData, this.selectedNodeId)
+            if (selectNode === null) {
+              this.selectedNodeId = this.treeData[0].id
+            }
+            this.$refs.frameTree.setCurrentKey(this.selectedNodeId)
+          })
+        }).catch(response => {
+          this.$message({
+            type: 'info',
+            message: response.message
+          })
+        })
+      }).catch(() => {
+
+      })
+    },
+
+    handleFrameSubmit(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          const params = this.MixinClone(this.frameInfo)
+          if (params.id) {
+            if (params.type === 4) {
+              params.full_name = params.name
+            } else {
+              params.full_name = params.parent_name + '-' + params.name + '床'
+            }
+            HospitalFrame_API.updateHospitalFrame(params.id, params).then(response => {
+              this.$message.success('修改成功!')
+              this.frameDialogVisible = false
+              this.getFrameTree().then(() => {
+                this.selectedNodeId = response.id
+                this.$refs.frameTree.setCurrentKey(this.selectedNodeId)
+              })
+            })
+          } else {
+            if (!params.part_id) {
+              params.part_id = this.$store.getters.partId
+            }
+            if (params.type === 4) {
+              params.full_name = params.name
+            } else {
+              params.full_name = params.parent_name + '-' + params.name + '床'
+            }
+
+            HospitalFrame_API.addHospitalFrame(params).then(response => {
+              this.$message.success('添加成功!')
+              this.frameDialogVisible = false
+              this.getFrameTree().then(() => {
+                this.selectedNodeId = response.id
+                this.$refs.frameTree.setCurrentKey(this.selectedNodeId)
+              })
+            })
+          }
+        } else {
+          this.$message.error('表单填写有误,请检查!')
+          return false
+        }
+      })
+    },
+    /** 开始拖拽之前保存treeData数据,拖拽完成后判定能否拖拽到目标节点,不允许拖拽把初始数据覆盖拖拽后的数据,否则拖拽成功
+             * @param node
+             * @param event
+             */
+    nodeDragStart(node, event) {
+      this.treeDataClone = this.MixinClone(this.treeData)
+    },
+    /** 拖拽结束 **/
+    nodeDrop(node, target, position, event) {
+      var success = true
+      const nparent = this.findNodeById(this.treeDataClone, node.data.parent_id)
+      const tparent = this.findNodeById(this.treeDataClone, target.data.parent_id)
+      if (position === 'inner') { // 进入了某个节点之中,不能将某一节点拖入同级节点,也不能跨级拖动
+        if (Number(node.data.type) <= Number(target.data.type) || Number(node.data.type) - Number(target.data.type) > 1) {
+          this.treeData = this.treeDataClone
+          success = false
+        }
+      } else {
+        // 查找Target和node的parent 判定target的parent类型与node的parent类型是否一致
+        if (nparent === null || tparent === null || nparent.type !== tparent.type) {
+          this.treeData = this.treeDataClone
+          success = false
+        }
+      }
+      if (success) { // 拖拽完成,更新node和target排序
+        HospitalFrame_API.sort(node.data.id, target.data.id, position).then(res => {
+          this.selectedNodeId = node.data.id
+          this.getFrameTree().then(() => {
+            this.$refs.frameTree.setCurrentKey(this.selectedNodeId)
+            console.log('sid', this.selectedNodeId)
+          })
+        })
+      }
+    },
+    /** 树形结构中查找指定Id节点 */
+    findNodeById(data, id) {
+      let node = null
+      if (data.length > 0) {
+        for (var i = 0; i < data.length; i++) {
+          if (data[i].id === id) {
+            node = data[i]
+            break
+          }
+          if (data[i].children && data[i].children.length > 0) {
+            const subresult = this.findNodeById(data[i].children, id)
+            if (subresult !== null) {
+              node = subresult
+              break
+            }
+          }
+        }
+      }
+      return node
+    },
+    /** 节点过滤方法 **/
+    filterNode(value, data) {
+      if (!value) return true
+      return data.full_name.indexOf(value) !== -1
+    },
+    /** 点击树形节点  **/
+    nodeClick(data, node, leaf) {
+      this.$set(this, 'selectedNodeId', data.id)
+      console.log(data)
+    },
+    /** 快速创建空间结构弹窗 **/
+    quickCreateFrame() {
+      this.frameQuickCreateVisible = true
+    },
+
+    quickCreateSubmit(formname) {
+      const params = this.createFrameModel
+      params.part_frame_id = this.treeData[0].id
+      HospitalFrame_API.quickCreate(params).then(res => {
+        this.$message.success('创建成功!')
+        this.frameQuickCreateVisible = false
+        this.getFrameTree().then(() => {
+          this.$refs.frameTree.setCurrentKey(this.selectedNodeId)
+        })
+      }).catch(err => {
+        this.$message.error(err)
+      })
+    },
+
+    /** 显示位数变化 **/
+    bitNumChange(val, frame_type) {
+      const s = Array(val).join(0) + 1
+      if (frame_type === 'room') {
+        this.room_num_demo = s
+      } else {
+        this.bed_num_demo = s
+      }
+    },
+    /** 起始位数变化 结束位置要根据起始位置的大小来变化 */
+    roomStartChange(val) {
+      console.log(val)
+      if (val > this.createFrameModel.room_end_no) {
+        this.createFrameModel.room_end_no = val
+      }
+    },
+    /**
+     * 提交新增表单
+     * @param formName
+     */
+    handlerFormSubmit(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          /** 新增 */
+          delete this.formmodel.id
+          this.formmodel.shop_type = 5
+          this.formmodel.full_name = this.formmodel.full_name + '-' + this.formmodel.shop_name
+          const _this = this
+          API_PartInfo.add(this.formmodel).then(() => {
+            _this.formshow = false
+            _this.$message.success('保存成功!')
+            _this.getFrameTree()
+          }).catch(err => {
+            _this.formshow = false
+            _this.$message.error(err)
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+    .el-aside {
+        margin: 8px;
+        padding: 8px;
+        border-width: 1px;
+        border-style: solid;
+        background: #fff;
+    }
+
+    .custom-tree-node {
+        flex: 1;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        font-size: 14px;
+        padding-right: 8px;
+    }
+
+    :root {
+        --icon-special-care: #f1526c;
+        --icon-primary-care: #34bfa3;
+    }
+
+    .panel-group {
+        margin-top: 0;
+
+        .card-panel-col {
+            margin-bottom: 0;
+        }
+
+        .special-care {
+            color: var(--icon-special-care) !important;
+        }
+
+        .primary-care {
+            color: var(--icon-primary-care) !important;
+        }
+
+        .card-panel {
+            height: 73px;
+            cursor: pointer;
+            font-size: 12px;
+            position: relative;
+            overflow: hidden;
+            color: #666;
+            background: #fff;
+            box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
+            border-color: rgba(0, 0, 0, .05);
+
+            &:hover {
+                .card-panel-icon-wrapper {
+                    color: #fff;
+                }
+
+                .icon-people {
+                    background: #40c9c6;
+                }
+
+                .icon-message {
+                    background: #36a3f7;
+                }
+
+                .icon-special-care {
+                    background: rgba(246, 42, 16, 0.42);
+                }
+
+                .icon-primary-care {
+                    background: var(--icon-primary-care)
+                }
+            }
+
+            .icon-people {
+                color: #40c9c6;
+            }
+
+            .icon-message {
+                color: #36a3f7;
+            }
+
+            .icon-special-care {
+                color: rgba(255, 143, 82, 0.42);
+            }
+
+            .icon-primary-care {
+                color: var(--icon-primary-care)
+            }
+
+            .card-panel-icon-wrapper {
+                float: left;
+                margin: 7px 0 0 14px;
+                padding: 6px;
+                transition: all 0.38s ease-out;
+                border-radius: 6px;
+            }
+
+            .card-panel-icon {
+                float: left;
+                font-size: 48px;
+            }
+
+            .card-panel-description {
+                float: right;
+                font-weight: bold;
+                margin: 10px 14px 10px;
+                margin-left: 0px;
+
+                .card-panel-text {
+                    line-height: 18px;
+                    color: rgba(0, 0, 0, 0.45);
+                    font-size: 16px;
+                    margin-bottom: 12px;
+                }
+
+                .card-panel-num {
+                    font-size: 20px;
+                }
+            }
+        }
+    }
+
+    @media (max-width: 550px) {
+        .card-panel-description {
+            display: none;
+        }
+
+        .card-panel-icon-wrapper {
+            float: none !important;
+            width: 100%;
+            height: 100%;
+            margin: 0 !important;
+
+            .svg-icon {
+                display: block;
+                margin: 14px auto !important;
+                float: none !important;
+            }
+        }
+    }
+</style>

+ 2 - 2
src/views/hospitalFrame/frameTreeView.vue

@@ -136,7 +136,7 @@
           <el-col :span="24">
             <!--每房床位数-->
             <el-form-item label="每房床位数" prop="beds_per_room">
-              <el-input-number v-model="createFrameModel.beds_per_room" :min="1" />
+              <el-input-number v-model="createFrameModel.beds_per_room" :min="1" :max="20" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -234,7 +234,7 @@ export default {
   },
   watch: {
     selectedNodeId(newval, old) {
-      console.log('watch',newval)
+      console.log('watch', newval)
       this.selectedNode = this.findNodeById(this.treeData, newval)
     },
     filterText(val) {

+ 1 - 0
src/views/ncs-clerk/clerkList.vue

@@ -213,6 +213,7 @@
           page_no: 1,
           sort: 'nc.member_id',
           dir: 'asc',
+          fixedCondition: 'nc.shop_id=' + this.$store.getters.partId
         },
         /** 列表数据 */
         tableData: [],

+ 0 - 1
src/views/ncs-device/components/deviceManager.vue

@@ -462,7 +462,6 @@ export default {
     deviceStatusFormatter(params) {
       if (params.value === null || params.value === undefined) return ''
       const item = this.deviceStatusTransfer.filter(p => p.value === params.value)[0]
-      console.log('item', item)
       if (item) {
         return '<span style="color:' + item.color + ';">' + item.key + '</span>'
       } else {