소스 검색

添加权限控制

wuyunfeng 4 년 전
부모
커밋
8a9f88c0ed

+ 4 - 1
package.json

@@ -30,6 +30,7 @@
     "js-cookie": "2.2.0",
     "jsonlint": "1.6.3",
     "jszip": "3.2.1",
+    "jwt-decode": "^3.1.2",
     "normalize.css": "7.0.0",
     "nprogress": "0.2.0",
     "particles.js": "2.0.0",
@@ -77,7 +78,9 @@
     "serve-static": "1.13.2",
     "svg-sprite-loader": "4.1.3",
     "svgo": "1.2.0",
-    "vue-template-compiler": "2.6.10"
+    "vue-template-compiler": "2.6.10",
+    "js-cookie": "2.2.0",
+    "js-md5": "^0.7.3"
   },
   "browserslist": [
     "> 1%",

+ 54 - 0
src/api/ncs_menu.js

@@ -0,0 +1,54 @@
+/**
+ * 菜单管理相关API
+ */
+
+import request from '@/utils/request'
+
+/**
+ * 获取菜单
+ * @param parent_id
+ */
+export function getMenusChildren(parent_id = 0) {
+  return request({
+    url: `/mgr/menus/${parent_id}/children`,
+    method: 'get',
+    params: { parent_id }
+  })
+}
+
+/**
+ * 添加菜单
+ * @param params
+ */
+export function addMenu(params) {
+  return request({
+    url: '/mgr/menus',
+    method: 'post',
+    data: params
+  })
+}
+
+/**
+ * 修改菜单
+ * @param id
+ * @param params
+ */
+export function editMenu(id, params) {
+  return request({
+    url: `/mgr/menus/${id}`,
+    method: 'put',
+    data: params
+  })
+}
+
+/**
+ * 删除菜单
+ * @param id
+ */
+export function deleteMenu(id) {
+  return request({
+    url: `/mgr/menus/${id}`,
+    method: 'delete'
+  })
+}
+

+ 40 - 7
src/api/user.js

@@ -1,6 +1,9 @@
 import request from '@/utils/request'
-
+import Storage from '@/utils/storage'
+import store from '@/store'
+import md5 from 'js-md5'
 export function login(data) {
+  data.password = md5(data.password)
   return request({
     url: '/Mgr/login',
     method: 'get',
@@ -8,6 +11,30 @@ export function login(data) {
   })
 }
 
+export function logout(data) {
+  return request({
+    url: '/Mgr/logout',
+    method: 'post',
+    data: {
+      uid: store.getters.userInfo.uid
+    }
+  })
+}
+/**
+ * 刷新用户token
+ * @param data refresh_token=token
+ * @returns {AxiosPromise | * | Promise<unknown>}
+ */
+export function refreshToken(data) {
+  return request({
+    url: '/Mgr/refresh_token',
+    method: 'post',
+    data: {
+      refresh_token: Storage.getItem('calling_refresh_token')
+    }
+  })
+}
+
 export function getInfo(token) {
   return request({
     url: '/vue-element-admin/user/info',
@@ -16,12 +43,6 @@ export function getInfo(token) {
   })
 }
 
-export function logout() {
-  return request({
-    url: '/vue-element-admin/user/logout',
-    method: 'post'
-  })
-}
 export function getList(data) {
   return request({
     url: '/Mgr/member/page',
@@ -50,3 +71,15 @@ export function remove(params) {
   })
 }
 
+/**
+ * 获取用户角色权限
+ * @param role_id
+ * @returns {*}
+ */
+export function getUserRolesPermissions(role_id) {
+  return request({
+    url: `/mgr/role/${role_id}/checked`,
+    method: 'get'
+  })
+}
+

BIN
src/assets/loginBg.jpg


+ 3 - 13
src/layout/components/Navbar.vue

@@ -7,7 +7,7 @@
     <div class="right-menu">
       <template v-if="device!=='mobile'">
         <!--        <search id="header-search" class="right-menu-item" />-->
-        <div class="right-menu-item" style="color: #409EFF">{{ partInfo.part_hospitalname }} {{ partInfo.part_name }}</div>
+        <div class="right-menu-item" style="color: #409EFF">{{ partInfo.full_name }} {{ partInfo.part_name }}</div>
         <div class="right-menu-item" style="color: #ff4949;font-size: 14px">{{ licence }}</div>
         <error-log class="errLog-container right-menu-item hover-effect" />
 
@@ -78,18 +78,7 @@ export default {
       'device'
     ]),
     partInfo() {
-      if (Number(this.$store.getters.partId) > 0 && this.$store.getters.partInfo !== undefined && this.$store.getters.partInfo !== null && this.$store.getters.partInfo !== '') {
-        if (typeof this.$store.getters.partInfo === 'string') {
-          return JSON.parse(this.$store.getters.partInfo)
-        } else {
-          return this.$store.getters.partInfo
-        }
-      } else {
-        return {
-          part_hospitalname: '',
-          part_name: ''
-        }
-      }
+      return this.$store.getters.organization
     }
   },
   mounted() {
@@ -115,6 +104,7 @@ export default {
     async logout() {
       await this.$store.dispatch('user/logout')
       this.$store.dispatch('permission/removeRoutes')
+      console.log('hello')
       this.$router.push(`/login?redirect=${this.$route.fullPath}`)
     }
   }

+ 16 - 9
src/permission.js

@@ -3,7 +3,6 @@ import store from './store'
 import { Message } from 'element-ui'
 import NProgress from 'nprogress' // progress bar
 import 'nprogress/nprogress.css' // progress bar style
-import { getToken } from '@/utils/auth' // get token from cookie
 import getPageTitle from '@/utils/get-page-title'
 
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
@@ -13,16 +12,17 @@ const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
 router.beforeEach(async(to, from, next) => {
   // start progress bar
   NProgress.start()
-  console.log(store.getters.uuid)
-  if (store.getters.uuid === undefined || store.getters.uuid === null) {
-    store.dispatch('user/setUUID')
-  }
+  // console.log(store.getters.uuid)
+  // if (store.getters.uuid === undefined || store.getters.uuid === null) {
+  //   store.dispatch('user/setUUID')
+  // }
   // set page title
   document.title = getPageTitle(to.meta.title)
 
   // determine whether the user has logged in
-  const username = store.getters.name
-  if (username) {
+  const userInfo = store.getters.userInfo
+  console.log('userInfo', userInfo)
+  if (userInfo) {
     if (to.path === '/login') {
       // if is logged in, redirect to the home page
       next({ path: '/' })
@@ -31,11 +31,17 @@ router.beforeEach(async(to, from, next) => {
       // generate accessible routes map based on roles
       console.log('hasname')
       // dynamically add accessible routes
+      console.log('addRoutes', store.getters.addRoutes)
       if (store.getters.addRoutes.length === 0) {
         store.dispatch('permission/generateRoutes').then(() => {
           router.addRoutes(store.getters.addRoutes)
-          console.log('addroute')
-          next({ ...to, replace: true })
+          console.log('router', router.match({ ...to }))
+          if (router.match({ ... to }).path === '/404') {
+            next({ path: '/' })
+          } else {
+            next({ ...to, replace: true })
+          }
+
         })
       } else {
         console.log('next')
@@ -69,6 +75,7 @@ router.beforeEach(async(to, from, next) => {
       NProgress.done()
     }
   } else {
+    console.log('logout')
     /* has no token*/
     if (whiteList.indexOf(to.path) !== -1) {
       // in the free login whitelist, go directly

+ 12 - 0
src/router/index.js

@@ -270,6 +270,18 @@ export const adminRoutes = [
       }
     ]
   },
+  {
+    path: '/calling-menu',
+    component: Layout,
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/ncs-menu/menuManager'),
+        name: 'menuSetting',
+        meta: { title: '菜单管理', icon: 'tree', noCache: true }
+      }
+    ]
+  },
   { path: '*', redirect: '/404', hidden: true }
 ]
 

+ 1 - 1
src/store/getters.js

@@ -10,7 +10,7 @@ const getters = {
   introduction: state => state.user.introduction,
   roles: state => state.user.roles,
   partId: state => state.user.partId,
-  partInfo: state => state.user.partInfo,
+  organization: state => state.user.organization,
   permission_routes: state => state.permission.routes,
   errorLogs: state => state.errorLog.logs,
   addRoutes: state => state.permission.addRoutes,

+ 45 - 6
src/store/modules/permission.js

@@ -1,5 +1,6 @@
 import { constantRoutes, partRoutes, adminRoutes } from '@/router'
 import store from '@/store'
+import { getUserRolesPermissions } from '@/api/user'
 /**
  * Use meta.role to determine if the current user has permission
  * @param roles
@@ -51,13 +52,31 @@ const actions = {
     return new Promise(resolve => {
       const accessedRoutes = [] // asyncRoutes || []
       let lastRoutes = []
-      if (store.getters.partId === '0') {
-        lastRoutes = accessedRoutes.concat(adminRoutes)
-      } else {
-        lastRoutes = accessedRoutes.concat(partRoutes)
+      const userInfo = store.getters.userInfo
+      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)
+        })
       }
-      commit('SET_ROUTES', lastRoutes)
-      resolve(lastRoutes)
     })
   },
   /** 退出时清除 动态挂载的路由 */
@@ -66,6 +85,26 @@ const actions = {
   }
 }
 
+/**
+ * 递归筛选出有权限的路由
+ * @param routers
+ * @param names
+ * @returns {Array}
+ */
+function filterRoleRouter(routers, names) {
+  const _routers = []
+  routers.forEach(item => {
+    if (names.includes(item.name) || item.hidden) {
+      if (item.children) {
+        item.children = filterRoleRouter(item.children, names)
+      }
+      _routers.push(item)
+    }
+  })
+
+  return _routers
+}
+
 export default {
   namespaced: true,
   state,

+ 115 - 93
src/store/modules/user.js

@@ -1,61 +1,98 @@
-import {login} from '@/api/user'
+import { login, logout } from '@/api/user'
 import * as API_Part from '@/api/calling-part'
 import * as Auth from '@/utils/auth'
-import router, {resetRouter} from '@/router'
-
+import router, { resetRouter } from '@/router'
+import Storage from '@/utils/storage'
 import uuidv1 from 'uuid/v1'
-import store from "@/store";
+import store from '@/store'
+import jwt_decode from 'jwt-decode'
 
+const _user = Storage.getItem('calling_user')
+const _shop = Storage.getItem('calling_shop')
+const _partid = Storage.getItem('part_id')
+const _uid = Storage.getItem('uid')
 const state = {
-  token: Auth.getToken(),
-  name: Auth.getUserName(),
-  avatar: '',
-  introduction: '',
-  partId: Auth.getPartId(),
-  roles: [],
-  partInfo: Auth.getPartInfo(),
-  editLock: Auth.getEditLock(),
-  uuid: Auth.getUUID(),
-  userInfo: Auth.getUserInfo()
+  userInfo: _user ? JSON.parse(_user) : '',
+  organization: _shop ? JSON.parse(_shop) : '',
+  partId: _partid
 }
 
 const mutations = {
-  SET_TOKEN: (state, token) => {
-    state.token = token
+
+  SET_USERINFO: (state, userInfo) => {
+    state.userInfo = userInfo
+    Storage.setItem('calling_user', userInfo)
   },
-  SET_INTRODUCTION: (state, introduction) => {
-    state.introduction = introduction
+  /**
+   * 设置访问令牌
+   * @param state
+   * @param token
+   * @constructor
+   */
+  SET_ACCESS_TOKEN: (state, token) => {
+    const expires = new Date(jwt_decode(token).exp * 1000)
+    Storage.setItem('calling_access_token', token, { expires })
   },
-  SET_NAME: (state, name) => {
-    state.name = name
-    Auth.setUserName(name)
+  /**
+   * 设置刷新令牌
+   * @param state
+   * @param token
+   * @constructor
+   */
+  SET_REFRESH_TOKEN: (state, token) => {
+    const expires = new Date(jwt_decode(token).exp * 1000)
+    Storage.setItem('calling_refresh_token', token, { expires })
+    // 同时延长用户信息失效时间
+    const user = Storage.getItem('calling_user')
+    Storage.setItem('calling_user', user, { expires })
   },
-  SET_AVATAR: (state, avatar) => {
-    state.avatar = avatar
+  /** 设置机构信息**/
+
+  SET_PARTINFO: (state, partInfo) => {
+    state.organization = partInfo
+    Storage.setItem('calling_shop', partInfo)
   },
-  SET_ROLES: (state, roles) => {
-    state.roles = roles
+
+  /**
+   * 移除用户信息
+   * @param state
+   * @constructor
+   */
+  REMOVE_USER: (state) => {
+    state.userInfo = ''
+    Storage.removeItem('calling_user')
   },
-  SET_PARTID: (state, partId) => {
-    state.partId = partId
-    Auth.setPartId(partId)
+
+  REMOVE_PARTINFO: (state) => {
+    state.organization = ''
+    Storage.removeItem('calling_shop')
   },
-  SET_PARTINFO: (state, partInfo) => {
-    state.partInfo = partInfo
-    Auth.setPartInfo(partInfo)
+
+  /**
+   * 移除访问令牌
+   * @param state
+   * @constructor
+   */
+  REMOVE_ACCESS_TOKEN: (state) => {
+    Storage.removeItem('calling_access_token')
   },
-  SET_EDITLOCK: (state, editLock) => {
-    state.partInfo = editLock
-    Auth.setEditLock(editLock)
+  /**
+   * 移除刷新令牌
+   * @param state
+   * @constructor
+   */
+  REMOVE_REFRESH_TOKEN: (state) => {
+    Storage.removeItem('calling_refresh_token')
   },
-  SET_UUID: (state, uuid) => {
-    state.uuid = uuid
-    Auth.setUUID(uuid)
+  SET_PARTID: (state, partid) => {
+    state.partId = partid
+    Storage.setItem('part_id', partid)
   },
-  SET_USERINFO: (state, userInfo) => {
-    state.userInfo = userInfo
-    Auth.setUserInfo(userInfo)
+  REMOVE_PARTID: (state) => {
+    state.partId = ''
+    Storage.removeItem('part_id')
   }
+
 }
 
 const actions = {
@@ -67,20 +104,15 @@ const actions = {
       // commit('SET_PARTID', 1)
       // commit('SET_NAME', username)
       // resolve()
-      login({ username: username.trim(), password: password.trim(), uuid: store.getters.uuid }).then(res => {
+      login({ username: username.trim(), password: password.trim() }).then(res => {
+        console.log(res)
+        const { access_token, refresh_token, ...user } = res
+        const expires = new Date(jwt_decode(refresh_token).exp * 1000)
+        commit('SET_ACCESS_TOKEN', access_token)
+        commit('SET_REFRESH_TOKEN', refresh_token)
         commit('SET_PARTID', res.last_login_shopid)
-        commit('SET_NAME', username)
-        const u = {
-          face: res.face,
-          founder: res.founder,
-          mobile: res.mobile,
-          nickname: res.nickname,
-          role_id: res.role_id,
-          sns_json: res.sns_json,
-          uid: res.uid,
-          username: res.username
-        }
-        commit('SET_USERINFO', u)
+        // commit('SET_NAME', username)
+        commit('SET_USERINFO', { ...user, expires })
         // dispatch('getInfo')
         resolve()
       }).catch(error => {
@@ -121,51 +153,41 @@ const actions = {
   // user logout
   logout({ commit, state, dispatch }) {
     return new Promise((resolve, reject) => {
-      commit('SET_PARTID', '')
-      commit('SET_NAME', null)
-      commit('SET_PARTINFO', '')
-      Auth.removePartId()
-      Auth.removeUserName()
-      Auth.removePartInfo()
-      resetRouter()
-
-      // reset visited views and cached views
-      // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
-      dispatch('tagsView/delAllViews', null, { root: true })
-
-      resolve()
+      logout().then(res => {
+        commit('REMOVE_ACCESS_TOKEN')
+        commit('REMOVE_REFRESH_TOKEN')
+        commit('REMOVE_USER')
+        commit('REMOVE_PARTID')
+        commit('REMOVE_PARTINFO')
+        resetRouter()
+
+        // reset visited views and cached views
+        // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
+        dispatch('tagsView/delAllViews', null, { root: true })
+        resolve()
+      }).catch(err => {
+        reject(err)
+      })
     })
   },
 
-  // remove token
-  resetToken({ commit }) {
-    return new Promise(resolve => {
-      commit('SET_TOKEN', '')
-      commit('SET_ROLES', [])
-      Auth.removeToken()
-      resolve()
-    })
+  /**
+   * 设置访问令牌
+   * @param commit
+   * @param token
+   */
+  setAccessTokenAction({ commit }, token) {
+    commit('SET_ACCESS_TOKEN', token)
   },
-
-  // dynamically modify permissions
-  async changeRoles({ commit, dispatch }, role) {
-    const token = role + '-token'
-
-    commit('SET_TOKEN', token)
-    Auth.setToken(token)
-
-    const { roles } = await dispatch('getInfo')
-
-    resetRouter()
-
-    // generate accessible routes map based on roles
-    const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
-    // dynamically add accessible routes
-    router.addRoutes(accessRoutes)
-
-    // reset visited views and cached views
-    dispatch('tagsView/delAllViews', null, { root: true })
+  /**
+   * 设置刷新令牌
+   * @param commit
+   * @param token
+   */
+  setRefreshTokenAction({ commit }, token) {
+    commit('SET_REFRESH_TOKEN', token)
   }
+
 }
 
 export default {

+ 102 - 0
src/utils/checkToken.js

@@ -0,0 +1,102 @@
+/**
+ * Created by Andste on 2018/5/7.
+ */
+
+import Storage from './storage'
+import store from '@/store'
+import router from '@/router'
+import * as API_User from '@/api/user'
+import { MessageBox } from 'element-ui'
+
+/**
+ * 检查token:
+ * 1. user/accessToken/refreshToken都不存在。
+ *    表示用户没有登录,没有权限,重定向到登录页
+ * 2. 不存在accessToken,但是user/refreshToken存在。
+ *    表示accessToken过期,需要重新获取accessToken。
+ *    如果重新获取accessToken返回token失效错误,说明已被登出。
+ * @param options
+ * @returns {Promise<any>}
+ */
+export default function checkToken(options) {
+  // user
+  const user = Storage.getItem('calling_user')
+  // 访问Token
+  const accessToken = Storage.getItem('calling_access_token')
+  // 刷新Token
+  const refreshToken = Storage.getItem('calling_refresh_token')
+  // 返回异步方法
+  return new Promise((resolve, reject) => {
+    /**
+     * 如果accessToken、user、refreshToken都存在。
+     * 说明必要条件都存在,可以直接通过,并且不需要后续操作。
+     */
+    if (accessToken && user && refreshToken) {
+      resolve()
+      return
+    }
+    /**
+     * 如果refreshToken或者user没有。
+     * 说明登录已失效、或者cookie有问题,需要重新登录。
+     */
+    if (!refreshToken || !user) {
+      MessageBox.alert('您的登录状态已失效,请重新登录!', '权限错误', {
+        type: 'error',
+        callback: () => {
+          store.dispatch('fedLogoutAction')
+          window.location.replace(`/login?forward=${location.pathname}`)
+        }
+      })
+      return
+    }
+    /**
+     * 不存在accessToken,但是user/refreshToken存在。
+     * 说明用户已登录,只是accessToken过期,需要重新获取accessToken。
+     * 如果没有needToken,说明不需要等待获取到新的accessToken后再请求。
+     * 否则,需要等待
+     */
+    if (!accessToken && refreshToken) {
+      /**
+       * 如果没有刷新token锁,需要刷新token。
+       * 如果有刷新token锁,则进入循环检测。
+       */
+      if (!window.__refreshTokenLock__) {
+        // console.log(options.url + ' | 检测到accessToken失效,这个请求需要等待刷新token。')
+        // 开始请求新的Token,并加锁。
+        window.__refreshTokenLock__ = true
+        API_User.refreshToken().then(response => {
+          store.dispatch('user/setAccessTokenAction', response.accessToken)
+          store.dispatch('user/setRefreshTokenAction', response.refreshToken)
+          window.__refreshTokenLock__ = null
+          // console.log(options.url + ' | 已拿到新的token。')
+          resolve()
+        }).catch(() => {
+          window.__refreshTokenLock__ = undefined
+          store.dispatch('user/logout')
+          window.location.replace(`/login?forward=${location.pathname}`)
+        })
+      } else {
+        // console.log('进入循环检测...')
+        // 循环检测刷新token锁,当刷新锁变为null时,说明新的token已经取回。
+        const checkLock = () => {
+          setTimeout(() => {
+            const __RTK__ = window.__refreshTokenLock__
+            // console.log(options.url + ' | 是否已拿到新的token:', __RTK__ === null)
+            if (__RTK__ === undefined) {
+              // console.log('登录已失效了,不用再等待了...')
+              store.dispatch('fedLogoutAction')
+              window.location.replace(`/login?forward=${location.pathname}`)
+              return
+            }
+            __RTK__ === null
+              ? resolve()
+              : checkLock()
+          }, 500)
+        }
+        checkLock()
+      }
+      return
+    }
+    resolve()
+  })
+}

+ 2 - 1
src/utils/domain.js

@@ -1,5 +1,6 @@
 module.exports = {
   serverUrl: 'http://localhost:8005',
-  runtimeUrl: 'http://localhost:8003'
+  runtimeUrl: 'http://localhost:8003',
+  apiMode: 'dev'
 }
 

+ 79 - 13
src/utils/request.js

@@ -1,8 +1,12 @@
 import axios from 'axios'
-import { MessageBox, Message } from 'element-ui'
+import { MessageBox, Message, Loading } from 'element-ui'
 import store from '@/store'
 import { getToken } from '@/utils/auth'
-import { serverUrl } from '@/utils/domain'
+import Storage from '@/utils/storage'
+import { serverUrl, apiMode } from '@/utils/domain'
+import * as Foundation from '@/utils/Foundation'
+import md5 from 'js-md5'
+import checkToken from '@/utils/checkToken'
 const qs = require('qs')
 // create an axios instance
 const service = axios.create({
@@ -15,15 +19,48 @@ const service = axios.create({
 // request interceptor
 service.interceptors.request.use(
   config => {
+    /** 配置全屏加载 */
+    if (config.loading !== false) {
+      const { loading } = config
+      const is_num = typeof (config.loading) === 'number'
+      if (is_num) config.loading_num = true
+      config.loading = Loading.service({
+        lock: true,
+        background: `rgba(0, 0, 0, ${is_num ? loading : '0.8'})`,
+        spinner: 'el-icon-loading'
+      })
+    }
+
+    // uuid
+    const uuid = Storage.getItem('calling_uuid')
+    config.headers['uuid'] = uuid
+
+    // 获取访问Token
+    const accessToken = Storage.getItem('calling_access_token')
+    if (accessToken) {
+      if (apiMode === 'prod') {
+        const uid = Storage.getItem('calling_uuid')
+        const nonce = Foundation.randomString(6)
+        const timestamp = parseInt(new Date().getTime() / 1000)
+        const sign = md5(uid + nonce + timestamp + accessToken)
+        const _params = { uid, nonce, timestamp, sign }
+        let params = config.params || {}
+        params = { ...params, ..._params }
+        config.params = params
+      } else {
+        config.headers['Authorization'] = accessToken
+      }
+    }
+
     // do something before request is sent
     // config.headers['Content-type'] = 'application/x-www-form-urlencoded;charset=utf-8'
     // 如果是put/post请求,用qs.stringify序列化参数
     const is_put_post = config.method === 'put' || config.method === 'post' || config.method === 'delete'
     // const is_json = config.headers['Content-Type'] === 'application/json'
-    if (is_put_post && config.headers['Content-Type'] === 'application/json') {
+    if (is_put_post && config.headers['Content-Type'] === 'application/json') { // 发送json数据
       config.data = JSON.stringify(config.data)
     }
-    if (is_put_post && config.headers['Content-Type'] !== 'application/json') {
+    if (is_put_post && config.headers['Content-Type'] !== 'application/json') { // 发送表单数据
       config.data = qs.stringify(config.data, { arrayFormat: 'repeat' })
     }
 
@@ -33,6 +70,7 @@ service.interceptors.request.use(
       // please modify it according to the actual situation
       config.headers['X-Token'] = getToken()
     }
+
     return config
   },
   error => {
@@ -54,7 +92,8 @@ service.interceptors.response.use(
    * Here is just an example
    * You can also judge the status by HTTP Status Code
    */
-  response => {
+  async response => {
+    await closeLoading(response)
     return response.data
     // if the custom code is not 20000, it is judged as an error.
     // if (res.code !== 20000) {
@@ -82,17 +121,44 @@ service.interceptors.response.use(
     //   return res
     // }
   },
-  error => {
+  async error => {
+    await closeLoading(error)
     const error_response = error.response || {}
     const error_data = error_response.data || {}
 
-    Message({
-      message: error_data.message,
-      type: 'error',
-      duration: 5 * 1000
-    })
-    // return Promise.reject(error_data)
+    // Message({
+    //   message: error_data.message,
+    //   type: 'error',
+    //   duration: 5 * 1000
+    // })
+    return Promise.reject(error_data.message)
   }
 )
 
-export default service
+/**
+ * 关闭全局加载
+ * 延迟200毫秒关闭,以免晃眼睛
+ * @param target
+ */
+const closeLoading = (target) => {
+  const { loading, loading_num } = target.config
+  if (!loading) return true
+  return new Promise((resolve, reject) => {
+    setTimeout(() => {
+      target.config.loading.close()
+      resolve()
+    }, loading_num ? 0 : 200)
+  })
+}
+
+export default function request(options) {
+  // 如果是请求【刷新token、登录、退出】不需要检查token,直接请求。
+  if (/mgr\/refresh_token|mgr\/login|mgr\/logout/.test(options.url.toLocaleLowerCase())) {
+    return service(options)
+  }
+  return new Promise((resolve, reject) => {
+    checkToken(options).then(() => {
+      service(options).then(resolve).catch(reject)
+    })
+  })
+}

+ 26 - 0
src/utils/storage.js

@@ -0,0 +1,26 @@
+/**
+ * Created by Andste on 2018/5/3.
+ */
+
+import Cookies from 'js-cookie'
+const psl = require('psl')
+
+export default {
+  setItem: (key, value, options = {}) => {
+    const p_psl = psl.parse(document.domain)
+    let domain = p_psl.domain
+    if (/\d+\.\d+\.\d+\.\d+/.test(p_psl.input)) domain = p_psl.input
+    options = { domain, ...options }
+    Cookies.set(key, value, options)
+  },
+  getItem: (key) => {
+    return Cookies.get(key)
+  },
+  removeItem: (key, options = {}) => {
+    const p_psl = psl.parse(document.domain)
+    let domain = p_psl.domain
+    if (/\d+\.\d+\.\d+\.\d+/.test(p_psl.input)) domain = p_psl.input
+    options = { domain, ...options }
+    Cookies.remove(key, options)
+  }
+}

+ 375 - 375
src/views/customer/customerEdit.vue

@@ -2,16 +2,16 @@
   <div class="formwrap">
     <el-tabs v-model="activeName" @tab-click="handleClick">
       <el-tab-pane label="用户管理" name="customerEdit">
-        <el-form :model="formmodel" :rules="rules" ref="editForm" label-width="140px">
+        <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-input>
+                <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-input>
+                <el-input v-model="formmodel.card_no" clearable placeholder="请输入病人编号" :maxlength="20" />
               </el-form-item>
             </el-col>
             <el-col :span="8">
@@ -53,31 +53,31 @@
           <el-row>
             <el-col :span="8">
               <el-form-item label="证件号">
-                <el-input v-model="formmodel.id_no" clearable placeholder="请输入证件号" :maxlength="20"></el-input>
+                <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-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-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>
@@ -85,22 +85,22 @@
           <el-row>
             <el-col :span="8">
               <el-form-item label="责任医生">
-                <el-select placeholder="请选择医生" v-model="formmodel.doctor_id" @change="doctorChange(1)">
-                  <el-option :label="item.clerk_name" :key="index" v-for="(item,index) in doctors" :value="item.clerk_id"></el-option>
+                <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 placeholder="请选择护士" v-model="formmodel.nurse_id" @change="doctorChange(2)">
-                  <el-option :label="item.clerk_name" :key="index" v-for="(item,index) in nurses" :value="item.clerk_id"></el-option>
+                <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 placeholder="请选择护工" v-model="formmodel.worker_id" @change="doctorChange(3)">
-                  <el-option :label="item.clerk_name" :key="index" v-for="(item,index) in workrs" :value="item.clerk_id"></el-option>
+                <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>
@@ -109,7 +109,7 @@
           <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 :placeholder="'请选择'+item[0]" v-model="nurseData[index].nurse_level" @change="changeNurseData(index)">
+                <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>
@@ -123,88 +123,89 @@
             <el-col :span="16">
               <el-form-item label="病况描述">
                 <el-input
-                        type="textarea"
-                        :autosize="{ minRows: 2, maxRows: 4}"
-                        :minlength="2"
-                        :maxlength="50"
-                        :placeholder="'请输入文本内容,长度2~50'"
-                        v-model="formmodel.illness_desc">
-                </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" @click="handlerSubmit('editForm')" :disabled="isDisabled" class="save">保存修改</el-button>
+            <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: left"><h4>用户备注</h4></div>
             <div style="float: right">
               <el-button type="success" @click="dialogAddVisible = true">添加备注</el-button>
             </div>
           </div>
           <div style="clear:both">
-            <div >
+            <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>
+                  <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="https://imgm.gmw.cn/attachement/jpg/site215/20210309/4101699327084478802.jpg" icon="el-icon-folder" type="success" target="_blank" :download="item.file_name">{{item.file_name}}</el-link>
-                </span>
+                    <span v-if="item.file_name">
+                      <el-link href="https://imgm.gmw.cn/attachement/jpg/site215/20210309/4101699327084478802.jpg" 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}}
+                      <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
-                      slot="pagination"
-                      v-if="pageData"
-                      :current-page="pageData.page_no"
-                      :page-sizes="[10, 30, 50, 100]"
-                      :page-size="pageData.page_size"
-                      @size-change="handlePageSizeChange"
-                      @current-change="handlePageCurrentChange"
-                      layout="total, sizes, prev, pager, next, jumper"
-                      :total="pageData.data_total">
-              </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 :model="formmodel" :rules="rules" ref="editForm" label-width="140px">
+          <el-form ref="editForm" :model="formmodel" :rules="rules" label-width="140px">
             <el-form-item label="内容">
               <el-input
-                      type="textarea"
-                      :autosize="{ minRows: 2, maxRows: 6}"
-                      :minlength="2"
-                      :maxlength="300"
-                      show-word-limit
-                      :placeholder="'请输入文本内容,长度300'"
-                      v-model="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="!fileName"
-                         class="avatar-uploader"
-                         :action="`${uploadServer}/ncs/remark/upload`"
-                         :show-file-list="false"
-                         :on-success="uploaded"
-                         :before-upload="handleShopLogoBefore"
+              <el-upload
+                v-if="!fileName"
+                class="avatar-uploader"
+                :action="`${uploadServer}/ncs/remark/upload`"
+                :show-file-list="false"
+                :on-success="uploaded"
+                :before-upload="handleShopLogoBefore"
               >
                 <i class="el-icon-plus avatar-uploader-icon" />
               </el-upload>
-              <span v-if="fileName">{{fileName}}</span>
+              <span v-if="fileName">{{ fileName }}</span>
             </el-form-item>
             <el-form-item>
               <el-button type="primary" @click="addRemark">立即添加</el-button>
@@ -214,7 +215,7 @@
         </el-dialog>
       </el-tab-pane>
       <el-tab-pane v-if="customerId != 0" label="病人亲属" name="customer-relative">
-        <customer-relative :member-id="memberId"></customer-relative>
+        <customer-relative :member-id="memberId" />
       </el-tab-pane>
     </el-tabs>
 
@@ -223,334 +224,333 @@
 </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_nurseConfig'
-  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'
+import * as customer_API from '@/api/ncs_customer'
+import * as clerk_API from '@/api/ncs_clerk'
+import * as NurseConfig_API from '@/api/ncs_nurseConfig'
+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 {
-    components: { customerRelative },
-    name: 'patientInfoEdit',
-    props: {
-      customerId: {
-        type: Number,
-        default: 0
-      },
-      frameId: {
-        type: Number,
-        default: 0
-      }
+export default {
+  name: 'PatientInfoEdit',
+  components: { customerRelative },
+  props: {
+    customerId: {
+      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()
-                }
+    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'
-          }],
-        },
-        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,
-        userInfo: JSON.parse(this.$store.getters.userInfo),
-        content: null,
-        activeName: 'customerEdit',
-        memberId: null
-      }
-    },
-    mounted() {
-      this.getEmployees()
-      if (this.nurseList.length === 0) {
-        this.getNurseConfigs()
-        this.hasCustomerId()
-      }
-    },
-    watch: {
-      frameId: function(newval) {
-        this.getNurseConfigs()
-        this.hasCustomerId()
-      }
-    },
-
-    methods: {
-      getEmployees() {
-        let _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;
-                  }, {});
-          let 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]
-              }
-            })
           }
-        })
+        ],
+        age: [{
+          required: true, message: '请输入年龄', trigger: 'blur'
+        }],
+        content: [{
+          required: true, message: '请输入备注内容', trigger: 'blur'
+        }]
       },
-      getNurseConfigs() {
-        this.nurseData = []
-        let _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;
-                  }, {});
-          // 以参数名称来分组
-          let groupData = groupBy(res, item => item.config_name)
-          _this.nurseList = Object.entries(groupData)
-          console.log(_this.nurseList)
-          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})
-            })
-          }
-
-        })
+      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'
       },
-      hasCustomerId() {
-        this.clearForm()
-        if (this.customerId !== 0) {
-          let _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
-            _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
-                  }
-                })
-              })
-            }
+      tableData: [],
+      pageData: [],
+      dialogAddVisible: false,
+      fileName: null,
+      filePath: null,
+      uploadServer: serverUrl,
+      userInfo: JSON.parse(this.$store.getters.userInfo),
+      content: null,
+      activeName: 'customerEdit',
+      memberId: null
+    }
+  },
+  watch: {
+    frameId: function(newval) {
+      this.getNurseConfigs()
+      this.hasCustomerId()
+    }
+  },
+  mounted() {
+    this.getEmployees()
+    if (this.nurseList.length === 0) {
+      this.getNurseConfigs()
+      this.hasCustomerId()
+    }
+    console.log('params',this.params)
+  },
 
+  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]
+            }
           })
         }
-
-      },
-      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
-            }
-          }
+      })
+    },
+    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)
+        console.log(_this.nurseList)
+        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 })
+          })
         }
-      },
-      /** 保存按钮处理事件 */
-      handlerSubmit(formName) {
-        this.$refs[formName].validate(valid => {
-          if (valid) {
-            this.isDisabled = true
-            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')
+      })
+    },
+    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
+          _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
+                }
               })
-            }
-          } 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: null,
-          out_date: null,
-          doctor_id: null,
-          nurse_id: null,
-          worker_id: null,
-          illness_desc: null
-        }
-        this.isDisabled = false
-        this.nurseConfigDtos = []
-      },
-      // 选择了护理项
-      changeNurseData(index) {
-        let 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() {
-        console.log('this.formmodel.member_id=', this.formmodel.member_id)
-        let _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
+      }
+    },
+    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
           }
-        })
-      },
-      /** 分页大小发生改变 */
-      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.file_path
-        this.fileName = res.file_name
-      },
-      /** 图片上传之前的校验 */
-      handleShopLogoBefore(file) {
-        return new Promise((resolve, reject) => {
-          let hz = file.name
-          let index = hz .lastIndexOf(".");
-          hz  = hz .substring(index + 1, hz .length);
-          console.log(hz)
-          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()
+        } 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
           }
-          if (!isLt5M) {
-            this.$message.error('上传复件大小不能超过 5MB!')
-            reject()
+        } else {
+          if (this.worker_mapping_id === null) {
+            this.formmodel.worker_mapping_id = 0 // 为0则新增,// 其他值为修改
+          } else {
+            this.formmodel.worker_mapping_id = this.worker_mapping_id
           }
-          resolve()
-        })
-      },
-      addRemark() {
-        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
         }
-        let _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
       }
+    },
+    /** 保存按钮处理事件 */
+    handlerSubmit(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          this.isDisabled = true
+          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: null,
+        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() {
+      console.log('this.formmodel.member_id=', this.formmodel.member_id)
+      const _this = this
+      console.log('this',_this.params)
+      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.file_path
+      this.fileName = res.file_name
+    },
+    /** 图片上传之前的校验 */
+    handleShopLogoBefore(file) {
+      return new Promise((resolve, reject) => {
+        let hz = file.name
+        const index = hz.lastIndexOf('.')
+        hz = hz.substring(index + 1, hz.length)
+        console.log(hz)
+        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() {
+      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>

+ 1 - 1
src/views/hospitalFrame/hospitalFrame.vue

@@ -178,7 +178,7 @@
     },
     methods: {
       GET_All() {
-        HospitalFrame_API.getHospitalFrameList(this.$store.getters.partId).then(response => {
+        HospitalFrame_API.getHospitalFrameList(this.$store.getters.userInfo.last_login_shopid).then(response => {
           if (response) {
             console.log(response)
             this.hospital_frame = response

+ 28 - 8
src/views/login/index.vue

@@ -64,23 +64,25 @@
 </template>
 
 <script>
-//import { validUsername } from '@/utils/validate'
+// import { validUsername } from '@/utils/validate'
 import SocialSign from './components/SocialSignin'
 import particlesjsConfig from '@/assets/particlesjs-config.json'
 import 'particles.js'
 import { Message } from 'element-ui'
+import uuidv1 from 'uuid/v1'
+import Storage from '@/utils/storage'
 export default {
   name: 'Login',
   components: { SocialSign },
   data() {
     return {
       loginForm: {
-        username: 'admin',
-        password: '123456'
+        username: '',
+        password: ''
       },
       loginRules: {
-        username: [{ required: true, trigger: 'blur' }],
-        password: [{ required: true, trigger: 'blur' }]
+        username: [{ required: true, trigger: 'blur', message: '用户名必须填写' }],
+        password: [{ required: true, trigger: 'blur', message: '登陆密码必须填写' }]
       },
       passwordType: 'password',
       capsTooltip: false,
@@ -106,6 +108,15 @@ export default {
     // window.addEventListener('storage', this.afterQRScan)
   },
   mounted() {
+    const uuid = Storage.getItem('calling_uuid')
+    if (uuid) {
+      this.uuid = uuid
+    } else {
+      const _uuid = uuidv1()
+      this.uuid = _uuid
+      Storage.setItem('calling_uuid', _uuid, { expires: 30 })
+    }
+
     if (this.loginForm.username === '') {
       this.$refs.username.focus()
     } else if (this.loginForm.password === '') {
@@ -142,9 +153,18 @@ export default {
           this.loading = true
           this.$store.dispatch('user/login', this.loginForm)
             .then(() => {
-              this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
-              // this.$router.push({ path: '/' })
-              this.loading = false
+              this.$store.dispatch('user/getInfo').then(res => {
+                this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
+                // this.$router.push({ path: '/' })
+                this.loading = false
+              }).catch(err => {
+                Message({
+                  message: err,
+                  type: 'error',
+                  duration: 5 * 1000
+                })
+                this.loading = false
+              })
             })
             .catch((error) => {
               Message({

+ 191 - 0
src/views/ncs-menu/menuManager.vue

@@ -0,0 +1,191 @@
+<template>
+  <div class="menus-container">
+    <el-tree
+      :data="menus"
+      node-key="identifier"
+      :expand-on-click-node="true"
+    >
+      <span slot-scope="{node, data}" class="custom-tree-node">
+        <span>{{ data.title }}</span>
+        <span>
+          <el-button
+            type="text"
+            size="mini"
+            :disabled="node.level === 3"
+            icon="el-icon-plus"
+            :title="node.level === 3 ? '菜单最多添加三级' : '增加'"
+            @click.stop="handleAddMenu(data)"
+          />
+          <el-button
+            type="text"
+            size="mini"
+            icon="el-icon-minus"
+            title="删除"
+            @click.stop="handleDeleteMenu(node, data)"
+          />
+          <el-button
+            type="text"
+            size="mini"
+            icon="el-icon-edit"
+            title="编辑"
+            @click.stop="handleEditMenu(data)"
+          />
+        </span>
+      </span>
+    </el-tree>
+    <el-button
+      v-if="menus"
+      type="text"
+      size="mini"
+      style="margin-top: 10px; margin-left: 20px"
+      @click="handleAddMenu('')"
+    >添加顶级菜单</el-button>
+    <el-dialog
+      :title="menuForm.menu_name ? '编辑菜单' : '添加菜单'"
+      :visible.sync="dialogMenuVisible"
+      width="500px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <el-form ref="menuForm" :model="menuForm" :rules="menuRules" label-width="100px">
+        <el-form-item label="菜单标题" prop="title">
+          <el-input v-model="menuForm.title" :maxlength="6" />
+        </el-form-item>
+        <el-form-item label="菜单标识" prop="identifier">
+          <el-input v-model="menuForm.identifier" :maxlength="50" />
+        </el-form-item>
+        <el-form-item label="菜单权限" prop="auth_regular">
+          <el-input v-model="menuForm.auth_regular" :maxlength="50" />
+        </el-form-item>
+
+<!--        <el-form-item label="默认给医生角色" prop="doctor_default">-->
+<!--          <el-checkbox v-model="menuForm.doctor_default" />-->
+<!--        </el-form-item>-->
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogMenuVisible = false">取 消</el-button>
+        <el-button type="primary" @click="submitMenuForm('menuForm')">确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import * as API_Menus from '@/api/ncs_menu'
+export default {
+  name: 'MenuManager',
+  data() {
+    return {
+      menus: [],
+      /** 添加、编辑菜单 表单 */
+      menuForm: {},
+      /** 添加、编辑菜单 表单规则 */
+      menuRules: {
+        title: [
+          this.MixinRequired('请输入菜单标题!'),
+          { min: 2, max: 6, message: '长度在 2 到 6 个字符', trigger: 'blur' }
+        ],
+        identifier: [
+          this.MixinRequired('请输入菜单标识!'),
+          { min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
+        ],
+        auth_regular: [
+          this.MixinRequired('请输入菜单权限!'),
+          { min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
+        ]
+      },
+      /** 添加、编辑菜单 dialog */
+      dialogMenuVisible: false,
+      /** 当前操作的menu */
+      currentMenu: ''
+    }
+  },
+  created() {
+    this.GET_Memus()
+  },
+  methods: {
+    /** 添加菜单 */
+    handleAddMenu(menu) {
+      this.menuForm = {
+        parent_id: menu ? menu.id : 0
+      }
+      this.currentMenu = menu || {}
+      this.dialogMenuVisible = true
+    },
+    /** 删除菜单 */
+    handleDeleteMenu(node, menu) {
+      this.$confirm('确定要删除这个菜单吗?如果有子菜单,子菜单也会被一并删除!', '提示', { type: 'warning' }).then(() => {
+        API_Menus.deleteMenu(menu.id).then(() => {
+          const parent = node.parent
+          const children = parent.data.children || parent.data
+          const index = children.findIndex(d => d.id === menu.id)
+          children.splice(index, 1)
+        })
+      }).catch(() => {})
+    },
+    /** 编辑菜单 */
+    handleEditMenu(menu) {
+      this.menuForm = JSON.parse(JSON.stringify(menu))
+      this.currentMenu = menu
+      this.dialogMenuVisible = true
+    },
+    /** 添加、编辑菜单 表单提交 */
+    submitMenuForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          const { id } = this.menuForm
+          if (id) {
+            API_Menus.editMenu(id, this.menuForm).then(response => {
+              this.dialogMenuVisible = false
+              this.$message.success('保存成功!')
+              this.GET_Memus()
+            })
+          } else {
+            API_Menus.addMenu(this.menuForm).then(response => {
+              const data = this.currentMenu
+              if (this.menuForm.parent_id === 0) {
+                this.menus.push(response)
+              } else {
+                if (!data.children) this.$set(data, 'children', [])
+                data.children.push(response)
+              }
+              this.dialogMenuVisible = false
+              this.$message.success('保存成功!')
+            })
+          }
+        } else {
+          this.$message.error('表单填写有误,请检查!')
+          return false
+        }
+      })
+    },
+    /** 获取菜单 */
+    GET_Memus(parent_id) {
+      API_Menus.getMenusChildren(parent_id).then(response => {
+        this.menus = response
+      })
+    }
+  }
+}
+</script>
+
+<style type="text/scss" scoped>
+  .menus-container {
+    padding: 10px;
+    background-color: #fff;
+  /deep/ .el-tree {
+    width: 500px;
+  }
+  /deep/ .el-icon-minus {
+    color: #F56C6C;
+  }
+  }
+  .custom-tree-node {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 14px;
+    padding-right: 8px;
+  }
+</style>