Sfoglia il codice sorgente

feat:对接平台及路由

刘恒 1 anno fa
parent
commit
425f25bb98

+ 115 - 5
package-lock.json

@@ -10,6 +10,7 @@
       "dependencies": {
         "@headlessui/vue": "^1.7.23",
         "@imengyu/vue3-context-menu": "^1.4.4",
+        "@vue/component-compiler-utils": "^3.3.0",
         "@vueuse/components": "^12.0.0",
         "@vueuse/core": "^12.0.0",
         "@vueuse/integrations": "^12.0.0",
@@ -5029,6 +5030,64 @@
         "he": "^1.2.0"
       }
     },
+    "node_modules/@vue/component-compiler-utils": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmmirror.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz",
+      "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==",
+      "license": "MIT",
+      "dependencies": {
+        "consolidate": "^0.15.1",
+        "hash-sum": "^1.0.2",
+        "lru-cache": "^4.1.2",
+        "merge-source-map": "^1.1.0",
+        "postcss": "^7.0.36",
+        "postcss-selector-parser": "^6.0.2",
+        "source-map": "~0.6.1",
+        "vue-template-es2015-compiler": "^1.9.0"
+      },
+      "optionalDependencies": {
+        "prettier": "^1.18.2 || ^2.0.0"
+      }
+    },
+    "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-4.1.5.tgz",
+      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+      "license": "ISC",
+      "dependencies": {
+        "pseudomap": "^1.0.2",
+        "yallist": "^2.1.2"
+      }
+    },
+    "node_modules/@vue/component-compiler-utils/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "license": "ISC"
+    },
+    "node_modules/@vue/component-compiler-utils/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmmirror.com/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "license": "MIT",
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/@vue/component-compiler-utils/node_modules/yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+      "license": "ISC"
+    },
     "node_modules/@vue/devtools-api": {
       "version": "6.6.4",
       "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
@@ -6048,7 +6107,6 @@
       "version": "3.7.2",
       "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
       "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
-      "dev": true,
       "license": "MIT"
     },
     "node_modules/boolbase": {
@@ -6968,6 +7026,19 @@
         "node": "^14.18.0 || >=16.10.0"
       }
     },
+    "node_modules/consolidate": {
+      "version": "0.15.1",
+      "resolved": "https://registry.npmmirror.com/consolidate/-/consolidate-0.15.1.tgz",
+      "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==",
+      "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog",
+      "license": "MIT",
+      "dependencies": {
+        "bluebird": "^3.1.1"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
     "node_modules/constant-case": {
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/constant-case/-/constant-case-3.0.4.tgz",
@@ -7230,7 +7301,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz",
       "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
-      "dev": true,
       "license": "MIT",
       "bin": {
         "cssesc": "bin/cssesc"
@@ -10188,6 +10258,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/hash-sum": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz",
+      "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
+      "license": "MIT"
+    },
     "node_modules/hasown": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
@@ -12811,6 +12887,15 @@
         "node": ">=4"
       }
     },
+    "node_modules/merge-source-map": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/merge-source-map/-/merge-source-map-1.1.0.tgz",
+      "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
+      "license": "MIT",
+      "dependencies": {
+        "source-map": "^0.6.1"
+      }
+    },
     "node_modules/merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -15381,7 +15466,6 @@
       "version": "6.1.2",
       "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
       "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "cssesc": "^3.0.0",
@@ -15605,6 +15689,22 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/prettier": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "license": "MIT",
+      "optional": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
     "node_modules/pretty-ms": {
       "version": "9.2.0",
       "resolved": "https://registry.npmmirror.com/pretty-ms/-/pretty-ms-9.2.0.tgz",
@@ -15658,6 +15758,12 @@
       "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
       "license": "MIT"
     },
+    "node_modules/pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+      "license": "ISC"
+    },
     "node_modules/punycode": {
       "version": "2.3.1",
       "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
@@ -17350,7 +17456,6 @@
       "version": "0.6.1",
       "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
       "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "dev": true,
       "license": "BSD-3-Clause",
       "engines": {
         "node": ">=0.10.0"
@@ -20253,7 +20358,6 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
-      "dev": true,
       "license": "MIT"
     },
     "node_modules/v8flags": {
@@ -21502,6 +21606,12 @@
         "vue": "^3.2.0"
       }
     },
+    "node_modules/vue-template-es2015-compiler": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
+      "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
+      "license": "MIT"
+    },
     "node_modules/vue-tsc": {
       "version": "2.2.0",
       "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.0.tgz",

+ 1 - 0
package.json

@@ -24,6 +24,7 @@
   "dependencies": {
     "@headlessui/vue": "^1.7.23",
     "@imengyu/vue3-context-menu": "^1.4.4",
+    "@vue/component-compiler-utils": "^3.3.0",
     "@vueuse/components": "^12.0.0",
     "@vueuse/core": "^12.0.0",
     "@vueuse/integrations": "^12.0.0",

+ 3 - 1
src/api/index.ts

@@ -11,6 +11,7 @@ import roleApi from './modules/role'
 import institutionApi from './modules/institution'
 import areaApi from "./modules/area"
 import operationApi from './modules/operation.ts'
+import menuApi from './modules/menu.ts'
 
 const axiosInstance:ApiInstance = axios.create({
   baseURL: (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY === 'true') ? '/proxy/' : import.meta.env.VITE_APP_API_BASEURL,
@@ -92,6 +93,7 @@ const api = {
   roleApi: roleApi(axiosInstance),
   institutionApi:institutionApi(axiosInstance),
   areaApi:areaApi(axiosInstance),
-  operationApi: operationApi(axiosInstance)
+  operationApi: operationApi(axiosInstance),
+  menuApi:menuApi(axiosInstance)
 }
 export default api

+ 15 - 0
src/api/modules/menu.ts

@@ -0,0 +1,15 @@
+import { ApiInstance } from '../type'
+interface menuData {
+  
+  systemCode: string,
+
+  [property:string]:any,
+}
+const menuApi = (axiosInstance: ApiInstance) => ({
+  // 获取菜单
+  getTenantConfig:(params:menuData) => axiosInstance.get('system/getInitConfig',{params}),
+  
+ 
+})
+
+export default menuApi

+ 1 - 1
src/api/modules/user.ts

@@ -332,7 +332,7 @@ const userApi = (axiosInstance: ApiInstance) => ({
   userDelete: (data: {id:string[]}) => axiosInstance.post('/userInfo/delete', data, { }),
 
   //离职
-  userQuitApply: (data: {id:string[]}) => axiosInstance.post('/userInfo/userQuitApply', data, { }),
+  userQuitApply: (data: {userId:string}) => axiosInstance.post('/userInfo/userQuitApply', data, { }),
   
   
   

+ 35 - 0
src/assets/styles/globals.css

@@ -247,3 +247,38 @@ textarea {
 .pad-3 {
   padding: 30px;
 }
+
+/* 消息提示弹窗 */
+.el-message-box {
+  padding: 32px 32px 24px;
+}
+
+.el-message-box .el-message-box__title {
+  gap: 17px;
+  align-items: center;
+  justify-content: flex-start;
+  font-weight: bold;
+}
+
+.el-message-box .el-message-box__title .el-icon {
+  font-size: x-large;
+}
+
+.el-message-box .el-message-box__title .el-message-box-icon--info {
+  color: #0083ff;
+}
+
+.el-message-box .el-message-box__btns {
+  justify-content: flex-end;
+  padding-top: 24px;
+}
+
+.el-message-box .el-message-box__content {
+  padding-left: 40px;
+}
+
+.el-message-box .el-message-box__content .el-message-box__container {
+  justify-content: flex-start;
+}
+
+/* 消息提示弹窗 */

+ 12 - 2
src/components/DialogSetDeptLeader/index.vue

@@ -6,6 +6,7 @@
       width="1000"
       append-to-body
       draggable
+      :before-close="handleClose"
     >
       <el-select
         v-model="userId"
@@ -72,7 +73,7 @@
       </div>
       <template #footer>
         <div class="dialog-footer">
-          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button @click="handleClose ">取消</el-button>
           <el-button type="primary" @click="submit">
             确认
           </el-button>
@@ -85,6 +86,7 @@
 <script setup lang="ts">
 import { defineProps, ref, onMounted, defineEmits } from "vue";
 import api from "@/api";
+import { ElMessage } from "element-plus";
 type tableType = {
   id: string;
   name: string;
@@ -112,7 +114,7 @@ const userId = ref<string>("");
 const loading = ref(false);
 const treeReId=ref<string>("");
 
-const emits=defineEmits(["closeDialog"]);
+const emits=defineEmits(["closeDialog",'cancelDialog']);
 
 
 const userList = ref<any[]>([]);
@@ -183,6 +185,7 @@ function submit(){
       }).then(res=>{
         
         if(res.code==200){
+          ElMessage.success(res.msg)
           emits('closeDialog')
         }
       })
@@ -205,6 +208,7 @@ function submit(){
         leaderId:flag.userId
       }).then(res=>{
         if(res.code==200){
+          ElMessage.success(res.msg)
           emits('closeDialog')
         }
       })
@@ -241,6 +245,12 @@ function submit(){
    
 }
 
+const handleClose = (done: () => void) => {
+  
+  emits('cancelDialog',false)
+    
+}
+
 
 </script>
 <style lang="scss" scoped>

+ 5 - 0
src/components/LoginForm/index.vue

@@ -2,6 +2,7 @@
 import type { FormInstance, FormRules } from "element-plus";
 import useUserStore from "@/store/modules/user";
 import { ref, useTemplateRef, onMounted,onUnmounted } from "vue";
+import { systemRoutes } from "@/router/routes";
 
 defineOptions({
   name: "LoginForm",
@@ -91,11 +92,15 @@ function handleLogin() {
           }
           localStorage.setItem("login_system", form.value.system);
           emits("onLogin", form.value.userName);
+          // userStore.getMenu({systemCode:form.value.system}).then((res:any)=>{
+          //   console.log(res)
+          // })
         })
         .finally(() => {
           loading.value = false;
           refreshCaptcha();
         });
+      
     }
   });
 }

+ 31 - 5
src/components/Table/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="container">
+  <div class="table-container">
     <div class="table_box">
       <div class="table-title-btn">
         <slot name="table-title-btn"></slot>
@@ -11,6 +11,8 @@
         style="width: 100%"
         row-key="id"
         :tree-props="props.treeProps"
+        @selection-change="selectChange"
+        @select-all="selectAllChange"
       >
         <el-table-column
           type="selection"
@@ -85,7 +87,7 @@ interface TableRow {
 interface TagTypes {
   [key: string]: string;
 }
-const emit = defineEmits(["getList"]);
+const emit = defineEmits(['getList', 'selectAllChange','selectChange']);
 const props = defineProps<{
   tableData: Array<TableRow>;
   columns: {
@@ -150,11 +152,35 @@ const handleCancle = (scope: { row: TableRow }) => {
 const headClass = (scope: { row: TableRow }) => {
   // return 'background:#F8F8F9'
 };
+
+//多选
+const newSelectionList = ref<string[]>([]);
+const selectAllChange = (value: any[]) => {
+  if (value.length>0) {
+    value.map(val => {
+      newSelectionList.value.push(val.id)
+    })
+  } else {
+    newSelectionList.value = [];
+  }
+  emit('selectAllChange', newSelectionList.value)
+
+}
+const selectChange = (value: any[]) => {
+  if (value.length>0) {
+    value.map(val => {
+      newSelectionList.value.push(val.id)
+    })
+  } else {
+    newSelectionList.value = [];
+  }
+  emit('selectChange', newSelectionList.value)
+}
 </script>
 <style lang="scss" scoped>
-.container {
-  width: 100%;
-  height: auto;
+.table-container {
+  // width: 100%;
+  // height: auto;
   margin: 5px;
   display: flex;
   flex-direction: column;

+ 1 - 0
src/layouts/components/Menu/index.vue

@@ -30,6 +30,7 @@ const isMenuPopup = computed<MenuInjection['isMenuPopup']>(() => {
 
 // 解析传入的 menu 数据,并保存到 items 和 subMenus 对象中
 function initItems(menu: MenuProps['menu'], parentPaths: string[] = []) {
+  console.log(menu)
   menu.forEach((item) => {
     const index = item.path ?? JSON.stringify(item)
     if (item.children) {

+ 3 - 0
src/router/guards.ts

@@ -73,11 +73,14 @@ function setupRoutes(router: Router) {
         // 记录的数据会在登出时会使用到,不使用 router.removeRoute 是考虑配置的路由可能不一定有设置 name ,则通过调用 router.addRoute() 返回的回调进行删除
         const removeRoutes: (() => void)[] = []
         routeStore.flatRoutes.forEach((route) => {
+
           if (!/^(?:https?:|mailto:|tel:)/.test(route.path)) {
+            console.log(router)
             removeRoutes.push(router.addRoute(route as RouteRecordRaw))
           }
         })
         if (settingsStore.settings.app.routeBaseOn !== 'filesystem') {
+     
           routeStore.flatSystemRoutes.forEach((route) => {
             removeRoutes.push(router.addRoute(route as RouteRecordRaw))
           })

+ 84 - 107
src/router/routes.ts

@@ -1,158 +1,135 @@
-import type { Route } from '#/global'
-import type { RouteRecordRaw } from 'vue-router'
-import useSettingsStore from '@/store/modules/settings'
-import generatedRoutes from 'virtual:generated-pages'
-import { setupLayouts } from 'virtual:meta-layouts'
-import MultilevelMenuExample from './modules/multilevel.menu.example'
-import organizationManagement from './modules/organization'
-import operationManagement from './modules/operation'
-import personnel from './modules/personnel'
-
-// 固定路由(默认路由)
+import type { Route } from "#/global";
+import type { RouteRecordRaw } from "vue-router";
+import useSettingsStore from "@/store/modules/settings";
+import generatedRoutes from "virtual:generated-pages";
+import { setupLayouts } from "virtual:meta-layouts";
+import MultilevelMenuExample from "./modules/multilevel.menu.example";
+import organizationManagement from "./modules/organization";
+import operationManagement from "./modules/operation";
+import personnel from "./modules/personnel";
+// import {  } from "@/store/modules/user";
+// 固定路由(默认路由
+// console.log(useUserStore)
+// const userStore = useUserStore()
 const constantRoutes: RouteRecordRaw[] = [
   {
-    path: '/login',
-    name: 'login',
-    component: () => import('@/views/login.vue'),
+    path: "/login",
+    name: "login",
+    component: () => import("@/views/login.vue"),
     meta: {
-      title: '登录',
+      title: "登录",
     },
   },
   {
-    path: '/:all(.*)*',
-    name: 'notFound',
-    component: () => import('@/views/[...all].vue'),
+    path: "/:all(.*)*",
+    name: "notFound",
+    component: () => import("@/views/[...all].vue"),
     meta: {
-      title: '找不到页面',
+      title: "找不到页面",
     },
   },
-]
+];
 
 // 系统路由
 const systemRoutes: RouteRecordRaw[] = [
   {
-    path: '/',
-    component: () => import('@/layouts/index.vue'),
+    path: "/",
+    component: () => import("@/layouts/index.vue"),
     meta: {
       title: () => useSettingsStore().settings.home.title,
       breadcrumb: false,
     },
     children: [
       {
-        path: '',
-        component: () => import('@/views/index.vue'),
+        path: "",
+        component: () => import("@/views/index.vue"),
         meta: {
           title: () => useSettingsStore().settings.home.title,
-          icon: 'i-ant-design:home-twotone',
+          icon: "i-ant-design:home-twotone",
           breadcrumb: false,
         },
       },
       {
-        path: 'reload',
-        name: 'reload',
-        component: () => import('@/views/reload.vue'),
+        path: "reload",
+        name: "reload",
+        component: () => import("@/views/reload.vue"),
         meta: {
-          title: '重新加载',
+          title: "重新加载",
           breadcrumb: false,
         },
       },
     ],
   },
-]
+];
 
+// console.log(userStore,666)
 // 动态路由(异步路由、导航栏路由)
+
 const asyncRoutes: Route.recordMainRaw[] = [
   {
     meta: {
-      title: '演示',
-      icon: 'i-uim:box',
+      title: "组织架构",
+      icon: "i-uim:box",
     },
-    children: [
-      MultilevelMenuExample,
-
-    ],
+    children: [personnel],
   },
   // {
   //   meta: {
-  //     title: '演示',
-  //     icon: 'i-uim:box',
+  //     title: "租户管理",
+  //     icon: "i-uim:box",
   //   },
-  //   children: [
-  //     MultilevelMenuExample,
-
-  //   ],
+  //   children: [],
   // },
   {
     meta: {
-      title: '组织架构',
-      icon: 'i-uim:box',
-    },
-    children: [
-      organizationManagement,
-      personnel
-    ],
-  },
-  {
-    meta: {
-      title: '租户管理',
-      icon: 'i-uim:box',
-    },
-    children: [
-      organizationManagement
-
-    ],
-  },
-  {
-    meta: {
-      title: '业务管理',
-      icon: 'i-uim:box',
-    },
-    children: [
-      operationManagement
-    ],
-  },
-  {
-    meta: {
-      title: '租户运营',
-      icon: 'i-uim:box',
-    },
-    children: [
-    ],
-  },
-  {
-    meta: {
-      title: '数据中心',
-      icon: 'i-uim:box',
+      title: "业务管理",
+      icon: "i-uim:box",
     },
-    children: [
-    ],
-  },
-  {
-    meta: {
-      title: '增值服务',
-      icon: 'i-uim:box',
-    },
-    children: [
-    ],
+    children: [operationManagement],
   },
-  {
-    meta: {
-      title: '基础设置',
-      icon: 'i-uim:box',
-    },
-    children: [
-    ],
-  },
-
-]
+  // {
+  //   meta: {
+  //     title: "租户运营",
+  //     icon: "i-uim:box",
+  //   },
+  //   children: [],
+  // },
+  // {
+  //   meta: {
+  //     title: "数据中心",
+  //     icon: "i-uim:box",
+  //   },
+  //   children: [],
+  // },
+  // {
+  //   meta: {
+  //     title: "增值服务",
+  //     icon: "i-uim:box",
+  //   },
+  //   children: [],
+  // },
+  // {
+  //   meta: {
+  //     title: "基础设置",
+  //     icon: "i-uim:box",
+  //   },
+  //   children: [],
+  // },
+];
 
 const constantRoutesByFilesystem = generatedRoutes.filter((item) => {
-  return item.meta?.enabled !== false && item.meta?.constant === true
-})
+  return item.meta?.enabled !== false && item.meta?.constant === true;
+});
 
-const asyncRoutesByFilesystem = setupLayouts(generatedRoutes.filter((item) => {
-  return item.meta?.enabled !== false && item.meta?.constant !== true && item.meta?.layout !== false
-}))
+const asyncRoutesByFilesystem = setupLayouts(
+  generatedRoutes.filter((item) => {
+    return (
+      item.meta?.enabled !== false &&
+      item.meta?.constant !== true &&
+      item.meta?.layout !== false
+    );
+  })
+);
 
 export {
   asyncRoutes,
@@ -160,4 +137,4 @@ export {
   constantRoutes,
   constantRoutesByFilesystem,
   systemRoutes,
-}
+};

+ 2 - 2
src/settings.default.ts

@@ -10,7 +10,7 @@ const globalSettingsDefault: RecursiveRequired<Settings.all> = {
     enablePermission: false,
     enableProgress: true,
     enableDynamicTitle: false,
-    routeBaseOn: 'frontend',
+    routeBaseOn: 'backend',
   },
   home: {
     enable: true,
@@ -21,7 +21,7 @@ const globalSettingsDefault: RecursiveRequired<Settings.all> = {
     enableMobileAdaptation: false,
   },
   menu: {
-    baseOn: 'frontend',
+    baseOn: 'backend',
     mode: 'side',
     switchMainMenuAndPageJump: false,
     subMenuUniqueOpened: true,

+ 2 - 2
src/settings.ts

@@ -11,7 +11,7 @@ const globalSettings: Settings.all = {
     enablePermission: true,
     enableProgress: true,
     enableDynamicTitle: false,
-    routeBaseOn: 'frontend',
+    routeBaseOn: 'backend',
   },
   home: {
     enable: true,
@@ -22,7 +22,7 @@ const globalSettings: Settings.all = {
     enableMobileAdaptation: true,
   },
   menu: {
-    baseOn: 'frontend',
+    baseOn: 'backend',
     mode: 'head',
     switchMainMenuAndPageJump: false,
     subMenuUniqueOpened: true,

+ 1 - 1
src/store/modules/menu.ts

@@ -144,7 +144,7 @@ const useMenuStore = defineStore(
       if (menu.meta?.auth) {
         if(permissions)
         isAuth = permissions.some((auth) => {
-          console.log(auth)
+          // console.log(auth)
           if (typeof menu.meta?.auth === 'string') {
             return menu.meta.auth !== '' ? menu.meta.auth === auth : true
           }

+ 16 - 5
src/store/modules/route.ts

@@ -1,10 +1,12 @@
 import type { Route } from '#/global'
 import type { RouteRecordRaw } from 'vue-router'
-import apiApp from '@/api/modules/app'
+import menuApi from '@/api/modules/menu'
 import { systemRoutes } from '@/router/routes'
 import { resolveRoutePath } from '@/utils'
 import { cloneDeep } from 'lodash-es'
 import useSettingsStore from './settings'
+import api from '@/api'
+
 
 const useRouteStore = defineStore(
   // 唯一ID
@@ -151,14 +153,18 @@ const useRouteStore = defineStore(
     // 格式化后端路由数据
     function formatBackRoutes(routes: any, views = import.meta.glob('../../views/**/*.vue')): Route.recordMainRaw[] {
       return routes.map((route: any) => {
+        // console.log(route.component)
         switch (route.component) {
-          case 'Layout':
+          case "layout":
             route.component = () => import('@/layouts/index.vue')
             break
           default:
             if (route.component) {
-              route.component = views[`../../views/${route.component}`]
+              route.component = views[`../../views${route.component}.vue`]
+             
             }
+           
+            
             else {
               delete route.component
             }
@@ -166,14 +172,19 @@ const useRouteStore = defineStore(
         if (route.children) {
           route.children = formatBackRoutes(route.children, views)
         }
+        // console.log(route)
         return route
       })
     }
     // 生成路由(后端获取)
     async function generateRoutesAtBack() {
-      await apiApp.routeList().then((res) => {
+      await api.menuApi.getTenantConfig({
+        systemCode:localStorage.getItem('login_system') || '',
+      }).then((res) => {
+        // console.log(JSON.parse(res.data.sysConfig))
         // 设置 routes 数据
-        routesRaw.value = converDeprecatedAttribute(formatBackRoutes(res.data) as any)
+        routesRaw.value = formatBackRoutes(JSON.parse(res.data.sysConfig)) as any
+        // console.log(routesRaw.value,66666)
         isGenerate.value = true
       }).catch(() => {})
     }

+ 18 - 3
src/store/modules/user.ts

@@ -17,14 +17,14 @@ const useUserStore = defineStore(
     const token = ref(localStorage.token ?? '')
     const avatar = ref(localStorage.avatar ?? '')
     const permissions = ref<string[]>([])
-
+    const staticRouter=ref<string[]>([])
     const isLogin = computed(() => {
       if (token.value) {
         return true
       }
       return false
     })
-
+    //登录
     async function login(data: {
       userName: string
       passWord: string
@@ -33,13 +33,25 @@ const useUserStore = defineStore(
       captchaId: number
     }) {
         const res = await api.userApi.login(data)
-        console.log(res)
+        
         localStorage.setItem('userName', data.userName)
         localStorage.setItem('token', res.data)
         userName.value = data.userName
         token.value = res.data
         avatar.value = 'https://fantastic-admin.hurui.me/logo.png'
     }
+    //获取运营交付菜单
+    async function getMenu(codeItem) {
+        const res = await api.menuApi.getTenantConfig({...codeItem})
+        
+      
+    
+       if(res.code===200){
+        // staticRouter.value=JSON.parse(res.data.sysConfig)
+        localStorage.setItem("menu",res.data.sysConfig)
+        // routeStore.routesRaw=JSON.parse(res.data.sysConfig)
+       }
+    }
     // 登出
     async function logout(redirect = router.currentRoute.value.fullPath) {
       localStorage.removeItem('userName')
@@ -78,10 +90,13 @@ const useUserStore = defineStore(
       avatar,
       permissions,
       isLogin,
+      staticRouter,
       login,
       logout,
       getPermissions,
       editPassword,
+      getMenu,
+      
     }
   },
 )

+ 62 - 9
src/utils/composables/routeUtils.ts

@@ -7,21 +7,25 @@ export const permissionDictionary: Record<string, string> = {
   // 添加更多操作类型映射
 };
 export interface RouteItem {
+  id:number;
   path: string;
   name?: string;
   meta?: {
     title?: string;
     icon?: string;
     auth?: string[];
+    menu?: boolean;
   };
+  component: any,
   children?: RouteItem[];
+  
 }
 
 export interface TreeNode {
-  id: number;
+  // id: number;
   title: string;
   icon?: string;
-  type?:string,
+  type?: string,
   children?: TreeNode[];
   [key: string]: any; // 允许任意其他属性
 }
@@ -32,21 +36,69 @@ let idCounter = ref(0);
 const generateId = (): number => {
   return ++idCounter.value;
 };
+function extractImportPath(func: any) {
+  if (!func) {
+    console.log("No function provided");
+    return null;
+  }
+
+  if (typeof func !== "function") {
+    console.error("Provided value is not a function");
+    return null;
+  }
+  // 将函数转换为字符串
+  const funcStr = func.toString();
+
+  // 如果字符串中包含 "layouts",返回 "layout"
+  if (funcStr.includes("layouts")) {
+    return "layout";
+  }
+
+  // 检查 import() 的结构是否存在
+  const startIndex = funcStr.indexOf('import("') + 8;
+  const endIndex = funcStr.indexOf('")', startIndex);
+
+  if (startIndex > 7 && endIndex > startIndex) {
+    let path = funcStr.substring(startIndex, endIndex);
+
+    // 如果路径中存在时间戳(例如 ?t=xxx),将其去掉
+    if (path.includes("?")) {
+      path = path.split("?")[0];
+    }
+
+    // 如果路径中存在 .vue 后缀,将其移除
+    if (path.endsWith(".vue")) {
+      path = path.slice(0, -4);
+    }
+
+    // 去掉路径中的 /src/views 前缀
+    const prefixToRemove = "/src/views";
+    if (path.startsWith(prefixToRemove)) {
+      path = path.slice(prefixToRemove.length);
+    }
+
+    return path;
+  }
+  return null;
+}
 
 // 预处理函数:确保 children 和 auth 类型正确
 export const preprocessRoutes = (routes: any[]): RouteItem[] => {
   return routes.map(route => {
+    
     const processedRoute: RouteItem = {
+      id: generateId(),
       path: route.path || '',
       name: route.name,
+      component: route.component ? extractImportPath(route.component) : '',
       meta: {
         ...route.meta,
         // 确保 meta.auth 始终是一个数组
         auth: Array.isArray(route.meta?.auth)
           ? route.meta.auth
           : route.meta?.auth
-          ? [route.meta.auth]
-          : [],
+            ? [route.meta.auth]
+            : [],
       },
       // 确保 children 存在且是数组
       children: route.children ? preprocessRoutes(route.children) : [],
@@ -73,18 +125,19 @@ const parseAuthToChildren = (authList: string[]): TreeNode[] => {
 };
 
 // 将 RouteItem 转换为 TreeNode
-export const convertToTreeData = (id:number,routes: RouteItem[]): TreeNode[] => {
-  idCounter.value=id;
-  return routes.map(route => {
+export const convertToTreeData = (id: number, routes: RouteItem[]): TreeNode[] => {
+  idCounter.value = id;
+  return routes.filter(route => route.meta?.menu !== false).map(route => {
     const node: TreeNode = {
       id: generateId(),
       title: route.meta?.title || route.name || '',
       icon: route.meta?.icon,
-      type:route.path?"1":'0',
+      type: route.path ? "1" : '0',
+
     };
 
     if (route.children && route.children.length > 0) {
-      node.children = convertToTreeData(idCounter.value,route.children);
+      node.children = convertToTreeData(idCounter.value, route.children);
     }
 
     if (route.meta?.auth) {

+ 174 - 120
src/views/login.vue

@@ -1,144 +1,198 @@
 <route lang="yaml">
-  meta:
-    title: 登录
-    constant: true
-    layout: false
-  </route>
-  <script setup lang="ts">
-  import { ref } from 'vue'
-  import { useRoute, useRouter } from 'vue-router'
-  import useUserStore from '@/store/modules/settings'
-  defineOptions({
-    name: 'Login',
-  })
+meta:
+  title: 登录
+  constant: true
+  layout: false
+</route>
+<script setup lang="ts">
+import { ref, onBeforeMount } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import useUserStore from "@/store/modules/settings";
+import { asyncRoutes } from "@/router/routes"; // 请根据实际路径调整
+import {
+  preprocessRoutes,
+  convertToTreeData,
+  TreeNode,
+} from "@/utils/composables/routeUtils"; // 导入工具方法
+defineOptions({
+  name: "Login",
+});
+import api from "@/api";
 
-  const route = useRoute()
-  const router = useRouter()
-  const settingsStore = useUserStore()
+const treeData = ref<TreeNode[]>([]);
+onBeforeMount(() => {
+  // 对 asyncRoutes 进行预处理并转换为树形结构
+  const processedRoutes = preprocessRoutes(asyncRoutes);
 
-  const redirect = ref(route.query.redirect?.toString() ?? settingsStore.settings.home.fullPath)
-  const account = ref<string>()
-  // // 表单类型
-  const formType = ref<'login' | 'register' | 'resetPassword'>('login')
-  </script>
+  treeData.value = convertToTreeData(0, processedRoutes);
 
-  <template>
-    <div class="bg-banner" />
-    <img class="bgback" src=".././assets/images/loginback1.png" alt="">
-    <div class="login-box">
-      <!-- <div class="login-banner">
+  api.roleApi
+    .updateConfig({
+      sysConfig: JSON.stringify(processedRoutes),
+      sysPerms: JSON.stringify(treeData.value),
+    })
+    .then((res) => {});
+});
+
+const route = useRoute();
+const router = useRouter();
+const settingsStore = useUserStore();
+
+const redirect = ref(
+  route.query.redirect?.toString() ?? settingsStore.settings.home.fullPath
+);
+const account = ref<string>();
+// // 表单类型
+const formType = ref<"login" | "register" | "resetPassword">("login");
+</script>
+
+<template>
+  <div class="bg-banner" />
+  <img class="bgback" src=".././assets/images/loginback1.png" alt="" />
+  <div class="login-box">
+    <!-- <div class="login-banner">
         <img
           src="@/assets/images/logo.png"
           class="absolute left-4 top-4 h-30px rounded ring ring-stone-2 dark-ring-stone-8"
         >
         <img src="@/assets/images/login-banner.png" class="banner">
       </div> -->
-      <div class="login-form flex-col-center">
-        <Transition name="fade" mode="out-in">
-          <LoginForm
-            v-if="formType === 'login'" :account @on-login="router.push(redirect)"
-            @on-register="(account) => { formType = 'register'; account = account }"
-            @on-reset-password="(account) => { formType = 'resetPassword'; account = account }"
-          />
-          <RegisterForm
-            v-else-if="formType === 'register'" :account
-            @on-register="(account) => { formType = 'login'; account = account }" @on-login="formType = 'login'"
-          />
-          <ResetPasswordForm
-            v-else-if="formType === 'resetPassword'" :account
-            @on-reset-password="(account) => { formType = 'login'; account = account }" @on-login="formType = 'login'"
-          />
-        </Transition>
-      </div>
+    <div class="login-form flex-col-center">
+      <Transition name="fade" mode="out-in">
+        <LoginForm
+          v-if="formType === 'login'"
+          :account
+          @on-login="router.push(redirect)"
+          @on-register="
+            (account) => {
+              formType = 'register';
+              account = account;
+            }
+          "
+          @on-reset-password="
+            (account) => {
+              formType = 'resetPassword';
+              account = account;
+            }
+          "
+        />
+        <RegisterForm
+          v-else-if="formType === 'register'"
+          :account
+          @on-register="
+            (account) => {
+              formType = 'login';
+              account = account;
+            }
+          "
+          @on-login="formType = 'login'"
+        />
+        <ResetPasswordForm
+          v-else-if="formType === 'resetPassword'"
+          :account
+          @on-reset-password="
+            (account) => {
+              formType = 'login';
+              account = account;
+            }
+          "
+          @on-login="formType = 'login'"
+        />
+      </Transition>
     </div>
-  </template>
-  <style lang="scss" scoped>
-  .bg-banner {
-    position: fixed;
-    z-index: 0;
-    width: 100%;
-    height: 100%;
-    background: radial-gradient(circle at center, var(--g-container-bg), var(--g-bg));
-    background-image: url(".././assets/images/loginback.png");
-    background-size: cover;
-  }
-  .bgback {
-    position: fixed;
-    top: 58%;
-    left: 35%;
-    z-index: 0;
-    transform: translateX(-50%) translateY(-50%);
-  }
-  [data-mode="mobile"] {
-    .login-box {
-      position: relative;
-      flex-direction: column;
-      justify-content: start;
-      width: 100%;
-      .login-banner {
-        width: 100%;
-        padding: 20px 0;
-        .banner {
-          position: relative;
-          top: inherit;
-          right: inherit;
-          display: inherit;
-          width: 100%;
-          max-width: 375px;
-          margin: 0 auto;
-          transform: translateY(0);
-        }
-      }
-      .login-form {
-        width: 100%;
-      }
-    }
-    .copyright {
-      position: relative;
-    }
-  }
+  </div>
+</template>
+<style lang="scss" scoped>
+.bg-banner {
+  position: fixed;
+  z-index: 0;
+  width: 100%;
+  height: 100%;
+  background: radial-gradient(
+    circle at center,
+    var(--g-container-bg),
+    var(--g-bg)
+  );
+  background-image: url(".././assets/images/loginback.png");
+  background-size: cover;
+}
+.bgback {
+  position: fixed;
+  top: 58%;
+  left: 35%;
+  z-index: 0;
+  transform: translateX(-50%) translateY(-50%);
+}
+[data-mode="mobile"] {
   .login-box {
-    position: absolute;
-    display: flex;
-    overflow: hidden;
-    background-color: var(--g-container-bg);
-    [data-mode="pc"] & {
-      top: 50%;
-      left: 70%;
-      border-radius: 10px;
-      box-shadow: var(--el-box-shadow);
-      transform: translateX(-50%) translateY(-50%);
-    }
+    position: relative;
+    flex-direction: column;
+    justify-content: start;
+    width: 100%;
     .login-banner {
-      position: relative;
-      width: 450px;
-      overflow: hidden;
-      background-color: var(--g-bg);
+      width: 100%;
+      padding: 20px 0;
       .banner {
-        position: absolute;
-        top: 50%;
+        position: relative;
+        top: inherit;
+        right: inherit;
+        display: inherit;
         width: 100%;
-        transform: translateY(-50%);
+        max-width: 375px;
+        margin: 0 auto;
+        transform: translateY(0);
       }
     }
     .login-form {
-      width: 500px;
-      transition: height 0.15s ease;
+      width: 100%;
     }
   }
   .copyright {
-    position: absolute;
-    bottom: 0;
-    width: 100%;
-    padding: 20px;
-    margin: 0;
+    position: relative;
+  }
+}
+.login-box {
+  position: absolute;
+  display: flex;
+  overflow: hidden;
+  background-color: var(--g-container-bg);
+  [data-mode="pc"] & {
+    top: 50%;
+    left: 70%;
+    border-radius: 10px;
+    box-shadow: var(--el-box-shadow);
+    transform: translateX(-50%) translateY(-50%);
   }
-  .fade-enter-active,
-  .fade-leave-active {
-    transition: opacity 0.15s ease;
+  .login-banner {
+    position: relative;
+    width: 450px;
+    overflow: hidden;
+    background-color: var(--g-bg);
+    .banner {
+      position: absolute;
+      top: 50%;
+      width: 100%;
+      transform: translateY(-50%);
+    }
   }
-  .fade-enter-from,
-  .fade-leave-to {
-    opacity: 0;
+  .login-form {
+    width: 500px;
+    transition: height 0.15s ease;
   }
-  </style>
+}
+.copyright {
+  position: absolute;
+  bottom: 0;
+  width: 100%;
+  padding: 20px;
+  margin: 0;
+}
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.15s ease;
+}
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+</style>

+ 21 - 5
src/views/personnel/institutionManage.vue

@@ -30,7 +30,8 @@
         :pageInfo="pageInfo"
         @getList="getList"
         :treeProps="{ children: 'children', hasChildren: 'hasChildren' }"
-        
+        @select-all-change="selectAllChange"
+        @select-change="selectChange"
       >
         <template v-slot:table-title-btn>
           <div>
@@ -204,11 +205,13 @@
         </div>
       </template>
     </el-dialog>
-    <setDept :dialogVisible="deptDialogVisible"
+    <setDept 
+    :dialogVisible="deptDialogVisible"
       :dept-list="tableData"
       :dept-ids="deptIdList"
       :title="'设置负责人'"
       @close-dialog="confirmCharge"
+      @cancel-dialog="deptDialogVisible=false"
     ></setDept>
   </div>
 </template>
@@ -248,8 +251,8 @@ function setDeptUser(item:any){
 
 function manySetDeptUser(){
   
-  // deptIdList.value=[item.id]
-  // deptDialogVisible.value=true
+  deptIdList.value=checkTableIdList.value
+  deptDialogVisible.value=true
 }
 
 function confirmCharge(){
@@ -352,7 +355,7 @@ const columns = [
     },
   },
   { prop: "address", label: "所属地区" },
-  { prop: "leaderHame", label: "负责人" },
+  { prop: "leaderName", label: "负责人" },
 ];
 
 const pageInfo = {
@@ -367,6 +370,18 @@ const getList = (item: PageInfo) => {
   pageInfo.pageNum = item.pageNum;
   pageInfo.pageSize = item.pageSize;
 };
+
+const checkTableIdList=ref([])
+//表格选择事件
+function selectAllChange(list:any){
+ 
+  checkTableIdList.value=list
+}
+
+function selectChange(list:any){
+ 
+  checkTableIdList.value=list
+}
 //添加子机构
 
 const isDisabledId = ref("");
@@ -401,6 +416,7 @@ const del = (item: any) => {
     confirmButtonText: "确认",
     cancelButtonText: "取消",
     type: "warning",
+    center:true
   })
     .then(() => {
       console.log(123);

+ 327 - 12
src/views/personnel/memberManagement.vue

@@ -55,6 +55,8 @@
         :showSelect="true"
         :pageInfo="pageInfo"
         @getList="getList"
+        @select-all-change="selectAllChange"
+        @select-change="selectChange"
       >
         <template v-slot:table-title-btn>
           <div>
@@ -79,7 +81,7 @@
                 </el-dropdown-menu>
               </template>
             </el-dropdown>
-            <el-button type="primary" @click="add(ruleFormRef)">
+            <el-button type="primary" @click="manySetDeptUser()">
               设置负责人</el-button
             >
           </div>
@@ -91,11 +93,18 @@
           <el-dropdown placement="bottom-start">
             <span class="el-dropdown-link"> 更 多 </span>
             <template #dropdown>
-              <el-dropdown-menu>
-                <el-dropdown-item>删除</el-dropdown-item>
-                <el-dropdown-item>禁用</el-dropdown-item>
-                <el-dropdown-item>启用</el-dropdown-item>
-              </el-dropdown-menu>
+              
+                
+                <el-dropdown-item v-on:click="changeDept(scope)"
+                  >变更机构</el-dropdown-item
+                >
+                <el-dropdown-item v-on:click="resign(scope)">操作离职</el-dropdown-item>
+                <el-dropdown-item v-on:click="transfer(scope)"
+                  >资源转移</el-dropdown-item
+                >
+                <el-dropdown-item v-on:click="delUser(scope)">删除</el-dropdown-item>
+            
+           
             </template>
           </el-dropdown>
         </template>
@@ -104,6 +113,107 @@
         </template>
       </Table>
     </div>
+    <el-dialog
+      v-model="dialogVisible"
+      title="资源转移"
+      width="800"
+      draggable
+      append-to-body
+    >
+      <el-row :gutter="24">
+        <el-col :span="20">
+          <div style="display: flex; align-items: center">
+            <div class="img-title">
+              {{ pinyin.getFullChars(operationForm.name).substring(0, 1) }}
+            </div>
+            <h4>{{ operationForm.name }}</h4>
+          </div>
+        </el-col>
+      </el-row>
+      <p style="margin-left: 50px">工号:{{ transferInfo.userId }}</p>
+      <p style="margin-left: 50px">所在机构:{{ transferInfo.deptName }}</p>
+      <p style="margin-left: 50px">需要转移的资源</p>
+      <el-table :data="[{}]" style="width: 100%">
+        <el-table-column prop="date" label="资源" width="120">
+          <template #default> 业务员 </template>
+        </el-table-column>
+        <el-table-column prop="name" label="描述" width="180">
+          <template #default> 转让该成员维护的业务员 </template>
+        </el-table-column>
+        <el-table-column prop="address" label="数量" width="80">
+          <template #default> {{ transferInfo.count }}人 </template>
+        </el-table-column>
+        <el-table-column prop="address" label="资源接收人">
+          <template #default>
+            <el-input
+              :value="receiveInfo?.name"
+              @click="deptDialogVisible = true"
+              placeholder="输入姓名,手机号,工号查找"
+            ></el-input>
+          </template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="confirmTransfer">
+            确认转移
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <setDept
+      :dialogVisible="deptDialogVisible"
+      :dept-list="deptTreeData"
+      :dept-ids="deptIdList"
+      @close-dialog="confirmDialogInfo"
+      :title="title"
+      @cancel-dialog="deptDialogVisible=false"
+    ></setDept>
+    <el-dialog
+      v-model="changeDeptDialog"
+      title="变更机构"
+      width="600"
+      append-to-body
+      draggable
+    >
+      <div>
+        <el-input
+          v-model="filterText"
+          style="width: 240px"
+          placeholder="请输入机构名称查找"
+          :prefix-icon="Search"
+        />
+        <el-tree
+          ref="treeRef"
+          style="max-width: 600px"
+          class="filter-tree"
+          :data="deptTreeData"
+          :props="defaultProps"
+          :default-expand-all="true"
+          :expand-on-click-node="false"
+          :filter-node-method="filterNode"
+          @node-click="treeClick"
+        >
+          <template #default="{ node, data }">
+            <span class="custom-tree-node">
+              <span>{{ node.label }}</span>
+              <span>
+                <a style="color: #00a0f4">
+                  {{ node.label == deptItem.name ? "已选" : "" }}
+                </a>
+              </span>
+            </span>
+          </template>
+        </el-tree>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="changeDeptDialog = false">取消</el-button>
+          <el-button type="primary" @click="submitChangeDept"> 确认 </el-button>
+        </div>
+      </template>
+    </el-dialog>
     
 
     <!-- <el-dialog v-model="dialogVisible" title="基本信息" width="800" draggable> -->
@@ -118,13 +228,14 @@ import { ref, reactive, watch,onMounted ,h} from "vue";
 import {useRouter} from "vue-router"
 import type { ComponentSize, FormInstance, FormRules } from "element-plus";
 import { Plus, Search } from "@element-plus/icons-vue";
-
-
+import { ElMessage, ElMessageBox } from "element-plus";
+import pinyin from "js-pinyin";
 import type Node from "element-plus/es/components/tree/src/model/node";
 // import universalTable from "../"
 import { ElTree } from "element-plus";
 import api from "@/api";
 import { getDictItems } from "@/api/dict";
+import setDept from "@/components/DialogSetDeptLeader/index.vue"
 interface dictType {
   value: string;
   id: string;
@@ -315,7 +426,7 @@ const getUserList= () => {
   api.userApi.memberList({
     ...pageInfo
   }).then((res:any)=>{
-    console.log(res)
+    
     if(res.code===200){
       tableData.value=res.data.records
       pageInfo.total=res.data.total
@@ -346,9 +457,7 @@ const add = (formEl: FormInstance | undefined) => {
   // pageInfo.pageSize=item.pageSize
 };
 
-const closeAddOperation = (bool: boolean) => {
-  dialogVisible.value = bool
-}
+
 
 const operationMany = (item: any) => {
   // pageInfo.pageNum=item.pageNum
@@ -375,6 +484,212 @@ const remove = (node: Node, data: Tree) => {
 const reset = (item: any) => {
   // ElMessage({})
 };
+
+const deptDialogVisible=ref(false)
+//判断当前机构是否可以进行变更
+const changeDeptDialog = ref(false);
+const operationForm=ref({})
+function changeDept(item:any) {
+  // changeDeptDialog.value=true
+  operationForm.value=item.operationData.row
+  api.userApi
+    .checkChangeDept({
+      userId: item.operationData.row.userId,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        // transferInfo.value=res.data
+
+        changeDeptDialog.value = true;
+      }
+    });
+}
+//选择变更的机构
+const deptItem = ref({});
+function treeClick(node: any) {
+  deptItem.value = node;
+}
+
+//提交变更机构信息
+
+function submitChangeDept() {
+  // changeDeptDialog.value=true
+  api.userApi
+    .changeDept({
+      userId: operationForm.value.userId,
+      deptId: deptItem.value.id,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        // transferInfo.value=res.data
+        ElMessage.success(res.msg);
+        changeDeptDialog.value = false;
+      }
+    });
+}
+
+//资源转移信息
+interface transfer {
+  [key: string]: any;
+}
+const transferInfo = ref<transfer>({});
+function transfer(item:any) {
+  // console.log(123)
+  title.value='资源转移'
+  operationForm.value=item.operationData.row
+  api.userApi
+    .getTransferInfo({
+      userId: operationForm.value.userId,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        transferInfo.value = res.data;
+        if (res.data.count < 1) {
+          ElMessage.error("当前用户没有可转移的资源");
+        } else {
+          dialogVisible.value = true;
+        }
+      }
+    });
+}
+
+//删除成员
+function delUser(item:any) {
+  operationForm.value=item.operationData.row
+  api.userApi
+    .checkChangeDept({
+      userId: operationForm.value.userId,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        // transferInfo.value=res.data
+
+        ElMessageBox.confirm(
+          "账号删除后,该账号将无法使用访问本企业,请确定是否删除 ",
+          "确认要删除账号吗?",
+          {
+            confirmButtonText: "确认删除",
+            cancelButtonText: "取消",
+            type: "warning",
+            center:true
+          }
+        )
+          .then(() => {
+            api.userApi
+              .userDelete({
+                id: [operationForm.value.id],
+                
+              })
+              .then((res: any) => {
+                if(res.code==200){
+                  ElMessage.success(res.msg)
+                  
+                }
+              });
+            // console.log(123);
+          })
+          .catch(() => {
+            ElMessage.warning("用户取消操作");
+          });
+      }
+    });
+}
+//确认弹框提交信息
+const receiveInfo = ref<transfer>({});
+function confirmDialogInfo(item: any) {
+  deptDialogVisible.value = false;
+  receiveInfo.value = item;
+}
+//资源转移确认
+function confirmTransfer() {
+  api.userApi
+    .transfer({
+      originalUserId: transferInfo.value.userId,
+      transferUserId: receiveInfo.value.id,
+    })
+    .then((res: any) => {
+      // console.log(res)
+      if (res.code === 200) {
+        ElMessage.success(res.msg);
+        dialogVisible.value = false;
+      }
+    });
+}
+const leave=ref(false)
+function resign(item:any) {
+  // console.log(123)
+  operationForm.value=item.operationData.row
+  leave.value=true
+  api.userApi
+    .getTransferInfo({
+      userId: operationForm.value.userId,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        transferInfo.value = res.data;
+        if (res.data.count < 1) {
+          // ElMessage.error("当前用户没有可转移的资源");
+          ElMessageBox.confirm(
+          "离职后,账号将无法访问本企业,请确定是否离职?",
+          `确定要将${operationForm.value.name}设置为离职吗?`,
+          {
+            confirmButtonText: "确认",
+            cancelButtonText: "取消",
+            type: "warning",
+            center:true
+          }
+        )
+          .then(() => {
+            api.userApi
+              .userQuitApply({
+                userId:operationForm.value.userId,
+              })
+              .then((res: any) => {
+                if(res.code==200){
+                  ElMessage.success(res.msg)
+                  getUserList()
+                }
+              });
+            // console.log(123);
+          })
+          .catch(() => {
+            ElMessage.warning("用户取消操作");
+          });
+        } else {
+          ElMessage.warning("当前用户有资源未转移,请转移后执行离职操作");
+          // dialogVisible.value = true;
+        }
+      }
+    });
+}
+
+//批量设置负责人
+//设置负责人弹框
+const checkTableIdList=ref([])
+//表格选择事件
+function selectAllChange(list:any){
+ 
+  checkTableIdList.value=list
+}
+
+function selectChange(list:any){
+ 
+  checkTableIdList.value=list
+}
+
+const deptIdList=ref([])
+
+const title=ref('')
+function manySetDeptUser(){
+  title.value='设置负责人'
+ 
+  deptIdList.value=checkTableIdList.value
+  deptDialogVisible.value=true
+  
+
+}
+
+
 </script>
 <style lang="scss" scoped>、
 :deep(.date-picker-custom.el-input__inner){

+ 45 - 19
src/views/personnel/modules/memberMessage.vue

@@ -596,7 +596,7 @@
     </div>
     <el-dialog
       v-model="dialogVisible"
-      title="资源转移"
+      :title="leave?'操作离职':'资源转移'"
       width="800"
       draggable
       append-to-body
@@ -613,19 +613,21 @@
       </el-row>
       <p style="margin-left: 50px">工号:{{ transferInfo.userId }}</p>
       <p style="margin-left: 50px">所在机构:{{ transferInfo.deptName }}</p>
-      <p style="margin-left: 50px">需要转移的资源</p>
-      <el-table :data="[{}]" style="width: 100%">
+      <el-divider v-show="leave"/>
+      <!-- 资源转移--->
+      <p style="margin-left: 50px" v-show="!leave">需要转移的资源</p>
+      <el-table :data="[{}]" style="width: 100%" v-show="!leave">
         <el-table-column prop="date" label="资源" width="120">
-          <template #default="scope"> 业务员 </template>
+          <template #default> 业务员 </template>
         </el-table-column>
         <el-table-column prop="name" label="描述" width="180">
-          <template #default="scope"> 转让该成员维护的业务员 </template>
+          <template #default> 转让该成员维护的业务员 </template>
         </el-table-column>
         <el-table-column prop="address" label="数量" width="80">
-          <template #default="scope"> {{ transferInfo.count }}人 </template>
+          <template #default> {{ transferInfo.count }}人 </template>
         </el-table-column>
         <el-table-column prop="address" label="资源接收人">
-          <template #default="scope">
+          <template #default>
             <el-input
               :value="receiveInfo?.name"
               @click="deptDialogVisible = true"
@@ -634,11 +636,18 @@
           </template>
         </el-table-column>
       </el-table>
+
+       <!-- 操作离职--->
+      <!-- <el-radio-group v-model="radio1">
+        <el-radio value="1" size="large">转移给其他成员</el-radio>
+        <el-radio value="0" size="large">不转移</el-radio>
+      </el-radio-group> -->
+    
       <template #footer>
         <div class="dialog-footer">
           <el-button @click="dialogVisible = false">取消</el-button>
           <el-button type="primary" @click="confirmTransfer">
-            确认转移
+            确认{{ leave?'离职':'转移' }}
           </el-button>
         </div>
       </template>
@@ -649,6 +658,7 @@
       :dept-ids="[]"
       @close-dialog="confirmDialogInfo"
       title="选择交接人"
+      @cancel-dialog="deptDialogVisible=false"
     ></setDept>
     <el-dialog
       v-model="changeDeptDialog"
@@ -1058,7 +1068,7 @@ interface transfer {
 const transferInfo = ref<transfer>({});
 function transfer() {
   // console.log(123)
-
+  leave.value=false
   api.userApi
     .getTransferInfo({
       userId: operationForm.value.userId,
@@ -1076,10 +1086,10 @@ function transfer() {
 }
 
 //操作离职
-
+const leave=ref(false)
 function resign() {
   // console.log(123)
-
+  leave.value=true
   api.userApi
     .getTransferInfo({
       userId: operationForm.value.userId,
@@ -1090,8 +1100,8 @@ function resign() {
         if (res.data.count < 1) {
           // ElMessage.error("当前用户没有可转移的资源");
           ElMessageBox.confirm(
-          "账号删除后,该账号将无法使用访问本企业,请确定是否删除 ",
-          "确认要删除账号吗?",
+          "离职后,账号将无法访问本企业,请确定是否离职?",
+          `确定要将${operationForm.value.name}设置为离职吗?`,
           {
             confirmButtonText: "确认",
             cancelButtonText: "取消",
@@ -1101,8 +1111,7 @@ function resign() {
           .then(() => {
             api.userApi
               .userQuitApply({
-                id: [operationForm.value.id],
-                
+                userId:operationForm.value.userId,
               })
               .then((res: any) => {
                 if(res.code==200){
@@ -1116,7 +1125,8 @@ function resign() {
             ElMessage.warning("用户取消操作");
           });
         } else {
-          dialogVisible.value = true;
+          ElMessage.warning("当前用户有资源未转移,请转移后执行离职操作");
+          // dialogVisible.value = true;
         }
       }
     });
@@ -1131,7 +1141,8 @@ function confirmDialogInfo(item: any) {
 
 //资源转移确认
 function confirmTransfer() {
-  api.userApi
+ 
+    api.userApi
     .transfer({
       originalUserId: transferInfo.value.userId,
       transferUserId: receiveInfo.value.id,
@@ -1143,6 +1154,21 @@ function confirmTransfer() {
         dialogVisible.value = false;
       }
     });
+
+    // api.userApi
+    // .userQuitApply({
+    //   originalUserId: transferInfo.value.userId,
+    //   transferUserId: receiveInfo.value.id,
+    // })
+    // .then((res: any) => {
+    //   // console.log(res)
+    //   if (res.code === 200) {
+    //     ElMessage.success(res.msg);
+    //     dialogVisible.value = false;
+    //   }
+    // });
+  
+  
 }
 
 //变更机构弹框
@@ -1172,7 +1198,7 @@ function changeDept() {
       if (res.code === 200) {
         // transferInfo.value=res.data
 
-        changeDeptDialog.value = false;
+        changeDeptDialog.value = true;
       }
     });
 }
@@ -1195,7 +1221,7 @@ function submitChangeDept() {
       if (res.code === 200) {
         // transferInfo.value=res.data
         ElMessage.success(res.msg);
-        changeDeptDialog.value = true;
+        changeDeptDialog.value = false;
       }
     });
 }

+ 4 - 3
src/views/personnel/roleManagement.vue

@@ -499,11 +499,12 @@ onBeforeMount(() => {
   const processedRoutes = preprocessRoutes(asyncRoutes);
 
   treeData.value = convertToTreeData(0, processedRoutes);
-
+  
   api.roleApi.updateConfig({
-    sysConfig:JSON.stringify(treeData.value)
+    sysConfig:JSON.stringify(processedRoutes),
+    sysPerms:JSON.stringify(treeData.value)
   }).then(res=>{
-    console.log(res)
+    
   })
 
 });