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

开发医院级的空间结构、设备管理、员工管理、用户管理

LAPTOP-LIQ71VDD\m 3 роки тому
батько
коміт
61e4de29d5

+ 9 - 0
src/api/ncs_clerk.js

@@ -17,6 +17,15 @@ export function getList(params) {
     headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
   })
 }
+export function getClerkList(params) {
+  return request({
+    url: '/ncs/clerk/getClerkAndMemberByShopId',
+    method: 'POST',
+    loading: true,
+    data: params,
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
+  })
+}
 export function add(params) {
   params = JSON.parse(JSON.stringify(params))
   params.password = md5(params.password)

+ 7 - 0
src/api/ncs_hospitalFrame.js

@@ -97,6 +97,13 @@ export function getFramesPartId(part_id) {
     loading: false
   })
 }
+export function getFramesHospital(hospital_id) {
+  return request({
+    url: `/ncs/frame/getFramesByHospitalId/${hospital_id}`,
+    method: 'GET',
+    loading: false
+  })
+}
 export function getFrameByType(id, deviceId, roleId) {
   return request({
     url: `/ncs/frame/getFrameByType/${id}/${deviceId}/${roleId}`,

+ 9 - 0
src/api/ncs_shop.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getShopList(partId) {
+  return request({
+    url: `/ncs/shop/getShopByHospitalId/${partId}`,
+    method: 'GET'
+  })
+}
+

+ 44 - 1
src/router/index.js

@@ -375,7 +375,50 @@ export const hospitalRoutes = [
         path: 'index',
         component: () => import('@/views/hospital/ncs_frame/frameTreeView'),
         name: 'hospital_frameTreeView',
-        meta: { title: '空间管理', icon: 'component', noCache: true }
+        meta: { title: '空间管理', icon: 'tree', noCache: true }
+      }
+    ]
+  },
+  {
+    path: '/hospital/ncs_device',
+    component: Layout,
+    redirect: '/ncs_device/index',
+    children: [
+      {
+        path: 'index',
+        // component: () => import('@/views/hospital/ncs_device/deviceManager'),
+        component: () => import('@/views/hospital/deviceManagement'),
+        name: 'hospital_deviceList',
+        meta: { title: '设备管理', icon: 'component', noCache: true }
+      }
+    ]
+  },
+  {
+    path: '/hospital/ncs_clerk',
+    component: Layout,
+    redirect: '/ncs_clerk/index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/hospital/clerkManager'),
+        name: 'hospital_clerkList',
+        meta: { title: '员工管理', icon: 'peoples', noCache: true }
+      }
+    ]
+  },
+  {
+    path: '/hospital/ncs_customer',
+    component: Layout,
+    redirect: '/ncs_customer/index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/hospital/customerManagement'),
+        name: 'hospital_customerList',
+        meta: { title: '用户管理', icon: 'el-icon-s-custom', noCache: true }
+        // component: () => uiVersion === 1 ? import('@/views/customer/patientManagement') : import('@/views/customer/customerManagement'),
+        // name: uiVersion === 1 ? 'hospital_patientList' : 'hospital_customerList',
+        // meta: { title: uiVersion === 1 ? '病人管理' : '用户管理', icon: 'el-icon-s-custom', noCache: true }
       }
     ]
   },

+ 1 - 1
src/utils/DeviceTypeEnum.js

@@ -1,4 +1,4 @@
-import createEnum from '@/utils/createEnum'
+import createEnum from '@/utils/enum/createEnum'
 
 export const DEVICE_TYPE = createEnum(
   {

+ 1 - 1
src/utils/FrameTypeEnum.js

@@ -5,7 +5,7 @@
 //   'ROOM': 4,
 //   'BED': 5
 // }
-import createEnum from '@/utils/createEnum'
+import createEnum from '@/utils/enum/createEnum'
 
 export const FRAME_TYPE = createEnum(
   {

+ 16 - 0
src/utils/enum/RoleTypeEnum.js

@@ -0,0 +1,16 @@
+import createEnum from '@/utils/enum/createEnum'
+
+export const ROLE_TYPE = createEnum(
+  {
+    PRINCIPAL: [0, '机构负责人'],
+    ADMINISTRATORS: [1, '管理员'],
+    DOCTOR: [2, '医生'],
+    NURSE: [3, '护士'],
+    WORKER: [4, '房间'],
+    NURSE_SUPERVISOR: [5, '护士主管'],
+    DIETITIAN: [6, '营养师'],
+    HOUSEKEEPER: [7, '管家'],
+    NURSE_HEAD: [8, '护士组长'],
+    LIFE_ASSISTANT: [9, '生活助理']
+  }
+)

src/utils/createEnum.js → src/utils/enum/createEnum.js


+ 3 - 2
src/views/customer/components/customerManager.vue

@@ -432,6 +432,7 @@ import * as RegExp from '@/utils/RegExp'
 import { serverUrl } from '@/utils/domain'
 import * as API_Remark from '@/api/ncs_remark'
 import * as API_User from '@/api/user'
+import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
 export default {
   name: 'CustomerManager',
   components: { ButtonCellRender, ListFilter, RadioFilter },
@@ -587,9 +588,9 @@ export default {
   },
   watch: {
     frame(val, oldvalue) {
-      if (val.type === 3) { // 科室
+      if (val.type === FRAME_TYPE.PART) { // 科室
         this.params.fixedCondition = ' part_id =' + this.frame.part_id
-      } else if (val.type === 4) { // 房间
+      } else if (val.type === FRAME_TYPE.ROOM) { // 房间
         const ids = []
         this.frame.children.forEach(item => {
           ids.push(item.id)

+ 840 - 0
src/views/hospital/clerkManager.vue

@@ -0,0 +1,840 @@
+<template>
+  <div>
+    <ag-grid-layout
+      :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"
+      row-height="50"
+      @filterChanged="filterModifed"
+      @sortChanged="gridSortChange"
+    >
+      <div slot="toolbar" class="inner-toolbar">
+        <div class="toolbar-search">
+          <en-table-search placeholder="请输入搜索关键字" @search="handlerSearch" />
+        </div>
+        <div class="toolbar-btns">
+          <el-button type="primary" @click="handleAddMember">新增</el-button>
+          <!-- <el-button type="danger" @click="batchDelete">禁用</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>
+    <!--添加会员 dialog-->
+    <el-dialog
+      title="编辑成员信息"
+      :visible.sync="dialogAddMemberVisible"
+      width="60%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <el-form ref="addMemberForm" :model="addMemberForm" :rules="addMemberRules" label-width="110px" class="formwrap">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="头像">
+              <el-upload
+                class="avatar-uploader"
+                :action="`${uploadurl}?scene=avatar`"
+                :show-file-list="false"
+                :on-success="uploaded"
+                :before-upload="handleShopLogoBefore"
+              >
+                <img v-if="imageUrl" :src="imageUrl" class="avatar">
+                <i v-else class="el-icon-plus avatar-uploader-icon" />
+              </el-upload>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="登录名" prop="uname">
+              <el-input v-model="addMemberForm.uname" :maxlength="20" />
+            </el-form-item>
+            <el-form-item label="密码" prop="password">
+              <el-input v-model="addMemberForm.password" :type="pwdType" :maxlength="20" />
+              <span class="show-pwd" @click="pwdType = pwdType === 'password' ? 'text' : 'password'">
+                <svg-icon :icon-class="pwdType === 'password' ? 'eye' : 'eye-open'" />
+              </span>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="真实姓名" prop="nickname">
+              <el-input v-model="addMemberForm.nickname" :maxlength="20" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="手机号码" prop="mobile">
+              <el-input v-model.number="addMemberForm.mobile" :maxlength="11" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="性别" class="form-item-sex">
+              <el-radio v-model="addMemberForm.sex" :label="1">男</el-radio>
+              <el-radio v-model="addMemberForm.sex" :label="0">女</el-radio>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <!--固定电话-->
+            <el-form-item label="身份证号">
+              <el-input v-model="addMemberForm.midentity" :maxlength="20" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12" />
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <!--生日-->
+            <el-form-item label="生日" prop="birthday">
+              <el-date-picker
+                v-model="addMemberForm.birthday"
+                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="12">
+            <el-form-item label="角色" prop="role_id">
+              <el-select
+                v-model="addMemberForm.role_id"
+                placeholder="请选择角色"
+                :disabled="roleTypeDisabled"
+                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-row>
+          <el-col :span="24">
+            <!--详细地址-->
+            <el-form-item label="详细地址" prop="address">
+              <el-input v-model="addMemberForm.address" :maxlength="50" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="所负责机构" prop="shop_id">
+              <el-select v-model="addMemberForm.shop_id" placeholder="选择机构" :disabled="shopDisabled" clearable>
+                <el-option v-for="(item, index) in shopOptions" :key="index" :label="item.shop_name" :value="item.shop_id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="nurseList.length > 0">
+          <el-col :span="24">
+            <el-form-item label="小组成员">
+              <div class="text item">
+                <el-row>
+                  <el-checkbox-group v-model="newCheckList">
+                    <el-col v-for="(bed,_index) in nurseClerkList" :key="_index" :xs="8" :sm="8" :md="6" :lg="6" :xl="6">
+                      <el-checkbox :label="bed.clerk_id" @change="handleCheckboxChanged(bed)">
+                        <span v-if="bed.group_id && !bed.checked" style="color: #13ce66">{{ bed.clerk_name }}  <span style="color: #302db4">{{ bed.group_name }}</span></span>
+                        <span v-else>{{ bed.clerk_name }}</span>
+                      </el-checkbox>
+                    </el-col>
+                  </el-checkbox-group>
+                  <el-col v-for="(bed,_index) in nurseClerkList" :key="_index" :xs="8" :sm="8" :md="6" :lg="6" :xl="6">
+                    <!--                    <el-checkbox v-model="bed.checked">-->
+                    <!--                      <span v-if="bed.group_id && !bed.checked" style="color: #13ce66">{{ bed.clerk_name }}  <span style="color: #302db4">{{ bed.group_name }}</span></span>-->
+                    <!--                      <span v-else>{{ bed.clerk_name }}</span>-->
+                    <!--                    </el-checkbox>-->
+                  </el-col>
+                </el-row>
+              </div>
+            </el-form-item>
+
+          </el-col>
+        </el-row>
+
+
+        <!--        <el-row>-->
+        <!--          <el-col :span="12">-->
+        <!--            &lt;!&ndash;地区&ndash;&gt;-->
+        <!--            <el-form-item label="地区" prop="region" class="form-item-region">-->
+        <!--              <en-region-picker :api="MixinRegionApi" @changed="(object) => { addMemberForm.region = object.last_id }"/>-->
+        <!--            </el-form-item>-->
+        <!--          </el-col>-->
+        <!--          <el-col :span="12">-->
+
+        <!--            &lt;!&ndash;邮箱&ndash;&gt;-->
+        <!--            <el-form-item label="邮箱" prop="email">-->
+        <!--              <el-input v-model="addMemberForm.email"></el-input>-->
+        <!--            </el-form-item>-->
+        <!--          </el-col>-->
+        <!--        </el-row>-->
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogAddMemberVisible = false">取 消</el-button>
+        <el-button type="primary" @click="submitAddMemberForm('addMemberForm')">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <template>
+      <image-viewer v-if="showViewer" :on-close="closeViewer" :url-list="srcList" />
+    </template>
+  </div>
+</template>
+
+<script>
+import { serverUrl } from '@/utils/domain'
+import * as clerk_API from '@/api/ncs_clerk'
+import * as shop_API from '@/api/ncs_shop'
+import * as RegExp from '@/utils/RegExp'
+import { AG_GRID_LOCALE_CN } from '@/utils/AgGridVueLocaleCn'
+import ButtonCellRender from '@/components/AgGridCellRender/ButtonCellRender'
+import AgGridImg from '@/components/AgGridImg/AgGridImg'
+import ImageViewer from 'element-ui/packages/image/src/image-viewer'
+import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
+import { ROLE_TYPE } from '@/utils/enum/RoleTypeEnum'
+let prevOverflow = ''
+
+export default {
+  name: 'CareDoctorManager',
+  components: { ButtonCellRender, AgGridImg, ImageViewer, RadioFilter },
+  props: {
+    partId: {
+      type: Number,
+      default: 0
+    }
+  },
+  data: function() {
+    return {
+      uploadurl: serverUrl + '/ncs/upload/uploadFile',
+      imageUrl: '',
+      /** 列表loading状态 */
+      loading: false,
+      /** 列表参数 */
+      params: {
+        page_size: 10,
+        page_no: 1,
+        sort: 'nc.member_id',
+        dir: 'asc'
+      },
+      /** 列表数据 */
+      tableData: [],
+      pageData: [],
+      /** 添加会员弹出框指示 */
+      dialogAddMemberVisible: false,
+      /** 添加会员 表单数据 */
+      addMemberForm: {},
+      /** 选中行数据 */
+      multipleSelection: [],
+      rolesOptions: [],
+      shopOptions: [],
+      /**
+       * 角色选择,如果是机构负责人无法选择
+       */
+      roleTypeDisabled: false,
+      /**
+       * 机构选择,如果是机构负责人无法选择
+       */
+      shopDisabled: false,
+      /** 添加会员 表单规则 */
+      addMemberRules: {
+        uname: [
+          this.MixinRequired('请输入用户名'),
+          { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
+        ],
+        password: [
+          this.MixinRequired('请输入密码!'),
+          {
+            validator: (rule, value, callback) => {
+              if (!RegExp.password.test(value)) {
+                callback(new Error('密码格式有误,密码只能包含字母数字和!#$%^&*.~,字符,长度为6-20位'))
+              } else {
+                callback()
+              }
+            },
+            trigger: 'blur'
+          }
+        ],
+        nickname: [
+          this.MixinRequired('请输入真实姓名'),
+          { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
+        ],
+        role_id: [this.MixinRequired('请选择角色')],
+        mobile: [
+          this.MixinRequired('请输入手机号码!'),
+          {
+            validator: (rule, value, callback) => {
+              if (!RegExp.mobile.test(value)) {
+                callback(new Error('手机格式格式有误'))
+              } else {
+                callback()
+              }
+            },
+            trigger: 'blur'
+          }
+        ],
+        address: [
+          { max: 50, message: '最长50个字符', trigger: 'blur' }
+        ],
+        shop_id: [
+          { required: true, message: '请选择机构', trigger: 'blur' }
+        ]
+      },
+      pwdType: 'password',
+      srcList: ['1'],
+      columnDefs: null, // 新表格
+      defaultColDef: null,
+      gridOptions: null,
+      gridApi: null,
+      columnApi: null,
+      localeText: AG_GRID_LOCALE_CN,
+      rowSelection: null,
+      showViewer: false,
+      sexTransfer: [
+        { key: '男', value: 1 },
+        { key: '女', value: 0 }
+      ],
+      roleId: null,
+      roleZzId: null,
+      newCheckList: [],
+      oldCheckList: [],
+      nurseList: [],
+      shopId: null,
+      nurseClerkList: []
+    }
+  },
+  computed: {
+    tableHeight() {
+      return this.mainAreaHeight - 130
+    }
+  },
+  watch: {
+    partId(val, oldvalue) {
+      if (val === null) {
+        this.shopId = this.$store.getters.partId
+      } else {
+        this.shopId = val
+      }
+      this.params.fixedCondition = 'nc.shop_id=' + this.shopId
+      this.GET_MemberList()
+    }
+  },
+  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: 'face', sortable: true, filter: false, width: 70,
+        cellRendererFramework: 'AgGridImg',
+        cellRendererParams: param => {
+          return {
+            onClick: this.lookBigImg,
+            face: 'face'
+          }
+        }
+      },
+      { headerName: '登录名', field: 'uname', sortable: true, filter: true, minWidth: 170 },
+      { headerName: '真实名字', field: 'clerk_name', sortable: true, filter: true, minWidth: 120 },
+      { headerName: '性别', field: 'sex', sortable: true, valueFormatter: this.formatterSex, width: 100, filterFramework: 'RadioFilter',
+        filterParams: {
+          listData: this.sexTransfer
+        }
+      },
+      { headerName: '手机', field: 'mobile', sortable: true, filter: true, minWidth: 170 },
+      { headerName: '角色', field: 'role_name', sortable: true, filter: false, valueFormatter: this.formatterRole, width: 120 },
+      { headerName: '操作', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.handlerEdit,
+            label: '编辑',
+            buttonType: 'primary',
+            buttonSize: 'mini'
+          }
+        },
+        filter: false,
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: 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.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
+    if (this.partId === 0) {
+      this.shopId = this.$store.getters.partId
+    } else {
+      this.shopId = this.partId
+    }
+    this.params.fixedCondition = 'ns.shop_id = ' + this.shopId + ' or ns.parent_id = ' + this.shopId
+    this.GET_MemberList()
+    this.getShopOptions(this.shopId)
+  },
+  activated() {
+    this.GET_MemberList()
+  },
+  methods: {
+    /** 选择行变化时,记录选中的行数据 */
+    selectFun(val) {
+      this.multipleSelection = val
+    },
+    /** 加载用户列表 */
+    GET_MemberList() {
+      this.loading = true
+      this.gridApi.showLoadingOverlay()
+      this.gridApi.sizeColumnsToFit()
+      clerk_API.getClerkList(this.params).then(response => {
+        this.loading = false
+        const size = 0
+        // response.data.forEach((item, index) => {
+        //   if (item.founder === 1) {
+        //     delete response.data[index]
+        //     size++
+        //   }
+        // })
+        this.tableData = response.data
+        this.pageData = {
+          page_no: response.page_no,
+          page_size: response.page_size,
+          data_total: response.data_total - size
+        }
+      }).catch(() => {
+        this.loading = false
+      })
+    },
+    /** 处理搜索 **/
+    handlerSearch(keywords) {
+      this.params.query = keywords
+      this.GET_MemberList()
+    },
+    /** 单条数据删除处理 */
+    handlerDelete(ids) {
+      this.$confirm('你确定要禁用此用户?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        clerk_API.remove(ids).then(
+          response => {
+            this.GET_MemberList()
+            this.$message({
+              type: 'success',
+              message: '已禁用!'
+            })
+          }
+        ).catch(response => {
+          this.$message({
+            type: 'info',
+            message: response.message
+          })
+        })
+      }).catch((response) => {
+        this.$message({
+          type: 'info',
+          message: '已取消禁用'
+        })
+      })
+    },
+    getRoles(param) {
+      // 获取角色
+      clerk_API.getRoles(param).then(res => {
+        this.rolesOptions = res.data
+        const nurseZz = res.data.find(item => item.role_name === '护士组长')
+        if (nurseZz) {
+          this.roleZzId = nurseZz.role_id
+          const nurse = res.data.find(item => item.role_name === '护士')
+          if (nurse) {
+            this.roleId = nurse.role_id
+          }
+        }
+      })
+    },
+    /** 批量数据删除处理(删除选中的行) */
+    batchDelete: function() {
+      if (this.multipleSelection.length === 0) {
+        this.$alert('没有选择任何记录!', '系统提示', {
+          confirmButtonText: '确定',
+          callback: action => {
+          }
+        })
+      } else {
+        const ids = []
+        this.multipleSelection.forEach(function(item) {
+          ids.push(item.member_id)
+        })
+        this.handlerDelete(ids.join(','))
+      }
+    },
+    /** 性别格式化 */
+    formatterSex(row) {
+      return row.data.sex === 1 ? '男' : row.data.sex === 0 ? '女' : '未知'
+    },
+    formatterRole(row) {
+      if (row.data.founder === 1) {
+        return '机构负责人'
+      } else {
+        return row.data.role_name
+      }
+    },
+    /** 提交添加会员表单 */
+    submitAddMemberForm(formName) {
+      const _this = this
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          const params = this.MixinClone(this.addMemberForm)
+          if (isNaN(params.birthday)) {
+            params.birthday = null
+          } else {
+            params.birthday = parseInt(params.birthday / 1000)
+          }
+          if (this.imageUrl) {
+            params.face = this.imageUrl
+          }
+          if (params.member_id) {
+            if (this.roleZzId === params.role_id) {
+              const addIds = this.newCheckList.filter(function(val) { return _this.oldCheckList.indexOf(val) === -1 })
+              console.log('addIds=', addIds)
+              const delIds = this.oldCheckList.filter(function(val) { return _this.newCheckList.indexOf(val) === -1 })
+              console.log('delIds=', delIds)
+              const data = {
+                clerkId: params.clerk_id,
+                addIds: addIds.join(','),
+                delIds: delIds.join(',')
+              }
+              console.log('data==', data)
+              clerk_API.updateParentById(data)
+            }
+            clerk_API.update(params.clerk_id, params).then(response => {
+              this.dialogAddMemberVisible = false
+              this.imageUrl = null
+              this.GET_MemberList()
+            })
+          } else {
+            clerk_API.add(params).then(response => {
+              this.dialogAddMemberVisible = false
+              this.imageUrl = null
+              this.GET_MemberList()
+            })
+          }
+        } else {
+          this.$message.error('表单填写有误,请检查!')
+          return false
+        }
+      })
+    },
+    /** 添加会员 */
+    handleAddMember() {
+      this.nurseList = []
+      this.imageUrl = null
+      this.addMemberForm = { sex: 1 }
+      this.addMemberRules.password[0].required = true
+      this.dialogAddMemberVisible = true
+      this.roleTypeDisabled = false
+      this.shopDisabled = false
+    },
+    /** 编辑用户 */
+    handlerEdit(row) {
+      this.addMemberForm = Object.assign({}, row)
+      this.nurseList = []
+      if (this.roleZzId && this.roleZzId === row.role_id) { // 只有护士组长才能编辑小组成员
+        // this.getNurseByRoleId(row.member_id)
+        this.getNurseByRoleId(row.member_id, this.addMemberForm.shop_id)
+        this.shopDisabled = false
+      } else if (row.role_id === ROLE_TYPE.PRINCIPAL) {
+        this.roleTypeDisabled = true
+        this.shopDisabled = true
+      } else {
+        this.roleTypeDisabled = false
+        this.shopDisabled = false
+      }
+      this.imageUrl = row.face
+      delete this.addMemberForm.password
+      this.addMemberRules.password[0].required = false
+      if (row.birthday) {
+        this.addMemberForm.birthday *= 1000
+      }
+      this.dialogAddMemberVisible = true
+    },
+    // getNurseByRoleId(id) {
+    getNurseByRoleId(id, shop_id) {
+      const _this = this
+      this.newCheckList = []
+      this.oldCheckList = []
+
+      // clerk_API.getNurseByRoleId(_this.roleId, this.shopId).then(r => {
+      clerk_API.getNurseByRoleId(_this.roleId, shop_id).then(r => {
+        _this.nurseList = r
+        // _this.getNurseIds(id)
+        _this.getNurseIds(id, shop_id)
+        // r.forEach(item => {
+        //   if (item.parent_id=== id) {
+        //     _this.newCheckList.push(item.clerk_id)
+        //     _this.oldCheckList.push(item.clerk_id)
+        //   }
+        // })
+      })
+    },
+    // getNurseIds(id) {
+    getNurseIds(id, shop_id) {
+      const _this = this
+      // clerk_API.getNurseIdsByPartId(this.shopId).then(r => {
+      clerk_API.getNurseIdsByPartId(shop_id).then(r => {
+        r.forEach(item => {
+          _this.nurseList.forEach(t => {
+            if (t.clerk_id === item.nurse_id) {
+              t.group_name = item.clerk_name
+              t.group_id = item.member_id
+              if (item.member_id === id) {
+                t.checked = true
+                _this.oldCheckList.push(item.nurse_id)
+                _this.newCheckList.push(item.nurse_id)
+              }
+            }
+          })
+        })
+        _this.nurseClerkList = _this.nurseList
+      })
+    },
+    handleCheckboxChanged(item) {
+      item.checked = !item.checked
+    },
+    /** 分页大小发生改变 */
+    handlePageSizeChange(size) {
+      this.params.page_size = size
+      this.GET_MemberList()
+    },
+
+    /** 分页页数发生改变 */
+    handlePageCurrentChange(page) {
+      this.params.page_no = page
+      this.GET_MemberList()
+    },
+    /** 图片上传之前的校验 */
+    handleShopLogoBefore(file) {
+      return new Promise((resolve, reject) => {
+        const isImg = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif'
+        const isLt2M = file.size / 1024 / 1024 < 2
+
+        if (!isImg) {
+          this.$message.error('上传头像图片只能是 JPG、PNG、GIF 格式!')
+          reject()
+        }
+        if (!isLt2M) {
+          this.$message.error('上传头像图片大小不能超过 2MB!')
+          reject()
+        }
+
+        const reader = new FileReader()
+        reader.onload = (event) => {
+          const image = new Image()
+          image.onload = () => {
+            const width = image.width
+            const height = image.height
+            if (width > 500 || width < 100) {
+              this.$message.error('图片宽度必须在100~500之间,宽高比为1:1!')
+              reject()
+            }
+            if (width !== height) {
+              this.$message.error('请上传宽高比为1:1的图片')
+              reject()
+            }
+            if (height > 500 || height < 100) {
+              this.$message.error('图片高度必须在100~500之间!')
+              reject()
+            }
+            resolve()
+          }
+          image.src = event.target.result
+        }
+        reader.readAsDataURL(file)
+      })
+    },
+
+    /** 上传成功后的钩子 更换图片 置空存储数组*/
+    uploaded(res) {
+      this.imageUrl = serverUrl + '/' + res
+      this.addMemberForm.face = this.imageUrl
+    },
+    lookBigImg(row) {
+      this.srcList = []
+      this.srcList.push(row.face)
+      prevOverflow = document.body.style.overflow
+      document.body.style.overflow = 'hidden'
+      this.showViewer = true
+    },
+    closeViewer() {
+      document.body.style.overflow = prevOverflow
+      this.showViewer = false
+    },
+    filterModifed(param) {
+      const model = param.api.getFilterModel()
+      this.params.filter = JSON.stringify(model)
+      this.GET_MemberList()
+    },
+    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_MemberList()
+    },
+    getShopOptions(part_id) {
+      shop_API.getShopList(part_id).then(res => {
+        this.shopOptions = res
+      })
+    }
+
+  }
+
+}
+</script>
+
+<style type="text/scss" scoped>
+
+  .show-pwd {
+    position: absolute;
+    top: 0;
+    right: 10px;
+    cursor: pointer;
+  }
+
+  .formwrap /deep/ .el-tabs__content {
+    overflow: visible !important;
+  }
+
+  .formwrap /deep/ .app-address-title {
+    height: 32px !important;
+    line-height: 32px !important;
+  }
+
+  .formwrap /deep/ .app-address {
+    width: 100% !important;
+  }
+
+  /deep/ div.toolbar {
+    height: 70px;
+    padding: 20px 0;
+  }
+
+  /deep/ .el-date-editor {
+    width: 100%;
+  }
+
+  /deep/ .el-table {
+    width: 100%;
+    overflow-x: scroll;
+
+    & td:not(.is-left) {
+      text-align: center;
+    }
+  }
+
+  .el-tag + .el-tag {
+    margin-left: 10px;
+    margin-bottom: 10px;
+  }
+
+  /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: 110px;
+    height: 110px;
+    line-height: 110px;
+    text-align: center;
+  }
+
+  /deep/ .avatar {
+    width: 110px;
+    height: 110px;
+    display: block;
+  }
+
+</style>

+ 22 - 0
src/views/hospital/customerManagement.vue

@@ -0,0 +1,22 @@
+<template>
+  <div>
+    <customer-manager :frame="frame" />
+  </div>
+</template>
+
+<script>
+import CustomerManager from './ncs_customer/customerManager'
+export default {
+  name: 'CustomerManagement',
+  components: { CustomerManager },
+  data() {
+    return {
+      frame: {}
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 22 - 0
src/views/hospital/deviceManagement.vue

@@ -0,0 +1,22 @@
+<template>
+  <div>
+    <device-manager :frame="frame" />
+  </div>
+</template>
+
+<script>
+import DeviceManager from './ncs_device/deviceManager'
+export default {
+  name: 'DeviceManagement',
+  components: { DeviceManager },
+  data() {
+    return {
+      frame: {}
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 130 - 35
src/views/hospital/ncs_customer/customerManager.vue

@@ -138,6 +138,13 @@
                         <el-input v-model="formmodel.nickname" clearable placeholder="请输入用户其他称呼" :maxlength="20" />
                       </el-form-item>
                     </el-col>
+                    <el-col :span="12">
+                      <el-form-item label="入住床位" prop="frame_id">
+                        <el-select v-model="formmodel.frame_id" :disabled="bedSelectabled" placeholder="请选择床位">
+                          <el-option v-for="(item,index) in emptyBeds" :key="index" :label="item.full_name" :value="item.id" />
+                        </el-select>
+                      </el-form-item>
+                    </el-col>
                   </el-row>
                   <el-form-item label="用户情况简述">
                     <el-input
@@ -351,14 +358,57 @@
     <!-- 用户换床-->
     <el-dialog :visible.sync="changeBedFormVisible" title="用户换床">
       <el-form ref="changeBedForm" :model="changeBedFormModel" :rules="changeBedRules" label-width="120px">
-        <el-form-item label="当前病床:"><svg-icon icon-class="bed" style="color: #9aaabf;margin-top: 5px" />{{ changeBedFormModel.current_bed }}</el-form-item>
-        <el-form-item label="可换病床:">
-          <el-radio-group v-model="changeBedFormModel.frame_id">
-            <el-radio v-for="(item, index) in emptyBeds" :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-row>
+          <el-col :span="12">
+            <el-form-item label="用户姓名" prop="named">
+              <el-input v-model="changeBedFormModel.named" clearable placeholder="请输入姓名" readonly :maxlength="20" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="入住编号">
+              <el-input v-model="changeBedFormModel.card_no" clearable placeholder="请输入病人编号" readonly :maxlength="20" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="性别" class="form-item-sex">
+              <el-radio v-model="changeBedFormModel.sex" :label="0" disabled>女</el-radio>
+              <el-radio v-model="changeBedFormModel.sex" :label="1" disabled>男</el-radio>
+              <el-radio v-model="changeBedFormModel.sex" :label="2" disabled>未知</el-radio>
+            </el-form-item>
+          </el-col>
+
+          <el-col :span="12">
+            <el-form-item label="年龄" prop="age">
+              <el-input v-model="changeBedFormModel.age" clearable :maxlength="4" readonly placeholder="请输入年龄">
+                <el-select slot="append" v-model="changeBedFormModel.age_unit" disabled 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="12">
+            <el-form-item label="当前床位" prop="nickname">
+              <el-input v-model="changeBedFormModel.current_bed" clearable readonly :maxlength="20" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="换到床位" prop="frame_id">
+              <el-select v-model="changeBedFormModel.frame_id" clearable filterable placeholder="请选择床位">
+                <el-option v-for="(item,index) in emptyBeds" :key="index" :label="item.full_name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+
+        </el-row>
+
         <el-form-item>
           <el-button type="primary" class="save" @click="handleChangeBedSubmit('changeBedForm')">确定</el-button>
         </el-form-item>
@@ -382,6 +432,8 @@ import { serverUrl } from '@/utils/domain'
 import * as API_Remark from '@/api/ncs_remark'
 import * as API_User from '@/api/user'
 import * as API_hospitalFrame from '@/api/ncs_hospitalFrame'
+import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
+import * as API_Frame from '@/api/ncs_hospitalFrame'
 export default {
   name: 'CustomerManager',
   components: { ButtonCellRender, ListFilter, RadioFilter },
@@ -489,7 +541,7 @@ export default {
       /** 空床位 **/
       emptyBeds: [],
       /** frame 是否为空床位 */
-      isEmptyFrame: false,
+      isEmptyFrame: true,
       rules: {
         named: [
           this.MixinRequired('请输入用户姓名!')
@@ -536,11 +588,11 @@ export default {
   },
   watch: {
     frame(val, oldvalue) {
-      if (val.type === 1) { // 医院
+      if (val.type === FRAME_TYPE.HOSPITAL) { // 医院
         this.params.fixedCondition = '1=1'
-      } else if (val.type === 3) { // 科室
+      } else if (val.type === FRAME_TYPE.PART) { // 科室
         this.params.fixedCondition = ' part_id =' + this.frame.part_id
-      } else if (val.type === 4) { // 房间
+      } else if (val.type === FRAME_TYPE.ROOM) { // 房间
         const ids = []
         this.frame.children.forEach(item => {
           ids.push(item.id)
@@ -554,6 +606,7 @@ export default {
         this.params.fixedCondition = ' frame_id = ' + this.frame.id
       }
       this.getList()
+      this.infoChanged()
     }
   },
   beforeMount() {
@@ -570,7 +623,10 @@ export default {
         resizable: false,
         valueGetter: this.hashValueGetter
       },
+      // { headerName: 'ID', field: 'id', sortable: true, filter: 'agNumberColumnFilter', width: 100 },
       { headerName: '用户姓名', field: 'named', sortable: true, filter: 'agTextColumnFilter', width: 160 },
+      { headerName: '昵称', field: 'nickname', sortable: true, filter: 'agTextColumnFilter', width: 130 },
+      { headerName: '入住床位', field: 'full_name', sortable: true, filter: 'agTextColumnFilter' },
       { headerName: '当前状态', field: 'status', sortable: true, filterFramework: 'RadioFilter', width: 130,
         filterParams: {
           listData: this.customerStatusTransfer
@@ -584,27 +640,35 @@ export default {
           listData: this.sexTransfer
         },
         cellRenderer: this.sexRenderer },
-      { headerName: '入住床位', field: 'full_name', sortable: true, filter: 'agTextColumnFilter', valueFormatter: this.fullNameFormatter },
-      { headerName: '年龄', field: 'age', sortable: true, filter: 'agNumberColumnFilter', valueFormatter: this.formatterAge, width: 130 },
-      { headerName: '手机号码', field: 'mobile', sortable: true, filter: 'agTextColumnFilter' },
-      { headerName: '住院时间', field: 'in_date', valueFormatter: this.formatterDate, sortable: true, minWidth: 220, filter: 'agDateColumnFilter',
-        filterParams: {
-          comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
-            const celldate = unixToDate(cellValue, 'yyyy-MM-dd 00:00:00')
-            return (new Date(celldate).getTime() / 1000) - (filterLocalDateAtMidnight.getTime() / 1000)
-          }
+
+      { headerName: '生日', field: 'birthday', sortable: true, filter: 'agDateColumnFilter', valueFormatter: this.unixDateFormatter, filterParams: {
+        comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
+          const celldate = unixToDate(cellValue, 'yyyy-MM-dd 00:00:00')
+          return (new Date(celldate).getTime() / 1000) - (filterLocalDateAtMidnight.getTime() / 1000)
         }
+      }},
+      { headerName: '年龄', field: 'age', sortable: true, filter: 'agNumberColumnFilter', width: 130
+      },
+      { headerName: '年龄单位', field: 'age_unit', sortable: true, filter: 'agTextColumnFilter', width: 130
       },
       { headerName: '入住编号', field: 'card_no', sortable: true, filter: 'agTextColumnFilter' },
       { headerName: '身份证件类型', field: 'id_type', sortable: true, filter: 'agTextColumnFilter' },
       { headerName: '证件号码', field: 'id_no', sortable: true, filter: 'agNumberColumnFilter', width: 160 },
-      { headerName: '生日', field: 'birthday', sortable: true, filter: 'agDateColumnFilter', valueFormatter: this.unixDateFormatter, filterParams: {
+      { headerName: '手机号码', field: 'mobile', sortable: true, filter: 'agTextColumnFilter' },
+      { headerName: '家庭住址', field: 'address', sortable: true, filter: 'agTextColumnFilter', width: 260 },
+
+      { headerName: '入住时间', field: 'in_date', sortable: true, filter: 'agDateColumnFilter', valueFormatter: this.unixDateFormatter, filterParams: {
+        comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
+          const celldate = unixToDate(cellValue, 'yyyy-MM-dd 00:00:00')
+          return (new Date(celldate).getTime() / 1000) - (filterLocalDateAtMidnight.getTime() / 1000)
+        }
+      }},
+      { headerName: '离开时间', field: 'out_date', sortable: true, filter: 'agDateColumnFilter', valueFormatter: this.unixDateFormatter, filterParams: {
         comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
           const celldate = unixToDate(cellValue, 'yyyy-MM-dd 00:00:00')
           return (new Date(celldate).getTime() / 1000) - (filterLocalDateAtMidnight.getTime() / 1000)
         }
       }},
-      { headerName: '家庭住址', field: 'address', sortable: true, filter: 'agTextColumnFilter', width: 260 },
       { headerName: '编辑', field: 'id',
         cellRendererFramework: 'ButtonCellRender',
         cellRendererParams: {
@@ -661,7 +725,7 @@ export default {
             label: '删除',
             buttonType: 'danger',
             buttonSize: 'mini',
-            disabled: param.data['member_name'] === 'superadmin' || param.data['status'] === 0
+            disabled: param.data['member_name'] === 'superadmin'
           }
         },
         pinned: 'right',
@@ -696,11 +760,23 @@ export default {
         }
       ]
     })
+    this.getEmptyBeds()
   },
   methods: {
     windowResize() {
       this.$set(this, 'mainAreaHeight', Number(document.documentElement.clientHeight) - 84)
     },
+    getEmptyBeds() {
+      return new Promise((resolve, reject) => {
+        API_Frame.getSickbedByPartId(this.$store.getters.partId).then(res => {
+          this.emptyBeds = [...res]
+          resolve()
+        }).catch(err => {
+          this.$message.error('获取空床位:' + err)
+          reject()
+        })
+      })
+    },
     /** 分页大小发生改变 */
     handlePageSizeChange(size) {
       this.params.page_size = size
@@ -723,15 +799,15 @@ export default {
           page_size: response.page_size,
           data_total: response.data_total
         }
-        if (this.frame.type === 5) { // 空间机构为床位
-          if (this.rowData.length > 0) {
-            this.isEmptyFrame = this.rowData.filter(p => p.status === 0).length === 0
-          } else {
-            this.isEmptyFrame = true
-          }
-        } else {
-          this.isEmptyFrame = false
-        }
+        // if (this.frame.type === FRAME_TYPE.BED) { // 空间机构为床位
+        //   if (this.rowData.length > 0) {
+        //     this.isEmptyFrame = this.rowData.filter(p => p.status === 0).length === 0
+        //   } else {
+        //     this.isEmptyFrame = true
+        //   }
+        // } else {
+        //   this.isEmptyFrame = false
+        // }
       }).catch(err => {
         this.$message.error(err)
       })
@@ -991,6 +1067,8 @@ export default {
       this.formmodel = {
         ...row
       }
+      // 编辑时把当前用户床位加入到空床位,否则会显示一个床位Id号
+      this.emptyBeds.push({ id: this.formmodel.frame_id, full_name: this.formmodel.full_name })
       if (this.formmodel.in_date) {
         this.$set(this.formmodel, 'in_date', this.formmodel.in_date * 1000)
       }
@@ -1017,18 +1095,24 @@ export default {
           this.$emit('saved')
           this.getList()
         })
+      }).catch(() => {
+        this.$message.info('取消操作!')
       })
     },
     /** 换床 **/
     handleChangeBed(row) {
       this.changeBedFormVisible = true
       this.changeBedFormModel = {
-        id: row.id,
+        ...row,
+        // id: row.id,
         current_bed: row.full_name,
         frame_id: null,
         status: row.status
       }
-      API_hospitalFrame.getSickbedByPartId(row.part_id).then(res => {
+      /** 只替换到当前科室 */
+      // API_hospitalFrame.getSickbedByPartId(row.part_id).then(res => {
+      /** 替换到所有科室下 */
+      API_hospitalFrame.getSickbedByPartId(this.$store.getters.partId).then(res => {
         this.emptyBeds = res
       })
     },
@@ -1162,6 +1246,17 @@ export default {
       } else {
         return '未知'
       }
+    },
+    /** 信息变化后操作,如床位状态改变,传入的空间结构变化了 **/
+    infoChanged() {
+      this.getEmptyBeds().then(() => {
+        // 传入结构是否为空床位
+        if (Object.keys(this.frame).length > 0) {
+          this.isEmptyFrame = this.emptyBeds.filter(p => p.id === this.frame.id).length > 0
+        }
+      }).catch(() => {
+
+      })
     }
   }
 }

+ 40 - 27
src/views/hospital/ncs_device/deviceManager.vue

@@ -114,9 +114,16 @@
           </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="设备位置">
-              <span>{{ deviceModel.full_name }}</span>
+            <el-form-item label="设备位置" prop="frame_id">
+              <el-select v-model="deviceModel.frame_id" filterable :disabled="frameSelectabled" placeholder="请选择安装位置">
+                <el-option v-for="(item,index) in typeFrames" :key="index" :label="item.full_name" :value="item.id" />
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -182,9 +189,10 @@ 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'
-import { DEVICE_TYPE } from '@/utils/DeviceTypeEnum'
+import { DEVICE_TYPE } from '@/utils/enum/DeviceTypeEnum'
 import * as API_Frame from '@/api/ncs_hospitalFrame'
-import { FRAME_TYPE } from '@/utils/FrameTypeEnum'
+import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
+import * as shop_API from '@/api/ncs_shop'
 export default {
   name: 'DeviceManager',
   components: { ButtonCellRender, ListFilter, RadioFilter },
@@ -249,9 +257,7 @@ export default {
           { required: true, message: '请选择总线转换盒', trigger: 'blur' }
         ]
       },
-      partFrameList: [],
-      roomFrameList: [],
-      bedFrameList: [],
+      partFrames: [],
       typeFrames: [],
       /** 设备类型转换数组 **/
       deviceTypeTransfer: [
@@ -411,6 +417,7 @@ export default {
         }
       ]
     })
+    this.getTypeFrame(this.$store.getters.partId)
   },
   methods: {
     /** 加载列表数据 */
@@ -427,19 +434,21 @@ export default {
       }).catch(err => {
         this.$message.error(err)
       })
-      this.getTypeFrame()
+      this.getTypeFrame(this.$store.getters.partId)
+      this.getShopOptions(this.$store.getters.partId)
     },
-    getTypeFrame() {
-      API_Frame.getFrameByPartIdAndFrameType(this.$store.getters.partId, FRAME_TYPE.PART).then(res => {
-        this.partFrameList = [...res]
-      })
-      API_Frame.getFrameByPartIdAndFrameType(this.$store.getters.partId, FRAME_TYPE.ROOM).then(res => {
-        this.roomFrameList = [...res]
-      })
-      API_Frame.getFrameByPartIdAndFrameType(this.$store.getters.partId, FRAME_TYPE.BED).then(res => {
-        this.bedFrameList = [...res]
+    getTypeFrame(hospital_id) {
+      // API_Frame.getFramesPartId(partId).then(res => {
+      API_Frame.getFramesHospital(hospital_id).then(res => {
+        this.partFrames = [...res]
       })
     },
+    /** 将partFrames做分割 */
+    getFramesByType(device_type) {
+      if (this.partFrames != null) {
+        this.typeFrames = this.partFrames.filter(item => item.type === device_type)
+      }
+    },
     /**
      * 过滤状态发生变化,发送到服务器检索数据
      */
@@ -508,7 +517,7 @@ export default {
       }
     },
     fullNameFormatter(params) {
-      if (params.data.type === 3) {
+      if (params.data.type === FRAME_TYPE.PART) {
         return params.value
       } else {
         return params.data.shop_name + '-' + params.value
@@ -545,13 +554,12 @@ export default {
     /** 设备类型选中变化  **/
     deviceTypeChange(val) {
       this.deviceTypeChangeToFrameTypeChange(val)
-      this.$set(this.deviceModel, 'frame_id', null)
       if (val === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
           val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
           val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT ||
           val === DEVICE_TYPE.EMERGENCY_BUTTON) { // 模拟设备不需要mac地址
         this.deviceRules.eth_mac[0].required = false
-        // this.deviceRules.eth_mac[1].pattern = null
+        this.deviceRules.eth_mac[1].pattern = null
       } else if (val === DEVICE_TYPE.REMOTE_CONTROL) {
         this.deviceRules.eth_mac[1].pattern = null
         this.deviceRules.eth_mac[0].required = true
@@ -575,20 +583,19 @@ export default {
           val === DEVICE_TYPE.TRANSFER_DEVICE ||
           val === DEVICE_TYPE.INFORMATION_BOARD ||
           val === DEVICE_TYPE.RS485_TRANSFER) {
-        // this.getTypeFrame(this.$store.getters.partId, FRAME_TYPE.PART)
-        this.typeFrames = this.partFrameList
+        this.getFramesByType(FRAME_TYPE.PART)
       } else if (val === DEVICE_TYPE.DOOR_DEVICE ||
           val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
           val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT ||
           val === DEVICE_TYPE.BEACON) {
-        // this.getTypeFrame(this.$store.getters.partId, FRAME_TYPE.ROOM)
-        this.typeFrames = this.roomFrameList
+        this.getFramesByType(FRAME_TYPE.ROOM)
       } else if (val === DEVICE_TYPE.DIGIT_BED_DEVICE ||
           val === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
           val === DEVICE_TYPE.REMOTE_CONTROL ||
           val === DEVICE_TYPE.CELL_PHONE) {
-        // this.getTypeFrame(this.$store.getters.partId, FRAME_TYPE.BED)
-        this.typeFrames = this.bedFrameList
+        this.getFramesByType(FRAME_TYPE.BED)
+      } else {
+        this.typeFrames = this.partFrames
       }
     },
     /** 添加设备事件 **/
@@ -611,12 +618,13 @@ export default {
       this.deviceDialogVisible = true
       this.deviceTypeDisabled = false // 新增设备可以选择设备类型
       this.deviceModel.full_name = this.frame.full_name
+      this.typeFrames = this.partFrames
     },
     /** 修改设备  **/
     handleEdit(params) {
       this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
       this.getDevices(this.$store.getters.partId)
-      console.log('param', params)
+      this.deviceTypeChangeToFrameTypeChange(params.device_type)
       this.hasRoleId = params.device_type === DEVICE_TYPE.NURSE_WATCH
       this.hasAudioId = params.device_type === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
           params.device_type === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
@@ -681,6 +689,11 @@ export default {
       API_Device.getDeviceByType(partId, DEVICE_TYPE.RS485_TRANSFER).then(response => {
         this.rs485Options = response
       })
+    },
+    getShopOptions(part_id) {
+      shop_API.getShopList(part_id).then(res => {
+        this.shopOptions = res
+      })
     }
   }
 }

+ 60 - 29
src/views/hospital/ncs_frame/frameTreeView.vue

@@ -8,13 +8,13 @@
             placeholder="输入关键字进行过滤"
             clearable
           />
-<!--          <el-button-->
-<!--            type="text"-->
-<!--            size="mini"-->
-<!--            style="margin-left: 10px;color: #67C23A"-->
-<!--            @click="quickCreateFrame"-->
-<!--          >快速创建-->
-<!--          </el-button>-->
+          <!--          <el-button-->
+          <!--            type="text"-->
+          <!--            size="mini"-->
+          <!--            style="margin-left: 10px;color: #67C23A"-->
+          <!--            @click="quickCreateFrame"-->
+          <!--          >快速创建-->
+          <!--          </el-button>-->
 
         </div>
         <el-tree
@@ -133,9 +133,9 @@
               <device-manager :frame="selectedNode" />
             </keep-alive>
           </el-tab-pane>
-          <el-tab-pane label="机构成员" name="clerkList">
+          <el-tab-pane label="机构成员" name="clerkManager">
             <keep-alive>
-              <clerk-list :part-id="selectedNode.part_id" />
+              <clerk-manager :part-id="selectedNode.part_id" />
             </keep-alive>
           </el-tab-pane>
         </el-tabs>
@@ -149,7 +149,7 @@
           <el-col :span="24">
             <!--医院结构名称-->
             <el-form-item label="名称" prop="name">
-              <el-input v-model="frameInfo.name" :maxlength="20">
+              <el-input v-model="frameInfo.name" :maxlength="20" @change="frameChange">
                 <template slot="append">{{ frameInfo.type === 4?"房":"床" }}</template>
               </el-input>
             </el-form-item>
@@ -158,6 +158,14 @@
         <el-row>
           <el-col :span="24">
             <!--医院结构别名-->
+            <el-form-item label="全称" prop="full_name">
+              <el-input v-model="frameInfo.full_name" :maxlength="20" />
+            </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>
@@ -288,13 +296,15 @@ import * as HospitalFrame_API from '@/api/ncs_hospitalFrame'
 import * as API_FrameGroup from '@/api/ncs_frameGroup'
 import CustomerManager from '@/views/hospital/ncs_customer/customerManager'
 import DeviceManager from '@/views/hospital/ncs_device/deviceManager'
-import ClerkList from '@/views/ncs-clerk/clerkList'
+// import ClerkList from '@/views/ncs-clerk/clerkList
+import ClerkManager from '@/views/hospital/clerkManager'
 import CountTo from 'vue-count-to'
 import * as API_PartInfo from '@/api/ncs_partInfo'
+import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
 
 export default {
   name: 'FrameTreeView',
-  components: { DeviceManager, CustomerManager, CountTo, ClerkList },
+  components: { DeviceManager, CustomerManager, CountTo, ClerkManager },
   data() {
     return {
       treeData: [],
@@ -318,6 +328,10 @@ export default {
         alias: [
           { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
         ],
+        full_name: [
+          this.MixinRequired('请输入全称!'),
+          { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
+        ],
         shop_name: [
           { required: true, message: '组织名称必须选择', trigger: 'blur' }
         ],
@@ -347,7 +361,8 @@ export default {
       /** 新建组织弹出参数 **/
       formtitle: '新建组织',
       formshow: false,
-      formmodel: {}
+      formmodel: {},
+      isShop: true
     }
   },
   computed: {
@@ -381,7 +396,7 @@ export default {
      * */
     getFrameTree() {
       return new Promise((resolve, reject) => {
-        API_FrameGroup.getframestruct(this.$store.getters.partId, 1).then(res => {
+        API_FrameGroup.getframestruct(this.$store.getters.partId, FRAME_TYPE.HOSPITAL).then(res => {
           console.log(res)
           this.bfCount = res.bfCount
           this.zcCount = res.zcCount
@@ -396,7 +411,7 @@ export default {
     },
 
     append(data) {
-      if (data.type === 1) {
+      if (data.type === FRAME_TYPE.HOSPITAL) {
         this.formmodel = {}
         this.formmodel.parent_id = data.hospital_id
         this.formmodel.frame_parent_id = data.id
@@ -404,14 +419,16 @@ export default {
         console.log('this.formmodel.parent_id=', this.formmodel.parent_id)
         this.formshow = true
       } else {
-        if (data.type === 4) {
+        if (data.type === FRAME_TYPE.ROOM) {
           this.frameEditTitle = '【' + data.full_name + '】添加床位'
         } else {
           this.frameEditTitle = '【' + data.full_name + '】添加房间'
         }
         this.frameInfo = {
+          part_id: data.part_id,
+          hospital_id: data.hospital_id,
           parent_id: data.id,
-          type: data.type === 4 ? 5 : 4,
+          type: data.type === FRAME_TYPE.ROOM ? FRAME_TYPE.BED : FRAME_TYPE.ROOM,
           parent_name: data.name,
           name: '',
           alias: ''
@@ -421,7 +438,7 @@ export default {
       }
     },
     edit(data, e) {
-      if (data.type === 3 || data.type === 1) {
+      if (data.type === FRAME_TYPE.PART || data.type === FRAME_TYPE.HOSPITAL) {
         console.log('暂未开发')
         return
       }
@@ -435,7 +452,7 @@ export default {
     },
     remove(data) {
       let warning = ''
-      if (data.type === 4) {
+      if (data.type === FRAME_TYPE.ROOM) {
         warning = '确定要删除【' + data.full_name + '】及其中的所有床位吗?'
       } else {
         warning = '确定删除床位【' + data.full_name + '】吗?'
@@ -474,11 +491,11 @@ export default {
         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 + '床'
-            }
+            // if (params.type === FRAME_TYPE.ROOM) {
+            //   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
@@ -491,11 +508,11 @@ export default {
             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 + '床'
-            }
+            // if (params.type === FRAME_TYPE.ROOM) {
+            //   params.full_name = params.name
+            // } else {
+            //   params.full_name = params.parent_name + '-' + params.name + '床'
+            // }
 
             HospitalFrame_API.addHospitalFrame(params).then(response => {
               this.$message.success('添加成功!')
@@ -609,6 +626,20 @@ export default {
       }
     },
     /**
+     * 名称输入变化
+     * @param val
+     */
+    frameChange(val) {
+      console.log('s', this.frameInfo)
+      if (!this.frameInfo.full_name) {
+        if (this.frameInfo.type === FRAME_TYPE.ROOM) {
+          this.$set(this.frameInfo, 'full_name', val + '房')
+        } else {
+          this.$set(this.frameInfo, 'full_name', this.frameInfo.parent_name + '-' + val + '床')
+        }
+      }
+    },
+    /**
      * 提交新增表单
      * @param formName
      */

+ 8 - 6
src/views/hospitalFrame/frameTreeView.vue

@@ -196,6 +196,7 @@ import CustomerManager from '../customer/components/customerManager'
 import DeviceManager from '../ncs-device/components/deviceManager'
 import PatientManager from '../customer/components/patientManager'
 import { uiVersion } from '@/utils/domain'
+import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
 export default {
   name: 'FrameTreeView',
   components: { PatientManager, DeviceManager, CustomerManager },
@@ -272,7 +273,7 @@ export default {
      * */
     getFrameTree() {
       return new Promise((resolve, reject) => {
-        API_FrameGroup.getframestruct(this.$store.getters.partId, 3).then(res => {
+        API_FrameGroup.getframestruct(this.$store.getters.partId, FRAME_TYPE.PART).then(res => {
           this.treeData = res.frameTree
           resolve()
         }).catch(err => {
@@ -282,14 +283,15 @@ export default {
     },
 
     append(data) {
-      if (data.type === 4) {
+      if (data.type === FRAME_TYPE.ROOM) {
         this.frameEditTitle = '【' + data.full_name + '】添加床位'
       } else {
         this.frameEditTitle = '【' + data.full_name + '】添加房间'
       }
       this.frameInfo = {
+        hospital_id: data.hospital_id,
         parent_id: data.id,
-        type: data.type === 4 ? 5 : 4,
+        type: data.type === FRAME_TYPE.ROOM ? FRAME_TYPE.BED : FRAME_TYPE.ROOM,
         parent_name: data.name,
         name: '',
         alias: ''
@@ -308,7 +310,7 @@ export default {
     },
     remove(data) {
       let warning = ''
-      if (data.type === 4) {
+      if (data.type === FRAME_TYPE.ROOM) {
         warning = '确定要删除【' + data.full_name + '】及其中的所有床位吗?'
       } else {
         warning = '确定删除床位【' + data.full_name + '】吗?'
@@ -477,8 +479,8 @@ export default {
     frameChange(val) {
       console.log('s', this.frameInfo)
       if (!this.frameInfo.full_name) {
-        if (this.frameInfo.type === 4) {
-          this.$set(this.frameInfo, 'full_name', val)
+        if (this.frameInfo.type === FRAME_TYPE.ROOM) {
+          this.$set(this.frameInfo, 'full_name', val + '房')
           // this.frameInfo.full_name = val
         } else {
           this.$set(this.frameInfo, 'full_name', this.frameInfo.parent_name + '-' + val + '床')

+ 17 - 26
src/views/ncs-device/components/deviceManager.vue

@@ -187,8 +187,8 @@ import * as API_Device from '@/api/ncs_device'
 import * as API_Frame from '@/api/ncs_hospitalFrame'
 import * as clerk_API from '@/api/ncs_clerk'
 import { DeviceUrl } from '@/utils/domain'
-import { FRAME_TYPE } from '@/utils/FrameTypeEnum'
-import { DEVICE_TYPE } from '@/utils/DeviceTypeEnum'
+import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
+import { DEVICE_TYPE } from '@/utils/enum/DeviceTypeEnum'
 export default {
   name: 'DeviceManager',
   components: { ButtonCellRender, ListFilter, RadioFilter },
@@ -260,9 +260,6 @@ export default {
         // ]
       },
       partFrames: [],
-      partFrameList: [],
-      roomFrameList: [],
-      bedFrameList: [],
       typeFrames: [],
       /** 设备类型转换数组 **/
       deviceTypeTransfer: [
@@ -454,10 +451,10 @@ export default {
     })
     /** 加载科室空间节点  **/
     if (this.part_view) {
-      this.getPartFrames(this.$store.getters.partId)
+      // this.getPartFrames(this.$store.getters.partId)
+      this.getTypeFrame(this.$store.getters.partId)
     }
     this.initWebSocket()
-    this.getTypeFrame(this.$store.getters.partId)
   },
   methods: {
     windowResize() {
@@ -497,23 +494,18 @@ export default {
       }).catch(err => {
         this.$message.error(err)
       })
+      this.typeFrames = this.partFrames
     },
-    /** 获取科室的所有空间节点 */
-    getPartFrames(partId) {
+    getTypeFrame(partId) {
       API_Frame.getFramesPartId(partId).then(res => {
         this.partFrames = [...res]
       })
     },
-    getTypeFrame(partId) {
-      API_Frame.getFrameByPartIdAndFrameType(partId, FRAME_TYPE.PART).then(res => {
-        this.partFrameList = [...res]
-      })
-      API_Frame.getFrameByPartIdAndFrameType(partId, FRAME_TYPE.ROOM).then(res => {
-        this.roomFrameList = [...res]
-      })
-      API_Frame.getFrameByPartIdAndFrameType(partId, FRAME_TYPE.BED).then(res => {
-        this.bedFrameList = [...res]
-      })
+    /** 将partFrames做分割 */
+    getFramesByType(device_type) {
+      if (this.partFrames != null) {
+        this.typeFrames = this.partFrames.filter(item => item.type === device_type)
+      }
     },
 
     /**
@@ -623,7 +615,6 @@ export default {
     /** 设备类型选中变化  **/
     deviceTypeChange(val) {
       this.deviceTypeChangeToFrameTypeChange(val)
-      this.$set(this.deviceModel, 'frame_id', null)
       if (val === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
           val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
           val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT ||
@@ -653,17 +644,19 @@ export default {
           val === DEVICE_TYPE.TRANSFER_DEVICE ||
           val === DEVICE_TYPE.INFORMATION_BOARD ||
           val === DEVICE_TYPE.RS485_TRANSFER) {
-        this.typeFrames = this.partFrameList
+        this.getFramesByType(FRAME_TYPE.PART)
       } else if (val === DEVICE_TYPE.DOOR_DEVICE ||
                  val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
                  val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT ||
                  val === DEVICE_TYPE.BEACON) {
-        this.typeFrames = this.roomFrameList
+        this.getFramesByType(FRAME_TYPE.ROOM)
       } else if (val === DEVICE_TYPE.DIGIT_BED_DEVICE ||
                  val === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
                  val === DEVICE_TYPE.REMOTE_CONTROL ||
                  val === DEVICE_TYPE.CELL_PHONE) {
-        this.typeFrames = this.bedFrameList
+        this.getFramesByType(FRAME_TYPE.BED)
+      } else {
+        this.typeFrames = this.partFrames
       }
     },
     /** 添加设备事件 **/
@@ -686,14 +679,12 @@ export default {
       this.deviceEditTitle = '添加设备'
       this.deviceDialogVisible = true
       this.deviceTypeDisabled = false // 新增设备可以选择设备类型
+      this.typeFrames = this.partFrames
     },
     /** 修改设备  **/
     handleEdit(params) {
       this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
       this.getDevices(params.part_id)
-      // if (!this.part_view) {
-      //   this.getPartFrames(params.part_id, params.device_type)
-      // }
       this.deviceTypeChangeToFrameTypeChange(params.device_type)
       this.hasRoleId = params.device_type === DEVICE_TYPE.NURSE_WATCH
       this.hasAudioId = params.device_type === DEVICE_TYPE.SIMULATE_BED_DEVICE ||

+ 1 - 1
src/views/ncs-device/device-edit.vue

@@ -147,7 +147,7 @@
 import * as API_Device from '@/api/ncs_device'
 import { returnDeviceType } from '@/utils/device_type'
 import * as clerk_API from '@/api/ncs_clerk'
-import { DEVICE_TYPE } from '@/utils/DeviceTypeEnum'
+import { DEVICE_TYPE } from '@/utils/enum/DeviceTypeEnum'
 
 export default {