Browse Source

企业+项目选择器

hexc 1 week ago
parent
commit
c93c5eb7fd
5 changed files with 237 additions and 29 deletions
  1. 109 26
      src/layout/components/TopNav.vue
  2. 13 1
      src/mixins/index.js
  3. 2 0
      src/permission.js
  4. 5 1
      src/store/getters.js
  5. 108 1
      src/store/modules/user.js

+ 109 - 26
src/layout/components/TopNav.vue

@@ -44,31 +44,61 @@
         </el-menu>
       </div>
       <div class="right-menu">
-        <template v-if="device !== 'mobile'">
-          <!-- <search id="header-search" class="right-menu-item" /> -->
-
-          <!-- <error-log class="errLog-container right-menu-item hover-effect" /> -->
-          <!-- <a target="_blank" href="https://bi.wookitech.com/" class="right-menu-item" title="人流统计系统">
-         <svg-icon icon-class="personnel" />
-       </a> -->
-          <!-- <a target="_blank" href="http://smoke.wookitech.com/" class="right-menu-item" title="烟雾感应系统">
-         <svg-icon icon-class="smoke" />
-       </a>
-       <a target="_blank" href="https://manage.wookitech.com/admin/totalData/login.html" class="right-menu-item" title="大数据屏">
-         <svg-icon icon-class="detectors" />
-       </a>
-
-       <a target="_blank" href="#" class="right-menu-item" title="打印系统">
-         <svg-icon icon-class="printing" />
-       </a> -->
-
-          <!-- <screenfull id="screenfull" class="right-menu-item hover-effect" /> -->
-
-          <!-- <el-tooltip content="Global Size" effect="dark" placement="bottom">
-         <size-select id="size-select" class="right-menu-item hover-effect" />
-       </el-tooltip> -->
-        </template>
-
+        <div
+          v-loading="projectLoading"
+          element-loading-text="项目加载中"
+          element-loading-spinner="el-icon-loading"
+          element-loading-background="rgba(0, 0, 0, 0)"
+          class="select-wrapper"
+        >
+          <div class="company-project-trigger">{{ globalProject.name }} <i class="el-icon-sort" /></div>
+          <el-select
+            v-if="globalFilter"
+            ref="appSelector"
+            default-first-option
+            class="company-project-selector"
+            :class="{show: isShowAppSelector}"
+            :value="globalProject"
+            value-key="id"
+            placeholder="请选择项目"
+            popper-class="project-el-select"
+            @change="selectProject"
+            @visible-change="isShowAppSelector=$event"
+          >
+            <template v-if="!companySelectMode">
+              <div v-if="isFujicaAdmin" class="project-nav" @click="companySelectMode = true"><i class="el-icon-arrow-left" /> {{ $store.state.user.company.name }}</div>
+              <el-input v-model="filterTextProject" placeholder="输入项目名称搜索" style="padding: 10px; box-sizing: border-box;" />
+              <el-option label="" value="" hidden />
+              <el-option v-for="(item, index) in projectListDisplay" :key="item.id" :label="item.name" :value="item">
+                <span style="float: left">{{ item.name }}</span>
+                <!-- <span style="float: right; color: #8492a6; font-size: 13px">{{ item.name }}</span> -->
+              </el-option>
+            </template>
+            <template v-else>
+              <el-input v-model="filterTextCompany" placeholder="输入企业名称搜索" style="padding: 10px; box-sizing: border-box;" />
+              <el-option label="" value="" hidden />
+              <el-tree
+                ref="tree"
+                :data="$store.state.user.companyList"
+                empty-text="暂无企业"
+                :props="{ children: 'children', label: 'name' }"
+                accordion
+                node-key="id"
+                :expand-on-click-node="false"
+                :check-on-click-node="true"
+                :filter-node-method="filterNode"
+                @node-click="selectCompany"
+              >
+                <span slot-scope="{ node, data }" class="custom-tree-node">
+                  <span>{{ node.label }}</span>
+                  <span v-if="data.projects.length" style="margin-right: 5px;">
+                    {{ `${data.projects.length}` }}<i class="el-icon-arrow-right" />
+                  </span>
+                </span>
+              </el-tree>
+            </template>
+          </el-select>
+        </div>
         <el-dropdown
           class="avatar-container right-menu-item hover-effect"
           trigger="click"
@@ -290,7 +320,10 @@ export default {
     }
   },
   computed: {
-    ...mapGetters(['avatar', 'device'])
+    ...mapGetters(['avatar', 'device']),
+    projectListDisplay(val) {
+      return this.$store.state.user.projectList.filter(p => p.name.indexOf(this.filterTextProject) !== -1)
+    }
   },
   watch: {
     'resetPasswordForm.password': function(newValue, oldValue) {
@@ -342,6 +375,24 @@ export default {
     window.removeEventListener('resize', this.setVisibleNumber)
   },
   methods: {
+    filterNode(value, data) {
+      if (!value) return true
+      return data.name.indexOf(value) !== -1
+    },
+    async selectCompany(e) {
+      const projectList = e.projects
+      if (!projectList?.length) {
+        this.$message.warning('该企业下没有项目')
+        return
+      }
+      this.companySelectMode = false // 切换到项目列表
+      this.$store.state.user.company = e
+      this.$store.state.user.projectList = projectList
+    },
+    selectProject(e) {
+      console.log(`TOPNAV_GLOBAL_PROJECT_CHANGE`, e.projectNo, e.name)
+      this.setGlobalProject(e)
+    },
     // 根据宽度计算设置显示栏数
     setVisibleNumber() {
       const width = document.body.getBoundingClientRect().width / 3
@@ -543,6 +594,38 @@ export default {
       &:focus {
         outline: none;
       }
+      .select-wrapper {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+        .company-project-trigger { display: none; }
+        .company-project-selector {
+          width: 0;
+          overflow: hidden;
+          transition: width .2s ease;
+          width: 250px;
+          margin-right: 10px;
+          /deep/ .el-input {
+            &__inner {
+              text-align: right;
+              background: #256cff;
+              border-color: #256cff;
+              color: #fff !important;
+            }
+            &__suffix {
+              top: -3px;
+            }
+          }
+          &.show { width: 250px; }
+          &:hover {
+            width: 250px;
+          }
+        }
+        &:hover {
+          .company-project-selector { width: 250px; }
+          .company-project-trigger { display: none; }
+        }
+      }
 
       .right-menu-item {
         display: inline-block;

+ 13 - 1
src/mixins/index.js

@@ -333,7 +333,7 @@ export default {
     }
   },
   computed: {
-    ...mapGetters(['public_dict']),
+    ...mapGetters(['public_dict', 'globalProject', 'globalUserInfo', 'globalFilter', 'globalCompany']),
     public_cartype() {
       const arr = this.public_dict[this.DICT_CODE.public_cartype] || []
       arr.forEach(item => {
@@ -341,6 +341,18 @@ export default {
         item.name = item.myname
       })
       return arr
+    },
+    globalProjectNo() { // 全局项目ID
+      return this.globalProject.projectNo
+    },
+    globalCompanyId() { // 全局企业ID【当前项目所属企业】
+      return this.isFujicaAdmin ? (this.$store.state.user.company?.id || 0) : this.globalUserInfo.companyId
+    },
+    isFujicaAdmin() { // 超管用户
+      return this.globalUserInfo.companyId === 0
+    },
+    isCompanyAdmin() { // 企业超管
+
     }
   },
   methods: {

+ 2 - 0
src/permission.js

@@ -36,6 +36,8 @@ router.beforeEach(async(to, from, next) => {
           // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
           await store.dispatch('user/getInfo')
 
+          await store.dispatch('user/getProject')
+
           // 拉取菜单
           const rtnArr = await store.dispatch('user/getMenue')
 

+ 5 - 1
src/store/getters.js

@@ -14,6 +14,10 @@ const getters = {
   permission_routes: state => state.permission.routes,
   errorLogs: state => state.errorLog.logs,
   operations: state => state.user.operations,
-  public_dict: state => state.dict.dict
+  public_dict: state => state.dict.dict,
+  globalUserInfo: state => state.user.userInfo,
+  globalProject: state => state.user.project,
+  globalFilter: state => state.user.globalFilter,
+  globalCompany: state => state.user.company
 }
 export default getters

+ 108 - 1
src/store/modules/user.js

@@ -13,6 +13,8 @@ import router, {
   resetRouter
 } from '@/router'
 import Layout from '@/layout'
+import { getProjectList } from '@/apiV2/project'
+import { getCompanyProjectList } from '@/apiV2/company'
 const state = {
   token: getToken(),
   name: '',
@@ -21,7 +23,13 @@ const state = {
   roles: [],
   topnav: '',
   toplist: [],
-  operations: []
+  operations: [],
+  userInfo: {}, // 当前用户信息
+  companyList: [], // 公司列表
+  company: {}, // 当前公司
+  projectList: [], // 项目列表
+  project: {}, // 当前项目
+  globalFilter: true, // 是否开启企业/项目筛选
 }
 /**
  * 添加动态(菜单)路由
@@ -87,6 +95,16 @@ const mutations = {
   },
   SET_OPERATION: (state, operations) => {
     state.operations = operations
+  },
+  SET_USERINFO: (state, userinfo) => {
+    state.userInfo = userinfo
+  },
+  SET_PROJECT: (state, project) => {
+    state.project = project
+    localStorage.setItem('globalProject', JSON.stringify(project))
+  },
+  SET_COMPANY: (state, project) => {
+    state.company = project
   }
 }
 
@@ -127,6 +145,7 @@ const actions = {
         const data = response
         localStorage.setItem('manager-userLogin', JSON.stringify(data.data))
         // localStorage.setItem('manager-companyId', JSON.stringify(response.data.enterprise.id))
+        commit('SET_USERINFO', data.data)
         if (!data) {
           reject('Verification failed, please Login again.')
         }
@@ -142,6 +161,9 @@ const actions = {
         commit('SET_AVATAR', avatar)
         commit('SET_INTRODUCTION', introduction) */
         commit('SET_ROLES', 'admin')
+        commit('SET_NAME', 'andy')
+        commit('SET_AVATAR', 'zhoudong')
+        commit('SET_INTRODUCTION', '第一个应用')
         commit('SET_OPERATION', menus)
         resolve(data)
       }).catch(error => {
@@ -260,6 +282,91 @@ const actions = {
         resolve(rtnArr)
       })
     })
+  },
+
+  setProject({ commit }, project) {
+    commit('SET_PROJECT', project)
+    window.location.reload()
+    // Bus.emit('projectChange', project)
+  },
+
+  async getProject({ state, dispatch }) {
+    const projectStr = localStorage.getItem('globalProject')
+    const isAdmin = state.userInfo.companyId === 0
+    /* 设置全局默认项目 */
+    if (isAdmin) { // 企业 + 项目
+      const setProjectByLocal = () => { // 设置项目(通过本地缓存)
+        const localProject = JSON.parse(projectStr)
+        let localProjectError = true
+        state.companyList.filter(company => company.projects?.length).map(company => {
+          const project = company.projects.find(project => project.projectNo === localProject.projectNo)
+          if (project) { // 项目合法
+            setCP(company, project)
+            localProjectError = false
+            console.log('PROJCET(local):', state.project)
+          }
+        })
+        if(localProjectError) setProjectByRemote()
+      }
+      const setProjectByRemote = () => { // 设置项目(取接口第一个)
+        const company = state.companyList.find(company => company.projects?.length)
+        if (company) {
+          setCP(company, company.projects[0])
+        }
+        console.log('PROJCET(remote):', state.project)
+      }
+      const setCP = (company, project) => { // 设置企业+项目
+        state.company = company
+        // company存在,要切到项目状态,右上角才会显示
+        state.project = project
+        state.projectList = company.projects
+      }
+      const res = await getCompanyProjectList()
+      if (res.success) {
+        state.companyList = res.data
+        if (projectStr) { // 缓存
+          try {
+            setProjectByLocal()
+          } catch (err) {
+            console.error(err)
+            setProjectByRemote()
+          }
+        } else { // 接口
+          setProjectByRemote()
+        }
+      }
+    } else { // 项目
+      const setProjectByRemote = () => {
+        if (state.projectList[0]) state.project = state.projectList[0] // dispatch('setProject', state.projectList[0])
+        else state.project = {} // dispatch('setProject', {})
+      }
+      const res = await getProjectList({ companyId: state.userInfo.companyId })
+      state.company = { id: state.userInfo.companyId, name: state.userInfo.companyName }
+      state.projectList = res.data || []
+      if (projectStr) { // 缓存
+        try {
+          const localProject = JSON.parse(projectStr)
+          const project = state.projectList.find(project => project.projectNo === localProject.projectNo)
+          if (project) { // 项目合法
+            state.project = project // dispatch('setProject', project)
+          } else {
+            setProjectByRemote()
+          }
+        } catch (err) {
+          setProjectByRemote()
+        }
+      } else { // 接口
+        setProjectByRemote()
+      }
+    }
+    return state.project
+  },
+  toggleGlobalFilter({ state, dispatch }, value = false) {
+    console.log(`GLOBAL_FILTER`, value)
+    state.globalFilter = value
+  },
+  closeGlobalFilter({ state, dispatch }) {
+    dispatch('toggleGlobalFilter', false)
   }
 }