소스 검색

Merge branch 'liuheng' into dev

刘恒 1 년 전
부모
커밋
ba80bc7132
46개의 변경된 파일9725개의 추가작업 그리고 716개의 파일을 삭제
  1. 6 6
      .editorconfig
  2. 3 1
      .env.development
  3. 164 39
      package-lock.json
  4. 2 0
      package.json
  5. 23 0
      src/api/dict.ts
  6. 12 0
      src/api/index.ts
  7. 12 0
      src/api/modules/area.ts
  8. 18 0
      src/api/modules/common.ts
  9. 24 0
      src/api/modules/institution.ts
  10. 15 0
      src/api/modules/menu.ts
  11. 102 0
      src/api/modules/operation.ts
  12. 22 1
      src/api/modules/role.ts
  13. 18 0
      src/api/modules/team.ts
  14. 313 0
      src/api/modules/user.ts
  15. 35 0
      src/assets/styles/globals.css
  16. 274 0
      src/components/DialogSetDeptLeader/index.vue
  17. 9 3
      src/components/LoginForm/index.vue
  18. 195 170
      src/components/Table/index.vue
  19. 1 0
      src/layouts/components/Menu/index.vue
  20. 1 0
      src/main.ts
  21. 3 0
      src/router/guards.ts
  22. 58 0
      src/router/modules/operation.ts
  23. 31 2
      src/router/modules/personnel.ts
  24. 88 91
      src/router/routes.ts
  25. 2 2
      src/settings.default.ts
  26. 2 2
      src/settings.ts
  27. 1 1
      src/store/modules/menu.ts
  28. 16 5
      src/store/modules/route.ts
  29. 18 3
      src/store/modules/user.ts
  30. 1 0
      src/types/components.d.ts
  31. 64 10
      src/utils/composables/routeUtils.ts
  32. 182 137
      src/views/login.vue
  33. 360 0
      src/views/operationManagement/channel.vue
  34. 239 0
      src/views/operationManagement/modules/addCard.vue
  35. 1046 0
      src/views/operationManagement/modules/addOperation.vue
  36. 170 0
      src/views/operationManagement/modules/addTeam.vue
  37. 180 0
      src/views/operationManagement/modules/allocation.vue
  38. 658 0
      src/views/operationManagement/operation.vue
  39. 556 0
      src/views/operationManagement/operationDetail.vue
  40. 360 0
      src/views/operationManagement/team.vue
  41. 360 0
      src/views/operationManagement/telemarketing.vue
  42. 671 0
      src/views/personnel/institutionManage.vue
  43. 464 202
      src/views/personnel/memberManagement.vue
  44. 1127 0
      src/views/personnel/modules/addOperation.vue
  45. 1344 0
      src/views/personnel/modules/memberMessage.vue
  46. 475 41
      src/views/personnel/roleManagement.vue

+ 6 - 6
.editorconfig

@@ -1,9 +1,9 @@
 root = true
 
 [*]
-charset = utf-8
-indent_style = space
-indent_size = 2
-end_of_line = lf
-insert_final_newline = true
-trim_trailing_whitespace = true
+charset = utf-8 # 字符编码 utf-8
+indent_style = space # 输入的 tab 都用空格代替
+indent_size = 2 # 一个 tab 用 2 个空格代替
+end_of_line = lf # 换行符使用 unix 的换行符 \n
+insert_final_newline = true # 去掉每行末尾的空格
+trim_trailing_whitespace = true # 文件末尾都加一个空行

+ 3 - 1
.env.development

@@ -4,7 +4,9 @@ VITE_APP_SETTING = true
 VITE_APP_TITLE = 掌柜运营平台
 # 接口请求地址,会设置到 axios 的 baseURL 参数上
 # VITE_APP_API_BASEURL = https://test.baoxianzhanggui.com/web-api #默认地址
-VITE_APP_API_BASEURL = http://192.168.5.148:8001  #田智
+VITE_APP_API_BASEURL = http://192.168.0.253:8001  #田智
+# VITE_APP_API_BASEURL = http://192.168.0.106:8001  #屈晨
+#VITE_APP_API_BASEURL = http://192.168.0.59:8001  #徐强
 
 # 调试工具,可设置 eruda 或 vconsole,如果不需要开启则留空
 VITE_APP_DEBUG_TOOL =

+ 164 - 39
package-lock.json

@@ -1,5 +1,5 @@
 {
-  "name": "operation-Backend",
+  "name": "tenant-Platform",
   "version": "4.12.1",
   "lockfileVersion": 3,
   "requires": true,
@@ -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",
@@ -21,6 +22,7 @@
         "eruda": "^3.4.1",
         "floating-vue": "5.2.2",
         "hotkeys-js": "^3.13.7",
+        "js-pinyin": "^0.2.7",
         "lodash-es": "^4.17.21",
         "mitt": "^3.0.1",
         "mockjs": "^1.1.0",
@@ -5028,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",
@@ -6047,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": {
@@ -6407,7 +6466,7 @@
       "version": "4.1.2",
       "resolved": "https://registry.npmmirror.com/camel-case/-/camel-case-4.1.2.tgz",
       "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "pascal-case": "^3.1.2",
@@ -6452,7 +6511,7 @@
       "version": "1.0.4",
       "resolved": "https://registry.npmmirror.com/capital-case/-/capital-case-1.0.4.tgz",
       "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "no-case": "^3.0.4",
@@ -6485,25 +6544,12 @@
       }
     },
     "node_modules/change-case": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmmirror.com/change-case/-/change-case-4.1.2.tgz",
-      "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
-      "devOptional": true,
+      "version": "5.4.4",
+      "resolved": "https://registry.npmmirror.com/change-case/-/change-case-5.4.4.tgz",
+      "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==",
       "license": "MIT",
-      "dependencies": {
-        "camel-case": "^4.1.2",
-        "capital-case": "^1.0.4",
-        "constant-case": "^3.0.4",
-        "dot-case": "^3.0.4",
-        "header-case": "^2.0.4",
-        "no-case": "^3.0.4",
-        "param-case": "^3.0.4",
-        "pascal-case": "^3.1.2",
-        "path-case": "^3.0.4",
-        "sentence-case": "^3.0.4",
-        "snake-case": "^3.0.4",
-        "tslib": "^2.0.3"
-      }
+      "optional": true,
+      "peer": true
     },
     "node_modules/character-entities": {
       "version": "2.0.2",
@@ -6980,11 +7026,24 @@
         "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",
       "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "no-case": "^3.0.4",
@@ -7242,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"
@@ -7708,7 +7766,7 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/dot-case/-/dot-case-3.0.4.tgz",
       "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "no-case": "^3.0.4",
@@ -10200,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",
@@ -10226,7 +10290,7 @@
       "version": "2.0.4",
       "resolved": "https://registry.npmmirror.com/header-case/-/header-case-2.0.4.tgz",
       "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "capital-case": "^1.0.4",
@@ -11834,6 +11898,12 @@
       "dev": true,
       "license": "BSD-3-Clause"
     },
+    "node_modules/js-pinyin": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmmirror.com/js-pinyin/-/js-pinyin-0.2.7.tgz",
+      "integrity": "sha512-Dbm7qJDwlC2MRHRXQo7GrVrL5w975tEOX6sfc0M8Z3oL9VhR4uUqgkwaETMqh4bAJ14w4zVs3tXsi9pDxWUmNg==",
+      "license": "MIT License"
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -12464,7 +12534,7 @@
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz",
       "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "tslib": "^2.0.3"
@@ -12817,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",
@@ -13840,7 +13919,7 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/no-case/-/no-case-3.0.4.tgz",
       "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "lower-case": "^2.0.2",
@@ -13912,6 +13991,27 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
     },
+    "node_modules/node-plop/node_modules/change-case": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmmirror.com/change-case/-/change-case-4.1.2.tgz",
+      "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "camel-case": "^4.1.2",
+        "capital-case": "^1.0.4",
+        "constant-case": "^3.0.4",
+        "dot-case": "^3.0.4",
+        "header-case": "^2.0.4",
+        "no-case": "^3.0.4",
+        "param-case": "^3.0.4",
+        "pascal-case": "^3.1.2",
+        "path-case": "^3.0.4",
+        "sentence-case": "^3.0.4",
+        "snake-case": "^3.0.4",
+        "tslib": "^2.0.3"
+      }
+    },
     "node_modules/node-plop/node_modules/cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -14770,7 +14870,7 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/param-case/-/param-case-3.0.4.tgz",
       "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "dot-case": "^3.0.4",
@@ -14892,7 +14992,7 @@
       "version": "3.1.2",
       "resolved": "https://registry.npmmirror.com/pascal-case/-/pascal-case-3.1.2.tgz",
       "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "no-case": "^3.0.4",
@@ -14919,7 +15019,7 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/path-case/-/path-case-3.0.4.tgz",
       "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "dot-case": "^3.0.4",
@@ -15366,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",
@@ -15590,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",
@@ -15643,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",
@@ -16954,7 +17075,7 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/sentence-case/-/sentence-case-3.0.4.tgz",
       "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "no-case": "^3.0.4",
@@ -17209,7 +17330,7 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmmirror.com/snake-case/-/snake-case-3.0.4.tgz",
       "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "dot-case": "^3.0.4",
@@ -17335,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"
@@ -19277,7 +19397,7 @@
       "version": "2.8.1",
       "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
       "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
-      "devOptional": true,
+      "dev": true,
       "license": "0BSD"
     },
     "node_modules/tsx": {
@@ -20183,7 +20303,7 @@
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/upper-case/-/upper-case-2.0.2.tgz",
       "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "tslib": "^2.0.3"
@@ -20193,7 +20313,7 @@
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/upper-case-first/-/upper-case-first-2.0.2.tgz",
       "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "tslib": "^2.0.3"
@@ -20238,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": {
@@ -21487,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",

+ 2 - 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",
@@ -35,6 +36,7 @@
     "eruda": "^3.4.1",
     "floating-vue": "5.2.2",
     "hotkeys-js": "^3.13.7",
+    "js-pinyin": "^0.2.7",
     "lodash-es": "^4.17.21",
     "mitt": "^3.0.1",
     "mockjs": "^1.1.0",

+ 23 - 0
src/api/dict.ts

@@ -0,0 +1,23 @@
+// import { ApiInstance } from './type'
+
+
+import { AxiosResponse } from 'axios';
+import api from "./index"
+
+
+
+
+// 定义获取字典项的函数
+const getDictItems = async (item:any): Promise<any> => {
+  try{
+    const response = await api.areaApi.systemList(item)
+    
+    return response.data
+    
+  }catch(error){
+    throw error;
+  }
+ 
+  
+};
+export { getDictItems };

+ 12 - 0
src/api/index.ts

@@ -8,6 +8,12 @@ import Message from 'vue-m-message'
 import appApi from './modules/app'
 import userApi from './modules/user'
 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'
+import commonApi from "./modules/common.ts";
+import teamApi from "@/api/modules/team.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,
@@ -87,5 +93,11 @@ const api = {
   appApi: appApi(axiosInstance),
   userApi: userApi(axiosInstance),
   roleApi: roleApi(axiosInstance),
+  institutionApi:institutionApi(axiosInstance),
+  areaApi:areaApi(axiosInstance),
+  operationApi: operationApi(axiosInstance),
+  menuApi:menuApi(axiosInstance),
+  commonApi: commonApi(axiosInstance),
+  teamApi: teamApi(axiosInstance)
 }
 export default api

+ 12 - 0
src/api/modules/area.ts

@@ -0,0 +1,12 @@
+import { ApiInstance } from '../type'
+
+const areaApi = (axiosInstance: ApiInstance) => ({
+  // 后端获取路由数据
+  areaList: (data:any) => axiosInstance.post('area/queryTree',data,{}),
+
+  systemList: (params:any) => axiosInstance.get('dict/get',{ params }),
+  
+  fileUpload: (data:any) => axiosInstance.post('file/upload',data,{})
+})
+
+export default areaApi

+ 18 - 0
src/api/modules/common.ts

@@ -0,0 +1,18 @@
+import { ApiInstance } from '../type'
+
+/*
+* 性别        gender
+  民族        nation
+  婚姻状况     marriage
+  政治面貌     political_status
+  健康状况     health_status
+  学历        educational
+  银行        bank_info
+* */
+const commonApi = (axiosInstance: ApiInstance) => ({
+  personInfo: (data: string) => axiosInstance.get(`/dict/get?dictCode=${data}`),
+  fileUpload: (data: any) => axiosInstance.post('/file/upload', data, {}), // 文件上传
+})
+
+export default commonApi
+

+ 24 - 0
src/api/modules/institution.ts

@@ -0,0 +1,24 @@
+import { ApiInstance } from '../type'
+interface institutionData {
+  name: string;
+  system: string,
+  [key: string]: any; // 允许其他任意字段
+}
+const institutionApi = (axiosInstance: ApiInstance) => ({
+  // 新增机构
+  institutionAdd: (data: institutionData) => axiosInstance.post('/dept/add', data, {}),
+
+  //机构树形列表
+  institutionList:(data: institutionData) => axiosInstance.post('/dept/getDeptTree', data, {}),
+
+  //编辑
+  institutionEdit: (data: institutionData) => axiosInstance.post('/dept/update', data, {}),
+  //删除
+  institutionDel: (data: institutionData) => axiosInstance.post('/dept/delete', data, {}),
+
+  //设置机构负责人
+  setDeptLeader: (data: institutionData) => axiosInstance.post('/dept/setDeptLeader', data, {})
+
+})
+
+export default institutionApi

+ 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

+ 102 - 0
src/api/modules/operation.ts

@@ -0,0 +1,102 @@
+import { ApiInstance } from '../type'
+import {LocationQueryValue} from "vue-router";
+
+// 新增
+export interface AddOperation {
+  typeAttr: string,
+  deptId: string,
+  name: string,
+  mobile: string,
+  identity: string,
+  identityTimeStart: string,
+  identityTimeEnd: string,
+  leaderId: string,
+  referrerId: string,
+
+  sex?: string,
+  birthday?: string,
+  nations?: string,
+  koseki?: string,
+  maritalStatus?: string,
+  politicsStatus?: string,
+  health?: string,
+  province?: string,
+  city?: string,
+  district?: string,
+  liveAddress?: string,
+  postalCode?: string,
+  education?: string,
+  graduationTime?: string,
+  school?: string,
+  isComputer?: string,
+  emergencyContactName?: string,
+  emergencyContactTel?: string,
+  salary?: string,
+  salaryLevel?: string,
+  bankCardId?: string,
+  bankName?: string,
+
+  sfz1?: string,
+  sfz2?: string,
+  qualification?: string,
+  contract?: string,
+  applicant?: string,
+  salaryTable?: string,
+  leaveTable?: string
+}
+// 列表
+export interface OperationSearch {
+  pages: number,
+  size: number,
+  salesman?: string,
+  organizationName?: string,
+  deptId?: string,
+  typeAttr?: string,
+  deptName?: string,
+  status?: number,
+  isEnable?: string,
+  leaderId?: string
+}
+// 银行卡
+export interface AddBankCard {
+  userJzgInfoId: string,
+  bankCardNumber: string,
+  bankName: string,
+  bankAddress: string,
+  attachment?: string
+}
+// 启用/禁用
+export interface OperationIsEnable {
+  ids: string[],
+  isEnable: number,
+  getAll: number
+}
+export interface OperationEdit extends AddOperation {
+  id: string
+}
+// 业务员管理相关接口
+const operationApi = (axiosInstance: ApiInstance) => ({
+  addOperation: (data: AddOperation) => axiosInstance.post('/userInfo/add', data), // 新赠
+  updateOperation: (data: any) => axiosInstance.post('/userInfo/update', data), //编辑
+  operationList: (data: OperationSearch) => axiosInstance.post('/userInfo/getUserInfoList', data), // 列表
+  operationDelete: (data: {
+    ids: string[],
+    getAll: number
+  }) => axiosInstance.post('/userInfo/delete', data), // 删除
+  operationIsEnable: (data: OperationIsEnable) => axiosInstance.post('/userInfo/isEnable', data), // 启用/禁用
+  operationDetail: (data: string | null | LocationQueryValue[] | undefined) => axiosInstance.get(`/userInfo/getUserInfo?id=${data}`), // 详情
+  setLeader: (data: {
+    ids: string[],
+    leaderId: string,
+    getAll: number
+  }) => axiosInstance.post('/userInfo/batchLeader', data), // 设置负责人
+  getUser: (data: string) => axiosInstance.post('/userInfo/getUser', { deptId: data }), // 获取管理人/推荐人
+  addBankCard: (data: AddBankCard) => axiosInstance.post('/userInfo/addBankCard', data), // 添加银行卡
+  salesmanAuthSuccess: (data: { userInfoId: string }) => axiosInstance.post('/userInfo/salesmanAuthSuccess', data), // 审核通过
+  salesmanAuthFailed: (data: {
+    userInfoId: string,
+    approvalOpinion: string
+  }) => axiosInstance.post('/userInfo/salesmanAuthFailed', data), // 审核不通过
+})
+
+export default operationApi

+ 22 - 1
src/api/modules/role.ts

@@ -4,11 +4,32 @@ interface roleData {
   desc: string;
   system: string,
   permsId: number[],
-  perms: string[]
+  perms: string[],
+  [property:string]:any,
 }
 const roleApi = (axiosInstance: ApiInstance) => ({
   // 新增角色
   roleAdd: (data: roleData) => axiosInstance.post('userRole/roleAdd', data, {}),
+
+  //角色列表
+  roleList:(data: roleData) => axiosInstance.post('userRole/roleList', data, {}),
+
+  //查询角色信息
+  roleInfo:(params: roleData) => axiosInstance.get('userRole/roleGet', {params}),
+
+  //编辑角色信息
+  roleUpdate:(data: roleData) => axiosInstance.post('userRole/roleUpdate', data,{}),
+
+  //角色删除检测
+  roleDeleteValid:(data: roleData) => axiosInstance.post('userRole/roleDeleteValid', data,{}),
+
+  //角色删除检测
+  roleDelete:(data: roleData) => axiosInstance.post('userRole/roleDelete', data,{}),
+
+  //配置路由
+  updateConfig:(data: any) => axiosInstance.post('system/updateConfig', data,{})
+  
+ 
 })
 
 export default roleApi

+ 18 - 0
src/api/modules/team.ts

@@ -0,0 +1,18 @@
+import { ApiInstance } from '../type'
+
+export interface AddTeamProps {
+  name: string,
+  deptId: number,
+  managerId: number,
+  systemCode: string,
+  attribute: number, // 1 团队 2 渠道 3 电销
+  describeInformation?: string
+}
+
+const teamApi = (axiosInstance: ApiInstance) => ({
+  teamList: (data: any) => axiosInstance.post('/sysOrganization/leftList', data), // 查询(不分页)
+  addTeam: (data: AddTeamProps) => axiosInstance.post('/sysOrganization/save', data), // 新增
+  queryPageList: (data: any) => axiosInstance.post('/sysOrganization/queryPageList', data), // 查询(分页)
+})
+
+export default teamApi

+ 313 - 0
src/api/modules/user.ts

@@ -10,6 +10,285 @@ interface PasswordEditData {
   password: string
   newpassword: string
 }
+/**
+ * SysUserVo,平台用户表VO
+ */
+/**
+ * SysUserVo,平台用户表VO
+ */
+export interface Request {
+  /**
+   * 用户状态 : 1 正常 0 锁定
+   */
+  accountStatus?: number;
+  /**
+   * 应聘表
+   */
+  applicant?: string;
+  /**
+   * 银行卡
+   */
+  bankCard?: string;
+  /**
+   * 银行卡号
+   */
+  bankCardId?: string;
+  /**
+   * 开户行
+   */
+  bankName?: string;
+  /**
+   * 出生日期
+   */
+  birthday?: string;
+  /**
+   * 市
+   */
+  city?: string;
+  /**
+   * 劳动合同
+   */
+  contract?: string;
+  /**
+   * 部门id
+   */
+  deptId?: string;
+  /**
+   * 区
+   */
+  district?: string;
+  /**
+   * 学历
+   */
+  education?: string;
+  /**
+   * 紧急联系人姓名
+   */
+  emergencyContactName?: string;
+  /**
+   * 紧急联系人电话
+   */
+  emergencyContactTel?: string;
+  /**
+   * 毕业时间
+   */
+  graduationTime?: string;
+  /**
+   * 健康状况
+   */
+  health?: string;
+  /**
+   * 平台用户id
+   */
+  id?: string;
+  /**
+   * 身份证号
+   */
+  identity?: string;
+  /**
+   * 身份证有效期止期
+   */
+  identityTimeEnd?: string;
+  /**
+   * 身份证有效期起期
+   */
+  identityTimeStart?: string;
+  /**
+   * 是否是计算机专业 1 是 0 否
+   */
+  isComputer?: string;
+  /**
+   * 是否启用 1 启用 0禁用
+   */
+  isEnable?: number;
+  /**
+   * 户籍
+   */
+  koseki?: string;
+  /**
+   * 领导人id
+   */
+  leaderId?: string;
+  /**
+   * 领导人姓名
+   */
+  leaderName?: string;
+  /**
+   * 离职表
+   */
+  leaveTable?: string;
+  /**
+   * 详细地址
+   */
+  liveAddress?: string;
+  /**
+   * 婚姻状况
+   */
+  maritalStatus?: string;
+  /**
+   * 手机号
+   */
+  mobile?: string;
+  /**
+   * 姓名
+   */
+  name?: string;
+  /**
+   * 民族
+   */
+  nations?: string;
+  page?: Page;
+  pages?: number;
+  /**
+   * 密码
+   */
+  password?: string;
+  /**
+   * 政治面貌
+   */
+  politicsStatus?: string;
+  /**
+   * 邮政编码
+   */
+  postalCode?: string;
+  /**
+   * 省
+   */
+  province?: string;
+  /**
+   * 展业资格证
+   */
+  qualification?: string;
+  /**
+   * 推荐人id
+   */
+  referrerId?: string;
+  /**
+   * 推荐人id
+   */
+  referrerName?: string;
+  /**
+   * 角色名称集合
+   */
+  roleNameList?: string[];
+  /**
+   * 薪资
+   */
+  salary?: string;
+  /**
+   * 薪资等级
+   */
+  salaryLevel?: string;
+  /**
+   * 定薪表
+   */
+  salaryTable?: string;
+  /**
+   * 毕业学校
+   */
+  school?: string;
+  /**
+   * 性别
+   */
+  sex?: string;
+  /**
+   * 身份证正面
+   */
+  sfz1?: string;
+  /**
+   * 身份证反面
+   */
+  sfz2?: string;
+  size?: number;
+  /**
+   * 系统编码
+   */
+  systemCode?: string;
+  /**
+   * 用户类型1.前线人员 2:后线人员 3:合伙人 4:工作室管理员 5:团队长 6:个代 7:电销 8 渠道
+   */
+  typeAttr?: string;
+  /**
+   * 平台信息id
+   */
+  userInfoId?: string;
+  /**
+   * 用户名
+   */
+  username?: string;
+  [property: string]: any;
+}
+
+/**
+* Page
+*/
+
+
+/**
+* PageObject
+*/
+
+
+/**
+* OrderItem
+*/
+
+
+/**
+* Page
+*/
+export interface Page {
+  countId?: string;
+  current?: number;
+  maxLimit?: number;
+  optimizeCountSql?: PageObject;
+  optimizeJoinOfCountSql?: boolean;
+  orders?: OrderItem[];
+  pages?: number;
+  records?: { [key: string]: any }[];
+  searchCount?: PageObject;
+  size?: number;
+  total?: number;
+  [property: string]: any;
+}
+
+/**
+* PageObject
+*/
+export interface PageObject {
+  countId?: string;
+  current?: number;
+  maxLimit?: number;
+  optimizeCountSql?: PageObject;
+  optimizeJoinOfCountSql?: boolean;
+  orders?: OrderItem[];
+  pages?: number;
+  records?: { [key: string]: any }[];
+  searchCount?: PageObject;
+  size?: number;
+  total?: number;
+  [property: string]: any;
+}
+
+/**
+* OrderItem
+*/
+export interface OrderItem {
+  asc?: boolean;
+  column?: string;
+  [property: string]: any;
+}
+
+/**
+* SysRoleVo,角色列表
+*/
+export interface SysRoleVo {
+  /**
+   * 角色id
+   */
+  id?: string;
+  [property: string]: any;
+}
 
 const userApi = (axiosInstance: ApiInstance) => ({
   // 登录
@@ -24,6 +303,40 @@ const userApi = (axiosInstance: ApiInstance) => ({
   passwordEdit: (data: PasswordEditData) => axiosInstance.post('user/password/edit', data, {
     baseURL: '/mock/',
   }),
+
+  //成员列表分页
+  memberList: (data: Page) => axiosInstance.post('/userInfo/getUserInfoList', data, { }),
+
+  //成员全部列表
+  AllMemberList: (data: SysRoleVo) => axiosInstance.post('/userInfo/getUser', data, { }),
+
+  //成员详情
+  getUserInfo: (params: Request) => axiosInstance.get('/userInfo/getUserInfo', {params}),
+
+  //编辑成员
+  updateUserInfo: (data: SysRoleVo) => axiosInstance.post('/userInfo/update', data, { }),
+
+  //获取是否可以资源转移信息
+  getTransferInfo: (params: Request) => axiosInstance.get('/userInfo/getTransferInfo', {params}),
+  
+  //资源转移
+  transfer: (data: Request) => axiosInstance.post('/userInfo/transfer', data, { }),
+
+  //检测是否可进行机构变更
+  checkChangeDept: (data: Request) => axiosInstance.post('/userInfo/checkChangeDept', data, { }),
+
+  //机构变更
+  changeDept: (data: Request) => axiosInstance.post('/userInfo/changeDept', data, { }),
+
+  //删除成员
+  userDelete: (data: {id:string[]}) => axiosInstance.post('/userInfo/delete', data, { }),
+
+  //离职
+  userQuitApply: (data: {userId:string}) => axiosInstance.post('/userInfo/userQuitApply', data, { }),
+  
+  
+  
+  
 })
 
 export default userApi

+ 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;
+}
+
+/* 消息提示弹窗 */

+ 274 - 0
src/components/DialogSetDeptLeader/index.vue

@@ -0,0 +1,274 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="props.dialogVisible"
+      :title="props.title"
+      width="1000"
+      append-to-body
+      draggable
+      :before-close="handleClose"
+    >
+      <el-select
+        v-model="userId"
+        filterable
+        remote
+        reserve-keyword
+        placeholder="输入姓名,手机号,工号查找"
+        :remote-method="remoteMethod"
+        :loading="loading"
+        style="width: 240px"
+        clearable
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="`${item.label}-${item.mobile}`"
+          :value="item.value"
+        >
+        </el-option>
+      </el-select>
+      <div class="dialog-mian">
+        <div v-show="userId == '' || userId == null">
+          <el-tree
+            ref="treeRef"
+            style="max-width: 600px"
+            class="filter-tree"
+            :data="deptList"
+            :props="defaultProps"
+            :default-expand-all="true"
+            :expand-on-click-node="false"
+            @node-click="treeClick"
+          >
+          </el-tree>
+        </div>
+        <div>
+          <el-radio-group v-model="userId" v-show="userId">
+            <div style="display: flex; flex-direction: column">
+              <el-radio
+                v-for="item in options"
+                :key="item.value"
+                :value="item.value"
+                style="margin-bottom: 15px"
+              >
+                <p style="margin: 0">{{ item.label }}</p>
+                <p style="margin: 0">{{ item.value }}</p>
+              </el-radio>
+            </div>
+          </el-radio-group>
+
+          <el-radio-group v-model="treeReId" v-show="userList.length > 0 && !userId">
+            <div style="display: flex; flex-direction: column">
+              <el-radio
+                v-for="item in userList"
+                :key="item.id"
+                :value="item.id"
+                style="margin-bottom: 15px"
+              >
+                <p style="margin: 0">{{ item.name }}</p>
+                <p style="margin: 0">{{ item.id }}</p>
+              </el-radio>
+            </div>
+          </el-radio-group>
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="handleClose ">取消</el-button>
+          <el-button type="primary" @click="submit">
+            确认
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<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;
+};
+
+const defaultProps = {
+  children: "children",
+  label: "name",
+};
+const props = defineProps<{
+  dialogVisible: boolean;
+  deptIds: Array<[]>;
+  deptList: Array<tableType>;
+  title: string;
+}>();
+
+interface ListItem {
+  value: string;
+  label: string;
+}
+
+const list = ref<ListItem[]>([]);
+const options = ref<ListItem[]>([]);
+const userId = ref<string>("");
+const loading = ref(false);
+const treeReId=ref<string>("");
+
+const emits=defineEmits(["closeDialog",'cancelDialog']);
+
+
+const userList = ref<any[]>([]);
+const remoteMethod = (query: string) => {
+  if (query) {
+    loading.value = true;
+    api.userApi
+      .AllMemberList({
+        name: query,
+      })
+      .then((res: any) => {
+        
+        if (res.code === 200) {
+          // userList.value = res.data;
+          let arr: any = [];
+          res.data.forEach((item) => {
+            arr.push({
+              label: item.name,
+              value: item.id,
+              mobile: item.mobile,
+            });
+          });
+          loading.value = false;
+          options.value = arr;
+        }
+      });
+    // setTimeout(() => {
+    //   loading.value = false
+    //   options.value = list.value.filter((item) => {
+    //     return item.label.toLowerCase().includes(query.toLowerCase())
+    //   })
+    // }, 200)
+  } else {
+    options.value = [];
+  }
+};
+function treeClick(node: any) {
+  api.userApi
+    .AllMemberList({
+      deptId: node.id,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        userList.value = res.data;
+
+        // options.value=arr
+      }
+    });
+}
+
+function submit(){
+ 
+  if(props.title=='设置负责人'){
+    if(userId.value){
+      
+     const obj=options.value.map((item:any)=>{
+        if(item.value==userId.value){
+          return {
+            name:item.label,
+            id:item.value,
+            mobile:item.mobile
+          }
+        }
+      })
+      api.institutionApi.setDeptLeader({
+        deptId:props.deptIds,
+        leaderId:obj[0].userId
+      }).then(res=>{
+        
+        if(res.code==200){
+          ElMessage.success(res.msg)
+          emits('closeDialog')
+        }
+      })
+      
+      
+    }else{
+      let flag={}
+     userList.value.some((item:any)=>{
+     
+         if( item.id==treeReId.value){
+          flag={...item}
+          return true
+         }
+         return false
+        
+      })
+    
+      api.institutionApi.setDeptLeader({
+        deptId:props.deptIds,
+        leaderId:flag.userId
+      }).then(res=>{
+        if(res.code==200){
+          ElMessage.success(res.msg)
+          emits('closeDialog')
+        }
+      })
+      // emits('closeDialog',flag)
+    }
+  }else{
+    if(userId.value){
+     const obj=options.value.map((item:any)=>{
+        if(item.value==userId.value){
+          return {
+            name:item.label,
+            id:item.value,
+            mobile:item.mobile
+          }
+        }
+      })
+      
+      emits('closeDialog',obj[0])
+    }else{
+      let flag={}
+      userList.value.some((item:any)=>{
+     
+         if( item.id==treeReId.value){
+          flag={...item}
+          return true
+         }
+         return false
+        
+      })
+      emits('closeDialog',flag)
+    }
+  }
+ 
+   
+}
+
+const handleClose = (done: () => void) => {
+  
+  emits('cancelDialog',false)
+    
+}
+
+
+</script>
+<style lang="scss" scoped>
+.dialog-mian {
+  display: flex;
+  border: 1px solid #ccc;
+  border-radius: 10px;
+  min-height: 500px;
+  margin-top: 20px;
+  > div {
+    flex: 1;
+    padding: 15px;
+    box-sizing: border-box;
+    max-height: 500px;
+    overflow-y: auto;
+  }
+  > div:last-child {
+    border-left: 1px solid #ccc;
+  }
+}
+</style>

+ 9 - 3
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",
@@ -44,7 +45,7 @@ const form = ref({
 });
 const rules = ref<FormRules>({
   userName: [{ required: true, trigger: "blur", message: "请输入用户名" }],
-  systemCode: [{ required: true, trigger: "blur", message: "请输入租户编码" }],
+  system: [{ required: true, trigger: "blur", message: "请输入租户编码" }],
   passWord: [
     { required: true, trigger: "blur", message: "请输入密码" },
     { min: 6, max: 18, trigger: "blur", message: "密码长度为6到18位" },
@@ -89,12 +90,17 @@ function handleLogin() {
           } else {
             localStorage.removeItem("login_account");
           }
+          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();
         });
+      
     }
   });
 }
@@ -165,9 +171,9 @@ function handleLogin() {
         <div class="tag"></div>
       </div>
       <div>
-        <ElFormItem prop="systemCode">
+        <ElFormItem prop="system">
           <ElInput
-            v-model="form.systemCode"
+            v-model="form.system"
             placeholder="输入租户编码"
             type="text"
             tabindex="1"

+ 195 - 170
src/components/Table/index.vue

@@ -1,191 +1,216 @@
-
 <template>
-	<div class="container">
-		<div class="table_box">
+  <div class="table-container">
+    <div class="table_box">
       <div class="table-title-btn">
         <slot name="table-title-btn"></slot>
       </div>
-			<el-table ref="multipleTableRef"  :header-cell-style="{'background-color': '#f2f2f2'}" :data="props.tableData" style="width: 100%">
-				<el-table-column type="selection" v-if="showSelect" :selectable="selectable" width="55" />
-				
-				<el-table-column v-if="showIndex" type="index" label="序号" width="55" />
-				<el-table-column
-					v-for="column in columns"
-					:key="column.prop"
-					:prop="column.prop"
-					:label="column.label"
-					:sortable="column.sortable ? 'custom' : false"
-					:width="column.width"
-				>
-					<template #header>
-						<slot name="search" :slotData="column"></slot>
-					</template>
-					<template #default="{ row }">
-						<template v-if="row._edit">
-							<el-input
-								v-if="
-									column.prop === 'Date' || column.prop === 'Name' || column.prop === 'Organization'
-								"
-								v-model="row[column.prop]"
-							/>
-							<el-select v-if="column.prop === 'Tag'" v-model="Tagvalue">
-								<el-option
-									v-for="(type, label) in tagTypes"
-									:key="label"
-									:label="label"
-									:value="label"
-								/>
-							</el-select>
-						</template>
-						<template v-else>
-							<span v-if="column.prop !== 'Tag'">{{ row[column.prop] }}</span>
-							<el-tag v-if="column.prop === 'Tag'" :type="getTagType(row[column.prop])">{{
-								row[column.prop]
-							}}</el-tag>
-						</template>
-					</template>
-				</el-table-column>
-				<el-table-column label="操作">
-                    <template #default="scope">
-                        <slot name="operation" :operationData="scope"></slot>
-                    </template>
-					<!-- <template #default="scope">
+      <el-table
+        ref="multipleTableRef"
+        :header-cell-style="{ 'background-color': '#f2f2f2' }"
+        :data="props.tableData"
+        style="width: 100%"
+        row-key="id"
+        :tree-props="props.treeProps"
+        @selection-change="selectChange"
+        @select-all="selectAllChange"
+      >
+        <el-table-column
+          type="selection"
+          v-if="showSelect"
+          :selectable="selectable"
+          width="55"
+        />
+
+        <el-table-column
+          v-if="showIndex"
+          type="index"
+          label="序号"
+          width="55"
+        />
+        <el-table-column
+          v-for="column in columns"
+          :key="column.prop"
+          :prop="column.prop"
+          :label="column.label"
+          :sortable="column.sortable ? 'custom' : false"
+          :width="column.width"
+        >
+          <template #header>
+            <slot name="search" :slotData="column"></slot>
+          </template>
+          <template #default="scope">
+            
+          
+              
+              <component v-if="column.formatter" :is="column.formatter(scope.row, column, scope.row[column.prop], scope.$index)" class="routerlick" />
+              <span v-else>{{ scope.row[column.prop] }}</span>
+            
+            
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template #default="scope">
+            <slot name="operation" :operationData="scope"></slot>
+          </template>
+          <!-- <template #default="scope">
 						<div v-if="scope.row._edit">
 							<el-button type="primary" @click="handleSave(scope)"> 保存 </el-button>
 							<el-button @click="handleCancle(scope)"> 取消 </el-button>
 						</div>
 						<el-button v-else type="primary" @click="handleEdit(scope)"> 编辑 </el-button>
 					</template> -->
-				</el-table-column>
-			</el-table>
-		</div>
-		<div class="page_box">
-			<el-pagination
-                v-model:current-page="props.pageInfo.pageNum"
-                v-model:page-size="props.pageInfo.pageSize"
-                :page-sizes="props.pageInfo.sizes"
-                layout="total, sizes, prev, pager, next, jumper"
-                :total="props.pageInfo.total"
-                @size-change="handleSizeChange"
-                @current-change="handleCurrentChange"
-            />
-		</div>
-	</div>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div class="page_box" v-show="props.pageInfo.show">
+      <el-pagination
+
+        v-model:current-page="props.pageInfo.pageNum"
+        v-model:page-size="props.pageInfo.pageSize"
+        :page-sizes="props.pageInfo.sizes"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="props.pageInfo.total"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
 </template>
- 
+
 <script lang="ts" setup>
-	import { defineProps, ref, onMounted,defineEmits  } from "vue";
-	import type { TableInstance } from "element-plus";
- 
-	interface TableRow {
-		[key: string]: any; 
-	}
-    interface TagTypes{
-        [key:string]:string;
-    }
-    const emit = defineEmits(['getList']);
-	const props = defineProps<{
-		tableData: Array<TableRow>;
-		columns: {
-			prop: string;
-			label: string;
-			sortable?: boolean;
-			width?: string;
-			style?: string;
-		}[];
-        pageInfo:{
-            pageNum: number;
-            pageSize: number;
-            sizes: number[];
-            total: number;
-        };
-        showSelect:boolean;
-        showIndex:boolean;
+import { defineProps, ref, onMounted, defineEmits } from "vue";
+import type { TableInstance } from "element-plus";
 
-	}>();
-	const multipleTableRef = ref<TableInstance>();
-	const TableData = ref<TableRow[]>();
-	onMounted(() => {
-		let counter = 1;
-		TableData.value = props.tableData.map((row) => ({
-			...row,
-			_edit: false, // 设置默认非编辑状态
-			counter: counter++
-		}));
-	});
-	const selectable = () => true;
-	const Tagvalue = ref("");
-	const tagTypes:TagTypes = {
-		'公司': "primary",
-		'甲方': "success",
-		'合作伙伴': "primary"
-	};
-    const handleSizeChange = (val: number) => {
-        
-        props.pageInfo.pageSize=val
-      
-        emit('getList', props.pageInfo);
-    }
-    const handleCurrentChange = (val: number) => {
-   
-        props.pageInfo.pageNum=val
-        emit('getList', props.pageInfo);
+interface TableRow {
+  [key: string]: any;
+}
+interface TagTypes {
+  [key: string]: string;
+}
+const emit = defineEmits(['getList', 'selectAllChange','selectChange']);
+const props = defineProps<{
+  tableData: Array<TableRow>;
+  columns: {
+    prop: string;
+    label: string;
+    sortable?: boolean;
+    width?: string;
+    style?: string;
+    formatter?: (row: any, column: any, cellValue: any, index: number) => any;
+  }[];
+  pageInfo: {
+    pageNum: number;
+    pageSize: number;
+    sizes: number[];
+    total: number;
+    show:boolean;
+  };
+  showSelect: boolean;
+  showIndex: boolean;
+  treeProps:{}
+}>();
+const multipleTableRef = ref<TableInstance>();
+const TableData = ref<TableRow[]>();
+onMounted(() => {
+  let counter = 1;
+  TableData.value = props.tableData.map((row) => ({
+    ...row,
+    _edit: false, // 设置默认非编辑状态
+    counter: counter++,
+  }));
+});
+const selectable = () => true;
+const Tagvalue = ref("");
+const tagTypes: TagTypes = {
+  公司: "primary",
+  甲方: "success",
+  合作伙伴: "primary",
+};
+const handleSizeChange = (val: number) => {
+  props.pageInfo.pageSize = val;
 
+  emit("getList", props.pageInfo);
+};
+const handleCurrentChange = (val: number) => {
+  props.pageInfo.pageNum = val;
+  emit("getList", props.pageInfo);
+};
+const getTagType = (tag: string) => {
+  return tagTypes[tag] || tagTypes["公司"];
+};
+const handleEdit = (scope: { row: TableRow }) => {
+  Tagvalue.value = scope.row.Tag || "";
+  scope.row._edit = true;
+};
+const handleSave = (scope: { row: TableRow }) => {
+  scope.row.Tag = Tagvalue.value;
+  scope.row._edit = false;
+};
+const handleCancle = (scope: { row: TableRow }) => {
+  scope.row._edit = false;
+};
+const headClass = (scope: { row: TableRow }) => {
+  // return 'background:#F8F8F9'
+};
 
-    }
-	const getTagType = (tag: string) => {
-		return tagTypes[tag] || tagTypes["公司"];
-	};
-	const handleEdit = (scope: { row: TableRow }) => {
-		Tagvalue.value = scope.row.Tag || "";
-		scope.row._edit = true;
-	};
-	const handleSave = (scope: { row: TableRow }) => {
-		scope.row.Tag = Tagvalue.value;
-		scope.row._edit = false;
-	};
-	const handleCancle = (scope: { row: TableRow }) => {
-		scope.row._edit = false;
-	};
-  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;
-		margin: 5px;
-		display: flex;
-		flex-direction: column;
-	}
- .table_box {
-		flex: 1;
-		margin-bottom: 10px;
-		overflow-y: auto;
-		.table_item_container {
-			margin-left: 20px;
-			padding: 0;
-			.table_item {
-				margin: 5px 0;
-			}
-		}
-    :deep(.cell){
-      display: flex;
-      align-items: center;
-      justify-content: center;
-    }
-    .table-title-btn {
-      margin-bottom: 20px;
-      :deep(.el-button){
-        margin-right: 20px;
-      }
+.table-container {
+  // width: 100%;
+  // height: auto;
+  margin: 5px;
+  display: flex;
+  flex-direction: column;
+}
+.table_box {
+  flex: 1;
+  margin-bottom: 10px;
+  overflow-y: auto;
+  .table_item_container {
+    margin-left: 20px;
+    padding: 0;
+    .table_item {
+      margin: 5px 0;
     }
-    
-	}
-  .page_box{
+  }
+  :deep(.cell) {
     display: flex;
     align-items: center;
-    justify-content: flex-end;
+    justify-content: center;
+  }
+  .table-title-btn {
+    margin-bottom: 20px;
+    :deep(.el-button) {
+      margin-right: 20px;
+    }
   }
-</style>
+}
+.page_box {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+}
+</style>

+ 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) {

+ 1 - 0
src/main.ts

@@ -39,6 +39,7 @@ app.use(Message)
 app.use(pinia)
 app.use(router)
 app.use(ui)
+
 directive(app)
 if (icons.isOfflineUse) {
   for (const info of icons.collections) {

+ 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))
           })

+ 58 - 0
src/router/modules/operation.ts

@@ -0,0 +1,58 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+const Layout = () => import('@/layouts/index.vue')
+
+const routes: RouteRecordRaw = {
+  path: '/operationManagement',
+  component: Layout,
+  redirect: '/operationManagement/operation',
+  name: 'OperationManagement',
+  meta: {
+    title: '业务团队',
+
+  },
+  children: [
+    {
+      path: '/operationDetail',
+      name: 'OperationDetail',
+      component: () => import('@/views/operationManagement/operationDetail.vue'),
+      meta: {
+        title: '业务员详情',
+        sidebar: false,
+        menu:false,
+      },
+    },
+    {
+      path: 'operation',
+      name: 'Operation',
+      component: () => import('@/views/operationManagement/operation.vue'),
+      meta: {
+        title: '业务员管理',
+      },
+    },{
+      path: 'team',
+      name: 'Team',
+      component: () => import('@/views/operationManagement/team.vue'),
+      meta: {
+        title: '团队管理',
+      },
+    },{
+      path: 'channel',
+      name: 'Channel',
+      component: () => import('@/views/operationManagement/channel.vue'),
+      meta: {
+        title: '渠道管理',
+      },
+    },{
+      path: 'telemarketing',
+      name: 'Telemarketing',
+      component: () => import('@/views/operationManagement/telemarketing.vue'),
+      meta: {
+        title: '电销组管理',
+      },
+    },
+
+  ],
+}
+
+export default routes

+ 31 - 2
src/router/modules/personnel.ts

@@ -8,7 +8,7 @@ const routes: RouteRecordRaw = {
   redirect: '/personnel/member',
   name: 'Personnel',
   meta: {
-    title: '成员管理',
+    title: '组织架构',
   },
   children: [
     {
@@ -18,7 +18,36 @@ const routes: RouteRecordRaw = {
       meta: {
         title: '成员管理',
 
-
+      },
+      children:[
+        {
+          path: 'memberMessage',
+          name: 'personnelMemberMessage',
+          component: () => import('@/views/personnel/modules/memberMessage.vue'),
+          meta: {
+            title: '成员详情',
+            menu:false
+          }, 
+        },
+        {
+          path: 'memberEdit',
+          name: 'personnelMemberEdit',
+          component: () => import('@/views/personnel/modules/addOperation.vue'),
+          meta: {
+            title: '成员管理',
+            menu:false
+          }, 
+        },
+      ]
+    },
+    
+    
+    {
+      path: 'institution',
+      name: 'personnelInstitution',
+      component: () => import('@/views/personnel/institutionManage.vue'),
+      meta: {
+        title: '机构管理',
       },
     },
     {

+ 88 - 91
src/router/routes.ts

@@ -1,138 +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 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',
-    },
-    children: [
-      MultilevelMenuExample,
-
-    ],
-  },
-  {
-    meta: {
-      title: '组织架构',
-      icon: 'i-uim:box',
-    },
-    children: [
-      organizationManagement,
-      personnel
-    ],
-  },
-  {
-    meta: {
-      title: '租户管理',
-      icon: 'i-uim:box',
-    },
-    children: [
-      organizationManagement
 
-    ],
-  },
-  {
-    meta: {
-      title: '租户运营',
-      icon: 'i-uim:box',
-    },
-    children: [
-    ],
-  },
-  {
-    meta: {
-      title: '数据中心',
-      icon: 'i-uim:box',
-    },
-    children: [
-    ],
-  },
+const asyncRoutes: Route.recordMainRaw[] = [
   {
     meta: {
-      title: '增值服务',
-      icon: 'i-uim:box',
+      title: "组织架构",
+      icon: "i-uim:box",
     },
-    children: [
-    ],
+    children: [personnel],
   },
+  // {
+  //   meta: {
+  //     title: "租户管理",
+  //     icon: "i-uim:box",
+  //   },
+  //   children: [],
+  // },
   {
     meta: {
-      title: '基础设置',
-      icon: 'i-uim:box',
+      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: [],
+  // },
+];
 
 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,
@@ -140,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 = converDeprecatedAttribute(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,
+      
     }
   },
 )

+ 1 - 0
src/types/components.d.ts

@@ -8,6 +8,7 @@ export {}
 declare module 'vue' {
   export interface GlobalComponents {
     Auth: typeof import('./../components/Auth/index.vue')['default']
+    DialogSetDeptLeader: typeof import('./../components/DialogSetDeptLeader/index.vue')['default']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
     FixedActionBar: typeof import('./../components/FixedActionBar/index.vue')['default']
     HButton: typeof import('./../layouts/ui-kit/HButton.vue')['default']

+ 64 - 10
src/utils/composables/routeUtils.ts

@@ -7,46 +7,98 @@ 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; // 允许任意其他属性
 }
 
-let idCounter = 0;
+let idCounter = ref(0);
 
 // 生成唯一 ID
 const generateId = (): number => {
-  return ++idCounter;
+  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,17 +125,19 @@ const parseAuthToChildren = (authList: string[]): TreeNode[] => {
 };
 
 // 将 RouteItem 转换为 TreeNode
-export const convertToTreeData = (routes: RouteItem[]): TreeNode[] => {
-  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(route.children);
+      node.children = convertToTreeData(idCounter.value, route.children);
     }
 
     if (route.meta?.auth) {

+ 182 - 137
src/views/login.vue

@@ -1,154 +1,185 @@
 <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',
-  })
-  
-  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">
+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 treeData = ref<TreeNode[]>([]);
+onBeforeMount(() => {
+  // 对 asyncRoutes 进行预处理并转换为树形结构
+  const processedRoutes = preprocessRoutes(asyncRoutes);
+
+  treeData.value = convertToTreeData(0, processedRoutes);
+
+  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;
+  </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%;
-    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;
+    .login-banner {
       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 {
+      padding: 20px 0;
+      .banner {
+        position: relative;
+        top: inherit;
+        right: inherit;
+        display: inherit;
         width: 100%;
+        max-width: 375px;
+        margin: 0 auto;
+        transform: translateY(0);
       }
     }
-  
-    .copyright {
-      position: relative;
+    .login-form {
+      width: 100%;
     }
   }
-  
-  .login-box {
-    position: absolute;
-    display: flex;
+  .copyright {
+    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%);
+  }
+  .login-banner {
+    position: relative;
+    width: 450px;
     overflow: hidden;
-    background-color: var(--g-container-bg);
-  
-    [data-mode="pc"] & {
+    background-color: var(--g-bg);
+    .banner {
+      position: absolute;
       top: 50%;
-      left: 70%;
-      border-radius: 10px;
-      box-shadow: var(--el-box-shadow);
-      transform: translateX(-50%) translateY(-50%);
-    }
-  
-    .login-banner {
-      position: relative;
-      width: 450px;
-      overflow: hidden;
-      background-color: var(--g-bg);
-  
-      .banner {
-        position: absolute;
-        top: 50%;
-        width: 100%;
-        transform: translateY(-50%);
-      }
-    }
-  
-    .login-form {
-      width: 500px;
-      transition: height 0.15s ease;
+      width: 100%;
+      transform: translateY(-50%);
     }
   }
-  
-  .copyright {
-    position: absolute;
-    bottom: 0;
-    width: 100%;
-    padding: 20px;
-    margin: 0;
+  .login-form {
+    width: 500px;
+    transition: height 0.15s ease;
   }
+
   
   .fade-enter-active,
   .fade-leave-active {
@@ -159,9 +190,23 @@
   .fade-leave-to {
     opacity: 0;
   }
-  </style>
-<<<<<<< HEAD
-  
-=======
-  
->>>>>>> 42d928175ed879069f8c0c2bb997b6902b8bc18b
+ 
+
+}
+.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>
+

+ 360 - 0
src/views/operationManagement/channel.vue

@@ -0,0 +1,360 @@
+<template>
+  <div class="team">
+    <el-row :gutter="20" style="width: 100%; overflow:hidden;">
+      <el-col :span="4">
+        <div class="teamTree">
+          <el-input class="search-input" v-model="treeValue" placeholder="渠道名称查找" prefix-icon="Search"></el-input>
+          <div class="custom-tree-node" v-for="item in teamData" :key="item.id">
+            <span class="custom-tree-node-label">{{ item.name }}</span>
+            <el-dropdown class="custom-tree-node-more" @command="treeNodeCommend(item, $event)">
+              <el-icon><MoreFilled /></el-icon>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                  <el-dropdown-item command="删除">删除</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </div>
+        <el-button class="add-btn" icon="plus" @click="addTeamShow = true">添加渠道</el-button>
+      </el-col>
+      <el-col :span="20">
+        <el-row :gutter="20">
+          <el-col :span="22" class="info">
+            <h3>渠道名称</h3>
+            <p>所属机构: 机构名称</p>
+            <p>管理人: 管理人姓名-管理人工号</p>
+            <p>描述:</p>
+          </el-col>
+          <el-col :span="2" class="btn">
+            <el-button plain @click="setPeople">设置负责人</el-button>
+          </el-col>
+        </el-row>
+        <el-input style="width: 300px; margin: 10px 0" v-model="searchValue" prefix-icon="Search" placeholder="输入姓名,手机号,工号查找" ></el-input>
+        <el-table
+          :data="tableData"
+          ref="operationListRef"
+          height="530"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column label="姓名" prop="name" width="80"></el-table-column>
+          <el-table-column label="手机号" prop="mobile" width="150"></el-table-column>
+          <el-table-column label="工号" prop="userId" width="200"></el-table-column>
+          <el-table-column label="类型" prop="typeAttr" width="100"></el-table-column>
+          <el-table-column label="归属" prop="deptName" width="200"></el-table-column>
+          <el-table-column label="所属机构" prop="deptName" width="200"></el-table-column>
+          <el-table-column label="人员状态" prop="status" width="150">
+            <template #default="scope">
+              {{ scope.row.status == '1'?'前线人员':scope.row.status == '2'?'后线人员':scope.row.status == '3'?'合伙人':scope.row.status == '4'?'工作室管理员':scope.row.status == '5'?'团队长':scope.row.status == '6'?'个代':scope.row.status == '7'?'电销':scope.row.status == '8'?'渠道': '--' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="账号状态" prop="isEnable" width="150"></el-table-column>
+          <el-table-column label="管理人" prop="leaderName" width="150"></el-table-column>
+          <el-table-column label="管理人工号" prop="leaderId" width="200"></el-table-column>
+          <el-table-column label="推荐人" prop="referrerName" width="150"></el-table-column>
+          <el-table-column label="推荐人工号" prop="referrerId" width="200"></el-table-column>
+          <el-table-column fixed="right" label="操作" width="120">
+            <template #default="scope">
+              <div style="display: flex; align-items: center; justify-content: space-between">
+                <a style="color: #409EFF; cursor: pointer" @click="showDetail(scope)">详情</a>&nbsp;
+                <el-dropdown placement="bottom" trigger="click" @command="tableDataCommand(scope, $event)">
+                  <a style="color: #409EFF; cursor: pointer">更多</a>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                      <el-dropdown-item command="启用">启用</el-dropdown-item>
+                      <el-dropdown-item command="禁用">禁用</el-dropdown-item>
+                      <el-dropdown-item command="删除">删除</el-dropdown-item>
+                      <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div style="display: flex; justify-content: center; margin-top: 15px">
+          <el-pagination
+            v-model:current-page="currentPage"
+            v-model:page-size="pageSize"
+            :page-sizes="[10, 20, 30, 40]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+          />
+        </div>
+      </el-col>
+    </el-row>
+    <el-dialog
+      v-model="dialogShow"
+      :title="title"
+      width="1000"
+    >
+      <addOperation @closeDialog="closeAddOperation" :options="options"></addOperation>
+    </el-dialog>
+    <el-dialog
+      v-model="addTeamShow"
+      title="添加"
+      width="800"
+    >
+      <addTeam @closeDialog="closeAddTeamDialog" :editData="editItemData"></addTeam>
+    </el-dialog>
+    <el-dialog
+      v-model="allocationShow"
+      title="分配管理人"
+      width="800"
+    >
+      <allocation></allocation>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import {ElMessageBox, ElMessage, TableInstance} from 'element-plus'
+import { useRouter } from 'vue-router'
+import api from "@/api";
+import addOperation from './modules/addOperation.vue'
+import allocation from './modules/allocation.vue'
+import addTeam from './modules/addTeam.vue'
+import Allocation from "@/views/operationManagement/modules/allocation.vue";
+import {initial} from "lodash-es";
+import team from "@/api/modules/team.ts";
+
+let myRouter = useRouter()
+
+// 机构数据
+let options = ref([])
+// 获取机构数据
+const institutionList = () => {
+  api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
+    if(res?.code == 200) {
+      options.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 渠道
+let treeValue = ref('')
+let teamData = ref([])
+let addTeamShow = ref(false)
+let editItemData = ref(null)
+const initTeam = () => {
+  api.teamApi.teamList({}).then(res => {
+    if(res.code == 200) {
+      teamData.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+const treeNodeCommend = (item, e) => {
+  switch (e) {
+    case '编辑':
+      addTeamShow.value = true
+      editItemData.value = item
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除渠道',
+        message: '确定要删除该渠道吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+  }
+}
+const closeAddTeamDialog = (type) => {
+  addTeamShow.value = false
+}
+
+// 分页
+let currentPage = ref(1)
+let pageSize = ref(10)
+let total = ref(0)
+const handleSizeChange = (size) => {
+
+}
+const handleCurrentChange = (page) => {
+
+}
+
+// 搜索字段
+let searchValue = ref('')
+// 列表数据
+let tableData = ref([
+  {name: 1}
+])
+// 编辑弹框
+let dialogShow = ref(false)
+// 编辑弹框标题
+let title = ref('编辑')
+// 表格组件中的勾选
+const handleSelectionChange = (row) => {
+
+}
+// 详情
+const showDetail = (scope) => {
+  myRouter.push({
+    path: '/operationDetail',
+    query: {
+      id: scope.row.id
+    }
+  })
+}
+
+// 分配管理人
+let allocationShow = ref(false)
+
+// 设置负责人
+const setPeople = () => {
+  allocationShow.value = true
+}
+// 更多
+const tableDataCommand = (scope, e) => {
+  switch (e) {
+    case '编辑':
+      dialogShow.value = true
+      title.value = '编辑'
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除业务员',
+        message: '确定要删除该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = [scope.row.id]
+
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '禁用':
+      ElMessageBox({
+        title: '禁用业务员',
+        message: '确定要禁用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let data = {
+            id: [scope.row.id],
+            isEnable: 0
+          }
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '启用':
+      ElMessageBox({
+        title: '启用业务员',
+        message: '确定要启用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm'){
+          let data = {
+            id: [scope.row.id],
+            isEnable: 1
+          }
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '分配管理人':
+      allocationShow.value = true
+      break;
+  }
+}
+
+const closeAddOperation = (type: string) => {
+  dialogShow.value = false
+}
+
+onMounted(() => {
+  institutionList()
+  initTeam()
+})
+
+</script>
+
+<style scoped lang="scss">
+.team{
+  height: 770px;
+  background: #fff;
+  .search-input{
+    padding: 10px 20px;
+  }
+  .teamTree{
+    height: 700px;
+    overflow-y: auto;
+    background: #fff;
+    .custom-tree-node{
+      width: calc(100% - 40px);
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 5px 10px;
+      margin: 5px auto;
+      &:hover{
+        background: rgba(0,0,0,.1);
+      }
+      .custom-tree-node-label{
+        width: 70%;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+  .add-btn{
+    display: block;
+    margin: 0 auto;
+  }
+  .info{
+    h3{
+      margin: 10px 0;
+    }
+    p{
+      margin: 6px 0;
+      font-size: 14px;
+      color: rgba(0,0,0,.7);
+    }
+  }
+  .btn{
+    display: flex;
+    justify-content: flex-end;
+    align-items: flex-end;
+  }
+}
+</style>

+ 239 - 0
src/views/operationManagement/modules/addCard.vue

@@ -0,0 +1,239 @@
+<template>
+  <div class="form">
+    <el-form ref="BankRef" :rules="bankRules" :model="bankForm" label-width="80">
+      <el-form-item prop="name" label="姓名">
+        <el-input v-model="bankForm.name" disabled></el-input>
+      </el-form-item>
+      <el-form-item prop="bank" label="银行">
+        <el-select v-model="bankForm.bankName" :disabled="bankForm.isRead">
+          <el-option v-for="item in bankOption" :key="item.id" :value="item.id" :label="item.label"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="card" label="银行卡号">
+        <el-input v-model="bankForm.bankCardNumber" :disabled="bankForm.isRead"></el-input>
+      </el-form-item>
+      <el-form-item prop="bankName" label="开户行">
+        <el-input v-model="bankForm.bankAddress" :disabled="bankForm.isRead"></el-input>
+      </el-form-item>
+      <el-form-item prop="photo" label="照片" class="upload-btn">
+        <el-upload :auto-upload="false" v-if="!bankForm.imageUrl" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage">
+          <el-button size="large" icon="Plus" />
+        </el-upload>
+        <div class="image-view" v-else>
+          <img :src="bankForm.imageUrl" />
+          <div class="btns" v-if="!bankForm.isRead">
+            <el-upload  :disabled="bankForm.isRead" style="display: inline" :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage">
+              <el-icon class="btn-icon"><Upload /></el-icon>
+            </el-upload>
+<!--            <el-icon class="btn-icon" @click="imageView"><View /></el-icon>-->
+          </div>
+        </div>
+      </el-form-item>
+      <div style="display: flex; justify-content: flex-end">
+        <el-button @click="onSubmit(BankRef, 0)">取消</el-button>
+        <el-button type="primary" @click="onSubmit(BankRef, 1)">确定</el-button>
+      </div>
+    </el-form>
+    <div class="image-show" v-show="imageShow" @click="() => { imageShow = false }">
+      <img :src="bankForm.imageUrl" />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, defineEmits, onMounted, watch } from 'vue'
+import {ElMessage, FormInstance} from 'element-plus'
+import api from "@/api";
+
+const BankRef = ref<FormInstance>()
+
+let props = defineProps<{
+  userInfo: {
+    userJzgInfoId: string,
+    name: string,
+    bankName?: string,
+    bankCardNumber?: string,
+    bankAddress?: string,
+    attachment?: string,
+    imageUrl?: string
+    isRead?: boolean
+  }
+}>()
+const emits = defineEmits(['closeDialog'])
+watch(() => props.userInfo, (newVal, oldVal) => {
+  console.log(123123123, newVal, oldVal)
+  bankForm.value = newVal
+}, { deep: true });
+
+let bankForm = ref({
+  userJzgInfoId: props.userInfo.userJzgInfoId,
+  name: props.userInfo.name,
+  bankName: props.userInfo.bankName,
+  bankCardNumber: props.userInfo.bankCardNumber,
+  bankAddress: props.userInfo.bankAddress,
+  attachment: props.userInfo.attachment,
+  imageUrl: props.userInfo.attachment,
+  isRead: props.userInfo.isRead
+})
+const bankRules = {
+  name: [
+    { required: true, message: '请填写姓名', trigger: 'blur' }
+  ],
+  bankName: [
+    { required: true, message: '请选择银行', trigger: 'change' }
+  ],
+  bankCardNumber: [
+    { required: true, message: '请填写银行卡号', trigger: 'blur' },
+    {
+      pattern: /^([1-9]{1})(\d{15}|\d{16}|\d{18})$/,
+      message: '请填写正确的银行卡号',
+      trigger: 'blur'
+    }
+  ],
+  bankAddress: [
+    { required: true, message: '请填写开户行', trigger: 'blur' }
+  ],
+}
+
+// 照片
+let imageShow = ref(false)
+const uploadImage = async (file) => {
+  let files = file.raw
+  const params = new FormData(); // 声明formData数据类型
+  params.append("file", files);
+  params.append("type", "image");
+  const { code, data, msg } = await api.commonApi.fileUpload(params)
+  console.log(123, data)
+  if(code == 200) {
+    bankForm.value.imageUrl = data.downloadUrl
+    bankForm.value.attachment = data.id
+  }
+}
+const imageView = () => {
+  imageShow.value = true
+}
+
+// 初始化银行数据
+let bankOption = ref([])
+const initBankCard = () => {
+  api.commonApi.personInfo('bank_info').then(res => {
+    if(res.code == 200) {
+      bankOption.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+const onSubmit = async (BankRef:FormInstance | undefined, type: number) => {
+  if(!BankRef) {
+    BankRef.resetFields()
+    emits('closeDialog', '取消')
+    return
+  }
+  if(type) {
+    await BankRef.validate((valid) => {
+      if(valid) {
+        api.operationApi.addBankCard(bankForm.value).then(res => {
+          if(res.code == 200) {
+            ElMessage({
+              message: res.msg,
+              type: 'success'
+            })
+          } else {
+            ElMessage({
+              message: res.msg,
+              type: 'warning'
+            })
+          }
+          BankRef.resetFields()
+          emits('closeDialog', '确定')
+        })
+      } else {
+        ElMessage({
+          message: '请正确填写相关信息!',
+          type: 'warning'
+        })
+      }
+    })
+  } else {
+    BankRef.resetFields()
+    emits('closeDialog', '取消')
+  }
+}
+
+onMounted(() => {
+  initBankCard()
+})
+
+</script>
+
+<style scoped lang="scss">
+.form{
+  position: relative;
+  .upload-btn{
+    :deep(.el-button) {
+      width: 80px;
+      height: 80px;
+      font-size: 30px;
+      color: #ccc;
+    }
+  }
+  .image-view{
+    width: 80px;
+    height: 80px;
+    border-radius: 5px;
+    position: relative;
+    img{
+      display: block;
+      width: 100%;
+      height: 100%;
+      border-radius: 5px;
+    }
+    .btns{
+      display: none;
+    }
+    &:hover{
+      .btns{
+        width: 100%;
+        height: 100%;
+        border-radius: 5px;
+        position: absolute;
+        background: rgba(0,0,0, .3);
+        top: 0;
+        left: 0;
+        line-height: 80px;
+        display: flex;
+        align-content: center;
+        justify-content: center;
+        .btn-icon{
+          color: #fff;
+          font-size: 18px;
+          margin: 0 10px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+  .image-show{
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    margin: auto;
+    top: 0;
+    left: 0;
+    display: flex;
+    align-content: center;
+    justify-content: center;
+    background: rgba(0,0,0,.4);
+    img{
+      display: block;
+      width: 80%;
+      height: 100%;
+    }
+  }
+}
+</style>

+ 1046 - 0
src/views/operationManagement/modules/addOperation.vue

@@ -0,0 +1,1046 @@
+<template>
+  <div>
+    <el-form
+      :model="operationForm"
+      ref="OperationFormRef"
+      :rules="operationRules"
+      label-width="120"
+    >
+      <el-descriptions title="基本信息">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="typeAttr" label="业务员类型">
+                  <el-select v-model="operationForm.typeAttr" placeholder="请选择业务员类型">
+                    <el-option key="1" value="1" label="前线人员"></el-option>
+                    <el-option key="2" value="2" label="后线人员"></el-option>
+                    <el-option key="3" value="3" label="合伙人"></el-option>
+                    <el-option key="4" value="4" label="工作室管理员"></el-option>
+                    <el-option key="5" value="5" label="团队长"></el-option>
+                    <el-option key="6" value="6" label="个代"></el-option>
+                    <el-option key="7" value="7" label="电销"></el-option>
+                    <el-option key="8" value="8" label="渠道"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="deptId" label="所属团队">
+                  <el-select v-model="operationForm.organizationId" placeholder="请选择所属团队" @change="deptChange">
+                    <el-option v-for="item in teamList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="name" label="姓名">
+                  <el-input v-model="operationForm.name" placeholder="请填写姓名"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="mobile" label="手机号">
+                  <el-input v-model="operationForm.mobile" placeholder="请填写手机号"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="organization" label="所属机构">
+                  <el-input disabled v-model="operationForm.organization"></el-input>
+<!--                  <el-cascader style="width: 100%" v-model="operationForm.organization" placeholder="请选择所属机构" :options="option" :props="cascaderProps"></el-cascader>-->
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="identity" label="证件号">
+                  <el-input v-model="operationForm.identity" placeholder="请填写证件号"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="identityTimeStart" label="证件有效期始">
+                  <el-date-picker
+                    v-model="operationForm.identityTimeStart"
+                    type="date"
+                    placeholder="请选择"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="identityTimeEnd" label="证件有效期止">
+                  <el-date-picker
+                    v-model="operationForm.identityTimeEnd"
+                    type="date"
+                    placeholder="请选择"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="其他信息">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="leaderId" label="管理人">
+                  <el-select v-model="operationForm.leaderId" filterable placeholder="请选择管理人" @change="(e) => {operationForm.leaderNumber = e}">
+                    <el-option v-for="(item, index) in userList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="leaderNumber" label="管理人工号">
+                  <el-input readonly v-model="operationForm.leaderNumber" placeholder="请填写管理人工号"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="referrerId" label="推荐人">
+                  <el-select v-model="operationForm.referrerId" filterable placeholder="请选择推荐人" @change="(e) => {operationForm.referrerNumber = e}">
+                    <el-option v-for="(item, index) in userList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="referrerNumber" label="推荐人工号">
+                  <el-input readonly v-model="operationForm.referrerNumber" placeholder="请填写推荐人工号"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="资料附件">
+        <el-descriptions-item>
+          <template #default>
+            <el-form-item prop="" label="身份证(人像面)" label-width="150">
+              <el-upload action="" v-if="!IDCardFront" :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 1)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ IDCardFrontName }}</div>
+                <div class="fileBtn">
+                  <el-upload :show-file-list="false" :auto-upload="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 1)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(1)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item prop="" label="身份证(国徽面)" label-width="150">
+              <el-upload v-if="!IDCardBack" :auto-upload="false"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 2)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ IDCardBackName }}</div>
+                <div class="fileBtn">
+                  <el-upload :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 2)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(2)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item prop="" label="展业资格证" label-width="150">
+              <el-upload :auto-upload="false" v-if="!certification"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 3)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ certificationName }}</div>
+                <div class="fileBtn">
+                  <el-upload :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 3)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(3)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-divider />
+      <el-button v-if="!recordShow" link type="primary" icon="plus" @click="recordShow = !recordShow">填写人事档案(选填)</el-button>
+      <el-button v-else link type="primary" icon="ArrowUp" @click="recordShow = !recordShow">收起人事档案(选填)</el-button>
+      <br/><br/>
+      <el-descriptions title="个人信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="sex" label="性别">
+                  <el-select v-model="operationForm.sex" placeholder="请选择性别">
+                    <el-option v-for="item in options[0]" :key="item.value" :value="item.value" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="birthday" label="出生日期">
+                  <el-date-picker
+                    v-model="operationForm.birthday"
+                    type="date"
+                    placeholder="请选择"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="nations" label="民族">
+                  <el-select v-model="operationForm.nations" placeholder="请选择业务员类型">
+                    <el-option v-for="item in options[1]" :key="item.value" :value="item.value" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="koseki" label="户籍">
+                  <el-input v-model="operationForm.koseki" placeholder="请填写户籍"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="maritalStatus" label="婚姻状况">
+                  <el-select v-model="operationForm.maritalStatus" placeholder="请选择婚姻状况">
+                    <el-option v-for="item in options[2]" :key="item.value" :value="item.value" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="politicsStatus" label="政治面貌">
+                  <el-select v-model="operationForm.politicsStatus" placeholder="请选择政治面貌">
+                    <el-option v-for="item in options[3]" :key="item.value" :value="item.value" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="health" label="健康状况">
+                  <el-select v-model="operationForm.health" placeholder="请选择健康状况">
+                    <el-option v-for="item in options[4]" :key="item.value" :value="item.value" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="address" label="居住地区">
+                  <el-cascader
+                    clearable
+                    style="width: 100%"
+                    v-model="operationForm.address"
+                    :options="areaOptions"
+                    :props="areaProps"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="liveAddress" label="详细地址">
+                  <el-input v-model="operationForm.liveAddress" placeholder="请填写详细地址"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="postalCode" label="邮政编码">
+                  <el-input v-model="operationForm.postalCode" placeholder="请填写邮政编码"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="学历信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="education" label="学历">
+                  <el-select v-model="operationForm.education" placeholder="请选择学历">
+                    <el-option v-for="item in options[5]" :key="item.value" :value="item.value" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="graduationTime" label="毕业时间">
+                  <el-date-picker
+                    v-model="operationForm.graduationTime"
+                    type="date"
+                    placeholder="请选择"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="school" label="毕业院校">
+                  <el-input v-model="operationForm.school" placeholder="请填写毕业院校"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="isComputer" label="是否计算机专业">
+                  <el-select v-model="operationForm.isComputer" placeholder="请选择是否计算机专业">
+                    <el-option key="1" value="1" label="是"></el-option>
+                    <el-option key="0" value="0" label="否"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="紧急联系人信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="emergencyContactName" label="姓名">
+                  <el-input v-model="operationForm.emergencyContactName" placeholder="请填写姓名"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="emergencyContactTel" label="手机号">
+                  <el-input v-model="operationForm.emergencyContactTel" placeholder="请填写手机号"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="工资信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="salary" label="工资">
+                  <el-input v-model="operationForm.salary" placeholder="请填写工资"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="salaryLevel" label="工资等级">
+                  <el-input v-model="operationForm.salaryLevel" placeholder="请填写工资等级"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item prop="bankCardId" label="银行卡号">
+                  <el-input v-model="operationForm.bankCardId" placeholder="请填写银行卡号"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item prop="bankName" label="开户行">
+                  <el-select v-model="operationForm.bankName" placeholder="请选择开户行">
+                    <el-option v-for="item in bankOption" :key="item.id" :value="item.id" :label="item.label"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-divider v-show="recordShow" />
+      <el-descriptions v-show="recordShow" title="其它附件">
+        <el-descriptions-item>
+          <template #default>
+            <el-form-item prop="" label="劳动合同" label-width="150">
+              <el-upload v-if="!contract" :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 4)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ contractName }}</div>
+                <div class="fileBtn">
+                  <el-upload :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 4)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(4)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item prop="" label="应聘表" label-width="150">
+              <el-upload v-if="!applicant" :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 5)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ applicantName }}</div>
+                <div class="fileBtn">
+                  <el-upload :auto-upload="false"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 5)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(5)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item prop="" label="定薪表" label-width="150">
+              <el-upload :auto-upload="false" v-if="!decidePay"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 6)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ decidePayName }}</div>
+                <div class="fileBtn">
+                  <el-upload :auto-upload="false"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 6)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(6)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item prop="" label="离职表" label-width="150">
+              <el-upload :auto-upload="false" v-if="!dimission"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 7)">
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ dimissionName }}</div>
+                <div class="fileBtn">
+                  <el-upload :auto-upload="false"  :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, 7)" style="display: flex; align-items: center">
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(7)"><View /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <div style="display: flex; justify-content: flex-end">
+        <el-button @click="onSubmit(OperationFormRef, 0)">取消</el-button>
+        <el-button type="primary" @click="onSubmit(OperationFormRef, 1)">确定</el-button>
+      </div>
+    </el-form>
+    <div class="image-view" v-if="imageShow" @click="imageShow = false">
+      <img :src="imageUrl" />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, defineEmits, onMounted } from 'vue'
+import type { AddOperation } from '@/api/modules/operation.ts'
+import type { FormRules, FormInstance } from "element-plus";
+import api from "@/api";
+import { ElMessage } from "element-plus";
+
+interface OperationFormProps extends AddOperation {
+  organization: string
+  leaderNumber: string,
+  referrerNumber: string,
+  address?: string[],
+  id?: string
+}
+
+let emits = defineEmits(['closeDialog'])
+let option = ref([])
+const OperationFormRef = ref<FormInstance>()
+// 添加/编辑业务员表单
+let operationForm = ref<OperationFormProps>({
+  typeAttr: '',
+  deptId: '',
+  organizationId: '',
+  name: '',
+  mobile: '',
+  identity: '',
+  identityTimeStart: '',
+  identityTimeEnd: '',
+  leaderId: '',
+  leaderNumber: '',
+  referrerId: '',
+  referrerNumber: '',
+
+  sex: null,
+  birthday: null,
+  nations: null,
+  koseki: null,
+  maritalStatus: null,
+  politicsStatus: null,
+  health: null,
+  province: null,
+  city: null,
+  district: null,
+  address: [],
+  liveAddress: null,
+  postalCode: null,
+  education: null,
+  graduationTime: null,
+  school: null,
+  isComputer: null,
+  emergencyContactName: null,
+  emergencyContactTel: null,
+  salary: null,
+  salaryLevel: null,
+  bankCardId: null,
+  bankName: null,
+
+  sfz1: null,
+  sfz2: null,
+  qualification: null,
+  contract: null,
+  applicant: null,
+  salaryTable: null,
+  leaveTable: null
+})
+// 机构数据渲染格式
+const cascaderProps = {
+  value: 'id',
+  label: 'name',
+  children: 'children'
+}
+// 添加/编辑业务员表单校验
+const operationRules = ref<FormRules>({
+  typeAttr: [
+    { required: true, trigger: "change", message: "请选择业务员类型" }
+  ],
+  deptId: [
+    { required: true, trigger: "change", message: "请选择所属团队" }
+  ],
+  name: [
+    { required: true, trigger: "blur", message: "请填写姓名" }
+  ],
+  mobile: [
+    { required: true, trigger: "blur", message: "请填写手机号" },
+    {
+      pattern: /^1[34578][0-9]{9}$/,
+      message: '请填写正确的手机号',
+      trigger: 'blur'
+    }
+  ],
+  organization: [
+    { required: true, trigger: "change", message: "请选择所属机构" }
+  ],
+  identity: [
+    { required: true, trigger: "blur", message: "请填写证件号" },
+    {
+      pattern: /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9X]$/,
+      message: '请填写正确的身份证号',
+      trigger: 'blur'
+    }
+  ],
+  identityTimeStart: [
+    { required: true, trigger: "change", message: "请选择证件有效期始" }
+  ],
+  identityTimeEnd: [
+    { required: true, trigger: "change", message: "请选择证件有效期止" }
+  ],
+  leaderId: [
+    { required: true, trigger: "change", message: "请选择管理人" }
+  ],
+  leaderNumber: [
+    { required: true, trigger: "blur", message: "请填写管理人工号" }
+  ],
+  referrerId: [
+    { required: true, trigger: "change", message: "请选择推荐人" }
+  ],
+  referrerNumber: [
+    { required: true, trigger: "blur", message: "请填写推荐人工号" }
+  ],
+  bankCardId: [
+    {
+      pattern: /^([1-9]{1})(\d{15}|\d{16}|\d{18})$/,
+      message: '请填写正确的银行卡号',
+      trigger: 'blur'
+    }
+  ],
+  emergencyContactTel: [
+    {
+      pattern: /^1[34578][0-9]{9}$/,
+      message: '请填写正确的手机号',
+      trigger: 'blur'
+    }
+  ],
+  postalCode: [
+    {
+      pattern: /^\d{6}$/,
+      message: '请填写正确的邮政编码',
+      trigger: 'blur'
+    }
+  ]
+})
+// 身份证人像面
+let IDCardFrontName = ref('')
+let IDCardFront = ref('')
+// 身份证国徽面
+let IDCardBackName = ref('')
+let IDCardBack = ref('')
+// 展业资格证
+let certificationName = ref('')
+let certification = ref('')
+// 劳务合同
+let contractName = ref('')
+let contract = ref('')
+// 应聘表
+let applicantName = ref('')
+let applicant = ref('')
+// 定薪表
+let decidePayName = ref('')
+let decidePay = ref('')
+// 离职表
+let dimissionName = ref('')
+let dimission = ref('')
+// 图片预览地址
+let imageShow = ref(false)
+let imageUrl = ref('')
+
+// 编辑时初始化数据
+// 编辑的id
+let editId = ref('')
+const initEditData = (id) => {
+  if(id) {
+    editId.value = id
+    api.operationApi.operationDetail(id).then(res => {
+      if(res?.code == 200) {
+        let formData = res.data
+        operationForm.value = formData
+        operationForm.value.organization = formData.deptName
+        operationForm.value.deptId = formData.deptId
+        operationForm.value.leaderNumber = formData.leaderId
+        operationForm.value.referrerNumber = formData.referrerId
+        let address = []
+        if(formData.province&&formData.city&&formData.district) {
+          address = [formData.province, formData.city, formData.district]
+        }
+        if(formData.province&&!formData.city&&!formData.district) {
+          address = [formData.province]
+        }
+        if(formData.fileList) {
+          let sfz1 = formData.fileList.find(item => item.fileType == 'sfz1')
+          let sfz2 = formData.fileList.find(item => item.fileType == 'sfz2')
+          let qualification = formData.fileList.find(item => item.fileType == 'qualification')
+          let contractImg = formData.fileList.find(item => item.fileType == 'contract')
+          let applicantImg = formData.fileList.find(item => item.fileType == 'applicant')
+          let salaryTable = formData.fileList.find(item => item.fileType == 'salary')
+          let leaveTable = formData.fileList.find(item => item.fileType == 'leave')
+          console.log('图片', formData.fileList)
+          console.log('身份证1', sfz1)
+          console.log('身份证2', sfz1)
+          console.log('展业资格证', qualification)
+          console.log('劳务合同', contract)
+          console.log('应聘表', applicant)
+          console.log('定薪表', salaryTable)
+          console.log('离职表', leaveTable)
+          if(sfz1) {
+            operationForm.value.sfz1 = sfz1.id
+            IDCardFrontName.value = sfz1.fileName
+            IDCardFront.value = sfz1.fileUrl
+          }
+          if(sfz2) {
+            operationForm.value.sfz2 = sfz2.id
+            IDCardBackName.value = sfz2.fileName
+            IDCardBack.value = sfz2.fileUrl
+          }
+          if(qualification) {
+            operationForm.value.qualification = qualification.id
+            certificationName.value = qualification.fileName
+            certification.value = qualification.fileUrl
+          }
+          if(contractImg) {
+            operationForm.value.contract = contract.id
+            contractName.value = contractImg.fileName
+            contract.value = contractImg.fileUrl
+          }
+          if(applicantImg) {
+            operationForm.value.applicant = applicant.id
+            applicantName.value = applicantImg.fileName
+            applicant.value = applicantImg.fileUrl
+          }
+          if(salaryTable) {
+            operationForm.value.salaryTable = salaryTable.id
+            decidePayName.value = salaryTable.fileName
+            decidePay.value = salaryTable.fileUrl
+          }
+          if(leaveTable) {
+            operationForm.value.leaveTable = leaveTable.id
+            dimissionName.value = leaveTable.fileName
+            dimission.value = leaveTable.fileUrl
+          }
+        }
+        operationForm.value.address = address
+        getUser(operationForm.value.deptId)
+        console.log(123123123, operationForm.value)
+      } else {
+        ElMessage({
+          message: res.msg,
+          type: 'warning'
+        })
+      }
+    })
+  }
+}
+
+// 上传接口
+let postUrl = ref(`${import.meta.env.VITE_APP_API_BASEURL}/file/upload`)
+// 上传图片
+const uploadImage = async (file, type) => {
+  let files = file.raw
+  const params = new FormData(); // 声明formData数据类型
+  params.append("file", files);
+  params.append("type", "image");
+  const { code, data, msg } = await api.commonApi.fileUpload(params)
+    if(code == 200) {
+      let result = {...data}
+      switch (type) {
+        case 1:
+          IDCardFrontName.value = result.fileName
+          IDCardFront.value = result.downloadUrl
+          operationForm.value.sfz1 = result.id
+          break;
+        case 2:
+          IDCardBackName.value = result.fileName
+          IDCardBack.value = result.downloadUrl
+          operationForm.value.sfz2 = result.id
+          break;
+        case 3:
+          certificationName.value = result.fileName
+          certification.value = result.downloadUrl
+          operationForm.value.qualification = result.id
+          break;
+        case 4:
+          contractName.value = result.fileName
+          contract.value = result.downloadUrl
+          operationForm.value.contract = result.id
+          break;
+        case 5:
+          applicantName.value = result.fileName
+          applicant.value = result.downloadUrl
+          operationForm.value.applicant = result.id
+          break;
+        case 6:
+          decidePayName.value = result.fileName
+          decidePay.value = result.downloadUrl
+          operationForm.value.salaryTable = result.id
+          break;
+        case 7:
+          dimissionName.value = result.fileName
+          dimission.value = result.downloadUrl
+          operationForm.value.leaveTable = result.id
+          break;
+      }
+    } else {
+      ElMessage({
+        message: msg,
+        type: 'error'
+      })
+    }
+}
+
+// 人事档案
+let recordShow = ref(false)
+
+// 图片预览
+const imageView = (type) => {
+  imageShow.value = true
+  switch (type) {
+    case 1:
+      imageUrl.value = IDCardFront.value
+      break;
+    case 2:
+      imageUrl.value = IDCardBack.value
+      break;
+    case 3:
+      imageUrl.value = certification.value
+      break;
+    case 4:
+      imageUrl.value = contract.value
+      break;
+    case 5:
+      imageUrl.value = applicant.value
+      break;
+    case 6:
+      imageUrl.value = decidePay.value
+      break;
+    case 7:
+      imageUrl.value = dimission.value
+      break;
+  }
+}
+// 管理人/推荐人
+let userList = ref([])
+const getUser = (id) => {
+  api.operationApi.getUser(id).then(res => {
+    if(res?.code == 200) {
+      userList.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+// 确定
+const onSubmit = async (OperationFormRef: FormInstance, type: number) => {
+  if(!OperationFormRef) {
+    emits('closeDialog', '取消')
+    recordShow.value = false
+    OperationFormRef.resetFields()
+    return
+  }
+  if(type) {
+    await OperationFormRef.validate((valid, error) => {
+      if(valid) {
+        let formData = {...operationForm.value}
+        // formData.organization = operationForm.value.organization[operationForm.value.organization.length - 1]
+        formData.systemCode = localStorage.getItem('login_system')?localStorage.getItem('login_system'):''
+        formData.province = operationForm.value.address?operationForm.value.address[0]:''
+        formData.city = operationForm.value.address?operationForm.value.address[1]?operationForm.value.address[1]:'':''
+        formData.district = operationForm.value.address?operationForm.value.address[2]?operationForm.value.address[2]:'':''
+        if(editId.value) {
+          api.operationApi.updateOperation(formData).then(res => {
+            if(res.code == 200) {
+              ElMessage({
+                message: res.msg,
+                type: 'success'
+              })
+              emits('closeDialog', '确定')
+            } else {
+              ElMessage({
+                message: res.msg,
+                type: 'error'
+              })
+            }
+            IDCardFrontName.value = ''
+            IDCardFront.value = ''
+            IDCardBackName.value = ''
+            IDCardBack.value = ''
+            certificationName.value = ''
+            certification.value = ''
+            contractName.value = ''
+            contract.value = ''
+            applicantName.value = ''
+            applicant.value = ''
+            decidePayName.value = ''
+            decidePay.value = ''
+            dimissionName.value = ''
+            dimission.value = ''
+            recordShow.value = false
+            OperationFormRef.resetFields()
+            emits('closeDialog', '取消')
+          })
+        } else {
+          api.operationApi.addOperation(formData).then(res => {
+            if(res.code == 200) {
+              ElMessage({
+                message: res.msg,
+                type: 'success'
+              })
+              emits('closeDialog', '确定')
+            } else {
+              ElMessage({
+                message: res.msg,
+                type: 'error'
+              })
+            }
+            IDCardFrontName.value = ''
+            IDCardFront.value = ''
+            IDCardBackName.value = ''
+            IDCardBack.value = ''
+            certificationName.value = ''
+            certification.value = ''
+            contractName.value = ''
+            contract.value = ''
+            applicantName.value = ''
+            applicant.value = ''
+            decidePayName.value = ''
+            decidePay.value = ''
+            dimissionName.value = ''
+            dimission.value = ''
+            recordShow.value = false
+            OperationFormRef.resetFields()
+            emits('closeDialog', '取消')
+          })
+        }
+      } else {
+        Object.keys(error).forEach((key,i)=>{
+          if(i==0){
+            const firstFiled = error[key][0].field
+            OperationFormRef.scrollToField(firstFiled)
+          }
+        })
+        ElMessage({
+          message: '请正确填写相关信息!',
+          type: 'warning'
+        })
+      }
+    })
+  } else {
+    IDCardFrontName.value = ''
+    IDCardFront.value = ''
+    IDCardBackName.value = ''
+    IDCardBack.value = ''
+    certificationName.value = ''
+    certification.value = ''
+    contractName.value = ''
+    contract.value = ''
+    applicantName.value = ''
+    applicant.value = ''
+    decidePayName.value = ''
+    decidePay.value = ''
+    dimissionName.value = ''
+    dimission.value = ''
+    recordShow.value = false
+    emits('closeDialog', '取消')
+    OperationFormRef.resetFields()
+  }
+}
+
+// 初始化个人信息
+let options = ref([])
+const initInfo = () => {
+/*
+* 性别        gender
+  民族        nation
+  婚姻状况        marriage
+  政治面貌        political_status
+  健康状况        health_status
+  学历        educational
+* */
+  let infoList = ['gender', 'nation', 'marriage', 'political_status', 'health_status', 'educational']
+  infoList.forEach((item: string, index: number) => {
+    api.commonApi.personInfo(item).then((res) => {
+      if(res?.code == 200) {
+        options.value[index] = [...res.data]
+      } else {
+        ElMessage({
+          message: res.msg,
+          type: 'warning'
+        })
+      }
+    })
+  })
+}
+// 获取地区数据
+const areaOptions = ref([]);
+const areaProps = ref({
+  value: "areaCode",
+  label: "areaCname",
+  children: "child",
+});
+const getArea = () => {
+  api.areaApi.areaList({}).then((res) => {
+    areaOptions.value = res.data;
+  });
+}
+
+// 团队数据
+let teamList = ref([])
+const getTeamList = async () => {
+  const { code, data, msg } = await api.teamApi.teamList({})
+  if(code == 200) {
+    teamList.value = data
+  } else {
+    ElMessage({
+      message: msg,
+      type: 'warning'
+    })
+  }
+}
+const deptChange = (e) => {
+  const obj = teamList.value.find(item => item.id == e)
+  operationForm.value.organization = obj.deptName
+  operationForm.value.deptId = obj.deptId
+  getUser(obj.deptId)
+}
+
+// 初始化银行数据
+let bankOption = ref([])
+const initBankCard = () => {
+  api.commonApi.personInfo('bank_info').then(res => {
+    if(res.code == 200) {
+      bankOption.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+onMounted(() => {
+  initInfo()
+  getArea()
+  getTeamList()
+  initBankCard()
+})
+
+defineExpose({
+  initEditData
+})
+
+
+</script>
+
+<style scoped lang="scss">
+.fileInfo{
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  padding: 2px 20px;
+  border-radius: 5px;
+  margin: 0 10px;
+  &:hover{
+    background: #ccc;
+  }
+  .fileName{
+    width: 200px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .fileBtn{
+    display: flex;
+    align-items: center;
+    .btn-icon{
+      margin: 0 10px;
+      font-size: 16px;
+      cursor: pointer;
+      &:hover{
+        color: #00a0f4;
+      }
+    }
+  }
+}
+.image-view{
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0,0,0,.6);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 9999;
+  img{
+    width: 800px;
+    height: 800px;
+    border-radius: 5px;
+  }
+}
+</style>

+ 170 - 0
src/views/operationManagement/modules/addTeam.vue

@@ -0,0 +1,170 @@
+<template>
+  <div class="addTeam">
+    <el-form ref="AddTeamRef" :model="teamForm" :rules="teamRules" label-width="100">
+      <el-form-item label="团队名称" prop="name">
+        <el-input v-model="teamForm.name" placeholder="请输入团队名称"></el-input>
+      </el-form-item>
+      <el-form-item label="所属机构" prop="deptId">
+        <el-cascader
+          clearable
+          v-model="teamForm.deptId"
+          :options="option"
+          :props="cascaderProps"
+          style="width: 100%"
+          placeholder="选择机构"
+          @change="deptIdChange"
+        ></el-cascader>
+      </el-form-item>
+      <el-form-item label="管理人" prop="managerId">
+        <el-select v-model="teamForm.managerId" placeholder="选择管理人">
+          <el-option v-for="item in userList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="管理人工号" prop="managerId">
+        <el-input disabled v-model="teamForm.managerId"></el-input>
+      </el-form-item>
+      <el-form-item label="描述" prop="describeInformation">
+        <el-input type="textarea" maxlength="500" placeholder="请输入" v-model="teamForm.describeInformation"></el-input>
+      </el-form-item>
+      <div style="display: flex; justify-content: flex-end">
+        <el-button @click="onSubmit(AddTeamRef, 0)">取消</el-button>
+        <el-button type="primary" @click="onSubmit(AddTeamRef, 1)">确定</el-button>
+      </div>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, defineEmits, onMounted, defineProps, defineExpose } from 'vue'
+import type { FormRules, FormInstance } from 'element-plus'
+import type { AddTeamProps } from '@/api/modules/team.ts'
+import { ElMessage } from "element-plus";
+import api from "@/api";
+
+interface EditDataProps extends AddTeamProps {
+  id: string
+}
+
+let emits = defineEmits(['closeDialog'])
+
+// 表单
+const AddTeamRef = ref<FormInstance>()
+let teamForm = ref<AddTeamProps>({
+  name: '',
+  deptId: [],
+  managerId: '',
+  describeInformation: '',
+  attribute: 1
+})
+
+
+let teamRules = ref<FormRules>({
+  name: [
+    { required: true, trigger: "blur", message: "请填写团队名称" }
+  ],
+  deptId: [
+    { required: true, trigger: "change", message: "请选择机构" }
+  ],
+  managerId: [
+    { required: true, trigger: "change", message: "请选择管理人" }
+  ]
+})
+
+const initEdit = (data) => {
+
+}
+
+// 机构
+let option = ref([])
+const cascaderProps = {
+  value: 'id',
+  label: 'name',
+  children: 'children'
+}
+// 获取机构数据
+const institutionList = () => {
+  api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
+    if(res?.code == 200) {
+      option.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+const deptIdChange = (e) => {
+  let id = e?e[e.length - 1]: ''
+  getUser(id)
+}
+
+// 管理人
+let userList = ref([])
+const getUser = (id) => {
+  api.operationApi.getUser(id).then(res => {
+    if(res?.code == 200) {
+      userList.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 提交/取消
+const onSubmit = async (AddTeamRef: FormInstance, type) => {
+  if(!AddTeamRef) {
+    emits('closeDialog', '取消')
+    AddTeamRef.resetFields()
+    return
+  }
+  if(type) {
+    await AddTeamRef.validate((valid) => {
+      if(valid) {
+        let formData = {...teamForm.value}
+        formData.deptId = teamForm.value.deptId[teamForm.value.deptId.length - 1]
+        formData.systemCode = localStorage.getItem('login_system')
+        api.teamApi.addTeam(formData).then(res => {
+          if(res.code == 200) {
+            ElMessage({
+              message: res.msg,
+              type: 'success'
+            })
+          } else {
+            ElMessage({
+              message: res.msg,
+              type: 'warning'
+            })
+          }
+          emits('closeDialog', '确认')
+          AddTeamRef.resetFields()
+        })
+      } else {
+        ElMessage({
+          message: '请正确填写相关信息!',
+          type: 'warning'
+        })
+      }
+    })
+  } else {
+    emits('closeDialog', '取消')
+    AddTeamRef.resetFields()
+  }
+}
+
+onMounted(() => {
+  institutionList()
+})
+
+defineExpose({
+  initEdit
+})
+
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 180 - 0
src/views/operationManagement/modules/allocation.vue

@@ -0,0 +1,180 @@
+<template>
+  <div class="allocation">
+    <el-input v-model="searchValue" style="width: 240px" placeholder="输入姓名、手机号、工号查找" clearable>
+      <template #prefix>
+        <el-icon class="el-input__icon"><Search /></el-icon>
+      </template>
+    </el-input>
+    <el-row :gutter="20" class="allocation-content">
+      <el-col :span="12" style="padding: 10px; box-sizing: border-box;">
+        <el-tree
+          ref="treeRef"
+          :data="options"
+          :props="cascaderProps"
+          node-key="id"
+          :default-expanded-keys="expandedKeys"
+          :default-checked-keys="checkedKeys"
+          @node-click="handleNodeClick"
+          :filter-node-method="filterNode"
+        />
+      </el-col>
+      <el-col :span="12" style="padding: 10px; box-sizing: border-box;border-left: 1px solid #ccc;">
+        <el-radio-group v-if="userList?.length>0" v-model="radioValue" class="allocation-radio">
+          <el-radio v-for="item in userList" :value="item.id" size="large">
+            <template #default>
+              <div>{{ item.name }}</div>
+              <div>{{ item.id }}</div>
+            </template>
+          </el-radio>
+        </el-radio-group>
+        <el-empty v-else description="暂无数据" />
+      </el-col>
+    </el-row>
+    <div style="display: flex; justify-content: flex-end">
+      <el-button @click="onSubmit('取消')">取消</el-button>
+      <el-button type="primary" @click="onSubmit('确定')">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, defineEmits } from 'vue'
+import api from '@/api'
+import { ElMessage } from 'element-plus'
+
+const cascaderProps = {
+  value: 'id',
+  label: 'name',
+  children: 'children'
+}
+
+let emits = defineEmits(['closeDialog'])
+
+// 初始化负责人
+let userList = ref([])
+const initUser = (id) => {
+  api.operationApi.getUser(id).then(res => {
+    if(res.code == 200) {
+      userList.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 初始化默认选中的数据
+let checkedKeys = ref([])
+let selectedIds = ref([])
+const initCheckedKeys = (id, type, ids) => {
+  checkedKeys.value = [id]
+  selectedIds.value = [...ids]
+  initUser(id)
+  radioValue.value = ''
+}
+
+// 搜索过滤
+let searchValue = ref('')
+const treeRef = ref(null)
+watch(searchValue, (val) => {
+  treeRef.value!.filter(val);
+});
+const handleSearch = () => {
+  filterNode(searchValue.value, options.value)
+}
+
+// 机构数据
+let options = ref([])
+// 默认展开
+let expandedKeys = ref([])
+// 获取机构数据
+const institutionList = () => {
+  api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
+    if(res?.code == 200) {
+      options.value = res.data
+      if(options.value) {
+        let list = []
+        options.value.forEach(item => {
+          list.push(item.id)
+        })
+        expandedKeys.value = [...list]
+      }
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+const handleNodeClick = (data) => {
+  console.log(data)
+  initUser(data.id)
+}
+const filterNode = (value: string, data: any) => {
+  if (!value) return true
+  return data.name.includes(value)
+}
+
+let radioValue = ref('')
+
+const onSubmit = (type) => {
+  if(type == '确定') {
+    if(!radioValue.value) {
+      ElMessage({
+        message: '请选择管理人',
+        type: 'warning'
+      })
+      return
+    }
+    api.operationApi.setLeader({
+      ids: selectedIds.value,
+      leaderId: radioValue.value,
+      getAll: 0
+    }).then(res => {
+      if(res.code == 200) {
+        ElMessage({
+          message: res.msg,
+          type: 'success'
+        })
+      } else {
+        ElMessage({
+          message: res.msg,
+          type: 'warning'
+        })
+      }
+    })
+  }
+  emits('closeDialog', false)
+}
+
+onMounted(() => {
+  institutionList()
+})
+
+defineExpose({
+  initCheckedKeys
+})
+
+</script>
+
+<style scoped lang="scss">
+.allocation {
+  .allocation-content {
+    width: 100%;
+    margin: 20px;
+    border: 1px solid #ccc;
+    border-radius: 5px;
+    .allocation-radio{
+      display: flex;
+      flex-direction: column;
+      :deep(.el-radio) {
+        margin-right: 0;
+        margin-top: 10px;
+      }
+    }
+  }
+}
+</style>

+ 658 - 0
src/views/operationManagement/operation.vue

@@ -0,0 +1,658 @@
+<template>
+  <div class="operation">
+    <el-form
+      class="operationForm"
+      ref="OperationRef"
+      :model="form"
+      label-width="auto"
+    >
+      <el-row :gutter="20">
+        <el-col :span="8">
+          <el-form-item label="业务员" class="formItem">
+            <el-input v-model="form.salesman" placeholder="输入姓名、手机号、工号查找" clearable></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="归属机构" class="formItem">
+            <el-cascader clearable style="width: 100%" :options="options" :props="cascaderProps" @change="organizationChange"  />
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="类型" class="formItem">
+            <el-select clearable v-model="form.typeAttr">
+              <el-option key="1" value="0" label="个代"></el-option>
+              <el-option key="2" value="1" label="渠道"></el-option>
+              <el-option key="3" value="2" label="团队"></el-option>
+              <el-option key="4" value="3" label="电销组"></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="8">
+          <el-form-item label="所属" class="formItem">
+            <el-input clearable v-model="form.deptName" placeholder="渠道、团队、电销组名称查找"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="人员状态" class="formItem">
+            <el-select clearable v-model="form.status">
+              <el-option key="4" value="0" label="待认证"></el-option>
+              <el-option key="1" value="1" label="已认证"></el-option>
+              <el-option key="2" value="2" label="待提交资料"></el-option>
+              <el-option key="3" value="3" label="已入职"></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="账号状态" class="formItem">
+            <el-select clearable v-model="form.isEnable">
+              <el-option key="0" value="0" label="启用"></el-option>
+              <el-option key="1" value="1" label="禁用"></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="8">
+          <el-form-item label="管理人" class="formItem">
+            <el-input clearable v-model="form.leaderId" placeholder="管理人姓名、工号"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-button type="primary" @click="search()">查询</el-button>
+          <el-button type="primary" plain @click="reset()">重置</el-button>
+        </el-col>
+      </el-row>
+    </el-form>
+    <el-row :gutter="20" style="margin: 20px 0" flex>
+      <el-col :span="3" style="display: flex">
+        <el-checkbox @change="selectAll" v-model="selectAllValue"></el-checkbox>&nbsp;
+        <el-select class="select-all" placeholder="全选" v-model="selectType" style="width: 120px" @change="selectTypeChange">
+          <el-option key="all" value="all" label="选中所有数据"></el-option>
+          <el-option key="cur" value="cur" label="选中本页数据"></el-option>
+        </el-select>
+      </el-col>
+      <el-col :span="2">
+        <el-button type="primary" icon="plus" @click="addNumber">添加成员</el-button>
+      </el-col>
+      <el-col :span="2">
+        <el-dropdown trigger="click" placement="bottom" @command="dropdownCommand">
+          <el-button>批量管理</el-button>
+          <template #dropdown>
+            <el-dropdown-menu>
+              <el-dropdown-item command="启用">启用</el-dropdown-item>
+              <el-dropdown-item command="禁用">禁用</el-dropdown-item>
+              <el-dropdown-item command="删除">删除</el-dropdown-item>
+              <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
+      </el-col>
+    </el-row>
+    <el-table
+      :data="tableData"
+      ref="operationListRef"
+      height="460"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column label="姓名" prop="name" width="80"></el-table-column>
+      <el-table-column label="手机号" prop="mobile" width="150"></el-table-column>
+      <el-table-column label="工号" prop="userId" width="200"></el-table-column>
+      <el-table-column label="类型" prop="typeAttr" width="100">
+        <template #default="scope">
+          {{ scope.row.typeAttr == '0'?'个代':scope.row.typeAttr == '1'?'渠道':scope.row.typeAttr == '2'?'团队':scope.row.typeAttr == '3'?'电销组': '' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="归属" prop="organizationName" width="200"></el-table-column>
+      <el-table-column label="所属机构" prop="deptName" width="200"></el-table-column>
+      <el-table-column label="人员状态" prop="status" width="150">
+        <template #default="scope">
+          {{ scope.row.status == '0'?'待认证':scope.row.status == '1'?'已认证':scope.row.status == '2'?'待提交资料':scope.row.status == '3'?'已入职':'' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="账号状态" prop="isEnable" width="150">
+        <template #default="scope">
+          {{ scope.row.isEnable == '1'?'禁用':scope.row.isEnable == '0'?'启用': '--' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="管理人" prop="leaderName" width="150"></el-table-column>
+      <el-table-column label="管理人工号" prop="leaderId" width="200"></el-table-column>
+      <el-table-column label="推荐人" prop="referrerName" width="150"></el-table-column>
+      <el-table-column label="推荐人工号" prop="referrerId" width="200"></el-table-column>
+      <el-table-column fixed="right" label="操作" width="120">
+        <template #default="scope">
+          <div style="display: flex; align-items: center; justify-content: space-between">
+            <a style="color: #409EFF; cursor: pointer" @click="showDetail(scope)">详情</a>&nbsp;
+            <el-dropdown placement="bottom" trigger="click" @command="tableDataCommand(scope, $event)">
+              <a style="color: #409EFF; cursor: pointer">更多</a>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                  <el-dropdown-item command="启用">启用</el-dropdown-item>
+                  <el-dropdown-item command="禁用">禁用</el-dropdown-item>
+                  <el-dropdown-item command="删除">删除</el-dropdown-item>
+                  <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
+                  <el-dropdown-item command="添加银行卡">添加银行卡</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div style="display: flex; justify-content: center; margin-top: 15px">
+      <el-pagination
+        v-model:current-page="currentPage"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 30, 40]"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="total"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+    <el-dialog
+      v-model="dialogShow"
+      :title="title"
+      width="1000"
+    >
+      <addOperation ref="AddOperationRef" @closeDialog="closeAddOperation"></addOperation>
+    </el-dialog>
+    <el-dialog
+      v-model="bankCardDialogShow"
+      title="添加银行卡"
+      width="500"
+    >
+      <addCard @closeDialog="closeAddBankCard" :userInfo="addName"></addCard>
+    </el-dialog>
+    <el-dialog
+      v-model="allocationShow"
+      title="分配管理人"
+      width="800"
+    >
+      <allocation ref="AllocationRef" @closeDialog="closeAllocation"></allocation>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick } from 'vue'
+import { useRouter } from 'vue-router'
+import addOperation from './modules/addOperation.vue'
+import addCard from './modules/addCard.vue'
+import allocation from './modules/allocation.vue'
+import setDept from "@/components/DialogSetDeptLeader/index.vue"
+import type { OperationSearch, OperationIsEnable } from '@/api/modules/operation.ts'
+import api from "@/api";
+import { ElMessageBox, ElMessage, TableInstance } from 'element-plus'
+import type { TabBarInstance } from 'element-plus'
+import Allocation from "@/views/operationManagement/modules/allocation.vue";
+
+let myRouter = useRouter()
+
+const operationListRef = ref<TableInstance>()
+const AddOperationRef = ref(null)
+const AllocationRef = ref(null)
+
+interface TableDataProps {
+  name: string,
+  mobile: string,
+  id: string,
+  typeAttr: string,
+  deptName: string,
+  userId: string,
+  status: number,
+  isEnable: number,
+  leaderName: string,
+  leaderId: string,
+  referrerName: string,
+  referrerId: string
+}
+
+const organizationChange = (e) => {
+  form.value.deptId = e[e.length - 1]
+}
+
+// 查询条件
+let form = ref<OperationSearch>({
+  salesman: '',
+  deptId: '',
+  typeAttr: '',
+  deptName: '',
+  status: '',
+  isEnable: '',
+  leaderId: ''
+})
+let options = ref([])
+const cascaderProps = {
+  value: 'id',
+  label: 'name',
+  children: 'children'
+}
+// 获取机构数据
+const institutionList = () => {
+  api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
+    if(res?.code == 200) {
+      options.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+// 获取列表数据
+const init = () => {
+  api.operationApi.operationList({
+    pages: currentPage.value,
+    size: pageSize.value,
+    ...form.value
+  }).then(res => {
+    if(res?.code == 200) {
+      tableData.value = res.data.records
+      total.value = res.data.total
+    } else {
+      ElMessage({
+        message: res?.msg,
+        type: 'error'
+      })
+    }
+  })
+}
+// 删除
+const operationDel = (id: string[]) => {
+  api.operationApi.operationDelete({
+    ids:id,
+    getAll: selectType.value == 'all'?1:0
+  }).then(res => {
+    if(res?.code == 200) {
+      ElMessage({
+        message: res.msg,
+        type: 'success'
+      })
+      init()
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+// 启用/禁用
+const operationIsEnable = (data: OperationIsEnable) => {
+  api.operationApi.operationIsEnable(data).then(res => {
+    if(res?.code == 200) {
+      ElMessage({
+        message: res.msg,
+        type: 'success'
+      })
+      init()
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+// 搜索
+const search = () => {
+  init();
+}
+// 重置
+const reset = () => {
+  form.value = {
+    salesman: '',
+    deptId: '',
+    typeAttr: '',
+    deptName: '',
+    status: '',
+    isEnable: '',
+    leaderId: ''
+  }
+  currentPage.value = 1
+  pageSize.value = 10
+  init()
+}
+// 选中的数据
+let selectedList = ref<TableDataProps[]>([])
+// 全选的类型
+let selectType = ref('')
+// 外部全选是否勾选
+let selectAllValue = ref(false)
+// 外部的全选
+const selectAll = (type: boolean) => {
+  if(type) {
+    if(selectType.value) {
+      tableData.value.forEach((item: TableDataProps) => {
+        operationListRef.value!.toggleRowSelection(item, true)
+      })
+      if(selectType.value == 'cur') {
+        selectedList.value = tableData.value
+      } else {
+        selectedList.value = []
+      }
+    }
+  } else {
+    tableData.value.forEach((item: TableDataProps) => {
+      operationListRef.value!.toggleRowSelection(item, false)
+    })
+    selectType.value = ''
+    selectedList.value = []
+  }
+}
+// 表格组件中的勾选
+const handleSelectionChange = (row: TableDataProps) => {
+  selectedList.value = row
+}
+// 全选类型改变
+const selectTypeChange = (type) => {
+  selectAllValue.value = true
+  tableData.value.forEach((item: TableDataProps) => {
+    operationListRef.value!.toggleRowSelection(item, true)
+  })
+  if(type == 'cur') {
+    selectedList.value = tableData.value
+  } else {
+    selectedList.value =[]
+  }
+}
+// 批量管理
+const dropdownCommand = (e) => {
+  switch (e) {
+    case '删除':
+      ElMessageBox({
+        title: '删除业务员',
+        message: '确定要删除该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = []
+          if(selectedList.value.length>0) {
+            selectedList.value.forEach(item => {
+              ids.push(item.id)
+            })
+          } else {
+            if(selectType == 'cur') {
+              ElMessage({
+                message: '请选择需要操作的数据',
+                type: 'warning'
+              })
+              return
+            }
+          }
+          operationDel(ids)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '禁用':
+      ElMessageBox({
+        title: '禁用业务员',
+        message: '确定要禁用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = []
+          if(selectedList.value.length>0) {
+            selectedList.value.forEach(item => {
+              ids.push(item.id)
+            })
+          } else {
+            if(selectType == 'cur') {
+              ElMessage({
+                message: '请选择需要操作的数据',
+                type: 'warning'
+              })
+              return
+            }
+          }
+          let data = {
+            ids: ids,
+            isEnable: 1,
+            getAll: selectType.value == 'all'?1:0
+          }
+          operationIsEnable(data)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '启用':
+      ElMessageBox({
+        title: '启用业务员',
+        message: '确定要启用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = []
+          if(selectedList.value.length>0) {
+            selectedList.value.forEach(item => {
+              ids.push(item.id)
+            })
+          } else {
+            if(selectType == 'cur') {
+              ElMessage({
+                message: '请选择需要操作的数据',
+                type: 'warning'
+              })
+              return
+            }
+          }
+          let data = {
+            ids: ids,
+            isEnable: 0,
+            getAll: selectType.value == 'all'?1:0
+          }
+          operationIsEnable(data)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '分配管理人':
+      allocationShow.value = true
+      break;
+  }
+}
+// 列表数据
+let tableData = ref<TableDataProps[]>([])
+
+// 分页数据
+// 页码
+let currentPage = ref(1)
+// 单页数量
+let pageSize = ref(10)
+// 总数
+let total = ref(0)
+// 单页数量变化
+const handleSizeChange = (size) => {
+  pageSize.value = size
+  init()
+}
+// 页码变化
+const handleCurrentChange = (page) => {
+  currentPage.value = page
+  init()
+}
+
+// 详情
+const showDetail = (scope) => {
+  myRouter.push({
+    path: '/operationDetail',
+    query: {
+      id: scope.row.id
+    }
+  })
+}
+
+// 添加银行卡弹框
+let addName = ref({
+  userJzgInfoId: '',
+  name: '',
+})
+let bankCardDialogShow = ref(false)
+
+// 更多
+const tableDataCommand = (scope, e) => {
+  switch (e) {
+    case '编辑':
+      dialogShow.value = true
+      nextTick(() => {
+        AddOperationRef.value.initEditData(scope.row.id)
+      })
+      title.value = '编辑'
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除业务员',
+        message: '确定要删除该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = [scope.row.id]
+          operationDel(ids)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '禁用':
+      ElMessageBox({
+        title: '禁用业务员',
+        message: '确定要禁用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let data = {
+            ids: [scope.row.id],
+            isEnable: 1,
+            getAll: selectType.value == 'all'?1:0
+          }
+          operationIsEnable(data)
+        }
+      }).catch(( action ) => {
+
+      })
+      // if(scope.row.isEnable == '0') {
+      //
+      // } else {
+      //   ElMessage({
+      //     message: '该业务员已是禁用状态!',
+      //     type: 'warning'
+      //   })
+      // }
+      break;
+    case '启用':
+      // if(scope.row.isEnable == '1') {
+      //
+      // } else {
+      //   ElMessage({
+      //     message: '该业务员已是启用状态!',
+      //     type: 'warning'
+      //   })
+      // }
+      ElMessageBox({
+        title: '启用业务员',
+        message: '确定要启用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm'){
+          let data = {
+            ids: [scope.row.id],
+            isEnable: 0,
+            getAll: selectType.value == 'all'?1:0
+          }
+          operationIsEnable(data)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '添加银行卡':
+      addName.value = {
+        userJzgInfoId: scope.row.id,
+        name: scope.row.name,
+      }
+      bankCardDialogShow.value = true
+      break;
+    case '分配管理人':
+      allocationShow.value = true
+      nextTick(() => {
+        AllocationRef.value.initCheckedKeys(scope.row.deptId, selectType.value, [scope.row.id])
+      })
+      break;
+  }
+}
+// 添加业务员
+const addNumber = () => {
+  dialogShow.value = true
+  title.value = '添加'
+}
+// 添加/编辑业务员弹框
+let dialogShow = ref(false)
+// 关闭新增弹框
+const closeAddOperation = (text: string) => {
+  if(text == '确定') {
+    init()
+  }
+  dialogShow.value = false
+}
+// 关闭添加银行卡弹框
+const closeAddBankCard = (type: string) => {
+  bankCardDialogShow.value = false
+}
+// 添加/编辑业务员弹框标题
+let title = ref('添加')
+
+// 分配管理人
+let allocationShow = ref(false)
+const closeAllocation = (type: boolean) => {
+  allocationShow.value = type
+}
+
+onMounted(() => {
+  init()
+  institutionList()
+})
+
+</script>
+
+<style scoped lang="scss">
+.operation{
+  margin: 0 20px;
+  .operationForm{
+    margin: 20px 0;
+  }
+  .formItem{
+    width: 350px;
+  }
+  :deep(.select-all .el-select__wrapper){
+    box-shadow: none;
+    background: none;
+  }
+}
+</style>

+ 556 - 0
src/views/operationManagement/operationDetail.vue

@@ -0,0 +1,556 @@
+<template>
+  <div class="detail">
+    <div class="state" v-if="dataDetail?.status == 5">
+      <el-icon :size="20" style="color: red; margin: 3px 10px 0 0;">
+        <CircleClose />
+      </el-icon>
+      <div>
+        <h3>审核不通过</h3>
+        <p>{{ dataDetail?.approvalOpinion }}如有问题,请联系审核人员或者拨打客服电话400-400-400。</p>
+        <el-button link type="primary" @click="editDetail">修改并重提交</el-button>
+      </div>
+    </div>
+    <div class="info">
+      <el-descriptions>
+        <template #title>
+          <el-row :gutter="20" flex justify="space-between">
+            <el-col :span="12" style="display: flex; align-items: center;">
+              <span class="firstName">{{ initName(dataDetail?.name) }}</span>
+              <span class="allName">{{ dataDetail?.name }}</span>
+            </el-col>
+            <el-col :span="12" style="display: flex; justify-content: flex-end">
+              <el-button plain @click="checkPass">审核通过</el-button>
+              <el-button plain @click="checkNotPass">审核不通过</el-button>
+              <el-button plain @click="editDetail">编辑</el-button>&nbsp;
+              <el-dropdown trigger="click" @command="handleCommand">
+                <el-button plain>更多</el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item command="启用">启用</el-dropdown-item>
+                    <el-dropdown-item command="禁用">禁用</el-dropdown-item>
+                    <el-dropdown-item command="删除">删除</el-dropdown-item>
+                    <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </el-col>
+          </el-row>
+        </template>
+        <el-descriptions-item label="工号:">{{ dataDetail?.userId }}</el-descriptions-item>
+        <el-descriptions-item label="所属机构:">{{ dataDetail?.deptName }}</el-descriptions-item>
+        <el-descriptions-item label="状态:">{{  dataDetail?.status == '0'?'待认证': dataDetail?.status == '1'?'已认证': dataDetail?.status == '2'?'待提交资料': dataDetail?.status == '3'?'已入职':'' }}</el-descriptions-item>
+        <el-descriptions-item label="类型:">{{  dataDetail?.typeAttr == '0'?'个代': dataDetail?.typeAttr == '1'?'渠道': dataDetail?.typeAttr == '2'?'团队': dataDetail?.typeAttr == '3'?'电销组': '' }}</el-descriptions-item>
+        <el-descriptions-item label="所属团队:">{{ dataDetail?.organizationName }}</el-descriptions-item>
+        <el-descriptions-item label="创建人:">{{ dataDetail?.updateBy }}</el-descriptions-item>
+        <el-descriptions-item label="创建时间:">{{ dataDetail?.updateTime }}</el-descriptions-item>
+      </el-descriptions>
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="(tab) => { activeName = tab }">
+        <el-tab-pane label="基本信息" name="msg">
+          <div class="other">
+            <el-descriptions title="个人信息">
+              <el-descriptions-item label="姓名:">{{ dataDetail?.name }}</el-descriptions-item>
+              <el-descriptions-item label="手机号:">{{ dataDetail?.mobile }}</el-descriptions-item>
+              <el-descriptions-item label="证件号:">{{ dataDetail?.identity }}</el-descriptions-item>
+              <el-descriptions-item label="证件有效期始:">{{ dataDetail?.identityTimeStart }}</el-descriptions-item>
+              <el-descriptions-item label="证件有效期止:">{{ dataDetail?.identityTimeEnd }}</el-descriptions-item>
+            </el-descriptions>
+            <el-descriptions title="其他信息">
+              <el-descriptions-item label="管理人:">{{ dataDetail?.leaderName }}</el-descriptions-item>
+              <el-descriptions-item label="管理人工号:">{{ dataDetail?.leaderId }}</el-descriptions-item>
+              <el-descriptions-item label="推荐人:">{{ dataDetail?.referrerName }}</el-descriptions-item>
+              <el-descriptions-item label="推荐人工号:">{{ dataDetail?.referrerId }}</el-descriptions-item>
+            </el-descriptions>
+            <el-descriptions title="银行卡信息">
+              <el-descriptions-item>
+                <template #default>
+                  <el-table
+                    :data="dataDetail?.bankCardList"
+                  >
+                    <el-table-column prop="name" label="姓名"></el-table-column>
+                    <el-table-column prop="bankName" label="开户行">
+                      <template #default="scope">
+                        {{ bankCardChange(bankOption, scope.row.bankName) }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="bankCardNumber" label="卡号"></el-table-column>
+                    <el-table-column prop="bankAddress" label="开户支行"></el-table-column>
+                    <el-table-column prop="auditStatus" label="审核状态">
+                      <template #default="scope">
+                        {{ scope.row.auditStatus == '0'?'未审核':scope.row.auditStatus == '1'?'审核通过':scope.row.auditStatus == '2'?'审核驳回':''}}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="" label="身份证件照">
+                      <template #default="scope">
+                        <img class="cardImage" :src="dataDetail?.fileList?.[0].fileUrl">
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="cardFile" label="银行卡照">
+                      <template #default="scope">
+                        <img class="cardImage" :src="scope.row.cardFile">
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="操作">
+                      <template #default="scope">
+                        <a style="color: #409EFF; cursor: pointer" @click="editBankCard(scope.row)">详情</a>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </template>
+              </el-descriptions-item>
+            </el-descriptions>
+            <el-button icon="plus" style="margin-left: 20px" @click="addBankCard">添加银行卡</el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="资料附件" name="file">
+          <div class="other">
+            <el-descriptions title="资料附件">
+              <el-descriptions-item>
+                <template #default>
+                  <div class="fileItem">
+                    <span class="label">身份证(人像面)</span>
+                    <div class="fileName">
+                      <span class="file-name">文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名文件名</span>
+                      <el-icon class="file-icon"><View /></el-icon>
+                    </div>
+                  </div>
+                  <div class="fileItem">
+                    <span class="label">身份证(国徽面)</span>
+                    <div class="fileName">
+                      <span class="file-name">文件名</span>
+                      <el-icon class="file-icon"><View /></el-icon>
+                    </div>
+                  </div>
+                  <div class="fileItem">
+                    <span class="label">展业资格证</span>
+                    <div class="fileName">
+                      <span class="file-name">文件名</span>
+                      <el-icon class="file-icon"><View /></el-icon>
+                    </div>
+                  </div>
+                </template>
+              </el-descriptions-item>
+            </el-descriptions>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+    <el-dialog
+      v-model="bankCardDialogShow"
+      :title="bankTitle"
+      width="500"
+    >
+      <addCard @closeDialog="closeAddBankCard" :userInfo="bankCardInfo"></addCard>
+    </el-dialog>
+    <el-dialog
+      v-model="dialogShow"
+      title="编辑"
+      width="1000"
+    >
+      <addOperation ref="AddOperationRef" @closeDialog="closeAddOperation"></addOperation>
+    </el-dialog>
+    <el-dialog
+      v-model="allocationShow"
+      title="分配管理人"
+      width="800"
+    >
+      <allocation ref="AllocationRef" @closeDialog="closeAllocation"></allocation>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {nextTick, ref} from 'vue'
+import addOperation from './modules/addOperation.vue'
+import addCard from './modules/addCard.vue'
+import allocation from './modules/allocation.vue'
+import pinyin from "js-pinyin";
+import { ElMessage, ElMessageBox } from 'element-plus'
+import Allocation from "@/views/operationManagement/modules/allocation.vue";
+import { useRoute, useRouter } from 'vue-router'
+import api from '@/api'
+import {OperationIsEnable} from "@/api/modules/operation.ts";
+import router from "@/router";
+
+let AddOperationRef = ref(null)
+const AllocationRef = ref(null)
+
+let myRouter = useRouter()
+const myRoute = useRoute()
+
+// 更多
+const handleCommand = (e) => {
+  switch (e) {
+    case '删除':
+      ElMessageBox({
+        title: '删除业务员',
+        message: '确定要删除该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = [myRoute.query.id]
+          operationDel(ids)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '禁用':
+      ElMessageBox({
+        title: '禁用业务员',
+        message: '确定要禁用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let data = {
+            ids: [myRoute.query.id],
+            isEnable: 1,
+            getAll: 0
+          }
+          operationIsEnable(data)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '启用':
+      ElMessageBox({
+        title: '启用业务员',
+        message: '确定要启用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm'){
+          let data = {
+            ids: [myRoute.query.id],
+            isEnable: 0,
+            getAll: 0
+          }
+          operationIsEnable(data)
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '分配管理人':
+      allocationShow.value = true
+      nextTick(() => {
+        AllocationRef.value.initCheckedKeys(dataDetail.value.deptId, 'cur', [dataDetail.value.id])
+      })
+      break;
+  }
+}
+// 分配管理人
+let allocationShow = ref(false)
+const closeAllocation = (type: boolean) => {
+  allocationShow.value = type
+}
+
+// 银行卡列表数据
+// let tableData = ref([])
+
+// Tabs切换
+let activeName = ref('msg')
+
+// 银行卡信息
+let bankCardInfo = ref(null)
+let bankTitle = ref('添加银行卡')
+// 添加银行卡弹框
+let bankCardDialogShow = ref(false)
+// 添加银行卡
+const addBankCard = () => {
+  bankTitle.value = '添加银行卡'
+  bankCardDialogShow.value = true
+  bankCardInfo.value = {
+    userJzgInfoId: dataDetail.value.id,
+    name: dataDetail.value.name,
+  }
+}
+// 编辑银行卡
+const editBankCard = (row) => {
+  bankTitle.value = '查看银行卡'
+  bankCardDialogShow.value = true
+  bankCardInfo.value = {
+    userJzgInfoId: dataDetail.value.id,
+    name: dataDetail.value.name,
+    bankName: row.bankName,
+    bankCardNumber: row.bankCardNumber,
+    bankAddress: row.bankAddress,
+    attachment: row.cardFile,
+    imageUrl: row.cardFile,
+    isRead: true
+  }
+}
+// 关闭添加银行卡弹框
+const closeAddBankCard = (type: string) => {
+  if(type == '确定') {
+    initDetail()
+  }
+  bankCardDialogShow.value = false
+}
+
+// 删除
+const operationDel = (id: string[]) => {
+  api.operationApi.operationDelete({
+    ids: id,
+    getAll: 0
+  }).then(res => {
+    if(res?.code == 200) {
+      ElMessage({
+        message: res.msg,
+        type: 'success'
+      })
+      myRouter.push({
+        path: 'operationManagement/operation',
+      })
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+// 启用/禁用
+const operationIsEnable = (data: OperationIsEnable) => {
+  api.operationApi.operationIsEnable(data).then(res => {
+    if(res?.code == 200) {
+      ElMessage({
+        message: res.msg,
+        type: 'success'
+      })
+      initDetail()
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 审核通过
+const checkPass = () => {
+  api.operationApi.salesmanAuthSuccess({ userInfoId: dataDetail.value.id }).then(res => {
+    if(res.code == 200) {
+      ElMessage({
+        message: res.msg,
+        type: 'success',
+      })
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning',
+      })
+    }
+  })
+}
+// 审核不通过
+const checkNotPass = () => {
+  ElMessageBox({
+    title: '审核不通过',
+    showInput: true,
+    inputPlaceholder: '请输入原因',
+    inputValue: '',
+    showCancelButton: true,
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+  }).then(({ value, action } ) => {
+    if(action == 'confirm') {
+      api.operationApi.salesmanAuthFailed({
+        userInfoId: dataDetail.value.id,
+        approvalOpinion: value
+      }).then(res => {
+        if(res.code == 200) {
+          ElMessage({
+            message: res.msg,
+            type: 'success',
+          })
+        } else {
+          ElMessage({
+            message: res.msg,
+            type: 'warning',
+          })
+        }
+      })
+    }
+  }).catch(( action ) => {
+
+  })
+}
+
+// 编辑/修改
+let dialogShow = ref(false)
+const editDetail = () => {
+  dialogShow.value = true
+  nextTick(() => {
+    AddOperationRef.value.initEditData(dataDetail.value.id)
+  })
+}
+const closeAddOperation = (text: string) => {
+  if(text == '确定') {
+    initDetail()
+  }
+  dialogShow.value = false
+}
+
+// 详情
+let dataDetail = ref(null)
+const initDetail = () => {
+  let id = myRoute.query?.id
+  api.operationApi.operationDetail(id).then(res => {
+    if(res?.code == 200) {
+      dataDetail.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 初始化银行数据
+let bankOption = ref([])
+const initBankCard = () => {
+  api.commonApi.personInfo('bank_info').then(res => {
+    if(res.code == 200) {
+      bankOption.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+// 转换
+const bankCardChange = (list, code) => {
+  if(code&&list.length>0) {
+    let obj = list.find(item => item.id == code)
+    return obj.label
+  }
+}
+
+// 名字转换首字母
+const initName = (name) => {
+  return name?pinyin.getFullChars(name).substring(0, 1):''
+}
+
+onMounted(() => {
+  initDetail()
+  initBankCard()
+})
+
+</script>
+
+<style scoped lang="scss">
+.detail{
+  margin: 0 10px;
+  .state{
+    border: 1px solid rgba(255,0,0,.3);
+    border-radius: 10px;
+    padding: 10px 20px;
+    background: #FFEFEE;
+    display: flex;
+    margin: 5px 0;
+    h3{
+      font-weight: 500;
+      margin: 0 0 10px;
+      color: rgba(0,0,0,.64);
+    }
+    p{
+      margin: 10px 0;
+      color: #888;
+    }
+  }
+  .info{
+    background: white;
+    padding: 5px 10px;
+    margin: 5px 0;
+    border-radius: 10px;
+    :deep(.el-descriptions__title) {
+      width: 100%;
+    }
+    :deep(.el-descriptions__body) {
+      padding-left: 60px;
+    }
+    :deep(.el-tabs__nav-wrap) {
+      padding: 0 25px;
+    }
+    :deep(.el-tabs__item) {
+      font-size: 18px;
+    }
+    .firstName{
+      width: 30px;
+      height: 30px;
+      text-align: center;
+      line-height: 30px;
+      border-radius: 15px;
+      background: #409EFF;
+      color: white;
+      font-size: 18px;
+      margin-right: 10px;
+      margin-left: 20px;
+    }
+    .allName{
+      font-size: 14px;
+    }
+    .other{
+      .fileItem{
+        display: flex;
+        justify-content: flex-start;
+        align-items: center;
+        margin: 10px 0;
+        .label{
+          width: 200px;
+        }
+        .fileName{
+          width: calc(100% - 500px);
+          line-height: 30px;
+          display: flex;
+          align-items: center;
+          padding: 0 20px;
+          &:hover{
+            background: #ccc;
+          }
+          .file-name{
+            width: 200px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            margin-right: 20px;
+          }
+          .file-icon{
+            display: flex;
+            justify-content: flex-start;
+            align-items: center;
+            height: 30px;
+            cursor: pointer;
+            &:hover{
+              color: #00a0f4;
+            }
+          }
+        }
+      }
+      .cardImage{
+        display: block;
+        width: 80px;
+        height: 80px;
+        border-radius: 5px;
+      }
+      :deep(.el-descriptions__title) {
+        padding-left: 20px;
+        font-size: 16px;
+      }
+    }
+  }
+}
+</style>

+ 360 - 0
src/views/operationManagement/team.vue

@@ -0,0 +1,360 @@
+<template>
+  <div class="team">
+    <el-row :gutter="20" style="width: 100%; overflow:hidden;">
+      <el-col :span="4">
+        <div class="teamTree">
+          <el-input class="search-input" v-model="treeValue" placeholder="团队名称查找" prefix-icon="Search"></el-input>
+          <div class="custom-tree-node" v-for="item in teamData" :key="item.id">
+            <span class="custom-tree-node-label">{{ item.name }}</span>
+            <el-dropdown class="custom-tree-node-more" @command="treeNodeCommend(item, $event)">
+              <el-icon><MoreFilled /></el-icon>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                  <el-dropdown-item command="删除">删除</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </div>
+        <el-button class="add-btn" icon="plus" @click="addTeamShow = true">添加团队</el-button>
+      </el-col>
+      <el-col :span="20">
+        <el-row :gutter="20">
+          <el-col :span="22" class="info">
+            <h3>团队名称</h3>
+            <p>所属机构: 机构名称</p>
+            <p>管理人: 管理人姓名-管理人工号</p>
+            <p>描述:</p>
+          </el-col>
+          <el-col :span="2" class="btn">
+            <el-button plain @click="setPeople">设置负责人</el-button>
+          </el-col>
+        </el-row>
+        <el-input style="width: 300px; margin: 10px 0" v-model="searchValue" prefix-icon="Search" placeholder="输入姓名,手机号,工号查找" ></el-input>
+        <el-table
+          :data="tableData"
+          ref="operationListRef"
+          height="530"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column label="姓名" prop="name" width="80"></el-table-column>
+          <el-table-column label="手机号" prop="mobile" width="150"></el-table-column>
+          <el-table-column label="工号" prop="userId" width="200"></el-table-column>
+          <el-table-column label="类型" prop="typeAttr" width="100"></el-table-column>
+          <el-table-column label="归属" prop="deptName" width="200"></el-table-column>
+          <el-table-column label="所属机构" prop="deptName" width="200"></el-table-column>
+          <el-table-column label="人员状态" prop="status" width="150">
+            <template #default="scope">
+              {{ scope.row.status == '1'?'前线人员':scope.row.status == '2'?'后线人员':scope.row.status == '3'?'合伙人':scope.row.status == '4'?'工作室管理员':scope.row.status == '5'?'团队长':scope.row.status == '6'?'个代':scope.row.status == '7'?'电销':scope.row.status == '8'?'渠道': '--' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="账号状态" prop="isEnable" width="150"></el-table-column>
+          <el-table-column label="管理人" prop="leaderName" width="150"></el-table-column>
+          <el-table-column label="管理人工号" prop="leaderId" width="200"></el-table-column>
+          <el-table-column label="推荐人" prop="referrerName" width="150"></el-table-column>
+          <el-table-column label="推荐人工号" prop="referrerId" width="200"></el-table-column>
+          <el-table-column fixed="right" label="操作" width="120">
+            <template #default="scope">
+              <div style="display: flex; align-items: center; justify-content: space-between">
+                <a style="color: #409EFF; cursor: pointer" @click="showDetail(scope)">详情</a>&nbsp;
+                <el-dropdown placement="bottom" trigger="click" @command="tableDataCommand(scope, $event)">
+                  <a style="color: #409EFF; cursor: pointer">更多</a>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                      <el-dropdown-item command="启用">启用</el-dropdown-item>
+                      <el-dropdown-item command="禁用">禁用</el-dropdown-item>
+                      <el-dropdown-item command="删除">删除</el-dropdown-item>
+                      <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div style="display: flex; justify-content: center; margin-top: 15px">
+          <el-pagination
+            v-model:current-page="currentPage"
+            v-model:page-size="pageSize"
+            :page-sizes="[10, 20, 30, 40]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+          />
+        </div>
+      </el-col>
+    </el-row>
+    <el-dialog
+      v-model="dialogShow"
+      :title="title"
+      width="1000"
+    >
+      <addOperation @closeDialog="closeAddOperation" :options="options"></addOperation>
+    </el-dialog>
+    <el-dialog
+      v-model="addTeamShow"
+      title="添加"
+      width="800"
+    >
+      <addTeam ref="AddTeamRef" @closeDialog="closeAddTeamDialog"></addTeam>
+    </el-dialog>
+    <el-dialog
+      v-model="allocationShow"
+      title="分配管理人"
+      width="800"
+    >
+      <allocation></allocation>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import {ElMessageBox, ElMessage, TableInstance} from 'element-plus'
+import { useRouter } from 'vue-router'
+import api from "@/api";
+import addOperation from './modules/addOperation.vue'
+import allocation from './modules/allocation.vue'
+import addTeam from './modules/addTeam.vue'
+import Allocation from "@/views/operationManagement/modules/allocation.vue";
+import {initial} from "lodash-es";
+import team from "@/api/modules/team.ts";
+
+let myRouter = useRouter()
+const AddTeamRef = ref(null)
+
+// 机构数据
+let options = ref([])
+// 获取机构数据
+const institutionList = () => {
+  api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
+    if(res?.code == 200) {
+      options.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 团队
+let treeValue = ref('')
+let teamData = ref([])
+let addTeamShow = ref(false)
+const initTeam = () => {
+  api.teamApi.teamList({}).then(res => {
+    if(res.code == 200) {
+      teamData.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+const treeNodeCommend = (item, e) => {
+  switch (e) {
+    case '编辑':
+      addTeamShow.value = true
+      AddTeamRef.value.initEdit(item)
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除团队',
+        message: '确定要删除该团队吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+  }
+}
+const closeAddTeamDialog = (type) => {
+  addTeamShow.value = false
+}
+
+// 分页
+let currentPage = ref(1)
+let pageSize = ref(10)
+let total = ref(0)
+const handleSizeChange = (size) => {
+
+}
+const handleCurrentChange = (page) => {
+
+}
+
+// 搜索字段
+let searchValue = ref('')
+// 列表数据
+let tableData = ref([
+  {name: 1}
+])
+// 编辑弹框
+let dialogShow = ref(false)
+// 编辑弹框标题
+let title = ref('编辑')
+// 表格组件中的勾选
+const handleSelectionChange = (row) => {
+
+}
+// 详情
+const showDetail = (scope) => {
+  myRouter.push({
+    path: '/operationDetail',
+    query: {
+      id: scope.row.id
+    }
+  })
+}
+
+// 分配管理人
+let allocationShow = ref(false)
+
+// 设置负责人
+const setPeople = () => {
+  allocationShow.value = true
+}
+// 更多
+const tableDataCommand = (scope, e) => {
+  switch (e) {
+    case '编辑':
+      dialogShow.value = true
+      title.value = '编辑'
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除业务员',
+        message: '确定要删除该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = [scope.row.id]
+
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '禁用':
+      ElMessageBox({
+        title: '禁用业务员',
+        message: '确定要禁用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let data = {
+            id: [scope.row.id],
+            isEnable: 0
+          }
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '启用':
+      ElMessageBox({
+        title: '启用业务员',
+        message: '确定要启用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm'){
+          let data = {
+            id: [scope.row.id],
+            isEnable: 1
+          }
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '分配管理人':
+      allocationShow.value = true
+      break;
+  }
+}
+
+const closeAddOperation = (type: string) => {
+  dialogShow.value = false
+}
+
+onMounted(() => {
+  institutionList()
+  initTeam()
+})
+
+</script>
+
+<style scoped lang="scss">
+.team{
+  height: 770px;
+  background: #fff;
+  .search-input{
+    padding: 10px 20px;
+  }
+  .teamTree{
+    height: 700px;
+    overflow-y: auto;
+    background: #fff;
+    .custom-tree-node{
+      width: calc(100% - 40px);
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 5px 10px;
+      margin: 5px auto;
+      &:hover{
+        background: rgba(0,0,0,.1);
+      }
+      .custom-tree-node-label{
+        width: 70%;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+  .add-btn{
+    display: block;
+    margin: 0 auto;
+  }
+  .info{
+    h3{
+      margin: 10px 0;
+    }
+    p{
+      margin: 6px 0;
+      font-size: 14px;
+      color: rgba(0,0,0,.7);
+    }
+  }
+  .btn{
+    display: flex;
+    justify-content: flex-end;
+    align-items: flex-end;
+  }
+}
+</style>

+ 360 - 0
src/views/operationManagement/telemarketing.vue

@@ -0,0 +1,360 @@
+<template>
+  <div class="team">
+    <el-row :gutter="20" style="width: 100%; overflow:hidden;">
+      <el-col :span="4">
+        <div class="teamTree">
+          <el-input class="search-input" v-model="treeValue" placeholder="电销组名称查找" prefix-icon="Search"></el-input>
+          <div class="custom-tree-node" v-for="item in teamData" :key="item.id">
+            <span class="custom-tree-node-label">{{ item.name }}</span>
+            <el-dropdown class="custom-tree-node-more" @command="treeNodeCommend(item, $event)">
+              <el-icon><MoreFilled /></el-icon>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                  <el-dropdown-item command="删除">删除</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </div>
+        <el-button class="add-btn" icon="plus" @click="addTeamShow = true">添加电销组</el-button>
+      </el-col>
+      <el-col :span="20">
+        <el-row :gutter="20">
+          <el-col :span="22" class="info">
+            <h3>电销组名称</h3>
+            <p>所属机构: 机构名称</p>
+            <p>管理人: 管理人姓名-管理人工号</p>
+            <p>描述:</p>
+          </el-col>
+          <el-col :span="2" class="btn">
+            <el-button plain @click="setPeople">设置负责人</el-button>
+          </el-col>
+        </el-row>
+        <el-input style="width: 300px; margin: 10px 0" v-model="searchValue" prefix-icon="Search" placeholder="输入姓名,手机号,工号查找" ></el-input>
+        <el-table
+          :data="tableData"
+          ref="operationListRef"
+          height="530"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column label="姓名" prop="name" width="80"></el-table-column>
+          <el-table-column label="手机号" prop="mobile" width="150"></el-table-column>
+          <el-table-column label="工号" prop="userId" width="200"></el-table-column>
+          <el-table-column label="类型" prop="typeAttr" width="100"></el-table-column>
+          <el-table-column label="归属" prop="deptName" width="200"></el-table-column>
+          <el-table-column label="所属机构" prop="deptName" width="200"></el-table-column>
+          <el-table-column label="人员状态" prop="status" width="150">
+            <template #default="scope">
+              {{ scope.row.status == '1'?'前线人员':scope.row.status == '2'?'后线人员':scope.row.status == '3'?'合伙人':scope.row.status == '4'?'工作室管理员':scope.row.status == '5'?'团队长':scope.row.status == '6'?'个代':scope.row.status == '7'?'电销':scope.row.status == '8'?'渠道': '--' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="账号状态" prop="isEnable" width="150"></el-table-column>
+          <el-table-column label="管理人" prop="leaderName" width="150"></el-table-column>
+          <el-table-column label="管理人工号" prop="leaderId" width="200"></el-table-column>
+          <el-table-column label="推荐人" prop="referrerName" width="150"></el-table-column>
+          <el-table-column label="推荐人工号" prop="referrerId" width="200"></el-table-column>
+          <el-table-column fixed="right" label="操作" width="120">
+            <template #default="scope">
+              <div style="display: flex; align-items: center; justify-content: space-between">
+                <a style="color: #409EFF; cursor: pointer" @click="showDetail(scope)">详情</a>&nbsp;
+                <el-dropdown placement="bottom" trigger="click" @command="tableDataCommand(scope, $event)">
+                  <a style="color: #409EFF; cursor: pointer">更多</a>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item command="编辑">编辑</el-dropdown-item>
+                      <el-dropdown-item command="启用">启用</el-dropdown-item>
+                      <el-dropdown-item command="禁用">禁用</el-dropdown-item>
+                      <el-dropdown-item command="删除">删除</el-dropdown-item>
+                      <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div style="display: flex; justify-content: center; margin-top: 15px">
+          <el-pagination
+            v-model:current-page="currentPage"
+            v-model:page-size="pageSize"
+            :page-sizes="[10, 20, 30, 40]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+          />
+        </div>
+      </el-col>
+    </el-row>
+    <el-dialog
+      v-model="dialogShow"
+      :title="title"
+      width="1000"
+    >
+      <addOperation @closeDialog="closeAddOperation" :options="options"></addOperation>
+    </el-dialog>
+    <el-dialog
+      v-model="addTeamShow"
+      title="添加"
+      width="800"
+    >
+      <addTeam @closeDialog="closeAddTeamDialog" :editData="editItemData"></addTeam>
+    </el-dialog>
+    <el-dialog
+      v-model="allocationShow"
+      title="分配管理人"
+      width="800"
+    >
+      <allocation></allocation>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import {ElMessageBox, ElMessage, TableInstance} from 'element-plus'
+import { useRouter } from 'vue-router'
+import api from "@/api";
+import addOperation from './modules/addOperation.vue'
+import allocation from './modules/allocation.vue'
+import addTeam from './modules/addTeam.vue'
+import Allocation from "@/views/operationManagement/modules/allocation.vue";
+import {initial} from "lodash-es";
+import team from "@/api/modules/team.ts";
+
+let myRouter = useRouter()
+
+// 机构数据
+let options = ref([])
+// 获取机构数据
+const institutionList = () => {
+  api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
+    if(res?.code == 200) {
+      options.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+
+// 电销组
+let treeValue = ref('')
+let teamData = ref([])
+let addTeamShow = ref(false)
+let editItemData = ref(null)
+const initTeam = () => {
+  api.teamApi.teamList({}).then(res => {
+    if(res.code == 200) {
+      teamData.value = res.data
+    } else {
+      ElMessage({
+        message: res.msg,
+        type: 'warning'
+      })
+    }
+  })
+}
+const treeNodeCommend = (item, e) => {
+  switch (e) {
+    case '编辑':
+      addTeamShow.value = true
+      editItemData.value = item
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除电销组',
+        message: '确定要删除该电销组吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+  }
+}
+const closeAddTeamDialog = (type) => {
+  addTeamShow.value = false
+}
+
+// 分页
+let currentPage = ref(1)
+let pageSize = ref(10)
+let total = ref(0)
+const handleSizeChange = (size) => {
+
+}
+const handleCurrentChange = (page) => {
+
+}
+
+// 搜索字段
+let searchValue = ref('')
+// 列表数据
+let tableData = ref([
+  {name: 1}
+])
+// 编辑弹框
+let dialogShow = ref(false)
+// 编辑弹框标题
+let title = ref('编辑')
+// 表格组件中的勾选
+const handleSelectionChange = (row) => {
+
+}
+// 详情
+const showDetail = (scope) => {
+  myRouter.push({
+    path: '/operationDetail',
+    query: {
+      id: scope.row.id
+    }
+  })
+}
+
+// 分配管理人
+let allocationShow = ref(false)
+
+// 设置负责人
+const setPeople = () => {
+  allocationShow.value = true
+}
+// 更多
+const tableDataCommand = (scope, e) => {
+  switch (e) {
+    case '编辑':
+      dialogShow.value = true
+      title.value = '编辑'
+      break;
+    case '删除':
+      ElMessageBox({
+        title: '删除业务员',
+        message: '确定要删除该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let ids = [scope.row.id]
+
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '禁用':
+      ElMessageBox({
+        title: '禁用业务员',
+        message: '确定要禁用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm') {
+          let data = {
+            id: [scope.row.id],
+            isEnable: 0
+          }
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '启用':
+      ElMessageBox({
+        title: '启用业务员',
+        message: '确定要启用该业务员吗?',
+        type: 'warning',
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+      }).then(( action ) => {
+        if(action === 'confirm'){
+          let data = {
+            id: [scope.row.id],
+            isEnable: 1
+          }
+        }
+      }).catch(( action ) => {
+
+      })
+      break;
+    case '分配管理人':
+      allocationShow.value = true
+      break;
+  }
+}
+
+const closeAddOperation = (type: string) => {
+  dialogShow.value = false
+}
+
+onMounted(() => {
+  institutionList()
+  initTeam()
+})
+
+</script>
+
+<style scoped lang="scss">
+.team{
+  height: 770px;
+  background: #fff;
+  .search-input{
+    padding: 10px 20px;
+  }
+  .teamTree{
+    height: 700px;
+    overflow-y: auto;
+    background: #fff;
+    .custom-tree-node{
+      width: calc(100% - 40px);
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 5px 10px;
+      margin: 5px auto;
+      &:hover{
+        background: rgba(0,0,0,.1);
+      }
+      .custom-tree-node-label{
+        width: 70%;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+  .add-btn{
+    display: block;
+    margin: 0 auto;
+  }
+  .info{
+    h3{
+      margin: 10px 0;
+    }
+    p{
+      margin: 6px 0;
+      font-size: 14px;
+      color: rgba(0,0,0,.7);
+    }
+  }
+  .btn{
+    display: flex;
+    justify-content: flex-end;
+    align-items: flex-end;
+  }
+}
+</style>

+ 671 - 0
src/views/personnel/institutionManage.vue

@@ -0,0 +1,671 @@
+<template>
+  <div class="institution">
+    <div class="institution-main">
+      <el-form label-position="left" label-width="auto">
+        <el-row :gutter="16">
+          <el-col :span="6">
+            <el-form-item label="">
+              <el-input
+                v-model="formAccessibility.firstName"
+                placeholder="输入机构名称查找"
+                :prefix-icon="Search"
+              />
+            </el-form-item>
+          </el-col>
+
+          <el-col :span="4">
+            <el-form-item label="">
+              <el-button type="primary">查询</el-button>
+              <el-button type="primary" plain @click="reset">重置</el-button>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <Table
+        :tableData="tableData"
+        :columns="columns"
+        :showIndex="false"
+        :showSelect="true"
+        :pageInfo="pageInfo"
+        @getList="getList"
+        :treeProps="{ children: 'children', hasChildren: 'hasChildren' }"
+        @select-all-change="selectAllChange"
+        @select-change="selectChange"
+      >
+        <template v-slot:table-title-btn>
+          <div>
+            <el-button type="primary" @click="add(ruleFormRef)">
+              <el-icon><Plus /></el-icon>添加机构</el-button
+            >
+            <el-dropdown placement="bottom-start">
+              <el-button>
+                批量操作<el-icon class="el-icon--right">
+                  <arrow-down />
+                </el-icon>
+              </el-button>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item>删除</el-dropdown-item>
+                  <el-dropdown-item v-on:click="manySetDeptUser()">设置负责人</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </template>
+        <template v-slot:operation="scope">
+          <el-button
+            type="primary"
+            link
+            @click="addChild(scope.operationData.row)"
+          >
+            添加子机构
+          </el-button>
+          <el-dropdown placement="bottom-start">
+            <span class="el-dropdown-link"> 更多 </span>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item v-on:click="editor(scope.operationData.row)"
+                  >编辑</el-dropdown-item
+                >
+                <el-dropdown-item v-on:click="del(scope.operationData.row)">
+                  删除
+                </el-dropdown-item>
+                <el-dropdown-item v-on:click="setDeptUser(scope.operationData.row)">设置负责人</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+        <template v-slot:search="scope">
+          {{ scope.slotData.label }}
+        </template>
+      </Table>
+    </div>
+
+    <el-dialog v-model="dialogVisible" title="基本信息" width="800" draggable>
+      <el-form
+        label-position="top"
+        label-width="auto"
+        :rules="rules"
+        :model="form"
+        ref="ruleFormRef"
+      >
+        <el-row :gutter="24">
+          <el-col :span="12">
+            <el-form-item label="机构名称" prop="name">
+              <el-input
+                v-model.trim="form.name"
+                maxlength="50"
+                placeholder="输入机构名称"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="上级机构" prop="parentId">
+              <el-cascader
+                clearable
+                style="width: 100%"
+                v-model="form.parentId"
+                :options="tableData"
+                :props="tableProps"
+                @change="handleChange"
+              />
+              <!-- <el-select v-model="form.parentId" placeholder="选择上级机构" clearable>
+                <el-option
+                  v-for="item in tableData"
+                  :key="item.id"
+                  :label="item.name"
+                  :value="item.id"
+                />
+
+              </el-select> -->
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="机构类型" prop="comType">
+              <el-select
+                v-model="form.comType"
+                placeholder="选择机构类型"
+                clearable
+              >
+                <el-option
+                  v-for="item in comTypeList"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="地区" prop="area">
+              <el-cascader
+                clearable
+                style="width: 100%"
+                v-model="form.area"
+                :options="areaOptins"
+                :props="areaProps"
+                @change="handleChange"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="展业范围" prop="exhibitionScope">
+              <el-select
+                v-model="form.exhibitionScope"
+                placeholder="选择展业范围"
+                multiple
+                clearable
+              >
+                <el-option
+                  v-for="item in exhibitionScopeTypeList"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="机构地址" prop="address">
+              <el-input
+                v-model.trim="form.address"
+                maxlength="50"
+                placeholder="请输入机构地址"
+                type="textarea"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="机构负责人" prop="leaderId">
+              <el-select
+                v-model="form.leaderId"
+                placeholder="选择机构负责人"
+                clearable
+              >
+                <el-option
+                  v-for="item in memberList"
+                  :key="item.id"
+                  :label="item.name"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">取 消</el-button>
+          <el-button type="primary" @click="confirm(ruleFormRef)">
+            保 存
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <setDept 
+    :dialogVisible="deptDialogVisible"
+      :dept-list="tableData"
+      :dept-ids="deptIdList"
+      :title="'设置负责人'"
+      @close-dialog="confirmCharge"
+      @cancel-dialog="deptDialogVisible=false"
+    ></setDept>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, watch, onMounted } from "vue";
+import type { ComponentSize, FormInstance, FormRules } from "element-plus";
+import { Plus, Search } from "@element-plus/icons-vue";
+
+import type Node from "element-plus/es/components/tree/src/model/node";
+// import universalTable from "../"
+import { ElMessage, ElMessageBox, ElPopconfirm, ElTree } from "element-plus";
+import api from "@/api";
+import { h } from "vue";
+import setDept from "@/components/DialogSetDeptLeader/index.vue"
+interface Tree {
+  [key: string]: any;
+}
+
+const filterText = ref("");
+const treeRef = ref<InstanceType<typeof ElTree>>();
+
+const defaultProps = {
+  children: "children",
+  label: "label",
+};
+//设置负责人弹框
+const deptDialogVisible=ref(false)
+const deptIdList=ref([])
+function setDeptUser(item:any){
+  
+  deptIdList.value=[item.id]
+  deptDialogVisible.value=true
+}
+
+//批量设置负责人
+
+function manySetDeptUser(){
+  
+  deptIdList.value=checkTableIdList.value
+  deptDialogVisible.value=true
+}
+
+function confirmCharge(){
+  deptDialogVisible.value=false
+}
+
+
+watch(filterText, (val) => {
+  treeRef.value!.filter(val);
+});
+
+const formAccessibility = reactive({
+  fullName: "",
+  firstName: "",
+  lastName: "",
+  phone: "",
+});
+const ruleFormRef = ref<FormInstance>();
+let form = reactive({
+  name: "", //机构名称
+  parentId: "", //上级机构id
+  comType: "", //机构类型
+  exhibitionScope: "", //展业范围
+  address: "", //地址
+  leaderId: "", //负责人id
+  area: [], //地区
+});
+
+interface RuleForm {
+  name: string; //机构名称
+  parentId: string; //上级机构id
+  comType: string; //机构类型
+  exhibitionScope: string[]; //展业范围
+  address: string; //地址
+  leaderId: string; //负责人id
+  area: string[]; //地区
+  id: string;
+}
+interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+  show:boolean;
+}
+const value = ref("");
+const dialogVisible = ref(false);
+
+
+const rules = reactive<FormRules<RuleForm>>({
+  name: [
+    { required: true, message: "请输入机构名称", trigger: "blur" },
+    { min: 1, max: 50, message: "请输入机构名称", trigger: "blur" },
+  ],
+  parentId: [{ required: true, message: "请选择上级机构", trigger: "change" }],
+  comType: [{ required: true, message: "请选择机构类型", trigger: "change" }],
+  exhibitionScope: [
+    { required: true, message: "请选择展业范围", trigger: "change" },
+  ],
+  address: [
+    { required: true, message: "请输入机构地址", trigger: "blur" },
+    { min: 1, max: 50, message: "请输入机构地址", trigger: "blur" },
+  ],
+  area: [{ required: true, message: "请选择机构所在地区", trigger: "change" }],
+});
+// import Select from "@/components/select/selectMain.vue";
+// import TestTable from "@/components/Table/index.vue";
+//机构列表
+type tableType = {
+  id: string;
+  name: string;
+};
+const tableData = ref<tableType[]>([]);
+const typeformatter = (row: any, column: any, cellValue: any) => {
+  let comType = "";
+  comTypeList.value.map((ele) => {
+    if (ele.value == row.comType) {
+      comType = ele.label;
+    }
+  });
+
+  return () => h("div", {}, comType);
+};
+const columns = [
+  { prop: "name", label: "机构名称" },
+  { prop: "Phone", label: "人数" },
+  { prop: "comType", label: "机构类型", formatter: typeformatter },
+  {
+    prop: "comAttribute",
+    label: "展业范围",
+    formatter: (row: any, column: any, cellValue: any) => {
+      let comType = "";
+      exhibitionScopeTypeList.value.map((ele) => {
+        if (ele.value == row.exhibitionScope) {
+          comType = ele.label;
+        }
+      });
+
+      return () => h("div", {}, comType);
+    },
+  },
+  { prop: "address", label: "所属地区" },
+  { prop: "leaderName", label: "负责人" },
+];
+
+const pageInfo = {
+  pageNum: 1,
+  pageSize: 10,
+  sizes: [10, 20, 30, 40, 50],
+  total: 100,
+  show:false
+};
+//分页列表功能
+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("");
+const addChild = (item: any) => {
+  // form.id=item.id
+  form.parentId = item.id;
+  isDisabledId.value = item.id;
+  dialogVisible.value = true;
+  operationType.value = "add";
+  disabledTree(tableData.value);
+  // pageInfo.pageNum=item.pageNum
+  // pageInfo.pageSize=item.pageSize
+};
+const editor = (item: any) => {
+  console.log(item);
+  // form={...item}
+  for (let key in item) {
+    form[key] = item[key];
+  }
+  isDisabledId.value=''
+  // form.area=[item.province,item.city,item.area]
+  dialogVisible.value = true;
+  operationType.value = "edit";
+  disabledTree(tableData.value)
+
+  // pageInfo.pageNum=item.pageNum
+  // pageInfo.pageSize=item.pageSize
+};
+const del = (item: any) => {
+  // ElPopconfirm('是否确认')
+  ElMessageBox.confirm("确认要删除当前数据吗?", "提示", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+    center:true
+  })
+    .then(() => {
+      console.log(123);
+      api.institutionApi
+        .institutionDel({
+          id: item.id,
+        })
+        .then((res) => {
+          ElMessage.success("操作成功");
+          getInstitutionList(); //机构列表
+        });
+    })
+    .catch(() => {
+      ElMessage.warning("用户取消操作");
+    });
+};
+
+//添加的弹框
+let operationType = ref("");
+const add = (formEl: FormInstance | undefined) => {
+  dialogVisible.value = true;
+  operationType.value = "add";
+
+  if (!formEl) return;
+  formEl.resetFields();
+  // pageInfo.pageNum=item.pageNum
+  // pageInfo.pageSize=item.pageSize
+};
+
+//保存功能
+
+interface institutionData {
+  name: string;
+  system: string;
+}
+const info = ref<institutionData>({
+  name: "",
+  system: "",
+});
+//获取全国省市区级联数据
+const areaOptins = ref([]);
+const areaProps = ref({
+  value: "areaCode",
+  label: "areaCname",
+  children: "child",
+});
+const tableProps = ref({
+  value: "id",
+  label: "name",
+  children: "children",
+  checkStrictly: true,
+});
+
+const getAreaList = () => {
+  api.areaApi.areaList({}).then((res) => {
+    areaOptins.value = res.data;
+  });
+};
+
+//获取机构类型字典值
+type comType = {
+  value: string;
+  label: string;
+};
+let comTypeList = ref<comType[]>([]);
+const getSystemList = () => {
+  api.areaApi
+    .systemList({
+      dictCode: "com_type",
+    })
+    .then((res) => {
+      comTypeList.value = res.data;
+    });
+};
+
+//展业范围
+type exhibitionScopeType = {
+  value: string;
+  label: string;
+};
+let exhibitionScopeTypeList = ref<exhibitionScopeType[]>([]);
+const getExhibitionScopeSystemList = () => {
+  api.areaApi
+    .systemList({
+      dictCode: "exhibition_scope",
+    })
+    .then((res) => {
+      exhibitionScopeTypeList.value = res.data;
+    });
+};
+const handleChange = (e: any) => {
+  console.log(e);
+};
+
+//禁用机构选择
+function disabledTree(list: tableType) {
+  for (let i = 0; i < list.length; i++) {
+    const node = list[i];
+    if (isDisabledId.value) {
+      if (list[i].id != isDisabledId.value) {
+        list[i].disabled = true;
+      }
+    } else {
+      list[i].disabled = false;
+    }
+
+    if (node.children && node.children.length > 0) {
+      disabledTree(node.children);
+    }
+  }
+}
+
+//获取机构列表
+const getInstitutionList = () => {
+  // pageInfo.pageNum=item.pageNum
+  api.institutionApi.institutionList(info.value).then((res) => {
+    // if(res.code===200){
+
+    // }
+    tableData.value = res.data;
+    console.log(tableData.value);
+  });
+  // pageInfo.pageSize=item.pageSize
+};
+
+//成员列表
+const memberList=ref([])
+const getAllMemberList = () => {
+  // pageInfo.pageNum=item.pageNum
+  api.userApi.AllMemberList({}).then((res:any) => {
+    
+    if(res.code===200)
+    memberList.value=res.data
+  });
+  // pageInfo.pageSize=item.pageSize
+};
+
+
+const confirm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      const obj = { ...form };
+      delete obj.area;
+
+      if (operationType.value == "add") {
+        api.institutionApi
+          .institutionAdd({
+            ...obj,
+            system: localStorage.getItem("login_system") || "",
+            province: form.area[0],
+            city: form.area[1],
+            area: form.area[2],
+            parentId:obj.parentId[obj.parentId.length-1]
+          })
+          .then((res) => {
+            if (res.code === 200) {
+              ElMessage.success("操作成功");
+              dialogVisible.value = false;
+              getInstitutionList(); //机构列表
+            }
+          });
+      } else {
+        api.institutionApi
+          .institutionEdit({
+            ...obj,
+            system: localStorage.getItem("login_system") || "",
+            province: form.area[0],
+            city: form.area[1],
+            area: form.area[2],
+            parentId:obj.parentId[obj.parentId.length-1]
+
+          })
+          .then((res) => {
+           
+            if (res.code === 200) {
+              ElMessage.success("操作成功");
+              dialogVisible.value = false;
+              getInstitutionList(); //机构列表
+            }
+          });
+      }
+    }
+  });
+};
+
+const remove = (node: Node, data: Tree) => {
+  const parent = node.parent;
+  const children: Tree[] = parent.data.children || parent.data;
+  const index = children.findIndex((d) => d.id === data.id);
+  children.splice(index, 1);
+  // dataSource.value = [...dataSource.value]
+};
+const reset = (item: any) => {
+  // ElMessage({})
+};
+
+onMounted(() => {
+  // 对 asyncRoutes 进行预处理并转换为树形结构
+  getInstitutionList(); //机构列表
+  getAreaList(); //省市区级联数据
+  getSystemList(); //机构类型字典
+  getExhibitionScopeSystemList(); //展业范围字段
+  getAllMemberList();//成员列表
+});
+</script>
+<style lang="scss" scoped>
+:deep(.table-title-btn) {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  > div {
+    display: flex;
+  }
+}
+.institution {
+  background: #fff;
+  width: 100%;
+  // height: 100%;
+  // padding: 20px;
+  box-sizing: border-box;
+  display: flex;
+  .institution-tree {
+    flex: none;
+    width: 20%;
+    padding: 20px;
+    box-sizing: border-box;
+    border-right: 1px solid #ccc;
+  }
+  .institution-main {
+    flex: 1;
+    // width: 80%;
+    padding: 20px;
+    box-sizing: border-box;
+  }
+}
+:deep(.el-dropdown-link) {
+  cursor: pointer;
+  color: var(--el-color-primary);
+  display: flex;
+  align-items: center;
+  margin-left: 15px;
+}
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+</style>

+ 464 - 202
src/views/personnel/memberManagement.vue

@@ -1,23 +1,29 @@
 <template>
   <div class="member">
     <div class="member-tree">
-      <el-input
+      <el-inputel-input
         v-model="filterText"
         style="width: 240px"
         placeholder="姓名,手机号,工号查询"
         :prefix-icon="Search"
       />
-
+      <div style="display: flex;justify-content: space-between;margin: 10px 0;">
+        <!-- <el-button type="primary" link @click="$router.push({path:'/personnel/institution'})">机构管理</el-button> -->
+        <el-button type="primary" link @click="expandTree">
+        
+          {{ isExpand?'全部收起':'全部展开' }}
+        </el-button>
+      </div>
       <el-tree
         ref="treeRef"
         style="max-width: 600px"
         class="filter-tree"
-        :data="data"
+        :data="deptTreeData"
         :props="defaultProps"
-        default-expand-all
+        :default-expand-all="isExpand"
         :filter-node-method="filterNode"
         :expand-on-click-node="false"
-      >
+        >
         <template #default="{ node, data }">
           <span class="custom-tree-node">
             <span>{{ node.label }}</span>
@@ -40,40 +46,7 @@
       </el-tree>
     </div>
     <div class="member-main">
-      <!-- <el-form label-position="left" label-width="auto">
-        <el-row :gutter="16">
-          <el-col :span="6">
-            <el-form-item label="成员信息">
-              <el-input
-                v-model="formAccessibility.firstName"
-                placeholder="输入姓名,手机号,工号查询"
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="6">
-            <el-form-item label="状态">
-              <el-select
-                v-model="value"
-                placeholder="成员状态"
-                style="width: 240px"
-              >
-                <el-option
-                  v-for="item in options"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="4">
-            <el-form-item label="">
-              <el-button type="primary">查询</el-button>
-              <el-button type="primary" plain @click="reset">重置</el-button>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form> -->
+      
 
       <Table
         :tableData="tableData"
@@ -82,6 +55,8 @@
         :showSelect="true"
         :pageInfo="pageInfo"
         @getList="getList"
+        @select-all-change="selectAllChange"
+        @select-change="selectChange"
       >
         <template v-slot:table-title-btn>
           <div>
@@ -106,23 +81,30 @@
                 </el-dropdown-menu>
               </template>
             </el-dropdown>
-            <el-button type="primary" @click="add(ruleFormRef)">
+            <el-button type="primary" @click="manySetDeptUser()">
               设置负责人</el-button
             >
           </div>
         </template>
         <template v-slot:operation="scope">
           <el-button type="primary" link @click="editor(scope)">
-            编辑
+            详情
           </el-button>
           <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>
@@ -131,82 +113,169 @@
         </template>
       </Table>
     </div>
-
-    <el-dialog v-model="dialogVisible" title="基本信息" width="800" draggable>
-      <el-form
-        label-position="top"
-        label-width="auto"
-        :rules="rules"
-        :model="form"
-        ref="ruleFormRef"
-      >
-        <el-row :gutter="24">
-          <el-col :span="12">
-            <el-form-item label="姓名" prop="name">
-              <el-input
-                v-model.trim="form.name"
-                maxlength="20"
-                placeholder="输入人员姓名"
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="手机号" prop="phone">
-              <el-input
-                v-model.number.trim="form.phone"
-                maxlength="11"
-                placeholder="输入人员手机号"
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="登录密码" prop="password">
-              <el-input
-                v-model.trim="form.password"
-                maxlength="20"
-                placeholder="输入登录密码(8-20位,包含字母和数字)"
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="角色" prop="role">
-              <el-select
-                v-model="form.role"
-                placeholder="选择角色"
-                style="width: 240px"
-              >
-                <el-option
-                  v-for="item in options"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
+    <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="dialogVisible = false">
-            保 存
+          <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> -->
+      <!-- <addOperation @closeDialog="closeAddOperation"></addOperation> -->
+      
+    <!-- </el-dialog> -->
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, watch } from "vue";
+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;
+  label: string;
+
+  [property: string]: any;
+}
+onMounted(async () => {
+  // 对 asyncRoutes 进行预处理并转换为树形结构
+
+
+  getInstitutionList();
+  getUserList()
+  statusList.value = await getDictItems({ dictCode: "person_status" });
+  
+ 
+});
+
+//性别字典
+const statusList = ref<dictType[]>([]);
+//机构列表
 
+type tableType = {
+  id: string;
+  name: string;
+};
+//获取机构列表
+const deptTreeData = ref<tableType[]>([]);
+
+const getInstitutionList = () => {
+  // pageInfo.pageNum=item.pageNum
+  api.institutionApi.institutionList({}).then((res) => {
+    // if(res.code===200){
+
+    // }
+    deptTreeData.value = [...res.data];
+    // deptTreeData.value = JSON.parse(JSON.stringify(res.data));
+  });
+  // pageInfo.pageSize=item.pageSize
+};
 interface Tree {
   [key: string]: any;
 }
@@ -216,7 +285,7 @@ const treeRef = ref<InstanceType<typeof ElTree>>();
 
 const defaultProps = {
   children: "children",
-  label: "label",
+  label: "name",
 };
 
 watch(filterText, (val) => {
@@ -224,59 +293,23 @@ watch(filterText, (val) => {
 });
 
 const filterNode = (value: string, data: Tree) => {
+  // console.log(data)
   if (!value) return true;
-  return data.label.includes(value);
+  return data.name.includes(value);
 };
-const data: Tree[] = [
-  {
-    id: 1,
-    label: "Level one 1",
-    children: [
-      {
-        id: 4,
-        label: "Level two 1-1",
-        children: [
-          {
-            id: 9,
-            label: "Level three 1-1-1",
-          },
-          {
-            id: 10,
-            label: "Level three 1-1-2",
-          },
-        ],
-      },
-    ],
-  },
-  {
-    id: 2,
-    label: "Level one 2",
-    children: [
-      {
-        id: 5,
-        label: "Level two 2-1",
-      },
-      {
-        id: 6,
-        label: "Level two 2-2",
-      },
-    ],
-  },
-  {
-    id: 3,
-    label: "Level one 3",
-    children: [
-      {
-        id: 7,
-        label: "Level two 3-1",
-      },
-      {
-        id: 8,
-        label: "Level two 3-2",
-      },
-    ],
-  },
-];
+//全部展示机构树,或全部收起
+const isExpand=ref(false)
+function expandTree(){
+  // console.log(treeRef.value)
+  
+
+  isExpand.value=!isExpand.value
+  // treeRef.value!.defaultExpandAll=!isExpand.value;
+  const nodes = treeRef.value?.store._getAllNodes();
+  if (nodes) {
+    nodes.forEach((item: any) => item.expanded = isExpand.value);
+  }
+}
 
 const formAccessibility = reactive({
   fullName: "",
@@ -303,31 +336,11 @@ interface PageInfo {
   pageSize: number;
   sizes: number[];
   total: number;
+  show:boolean
 }
-const value = ref("");
+
 const dialogVisible = ref(false);
-const options = [
-  {
-    value: "Option1",
-    label: "Option1",
-  },
-  {
-    value: "Option2",
-    label: "Option2",
-  },
-  {
-    value: "Option3",
-    label: "Option3",
-  },
-  {
-    value: "Option4",
-    label: "Option4",
-  },
-  {
-    value: "Option5",
-    label: "Option5",
-  },
-];
+
 const validatePhone = (rule: any, value: string, callback: any) => {
   const reg = /^1[3-9]\d{9}$/;
   if (!value) {
@@ -359,21 +372,34 @@ const rules = reactive<FormRules<RuleForm>>({
 });
 // import Select from "@/components/select/selectMain.vue";
 // import TestTable from "@/components/Table/index.vue";
-const tableData = [
-  {
-    size: "2024/12/1",
-    Name: "Dec",
-    Phone: "13333333333",
-    role: "公司",
-    status: "123",
-  },
-];
+
+interface Page {
+   
+   [key: string]: any 
+   
+}
+const tableData = ref<Page>([])
 const columns = [
-  { prop: "Name", label: "姓名" },
-  { prop: "Phone", label: "手机号" },
-  { prop: "size", label: "工号" },
-  { prop: "role", label: "角色" },
-  { prop: "status", label: "状态" },
+  { prop: "name", label: "姓名" },
+  { prop: "mobile", label: "手机号" },
+  { prop: "deptName", label: "所属机构" },
+  { prop: "userId", label: "工号" },
+  { prop: "roleName", label: "角色" },
+  { prop: "status", label: "状态",
+  formatter: (row: any, column: any, cellValue: any) => {
+    // console.log(row)
+      let comType = "";
+      statusList.value.forEach((item:any)=>{
+        if(item.value==row.status){
+          comType=item.label
+        }
+      })
+        
+      
+
+      return () => h("div", {}, comType);
+    },
+   },
   // { prop: "operation", label: "操作",fixed:true },
 
   // {
@@ -384,29 +410,55 @@ const columns = [
   //     }]
   // },
 ];
-const pageInfo = {
+const pageInfo =reactive( {
   pageNum: 1,
   pageSize: 10,
   sizes: [10, 20, 30, 40, 50],
-  total: 100,
-};
+  total: 0,
+  show:true
+});
 const getList = (item: PageInfo) => {
   pageInfo.pageNum = item.pageNum;
   pageInfo.pageSize = item.pageSize;
 };
+
+const getUserList= () => {
+  api.userApi.memberList({
+    ...pageInfo
+  }).then((res:any)=>{
+    
+    if(res.code===200){
+      tableData.value=res.data.records
+      pageInfo.total=res.data.total
+    }
+  })
+};
 const editor = (item: any) => {
-  dialogVisible.value = true;
+  console.log(item)
+  router.push({
+    path:"/personnel/member/memberMessage",
+    query:{
+      id:item.operationData.row.userId
+    }
+  })
   // pageInfo.pageNum=item.pageNum
   // pageInfo.pageSize=item.pageSize
 };
+const router=useRouter()
 const add = (formEl: FormInstance | undefined) => {
-  dialogVisible.value = true;
+  
+  
+  router.push({
+    path:"/personnel/member/memberEdit"
+  })
   if (!formEl) return;
   formEl.resetFields();
   // pageInfo.pageNum=item.pageNum
   // pageInfo.pageSize=item.pageSize
 };
 
+
+
 const operationMany = (item: any) => {
   // pageInfo.pageNum=item.pageNum
   // pageInfo.pageSize=item.pageSize
@@ -432,8 +484,218 @@ 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>
+<style lang="scss" scoped>、
+:deep(.date-picker-custom.el-input__inner){
+  display: flex;
+  flex-direction: row-reverse;
+}
 :deep(.table-title-btn){
   display: flex;
   align-items: center;
@@ -451,7 +713,7 @@ const reset = (item: any) => {
   display: flex;
   .member-tree {
     flex: none;
-    width: 20%;
+    width: 18%;
     padding: 20px;
     box-sizing: border-box;
     border-right: 1px solid #ccc;

+ 1127 - 0
src/views/personnel/modules/addOperation.vue

@@ -0,0 +1,1127 @@
+<template>
+  <div>
+    <el-form
+      :model="operationForm"
+      ref="OperationFormRef"
+      :rules="operationRules"
+      label-width="120"
+      label-position="top"
+      style="background-color: #fff; padding: 20px; box-sizing: border-box"
+    >
+      <el-descriptions title="基本信息">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="name" label="姓名">
+                  <el-input
+                    v-model="operationForm.name"
+                    placeholder="请填写姓名"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="mobile" label="手机号">
+                  <el-input
+                    v-model="operationForm.mobile"
+                    placeholder="请填写手机号"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="roleIds" label="角色">
+                  
+                  <el-select
+                    v-model="operationForm.roleIds"
+                    placeholder="请选择性别"
+                    multiple
+                  >
+                    <el-option
+                      v-for="item in roleList"
+                      :key="item.id"
+                      :value="item.id"
+                      :label="item.name"
+                    ></el-option>
+                  </el-select>
+                  <!-- <el-input
+                    v-model="operationForm.name"
+                    placeholder="请填写姓名"
+                  ></el-input> -->
+                </el-form-item>
+              </el-col>
+              <el-col :span="12" >
+                <el-form-item  :prop="$route.query.id ? '':'password'" label="登录密码">
+                  <el-input
+                    :disabled="$route.query.id ? true:false"
+                    type="password"
+                    v-model="operationForm.password"
+                    placeholder="请填写登录密码"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="deptId" label="所属机构">
+                  <!-- <el-select v-model="operationForm.deptId" placeholder="请选择所属机构">
+                    <el-option key="1" value="机构1"></el-option>
+                  </el-select> -->
+                  <el-cascader
+                    clearable
+                    style="width: 100%"
+                    v-model="operationForm.deptId"
+                    :options="tableData"
+                    :props="tableProps"
+                    @change="deptChange"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="identity" label="证件号">
+                  <el-input
+                    v-model="operationForm.identity"
+                    placeholder="请填写证件号"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="identityTimeStart" label="证件有效期始">
+                  <el-date-picker
+                    v-model="operationForm.identityTimeStart"
+                    type="date"
+                    placeholder="请选择"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="identityTimeEnd" label="证件有效期止">
+                  <el-date-picker
+                    v-model="operationForm.identityTimeEnd"
+                    type="date"
+                    placeholder="请选择"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+
+      <el-divider />
+      <el-button
+        v-if="!recordShow"
+        link
+        type="primary"
+        icon="plus"
+        @click="recordShow = !recordShow"
+        >填写人事档案(选填)</el-button
+      >
+      <el-button
+        v-else
+        link
+        type="primary"
+        icon="ArrowUp"
+        @click="recordShow = !recordShow"
+        >收起人事档案(选填)</el-button
+      >
+      <br /><br />
+      <el-descriptions title="个人信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="sex" label="性别">
+                  <el-select
+                    v-model="operationForm.sex"
+                    placeholder="请选择性别"
+                  >
+                    <el-option
+                      v-for="item in genderList"
+                      :key="item.id"
+                      :value="item.value"
+                      :label="item.label"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="born" label="出生日期">
+                  <el-date-picker
+                    v-model="operationForm.birthday"
+                    type="date"
+                    placeholder="请选择"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="type" label="民族">
+                  <el-select
+                    v-model="operationForm.nations"
+                    placeholder="请选择名族"
+                  >
+                    <el-option
+                      v-for="item in nation"
+                      :key="item.id"
+                      :value="item.value"
+                      :label="item.label"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="户籍">
+                  <el-input
+                    v-model="operationForm.koseki"
+                    placeholder="请填写户籍"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="type" label="婚姻状况">
+                  <el-select
+                    v-model="operationForm.maritalStatus"
+                    placeholder="请选择婚姻状况"
+                  >
+                    <el-option
+                      v-for="item in marriage"
+                      :key="item.id"
+                      :value="item.value"
+                      :label="item.label"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="政治面貌">
+                  <el-select
+                    v-model="operationForm.politicsStatus"
+                    placeholder="请选择政治面貌"
+                  >
+                    <el-option
+                      v-for="item in political_status"
+                      :key="item.id"
+                      :value="item.value"
+                      :label="item.label"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="type" label="健康状况">
+                  <el-select
+                    v-model="operationForm.health"
+                    placeholder="请选择健康状况"
+                  >
+                    <el-option
+                      v-for="item in health_status"
+                      :key="item.id"
+                      :value="item.value"
+                      :label="item.label"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="居住地区">
+                  <!-- <el-select
+                    v-model="operationForm.address"
+                    placeholder="请选择居住地区"
+                  >
+                    <el-option key="1" value="团队1"></el-option>
+                  </el-select> -->
+                  <el-cascader
+                    clearable
+                    style="width: 100%"
+                    v-model="operationForm.address"
+                    :options="areaOptins"
+                    :props="areaProps"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="team" label="详细地址">
+                  <el-input
+                    v-model="operationForm.liveAddress"
+                    placeholder="请填写详细地址"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="邮政编码">
+                  <el-input
+                    v-model="operationForm.postalCode"
+                    placeholder="请填写邮政编码"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="学历信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="sex" label="学历">
+                  <el-select
+                    v-model="operationForm.education"
+                    placeholder="请选择学历"
+                  >
+                    <el-option
+                      v-for="item in educational"
+                      :key="item.id"
+                      :value="item.value"
+                      :label="item.label"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="born" label="毕业时间">
+                  <el-date-picker
+                    v-model="operationForm.graduationTime"
+                    type="date"
+                    placeholder="请选择"
+                    value-format="YYYY-MM-DD"
+                    style="width: 100%"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="type" label="毕业院校">
+                  <el-input
+                    v-model="operationForm.school"
+                    placeholder="请填写毕业院校"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="是否计算机专业">
+                  <el-select
+                    v-model="operationForm.isComputer"
+                    placeholder="请选择是否计算机专业"
+                  >
+                    <el-option label="是" value="1"></el-option>
+                    <el-option label="否" value="0"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="紧急联系人信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="team" label="姓名">
+                  <el-input
+                    v-model="operationForm.emergencyContactName"
+                    placeholder="请填写姓名"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="手机号">
+                  <el-input
+                    v-model="operationForm.emergencyContactTel"
+                    placeholder="请填写手机号"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions title="工资信息" v-show="recordShow">
+        <el-descriptions-item>
+          <template #default>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="team" label="工资">
+                  <el-input
+                    v-model="operationForm.salary"
+                    placeholder="请填写工资"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="工资等级">
+                  <el-input
+                    v-model="operationForm.salaryLevel"
+                    placeholder="请填写工资等级"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item prop="team" label="银行卡号">
+                  <el-input
+                    v-model="operationForm.bankCardId"
+                    placeholder="请填写银行卡号"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="team" label="开户行">
+                  <el-input
+                    v-model="operationForm.bankName"
+                    placeholder="请填写开户行"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-divider v-show="recordShow" />
+      <el-descriptions v-show="recordShow" title="其它附件">
+        <el-descriptions-item>
+          <template #default>
+            <el-form-item
+              prop=""
+              label="身份证(人像面)"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!IDCardFront"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 1)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ IDCardFrontName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 1)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(1)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              prop=""
+              label="身份证(国徽面)"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!IDCardBack"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 2)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ IDCardBackName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 2)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(2)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              prop=""
+              label="银行卡"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!bankSize"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 3)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ bankName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 3)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(3)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              prop=""
+              label="劳动合同"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!contract"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 4)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ contractName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 4)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(4)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              prop=""
+              label="应聘表"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!applicant"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 5)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ applicantName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 5)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(5)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              prop=""
+              label="定薪表"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!decidePay"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 6)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ decidePayName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 6)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(6)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              prop=""
+              label="离职表"
+              label-width="150"
+              label-position="left"
+            >
+              <el-upload
+                :auto-upload="false"
+                v-if="!dimission"
+                action="#"
+                :show-file-list="false"
+                accept=".png, .jpg, .jpeg"
+                @change="uploadImage($event, 7)"
+              >
+                <el-button link type="primary">上传</el-button>
+              </el-upload>
+              <div class="fileInfo" v-else>
+                <div class="fileName">{{ dimissionName }}</div>
+                <div class="fileBtn">
+                  <el-upload
+                    :auto-upload="false"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 7)"
+                    style="display: flex; align-items: center"
+                  >
+                    <el-icon class="btn-icon"><Upload /></el-icon>
+                  </el-upload>
+                  <el-icon class="btn-icon" @click="imageView(7)"
+                    ><View
+                  /></el-icon>
+                  <el-icon class="btn-icon"><Download /></el-icon>
+                  <el-icon class="btn-icon"><Delete /></el-icon>
+                </div>
+              </div>
+            </el-form-item>
+          </template>
+        </el-descriptions-item>
+      </el-descriptions>
+      <div style="display: flex; justify-content: flex-end">
+        <el-button @click="onSubmit(0)">取消</el-button>
+        <el-button type="primary" @click="onSubmit(OperationFormRef, 1)"
+          >确定</el-button
+        >
+      </div>
+    </el-form>
+    <div class="image-view" v-if="imageShow" @click="imageShow = false">
+      <img :src="imageUrl" />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, defineEmits, onMounted } from "vue";
+import { memberType } from "@/api/modules/user";
+import type { FormRules, FormInstance } from "element-plus";
+import api from "@/api";
+import { ElMessage } from "element-plus";
+import { getDictItems } from "@/api/dict";
+import { useRoute,useRouter } from "vue-router";
+
+interface dictType {
+  value: string;
+  id: string;
+  label: string;
+
+  [property: string]: any;
+}
+interface institutionData {
+  name: string;
+  system: string;
+}
+const info = ref<institutionData>({
+  name: "",
+  system: "",
+});
+//
+const route = useRoute();
+const router=useRouter()
+onMounted(async () => {
+  genderList.value = await getDictItems({ dictCode: "gender" });
+  nation.value = await getDictItems({ dictCode: "nation" });
+  marriage.value = await getDictItems({ dictCode: "marriage" });
+  political_status.value = await getDictItems({ dictCode: "political_status" });
+  health_status.value = await getDictItems({ dictCode: "health_status" });
+  educational.value = await getDictItems({ dictCode: "educational" });
+  getAreaList(); //省市区级联数据
+  getRoleList();//获取角色列表
+  api.institutionApi.institutionList(info.value).then((res) => {
+    // if(res.code===200){
+
+    // }
+    tableData.value = [...res.data];
+  });
+  if(route.query.id)
+  api.userApi
+    .getUserInfo({
+      id: route.query.id || "",
+    })
+    .then((res: any) => {
+      // console.log(res);
+      if (res.code === 200) {
+        operationForm.value = res.data;
+        if(res.data.address==null){
+          operationForm.value.address=[]
+        }
+      }
+    });
+});
+const areaOptins = ref([]);
+const areaProps = ref({
+  value: "areaCode",
+  label: "areaCname",
+  children: "child",
+});
+const getAreaList = () => {
+  api.areaApi.areaList({}).then((res) => {
+    areaOptins.value = res.data;
+  });
+};
+//性别字典
+const genderList = ref<dictType[]>([]);
+//民族
+const nation = ref<dictType[]>([]);
+//婚姻状况
+const marriage = ref<dictType[]>([]);
+//政治面貌
+const political_status = ref<dictType[]>([]);
+//健康状况
+const health_status = ref<dictType[]>([]);
+//学历
+const educational = ref<dictType[]>([]);
+
+interface OperationFormProps extends memberType {
+  deptId: string;
+  leaderNumber: string;
+  referrerNumber: string;
+  address?: string[];
+  [key:string]:any
+}
+// console.log(memberType,5555)
+
+let emits = defineEmits(["closeDialog"]);
+
+const OperationFormRef = ref<FormInstance>();
+// 添加/编辑业务员表单
+let operationForm = ref<OperationFormProps>({
+  deptId: "",
+  name: "",
+  mobile: "",
+  identity: "",
+  identityTimeStart: "",
+  identityTimeEnd: "",
+  leaderId: "",
+  leaderNumber: "",
+  referrerId: "",
+  referrerNumber: "",
+  roleIds:[],
+  password:"",
+  sex: "",
+  birthday: "",
+  nations: "",
+  koseki: "",
+  maritalStatus: "",
+  politicsStatus: "",
+  health: "",
+  province: "",
+  city: "",
+  district: "",
+  address: [],
+  liveAddress: "",
+  postalCode: "",
+  education: "",
+  graduationTime: "",
+  school: "",
+  isComputer: "",
+  emergencyContactName: "",
+  emergencyContactTel: "",
+  salary: "",
+  salaryLevel: "",
+  bankCardId: "",
+  bankName: "",
+});
+// 添加/编辑业务员表单校验
+const operationRules = ref<FormRules>({
+  name: [{ required: true, trigger: "blur", message: "请填写姓名" }],
+  roleIds: [{ required: true, trigger: "change", message: "请选择角色" }],
+  password: [{ required: true, trigger: "blur", message: "请输入登录密码" },
+    {
+      pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
+      message: "密码至少包含大写字母,小写字母,数字,且不少于8位",
+      trigger: "blur",
+    },
+  ],
+  mobile: [
+    { required: true, trigger: "blur", message: "请填写手机号" },
+    {
+      pattern: /^1[34578][0-9]{9}$/,
+      message: "请填写正确的手机号",
+      trigger: "blur",
+    },
+  ],
+  deptId: [{ required: true, trigger: "change", message: "请选择所属机构" }],
+  identity: [
+    { required: true, trigger: "blur", message: "请填写证件号" },
+    {
+      pattern:
+        /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9X]$/,
+      message: "请填写正确的身份证号",
+      trigger: "blur",
+    },
+  ],
+  identityTimeStart: [
+    { required: true, trigger: "change", message: "请选择证件有效期始" },
+  ],
+  identityTimeEnd: [
+    { required: true, trigger: "change", message: "请选择证件有效期止" },
+  ],
+  leaderId: [{ required: true, trigger: "change", message: "请选择管理人" }],
+  leaderNumber: [
+    { required: true, trigger: "blur", message: "请填写管理人工号" },
+  ],
+  referrerId: [{ required: true, trigger: "change", message: "请选择推荐人" }],
+  referrerNumber: [
+    { required: true, trigger: "blur", message: "请填写推荐人工号" },
+  ],
+});
+// 身份证人像面
+let IDCardFrontName = ref("");
+let IDCardFront = ref("");
+let sfz1= ref("");
+// 身份证国徽面
+let IDCardBackName = ref("");
+let IDCardBack = ref("");
+let sfz2= ref("");
+// 银行卡
+let bankName = ref("");
+let bankSize = ref("");
+let bankCard=ref("");
+// 劳务合同
+let contractName = ref("");
+let contract = ref("");
+let contractId=ref("");
+// 应聘表
+let applicantName = ref("");
+let applicant = ref("");
+let applicantId = ref("");
+// 定薪表
+let decidePayName = ref("");
+let decidePay = ref("");
+let salaryTable=ref('')
+// 离职表
+let dimissionName = ref("");
+let dimission = ref("");
+let leaveTable= ref("");
+// 图片预览地址
+let imageShow = ref(false);
+let imageUrl = ref("");
+
+//机构列表
+type tableType = {
+  id: string;
+  name: string;
+};
+const tableData = ref<tableType[]>([]);
+const tableProps = ref({
+  value: "id",
+  label: "name",
+  children: "children",
+  checkStrictly: true,
+});
+
+//根据所属id 判断组织架构权限是否可选
+function deptChange(e: any) {
+  // console.log(e)
+  if (e != undefined) {
+    let deptId = e[e?.length - 1];
+    operationForm.deptId = deptId;
+  } else {
+    operationForm.deptId = "";
+  }
+}
+
+//数组去重
+
+// 上传图片
+const uploadImage = (file, type) => {
+  let files = file.raw;
+  let url = window.URL.createObjectURL(files); //转临时路径
+  const params = new FormData(); // 声明formData数据类型
+  params.append("file", files);
+
+  // params.append("multipartFile", files);
+  // params.append("type", "image");
+  api.areaApi.fileUpload(params).then((res: any) => {
+   
+    if (res.code === 200) {
+      switch (type) {
+        case 1:
+          IDCardFrontName.value = res.data.fileName;
+          IDCardFront.value = res.data.downloadUrl;
+          sfz1.value=res.data.id
+          break;
+        case 2:
+          IDCardBackName.value = res.data.fileName;
+          IDCardBack.value = res.data.downloadUrl;
+          sfz2.value=res.data.id
+          break;
+        case 3:
+          bankName.value = res.data.fileName;
+          bankSize.value = res.data.downloadUrl;
+          bankCard.value=res.data.id
+          break;
+        case 4:
+          contractName.value = res.data.fileName;
+          contract.value = res.data.downloadUrl;
+          contractId.value=res.data.id
+
+          break;
+        case 5:
+          applicantName.value = res.data.fileName;
+          applicant.value = res.data.downloadUrl;
+          applicantId.value=res.data.id
+
+          break;
+        case 6:
+          decidePayName.value = res.data.fileName;
+          decidePay.value = res.data.downloadUrl;
+          salaryTable.value=res.data.id
+
+          break;
+        case 7:
+          dimissionName.value = res.data.fileName;
+          dimission.value = res.data.downloadUrl;
+          leaveTable.value = res.data.id;
+          break;
+      }
+    }
+  });
+};
+
+// 人事档案
+let recordShow = ref(false);
+
+const imageView = (type) => {
+  imageShow.value = true;
+  switch (type) {
+    case 1:
+      imageUrl.value = IDCardFront.value;
+      break;
+    case 2:
+      imageUrl.value = IDCardBack.value;
+      break;
+    case 3:
+      imageUrl.value = bankSize.value;
+      break;
+    case 4:
+      imageUrl.value = contract.value;
+      break;
+    case 5:
+      imageUrl.value = applicant.value;
+      break;
+    case 6:
+      imageUrl.value = decidePay.value;
+      break;
+    case 7:
+      imageUrl.value = dimission.value;
+      break;
+  }
+};
+
+const onSubmit = async (OperationFormRef: FormInstance, type: number) => {
+  if (!OperationFormRef) {
+    emits("closeDialog", false);
+    return;
+  }
+  await OperationFormRef.validate((valid) => {
+    if (valid) {
+      if(!route.query.id){
+      api.operationApi.addOperation({
+        ...operationForm.value,
+        province:operationForm.value.address.length?operationForm.value.address[0]:'',
+        city:operationForm.value.address.length?operationForm.value.address[1]:'',
+        district:operationForm.value.address.length?operationForm.value.address[2]:'',
+        deptId:operationForm.value.deptId[operationForm.value.deptId.length-1],
+        typeAttr:2,
+        sfz1:sfz1.value,
+        sfz2:sfz2.value,
+        bankCard:bankCard.value,
+        contractId:contractId.value,
+        applicantId:applicantId.value,
+        salaryTable:salaryTable.value,
+        leaveTable:leaveTable.value,
+        
+      }).then((res:any) => {
+        // console.log(123, res);
+        if(res.code===200){
+          ElMessage.success(res.msg)
+          router.back()
+        }
+      });
+    }else{
+      api.userApi.updateUserInfo({
+        ...operationForm.value,
+        province:operationForm.value.address.length?operationForm.value.address[0]:'',
+        city:operationForm.value.address.length?operationForm.value.address[1]:'',
+        district:operationForm.value.address.length?operationForm.value.address[2]:'',
+        deptId:operationForm.value.deptId[operationForm.value.deptId.length-1],
+        typeAttr:2,
+        sfz1:sfz1.value,
+        sfz2:sfz2.value,
+        bankCard:bankCard.value,
+        contractId:contractId.value,
+        applicantId:applicantId.value,
+        salaryTable:salaryTable.value,
+        leaveTable:leaveTable.value,
+        id:operationForm.value.id
+        
+      }).then((res:any) => {
+        // console.log(123, res);
+        if(res.code===200){
+          ElMessage.success(res.msg)
+          router.back()
+        }
+      });
+    }
+    } else {
+      ElMessage({
+        message: "请正确填写相关信息!",
+        type: "warning",
+      });
+    }
+  });
+};
+
+//获取角色列表
+const roleList=ref([])
+function getRoleList() {
+  api.roleApi
+    .roleList({
+      system: localStorage.getItem("login_system") || "",
+      name: "",
+      desc: "",
+      permsId: [],
+      perms: [],
+    })
+    .then((res) => {
+      roleList.value = res.data;
+      // roleId.value = res.data[0].id;
+    });
+}
+</script>
+
+<style scoped lang="scss">
+.fileInfo {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  padding: 2px 20px;
+  border-radius: 5px;
+  margin: 0 10px;
+  &:hover {
+    background: #ccc;
+  }
+  .fileName {
+    width: 200px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .fileBtn {
+    display: flex;
+    align-items: center;
+    .btn-icon {
+      margin: 0 10px;
+      font-size: 16px;
+      cursor: pointer;
+      &:hover {
+        color: #00a0f4;
+      }
+    }
+  }
+}
+.image-view {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.6);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 9999;
+  img {
+    width: 800px;
+    height: 800px;
+    border-radius: 5px;
+  }
+}
+</style>

+ 1344 - 0
src/views/personnel/modules/memberMessage.vue

@@ -0,0 +1,1344 @@
+<template>
+  <div class="message-info">
+    <div class="error"></div>
+    <div style="background-color: #fff; padding: 15px; box-sizing: border-box">
+      <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-col :span="4">
+          <el-button type="primary" @click="editMember">编辑</el-button>
+          <el-dropdown style="margin-left: 15px">
+            <el-button type="primary"> 更多 </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item v-on:click="changeDept()"
+                  >变更机构</el-dropdown-item
+                >
+                <el-dropdown-item v-on:click="resign()">操作离职</el-dropdown-item>
+                <el-dropdown-item v-on:click="transfer()"
+                  >资源转移</el-dropdown-item
+                >
+                <el-dropdown-item v-on:click="delUser()">删除</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </el-col>
+      </el-row>
+      <el-row :gutter="24">
+        <el-col :span="18">
+          <el-descriptions title="" class="info-list" :column="2">
+            <el-descriptions-item label="工号:">{{
+              operationForm.userId
+            }}</el-descriptions-item>
+            <el-descriptions-item label="手机号:">{{
+              operationForm.mobile
+            }}</el-descriptions-item>
+            <el-descriptions-item label="所在机构:">
+              {{ operationForm.deptName }}
+            </el-descriptions-item>
+            <el-descriptions-item label="角色:">
+              {{ operationForm.deptName }}
+            </el-descriptions-item>
+            <el-descriptions-item label="创建人:">
+              {{ operationForm.createBy }}
+            </el-descriptions-item>
+            <el-descriptions-item label="创建时间:">
+              {{ operationForm.createTime }}
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-col>
+        <el-col :span="6">
+          <h2>
+            {{
+              statusList
+                .map((item) => {
+                  return item.value == operationForm.status ? item.label : "";
+                })
+                .join("")
+            }}
+          </h2>
+          <p>状态</p>
+        </el-col>
+      </el-row>
+    </div>
+    <el-form
+      :model="operationForm"
+      ref="OperationFormRef"
+      label-width="120"
+      style="background-color: #fff; padding: 20px; box-sizing: border-box"
+    >
+      <el-tabs v-model="activeName" class="demo-tabs">
+        <el-tab-pane label="基本信息" name="first">
+          <el-descriptions title="个人信息">
+            <el-descriptions-item>
+              <template #default>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="name" label="姓名:">
+                      {{ operationForm.name }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="mobile" label="手机号:">
+                      {{ operationForm.mobile }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="deptId" label="所属机构:">
+                      {{ operationForm.deptName || "--" }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="identity" label="证件号:">
+                      {{ operationForm.identity }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item
+                      prop="identityTimeStart"
+                      label="证件有效期始:"
+                    >
+                      {{ operationForm.identityTimeStart }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="identityTimeEnd" label="证件有效期止:">
+                      {{ operationForm.identityTimeEnd }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="sex" label="性别:">
+                      {{
+                        genderList
+                          .map((item) => {
+                            return item.value == operationForm.sex
+                              ? item.label
+                              : "";
+                          })
+                          .join("")
+                      }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="born" label="出生日期:">
+                      {{ operationForm.birthday }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="type" label="民族:">
+                      {{
+                        nation
+                          .map((item) => {
+                            return item.value == operationForm.nations
+                              ? item.label
+                              : "";
+                          })
+                          .join("")
+                      }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="户籍:">
+                      {{ operationForm.koseki }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="type" label="婚姻状况:">
+                      {{
+                        marriage
+                          .map((item) => {
+                            return item.value == operationForm.maritalStatus
+                              ? item.label
+                              : "";
+                          })
+                          .join("")
+                      }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="政治面貌:">
+                      {{
+                        political_status
+                          .map((item) => {
+                            return item.value == operationForm.politicsStatus
+                              ? item.label
+                              : "";
+                          })
+                          .join("")
+                      }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="type" label="健康状况:">
+                      {{
+                        health_status
+                          .map((item) => {
+                            return item.value == operationForm.health
+                              ? item.label
+                              : "";
+                          })
+                          .join("")
+                      }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="居住地区:">
+                      <!-- <el-select
+                    v-model="operationForm.address"
+                    placeholder="请选择居住地区"
+                  >
+                    <el-option key="1" value="团队1"></el-option>
+                  </el-select> -->
+                      {{ operationForm.region || "--" }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="详细地址:">
+                      {{ operationForm.liveAddress }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="邮政编码:">
+                      {{ operationForm.postalCode }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+              </template>
+            </el-descriptions-item>
+          </el-descriptions>
+
+          <el-descriptions title="学历信息" v-show="recordShow">
+            <el-descriptions-item>
+              <template #default>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="sex" label="学历:">
+                      {{
+                        educational
+                          .map((item) => {
+                            return item.value == operationForm.education
+                              ? item.label
+                              : "";
+                          })
+                          .join("")
+                      }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="born" label="毕业时间:">
+                      {{ operationForm.graduationTime }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="type" label="毕业院校:">
+                      {{ operationForm.school }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="是否计算机专业:">
+                      {{ operationForm.isComputer }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+              </template>
+            </el-descriptions-item>
+          </el-descriptions>
+          <el-descriptions title="紧急联系人信息" v-show="recordShow">
+            <el-descriptions-item>
+              <template #default>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="姓名:">
+                      {{ operationForm.emergencyContactName }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="手机号:">
+                      {{ operationForm.emergencyContactTel }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+              </template>
+            </el-descriptions-item>
+          </el-descriptions>
+          <el-descriptions title="工资信息" v-show="recordShow">
+            <el-descriptions-item>
+              <template #default>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="工资:">
+                      {{ operationForm.salary }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="工资等级:">
+                      {{ operationForm.salaryLevel }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row :gutter="24">
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="银行卡号:">
+                      {{ operationForm.bankCardId }}
+                    </el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                    <el-form-item prop="team" label="开户行:">
+                      {{ operationForm.bankName }}
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+              </template>
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-tab-pane>
+        <el-tab-pane label="资料附件" name="second">
+          <el-descriptions v-show="recordShow" title="资料附件">
+            <el-descriptions-item>
+              <template #default>
+                <el-form-item
+                  prop=""
+                  label="身份证(人像面)"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!IDCardFront"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 1)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ IDCardFrontName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 1)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(1)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+                <el-form-item
+                  prop=""
+                  label="身份证(国徽面)"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!IDCardBack"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 2)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ IDCardBackName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 2)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(2)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+                <el-form-item
+                  prop=""
+                  label="银行卡"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!bankSize"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 3)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ bankName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 3)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(3)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+                <el-form-item
+                  prop=""
+                  label="劳动合同"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!contract"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 4)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ contractName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 4)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(4)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+                <el-form-item
+                  prop=""
+                  label="应聘表"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!applicant"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 5)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ applicantName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 5)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(5)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+                <el-form-item
+                  prop=""
+                  label="定薪表"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!decidePay"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 6)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ decidePayName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 6)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(6)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+                <el-form-item
+                  prop=""
+                  label="离职表"
+                  label-width="150"
+                  label-position="left"
+                >
+                  <el-upload
+                    :auto-upload="false"
+                    v-if="!dimission"
+                    action="#"
+                    :show-file-list="false"
+                    accept=".png, .jpg, .jpeg"
+                    @change="uploadImage($event, 7)"
+                  >
+                    <el-button link type="primary">上传</el-button>
+                  </el-upload>
+                  <div class="fileInfo" v-else>
+                    <div class="fileName">{{ dimissionName }}</div>
+                    <div class="fileBtn">
+                      <el-upload
+                        :auto-upload="false"
+                        action="#"
+                        :show-file-list="false"
+                        accept=".png, .jpg, .jpeg"
+                        @change="uploadImage($event, 7)"
+                        style="display: flex; align-items: center"
+                      >
+                        <el-icon class="btn-icon"><Upload /></el-icon>
+                      </el-upload>
+                      <el-icon class="btn-icon" @click="imageView(7)"
+                        ><View
+                      /></el-icon>
+                      <el-icon class="btn-icon"><Download /></el-icon>
+                      <el-icon class="btn-icon"><Delete /></el-icon>
+                    </div>
+                  </div>
+                </el-form-item>
+              </template>
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-tab-pane>
+      </el-tabs>
+
+      <!-- <div style="display: flex; justify-content: flex-end">
+        <el-button @click="onSubmit(0)">取消</el-button>
+        <el-button type="primary" @click="onSubmit(OperationFormRef, 1)"
+          >确定</el-button
+        >
+      </div> -->
+    </el-form>
+    <div class="image-view" v-if="imageShow" @click="imageShow = false">
+      <img :src="imageUrl" />
+    </div>
+    <el-dialog
+      v-model="dialogVisible"
+      :title="leave?'操作离职':'资源转移'"
+      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>
+      <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> 业务员 </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>
+
+       <!-- 操作离职--->
+      <!-- <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>
+    </el-dialog>
+    <setDept
+      :dialogVisible="deptDialogVisible"
+      :dept-list="tableData"
+      :dept-ids="[]"
+      @close-dialog="confirmDialogInfo"
+      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="tableData"
+          :props="tableProps"
+          :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>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, defineEmits, onMounted, watch } from "vue";
+import { memberType } from "@/api/modules/user";
+import type { FormRules, FormInstance, ElTree } from "element-plus";
+import api from "@/api";
+import { Search } from "@element-plus/icons-vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { getDictItems } from "@/api/dict";
+import { useRoute } from "vue-router";
+import pinyin from "js-pinyin";
+import { useRouter } from "vue-router";
+import setDept from "@/components/DialogSetDeptLeader/index.vue";
+interface dictType {
+  value: string;
+  id: string;
+  label: string;
+
+  [property: string]: any;
+}
+
+interface institutionData {
+  name: string;
+  system: string;
+}
+const info = ref<institutionData>({
+  name: "",
+  system: "",
+});
+//转移资源
+const dialogVisible = ref(false);
+
+//选择交接人
+const deptDialogVisible = ref(false);
+const route = useRoute();
+
+const activeName = ref("first");
+const statusList = ref<dictType[]>([]);
+onMounted(async () => {
+  genderList.value = await getDictItems({ dictCode: "gender" });
+  nation.value = await getDictItems({ dictCode: "nation" });
+  marriage.value = await getDictItems({ dictCode: "marriage" });
+  political_status.value = await getDictItems({ dictCode: "political_status" });
+  health_status.value = await getDictItems({ dictCode: "health_status" });
+  educational.value = await getDictItems({ dictCode: "educational" });
+  statusList.value = await getDictItems({ dictCode: "person_status" });
+  getAreaList(); //省市区级联数据
+  api.institutionApi.institutionList(info.value).then((res) => {
+    tableData.value = [...res.data];
+  });
+  api.userApi
+    .getUserInfo({
+      id: route.query.id || "",
+    })
+    .then((res: any) => {
+      console.log(res);
+      if (res.code === 200) {
+        operationForm.value = res.data;
+      }
+    });
+});
+const areaOptins = ref([]);
+
+const getAreaList = () => {
+  api.areaApi.areaList({}).then((res) => {
+    areaOptins.value = res.data;
+  });
+};
+//性别字典
+const genderList = ref<dictType[]>([]);
+//民族
+const nation = ref<dictType[]>([]);
+//婚姻状况
+const marriage = ref<dictType[]>([]);
+//政治面貌
+const political_status = ref<dictType[]>([]);
+//健康状况
+const health_status = ref<dictType[]>([]);
+//学历
+const educational = ref<dictType[]>([]);
+
+interface OperationFormProps extends memberType {
+  deptId: string;
+  leaderNumber: string;
+  referrerNumber: string;
+  address?: [];
+  [key: string]: any;
+}
+// console.log(memberType,5555)
+
+let emits = defineEmits(["closeDialog"]);
+
+const OperationFormRef = ref<FormInstance>();
+// 添加/编辑业务员表单
+let operationForm = ref<OperationFormProps>({
+  deptId: "",
+  name: "",
+  mobile: "",
+  identity: "",
+  identityTimeStart: "",
+  identityTimeEnd: "",
+  leaderId: "",
+  leaderNumber: "",
+  referrerId: "",
+  referrerNumber: "",
+
+  sex: "",
+  birthday: "",
+  nations: "",
+  koseki: "",
+  maritalStatus: "",
+  politicsStatus: "",
+  health: "",
+  province: "",
+  city: "",
+  district: "",
+  address: [],
+  liveAddress: "",
+  postalCode: "",
+  education: "",
+  graduationTime: "",
+  school: "",
+  isComputer: "",
+  emergencyContactName: "",
+  emergencyContactTel: "",
+  salary: "",
+  salaryLevel: "",
+  bankCardId: "",
+  bankName: "",
+});
+// 添加/编辑业务员表单校验
+const operationRules = ref<FormRules>({
+  name: [{ required: true, trigger: "blur", message: "请填写姓名" }],
+  mobile: [
+    { required: true, trigger: "blur", message: "请填写手机号" },
+    {
+      pattern: /^1[34578][0-9]{9}$/,
+      message: "请填写正确的手机号",
+      trigger: "blur",
+    },
+  ],
+  deptId: [{ required: true, trigger: "change", message: "请选择所属机构" }],
+  identity: [
+    { required: true, trigger: "blur", message: "请填写证件号" },
+    {
+      pattern:
+        /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9X]$/,
+      message: "请填写正确的身份证号",
+      trigger: "blur",
+    },
+  ],
+  identityTimeStart: [
+    { required: true, trigger: "change", message: "请选择证件有效期始" },
+  ],
+  identityTimeEnd: [
+    { required: true, trigger: "change", message: "请选择证件有效期止" },
+  ],
+  leaderId: [{ required: true, trigger: "change", message: "请选择管理人" }],
+  leaderNumber: [
+    { required: true, trigger: "blur", message: "请填写管理人工号" },
+  ],
+  referrerId: [{ required: true, trigger: "change", message: "请选择推荐人" }],
+  referrerNumber: [
+    { required: true, trigger: "blur", message: "请填写推荐人工号" },
+  ],
+});
+// 身份证人像面
+let IDCardFrontName = ref("");
+let IDCardFront = ref("");
+let sfz1 = ref("");
+// 身份证国徽面
+let IDCardBackName = ref("");
+let IDCardBack = ref("");
+let sfz2 = ref("");
+// 银行卡
+let bankName = ref("");
+let bankSize = ref("");
+let bankCard = ref("");
+// 劳务合同
+let contractName = ref("");
+let contract = ref("");
+let contractId = ref("");
+// 应聘表
+let applicantName = ref("");
+let applicant = ref("");
+let applicantId = ref("");
+// 定薪表
+let decidePayName = ref("");
+let decidePay = ref("");
+let salaryTable = ref("");
+// 离职表
+let dimissionName = ref("");
+let dimission = ref("");
+let leaveTable = ref("");
+// 图片预览地址
+let imageShow = ref(false);
+let imageUrl = ref("");
+
+//机构列表
+type tableType = {
+  id: string;
+  name: string;
+};
+const tableData = ref<tableType[]>([]);
+const tableProps = ref({
+  value: "id",
+  label: "name",
+  children: "children",
+  checkStrictly: true,
+});
+
+//跳转编辑页面
+const router = useRouter();
+function editMember(e: any) {
+  router.push({
+    path: "/personnel/member/memberEdit",
+    query: {
+      id: operationForm.value.userId,
+    },
+  });
+  // console.log(e)
+  // if (e != undefined) {
+  //   let deptId = e[e?.length - 1];
+  //   operationForm.deptId = deptId;
+  // } else {
+  //   operationForm.deptId = "";
+  // }
+}
+
+//数组去重
+
+// 上传图片
+const uploadImage = (file: any, type: number) => {
+  let files = file.raw;
+  let url = window.URL.createObjectURL(files); //转临时路径
+  const params = new FormData(); // 声明formData数据类型
+  params.append("file", files);
+
+  // params.append("multipartFile", files);
+  // params.append("type", "image");
+  api.areaApi.fileUpload(params).then((res: any) => {
+    console.log(res);
+    if (res.code === 200) {
+      switch (type) {
+        case 1:
+          IDCardFrontName.value = res.data.fileName;
+          IDCardFront.value = res.data.downloadUrl;
+          sfz1.value = res.data.id;
+          break;
+        case 2:
+          IDCardBackName.value = res.data.fileName;
+          IDCardBack.value = res.data.downloadUrl;
+          sfz2.value = res.data.id;
+          break;
+        case 3:
+          bankName.value = res.data.fileName;
+          bankSize.value = res.data.downloadUrl;
+          bankCard.value = res.data.id;
+          break;
+        case 4:
+          contractName.value = res.data.fileName;
+          contract.value = res.data.downloadUrl;
+          contractId.value = res.data.id;
+
+          break;
+        case 5:
+          applicantName.value = res.data.fileName;
+          applicant.value = res.data.downloadUrl;
+          applicantId.value = res.data.id;
+
+          break;
+        case 6:
+          decidePayName.value = res.data.fileName;
+          decidePay.value = res.data.downloadUrl;
+          salaryTable.value = res.data.id;
+
+          break;
+        case 7:
+          dimissionName.value = res.data.fileName;
+          dimission.value = res.data.downloadUrl;
+          leaveTable.value = res.data.id;
+          break;
+      }
+    }
+  });
+};
+
+// 人事档案
+let recordShow = ref(true);
+
+const imageView = (type: number) => {
+  imageShow.value = true;
+  switch (type) {
+    case 1:
+      imageUrl.value = IDCardFront.value;
+      break;
+    case 2:
+      imageUrl.value = IDCardBack.value;
+      break;
+    case 3:
+      imageUrl.value = bankSize.value;
+      break;
+    case 4:
+      imageUrl.value = contract.value;
+      break;
+    case 5:
+      imageUrl.value = applicant.value;
+      break;
+    case 6:
+      imageUrl.value = decidePay.value;
+      break;
+    case 7:
+      imageUrl.value = dimission.value;
+      break;
+  }
+};
+
+const onSubmit = async (OperationFormRef: FormInstance, type: number) => {
+  if (!OperationFormRef) {
+    emits("closeDialog", false);
+    return;
+  }
+  await OperationFormRef.validate((valid) => {
+    if (valid) {
+      api.operationApi
+        .addOperation({
+          ...operationForm.value,
+          province: operationForm.value.address[0],
+          city: operationForm.value.address[1],
+          district: operationForm.value.address[2],
+          deptId:
+            operationForm.value.deptId[operationForm.value.deptId.length - 1],
+          typeAttr: 2,
+          sfz1: sfz1.value,
+          sfz2: sfz2.value,
+          bankCard: bankCard.value,
+          contractId: contractId.value,
+          applicantId: applicantId.value,
+          salaryTable: salaryTable.value,
+          leaveTable: leaveTable.value,
+        })
+        .then((res: any) => {
+          // console.log(123, res);
+          if (res.code === 200) {
+            ElMessage.success(res.msg);
+          }
+        });
+    } else {
+      ElMessage({
+        message: "请正确填写相关信息!",
+        type: "warning",
+      });
+    }
+  });
+};
+interface transfer {
+  [key: string]: any;
+}
+//资源转移信息
+const transferInfo = ref<transfer>({});
+function transfer() {
+  // console.log(123)
+  leave.value=false
+  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;
+        }
+      }
+    });
+}
+
+//操作离职
+const leave=ref(false)
+function resign() {
+  // console.log(123)
+  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",
+          }
+        )
+          .then(() => {
+            api.userApi
+              .userQuitApply({
+                userId:operationForm.value.userId,
+              })
+              .then((res: any) => {
+                if(res.code==200){
+                  ElMessage.success(res.msg)
+                  router.back()
+                }
+              });
+            // console.log(123);
+          })
+          .catch(() => {
+            ElMessage.warning("用户取消操作");
+          });
+        } else {
+          ElMessage.warning("当前用户有资源未转移,请转移后执行离职操作");
+          // dialogVisible.value = true;
+        }
+      }
+    });
+}
+
+//确认弹框提交信息
+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;
+      }
+    });
+
+    // 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;
+    //   }
+    // });
+  
+  
+}
+
+//变更机构弹框
+interface Tree {
+  [key: string]: any;
+}
+const filterText = ref("");
+const treeRef = ref<InstanceType<typeof ElTree>>();
+
+watch(filterText, (val) => {
+  treeRef.value!.filter(val);
+});
+const filterNode = (value: string, data: Tree) => {
+  // console.log(data)
+  if (!value) return true;
+  return data.name.includes(value);
+};
+//判断当前机构是否可以进行变更
+const changeDeptDialog = ref(false);
+function changeDept() {
+  // changeDeptDialog.value=true
+  api.userApi
+    .checkChangeDept({
+      userId: operationForm.value.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;
+      }
+    });
+}
+
+//删除成员
+function delUser() {
+  api.userApi
+    .checkChangeDept({
+      userId: operationForm.value.userId,
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        // transferInfo.value=res.data
+
+        ElMessageBox.confirm(
+          "账号删除后,该账号将无法使用访问本企业,请确定是否删除 ",
+          "确认要删除账号吗?",
+          {
+            confirmButtonText: "确认删除",
+            cancelButtonText: "取消",
+            type: "warning",
+          }
+        )
+          .then(() => {
+            api.userApi
+              .userDelete({
+                id: [operationForm.value.id],
+                
+              })
+              .then((res: any) => {
+                if(res.code==200){
+                  ElMessage.success(res.msg)
+                  router.back()
+                }
+              });
+            // console.log(123);
+          })
+          .catch(() => {
+            ElMessage.warning("用户取消操作");
+          });
+      }
+    });
+}
+</script>
+
+<style scoped lang="scss">
+.message-info {
+  // background: #fff;
+  padding: 15px;
+  box-sizing: border-box;
+  h4 {
+    margin: 0;
+  }
+}
+.img-title {
+  border-radius: 50%;
+  width: 30px;
+  height: 30px;
+  color: #fff;
+  background: #00a0f4;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20px;
+}
+.fileInfo {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  padding: 2px 20px;
+  border-radius: 5px;
+  margin: 0 10px;
+  &:hover {
+    background: #ccc;
+  }
+  .fileName {
+    width: 200px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .fileBtn {
+    display: flex;
+    align-items: center;
+    .btn-icon {
+      margin: 0 10px;
+      font-size: 16px;
+      cursor: pointer;
+      &:hover {
+        color: #00a0f4;
+      }
+    }
+  }
+}
+.image-view {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.6);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 9999;
+  img {
+    width: 800px;
+    height: 800px;
+    border-radius: 5px;
+  }
+}
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+</style>

+ 475 - 41
src/views/personnel/roleManagement.vue

@@ -4,18 +4,40 @@
       <ElCol :md="6">
         <PageMain class="vh100">
           <ElFormItem prop="roleName">
-            <ElCol :md="17">
-              <ElInput v-model="roleName" placeholder="角色名称查找" type="text" tabindex="1">
+            <ElCol :md="20">
+              <ElInput
+                v-model="roleName"
+                placeholder="角色名称查找"
+                type="text"
+                tabindex="1"
+              >
                 <template #prefix>
                   <SvgIcon name="i-ri:user-3-fill" />
                 </template>
               </ElInput>
             </ElCol>
-            <ElCol :md="6">
+            <ElCol :md="20" style="margin-top: 20px">
+              <ElButton type="primary" @click="addRole">
+                <el-icon><Plus /></el-icon>
+                添加</ElButton
+              >
+
               <ElButton type="primary">查找</ElButton>
             </ElCol>
+            <ElCol :md="24">
+              <div
+                v-for="item in roleList"
+                :key="item.id"
+                :class="roleId == item.id ? 'on' : 'role-item'"
+                @click="chooseRole(item)"
+              >
+                <p>{{ item.name }}</p>
+                <p>
+                  <span>{{ item.remark || "--" }}</span>
+                </p>
+              </div>
+            </ElCol>
           </ElFormItem>
-
         </PageMain>
       </ElCol>
       <ElCol :md="18">
@@ -25,65 +47,157 @@
               <span class="strong">角色管理</span>
               <div>
                 <ElButton type="primary" @click="roleSubmit">提交</ElButton>
+                <ElButton type="danger" @click="deleteRole">删除</ElButton>
               </div>
             </div>
           </template>
           <h5>基本信息</h5>
-          <ElCol :md="6"></ElCol>
-          <ElForm :model="roleInfo" :rules="roleRules" label-width="auto" size="" style="max-width: 500px;">
+          <!-- <ElCol :md="6"></ElCol> -->
+          <ElForm
+            :model="roleInfo"
+            :rules="roleRules"
+            label-width="auto"
+            size=""
+            style="max-width: 500px"
+          >
             <ElFormItem prop="name" label="角色名称">
-              <ElInput v-model="roleInfo.name" placeholder="输入20个字以内的角色名称" type="text" tabindex="1">
+              <ElInput
+                v-model="roleInfo.name"
+                placeholder="输入20个字以内的角色名称"
+                type="text"
+                tabindex="1"
+              >
               </ElInput>
             </ElFormItem>
+            <ElFormItem prop="deptId" label="所属机构">
+              <el-cascader
+                clearable
+                style="width: 100%"
+                v-model="roleInfo.deptId"
+                :options="tableData"
+                :props="tableProps"
+                @change="deptChange"
+              />
+            </ElFormItem>
             <ElFormItem prop="desc" label="角色描述">
-              <ElInput v-model="roleInfo.desc" placeholder="请输入" type="textarea" tabindex="2">
+              <ElInput
+                v-model="roleInfo.desc"
+                placeholder="请输入"
+                type="textarea"
+                tabindex="2"
+              >
               </ElInput>
             </ElFormItem>
           </ElForm>
           <ElDivider></ElDivider>
-          <div>
-            <h5>角色权限</h5>
-            <ElTree style="max-height: 350px;overflow-y: auto;" :data="treeData" :props="defaultProps" show-checkbox
-              node-key="id" :default-expand-all="true" :default-checked-keys="[6]" @check="handleCheckChange" />
+          <div style="min-height: 500px">
+            <h5>
+              角色权限<span
+                style="color: #ccc; font-size: 12px; font-weight: 400"
+                >(该角色享有的后台模块功能权限剩余数据权限)</span
+              >
+            </h5>
+            <el-tabs
+              :tab-position="'left'"
+              style="height: 500px"
+              class="demo-tabs"
+            >
+              <el-tab-pane label="菜单/操作权限">
+                <ElTree
+                  style="max-height: 500px; overflow-y: auto"
+                  :data="treeData"
+                  :props="defaultProps"
+                  show-checkbox
+                  node-key="id"
+                  :default-expand-all="true"
+                  :default-checked-keys="checkedKeys"
+                  @check="handleCheckChange"
+                />
+              </el-tab-pane>
+              <el-tab-pane label="组织架构权限">
+                <el-radio-group
+                  v-model="roleInfo.dataMark"
+                  @change="dataMarkChange"
+                >
+                  <el-radio value="1" size="large">可见本机构下的数据</el-radio>
+                  <el-radio value="2" size="large"
+                    >可见本机构及下级机构数据</el-radio
+                  >
+                  <el-radio value="3" size="large">指定机构</el-radio>
+                </el-radio-group>
+                <ElTree
+                  style="max-height: 500px; overflow-y: auto"
+                  :data="deptTreeData"
+                  :props="deptProps"
+                  show-checkbox
+                  node-key="id"
+                  :check-strictly="true"
+                  :default-expand-all="true"
+                  :default-checked-keys="roleInfo.deptIds"
+                  @check="handleDeptCheckChange"
+                  ref="deptTree"
+                />
+              </el-tab-pane>
+            </el-tabs>
           </div>
         </PageMain>
       </ElCol>
     </ElRow>
-
   </div>
 </template>
 
-<script lang='ts' setup>
-import { asyncRoutes } from '@/router/routes' // 请根据实际路径调整
-import { ref, reactive, onMounted } from 'vue';
-import type { FormRules } from 'element-plus';
-import { preprocessRoutes, convertToTreeData, TreeNode } from '@/utils/composables/routeUtils'; // 导入工具方法
-import api from '@/api'
+<script lang="ts" setup>
+import { asyncRoutes } from "@/router/routes"; // 请根据实际路径调整
+import { ref, reactive, onMounted, onBeforeMount, } from "vue";
+import {
+  type FormRules,
+  type ElTree,
+  ElMessage,
+  ElMessageBox,
+} from "element-plus";
+import {
+  preprocessRoutes,
+  convertToTreeData,
+  TreeNode,
+} from "@/utils/composables/routeUtils"; // 导入工具方法
+import api from "@/api";
 const roleName = ref<string>("");
 
-const roleInfo = reactive<{
+let roleInfo = reactive<{
   name: string;
   desc: string;
-  system: string,
-  permsId: number[],
-  perms: string[]
+  system: string;
+  permsId: number[];
+  perms: any[];
+  deptId: string;
+  deptIds: any[];
+  dataMark: string;
 }>({
-  name: "",//角色
-  desc: "",//描述
-  system: "PLATFORM",//系统
-  permsId: [],//权限id
-  perms: [],//权限标识
+  name: "", //角色
+  desc: "", //描述
+  system: "PLATFORM", //系统
+  permsId: [], //权限id
+  perms: [], //权限标识
+  deptId: "",
+  deptIds: [],
+  dataMark: "1",
 });
 const roleRules = ref<FormRules>({
   name: [
-    { required: true, trigger: 'blur', message: '请输入角色名称' },
+    { required: true, trigger: "blur", message: "请输入角色名称" },
+    { min: 1, max: 20, message: "请输入机构名称", trigger: "blur" },
   ],
-
+  deptId: [{ required: true, message: "请选择机构", trigger: "change" }],
 });
 const treeData = ref<TreeNode[]>([]);
 const defaultProps = {
-  children: 'children',
-  label: 'title',
+  children: "children",
+  label: "title",
+};
+
+const deptProps = {
+  children: "children",
+  label: "name",
 };
 const handleCheckChange = (
   _checkedNodes: TreeNode[],
@@ -98,24 +212,308 @@ const handleCheckChange = (
   // console.log(checkedInfo.checkedNodes);
   roleInfo.permsId = checkedInfo.checkedKeys;
   roleInfo.perms = [];
-  checkedInfo.checkedNodes.forEach(val => {
-    if (val.type === '2' ) {
-      roleInfo.perms.push(val.auth);
-    }
+  roleInfo.perms = checkedInfo.checkedNodes;
+};
+
+const handleDeptCheckChange = (
+  _checkedNodes: TreeNode[],
+  checkedInfo: {
+    checkedKeys: number[];
+    checkedNodes: TreeNode[];
+    halfCheckedKeys: number[];
+    halfCheckedNodes: TreeNode[];
+  }
+) => {
+  // console.log('Checked keys:', checkedInfo.checkedKeys);
+  // console.log(checkedInfo.checkedNodes);
+
+  roleInfo.deptIds = checkedInfo.checkedKeys;
+
+  // roleInfo.perms = [];
+  // checkedInfo.checkedNodes.forEach((val) => {
+  //   if (val.type === "2") {
+  //     roleInfo.perms.push(val.auth);
+  //   }
+  // });
+};
+
+//机构列表
+type tableType = {
+  id: string;
+  name: string;
+};
+const tableData = ref<tableType[]>([]);
+const tableProps = ref({
+  value: "id",
+  label: "name",
+  children: "children",
+  checkStrictly: true,
+});
+interface institutionData {
+  name: string;
+  system: string;
+}
+const info = ref<institutionData>({
+  name: "",
+  system: "",
+});
+//获取机构列表
+const deptTreeData = ref<tableType[]>([]);
+const getInstitutionList = () => {
+  // pageInfo.pageNum=item.pageNum
+  api.institutionApi.institutionList(info.value).then((res) => {
+    // if(res.code===200){
+
+    // }
+    tableData.value = [...res.data];
+    deptTreeData.value = JSON.parse(JSON.stringify(res.data));
   });
+  // pageInfo.pageSize=item.pageSize
 };
-   function roleSubmit() {
-    api.roleApi.roleAdd(roleInfo).then((res)=>{
-      console.log(res)
+
+const showRole = ref(false);
+interface Perm {
+  id: string; // 根据实际情况,id 可能是数字或字符串
+}
+const checkedKeys = ref<string[]>([]);
+//选择角色
+function chooseRole(item: any) {
+  roleId.value = item.id;
+  api.roleApi
+    .roleInfo({
+      roleId: item.id,
+      name: "",
+      desc: "",
+      system: "",
+      permsId: [],
+      perms: [],
+    })
+    .then((res) => {
+      // console.log(res);
+      roleInfo.name = res.data.name;
+
+      roleInfo.desc = res.data.remark;
+      roleInfo.deptId = res.data.deptId;
+      roleInfo.permsId = res.data.perms.map((val: Perm) => val.id);
+      roleInfo.perms = res.data.perms;
+      checkedKeys.value = res.data.perms.map((val: Perm) => val.id);
+      if(res.data.dataScope?.deptIds){
+        deptTree.value!.setCheckedKeys(res.data.dataScope?.deptIds, true);
+        roleInfo.dataMark = res.data.dataScope?.dataMark;
+      }else{
+        deptTree.value!.setCheckedKeys([], false);
+        roleInfo.dataMark = '1';
+      }
+      
+      roleInfo.deptIds = res.data.dataScope?.deptIds;
+    });
+  operationType.value = "edit";
+  // roleInfo.name=item.name
+  // roleInfo.desc=item.ramark
+  // roleInfo.desc=item.desc
+  // roleInfo={...item}
+  // for(let key in roleInfo){
+  //   roleInfo[key]=item[key]
+  // }
+  // console.log(roleInfo)
+}
+
+//添加角色页面及配置权限
+const operationType = ref("add");
+function addRole() {
+  showRole.value = true;
+  operationType.value = "add";
+}
+//提交角色信息
+function roleSubmit() {
+  if (operationType.value == "add") {
+    api.roleApi
+      .roleAdd({
+        name: roleInfo.name,
+        desc: roleInfo.desc,
+        system: localStorage.getItem("login_system") || "",
+        permsId: roleInfo.permsId,
+        perms: roleInfo.perms,
+        deptId: roleInfo.deptId,
+        dataScope: {
+          deptIds: roleInfo.deptIds,
+          dataMark: roleInfo.dataMark,
+        },
+      })
+      .then((res) => {
+        // console.log(res);
+        ElMessage.success("操作成功");
+        getRoleList();
+      });
+  } else {
+    api.roleApi
+      .roleUpdate({
+        // roleId: roleInfo.id,
+        id: roleId.value,
+        name: roleInfo.name,
+        desc: roleInfo.desc,
+        system: localStorage.getItem("login_system") || "",
+        permsId: roleInfo.permsId,
+        perms: roleInfo.perms,
+        deptId: roleInfo.deptId,
+        dataScope: {
+          deptIds: roleInfo.deptIds,
+          dataMark: roleInfo.dataMark,
+        },
+      })
+      .then((res) => {
+        // console.log(res);
+        ElMessage.success("操作成功");
+        getRoleList();
+      });
+  }
+}
+//删除角色
+function deleteRole() {
+  api.roleApi
+    .roleDeleteValid({
+      id: roleId.value,
     })
+    .then((res) => {
+      console.log(res);
+      if (res.code == 200) {
+        ElMessageBox.confirm("确认要删除当前数据吗?", "提示", {
+          confirmButtonText: "确认",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+          .then(() => {
+            api.roleApi
+              .roleDelete({
+                id: roleId.value,
+              })
+              .then((res) => {
+                ElMessage.success("操作成功");
+                getRoleList();
+              });
+          })
+          .catch(() => {
+            ElMessage.warning("用户取消操作");
+          });
+      }
+    });
+}
+// const deptIds=re
+//机构单选切换
+const dataMarkChange = () => {
+  deptIds.value = [];
+  disabledTree(deptTreeData.value, roleInfo.deptId);
+  roleInfo.deptIds = deptIds.value;
+  if (deptIds.value.length == 0) {
+    deptTree.value!.setCheckedKeys([], false);
+  } else {
+    deptTree.value!.setCheckedKeys(deptIds.value, true);
   }
-onMounted(() => {
+};
+
+//根据所属id 判断组织架构权限是否可选
+function deptChange(e:any) {
+  // console.log(e)
+  if (e != undefined) {
+    let deptId = e[e?.length - 1];
+    roleInfo.deptId = deptId;
+    // if(roleInfo.dataMark=='1'){
+    // let arr=[...deptTreeData.value]
+    deptIds.value=[]
+    disabledTree(deptTreeData.value, deptId);
+    deptTree.value!.setCheckedKeys(deptIds.value, true);
+    roleInfo.deptIds = deptIds.value;
+  }else{
+    roleInfo.deptId=''
+  }
+
+  // deptTree.value.defaultCheckedKeys=roleInfo.deptIds
+  // }
+}
+const deptIds = ref([]);
+const deptTree = ref<InstanceType<typeof ElTree>>();
+//禁用机构选择
+function disabledTree(list: any[], id: string) {
+  for (let i = 0; i < list.length; i++) {
+    const node = list[i];
+
+    if (roleInfo.dataMark == "1") {
+      if (id) {
+        if (list[i].id != id) {
+          list[i].disabled = true;
+        } else {
+          deptIds.value.push(list[i].id);
+        }
+      } else {
+        list[i].disabled = false;
+      }
+    } else if (roleInfo.dataMark == "2") {
+      if (id) {
+        if (list[i].id != id && list[i].parentId != id) {
+          list[i].disabled = true;
+        } else {
+          list[i].disabled = false;
+          deptIds.value.push(list[i].id);
+        }
+        // if (list[i].disabled == false) {
+        //   deptIds.value.push(list[i].id);
+        // }
+      } else {
+        list[i].disabled = false;
+      }
+
+      //
+    } else {
+      list[i].disabled = false;
+    }
+    // console.log(list[i].disabled)
+
+    if (node.children && node.children.length > 0) {
+      disabledTree(node.children, id);
+    }
+  }
+}
+
+//角色列表
+interface roleitem {
+  [key: string]: any;
+}
+const roleId = ref("");
+const roleList = ref<roleitem>([]);
+function getRoleList() {
+  api.roleApi
+    .roleList({
+      system: localStorage.getItem("login_system") || "",
+      name: "",
+      desc: "",
+      permsId: [],
+      perms: [],
+    })
+    .then((res) => {
+      roleList.value = res.data;
+      // roleId.value = res.data[0].id;
+    });
+}
+onBeforeMount(() => {
   // 对 asyncRoutes 进行预处理并转换为树形结构
   const processedRoutes = preprocessRoutes(asyncRoutes);
-  treeData.value = convertToTreeData(processedRoutes);
+
+  treeData.value = convertToTreeData(0, processedRoutes);
+  
+  api.roleApi.updateConfig({
+    sysConfig:JSON.stringify(processedRoutes),
+    sysPerms:JSON.stringify(treeData.value)
+  }).then(res=>{
+    
+  })
 
 });
+onMounted(() => {
+  // 对 asyncRoutes 进行预处理并转换为树形结构
 
+  getRoleList();
+  getInstitutionList();
+});
 </script>
 
 <style lang="scss" scoped>
@@ -133,4 +531,40 @@ onMounted(() => {
 .active {
   background: #b4b2b2;
 }
+p {
+  margin: 0;
+}
+.role-item {
+  padding: 0 10px;
+  box-sizing: border-box;
+  cursor: pointer;
+  margin-top: 10px;
+
+  > p {
+    span {
+      color: #b4b2b2;
+      font-size: 10px;
+    }
+  }
+  // >p:last-child{
+  //   // margin: 5px 0;
+
+  // }
+}
+.on {
+  background: rgb(242, 242, 242);
+  padding: 0 10px;
+  box-sizing: border-box;
+  margin-top: 10px;
+  cursor: pointer;
+  > p {
+    span {
+      color: #b4b2b2;
+      font-size: 10px;
+    }
+  }
+}
+:deep(.p-5) {
+  padding: 0.2rem !important;
+}
 </style>