#4 login

Sapludināts
wuheng sapludināja 15 revīzijas no wuheng/bingjie uz wuheng/master 1 gadu atpakaļ
55 mainītis faili ar 5004 papildinājumiem un 444 dzēšanām
  1. 1 1
      .vscode/settings.json
  2. 14 6
      package.json
  3. 447 26
      pnpm-lock.yaml
  4. 2 2
      src/config/regexp.ts
  5. 1 1
      src/config/service.ts
  6. 4 8
      src/constants/business.ts
  7. 1 0
      src/hooks/business/use-table.ts
  8. 3 2
      src/locales/lang/zh-cn.ts
  9. 11 0
      src/router/modules/management.ts
  10. 28 5
      src/service/api/auth.ts
  11. 0 0
      src/service/api/login.ts
  12. 0 0
      src/service/api/man.ts
  13. 166 0
      src/service/api/sort.ts
  14. 116 0
      src/service/api/user.ts
  15. 6 1
      src/service/request/index.ts
  16. 7 4
      src/service/request/instance.ts
  17. 1 0
      src/service/request/request.ts
  18. 30 28
      src/store/modules/auth/index.ts
  19. 29 0
      src/typings/api.copy.ts
  20. 9 16
      src/typings/api.d.ts
  21. 4 7
      src/typings/business.d.ts
  22. 2 0
      src/typings/page-route.d.ts
  23. 22 0
      src/typings/sort.ts
  24. 2 0
      src/typings/system.d.ts
  25. 19 8
      src/utils/crypto/index.ts
  26. 7 20
      src/utils/form/rule.ts
  27. 356 0
      src/views/_builtin/login/components/pwd-login/components/verifition/Verify.vue
  28. 260 0
      src/views/_builtin/login/components/pwd-login/components/verifition/Verify/VerifyPoints.vue
  29. 550 0
      src/views/_builtin/login/components/pwd-login/components/verifition/Verify/VerifySlide.vue
  30. 27 0
      src/views/_builtin/login/components/pwd-login/components/verifition/api/index.js
  31. 11 0
      src/views/_builtin/login/components/pwd-login/components/verifition/utils/ase.js
  32. 30 0
      src/views/_builtin/login/components/pwd-login/components/verifition/utils/axios.js
  33. 35 0
      src/views/_builtin/login/components/pwd-login/components/verifition/utils/util.js
  34. 143 51
      src/views/_builtin/login/components/pwd-login/index.vue
  35. 69 0
      src/views/_builtin/login/components/pwd-login/indexCp.vue
  36. 224 0
      src/views/_builtin/login/components/pwd-login/indexppp.vue
  37. 0 1
      src/views/crud/demo/crud.tsx
  38. 1 0
      src/views/index.ts
  39. 88 3
      src/views/management/auth/index.vue
  40. 88 3
      src/views/management/role/index.vue
  41. 110 0
      src/views/management/role/queryUser.vue
  42. 38 0
      src/views/management/role/userPa.vue
  43. 9 1
      src/views/management/route/index.vue
  44. 49 0
      src/views/management/sort/api.ts
  45. 88 0
      src/views/management/sort/components/column-search.vue
  46. 214 0
      src/views/management/sort/components/table-action-add.vue
  47. 181 0
      src/views/management/sort/crud.tsx
  48. 334 0
      src/views/management/sort/index.vue
  49. 126 0
      src/views/management/sort/index.vuebak
  50. 317 0
      src/views/management/sort/indexcopy.vue
  51. 251 0
      src/views/management/sort/indexsss.vue
  52. 132 95
      src/views/management/user/components/table-action-modal.vue
  53. 213 154
      src/views/management/user/index.vue
  54. 127 0
      src/views/management/user/indexCopy.vue
  55. 1 1
      tsconfig.json

+ 1 - 1
.vscode/settings.json

@@ -43,7 +43,7 @@
   "terminal.integrated.fontWeight": 500,
   "terminal.integrated.tabs.enabled": true,
   "workbench.iconTheme": "material-icon-theme",
-  "workbench.colorTheme": "Default Light Modern",
+  "workbench.colorTheme": "蓝色空间——浅色🌷",
   "[html]": {
     "editor.defaultFormatter": "esbenp.prettier-vscode"
   },

+ 14 - 6
package.json

@@ -46,7 +46,6 @@
     "typecheck": "vue-tsc --noEmit --skipLibCheck",
     "lint": "eslint . --fix --ext .js,.jsx,.mjs,.json,.ts,.tsx,.vue",
     "format": "soy prettier-format",
-    "commit": "soy git-commit",
     "cleanup": "soy cleanup",
     "update-pkg": "soy update-pkg",
     "tsx": "tsx",
@@ -57,13 +56,13 @@
   },
   "dependencies": {
     "@ant-design/icons-vue": "^6.1.0",
-    "@fast-crud/fast-crud": "^1.13.6",
-    "@fast-crud/fast-extends": "^1.13.6",
-    "@fast-crud/ui-naive": "^1.13.6",
-    "@fast-crud/ui-interface": "^1.13.6",
     "@antv/data-set": "^0.11.8",
     "@antv/g2": "^4.2.10",
     "@better-scroll/core": "^2.5.1",
+    "@fast-crud/fast-crud": "^1.13.6",
+    "@fast-crud/fast-extends": "^1.13.6",
+    "@fast-crud/ui-interface": "^1.13.6",
+    "@fast-crud/ui-naive": "^1.13.6",
     "@soybeanjs/vue-materials": "^0.1.9",
     "@vueuse/core": "^10.1.2",
     "axios": "1.4.0",
@@ -73,8 +72,8 @@
     "dayjs": "^1.11.7",
     "echarts": "^5.4.2",
     "form-data": "^4.0.0",
+    "local-pkg": "^0.4.3",
     "lodash-es": "^4.17.21",
-    "naive-ui": "2.34.4",
     "pinia": "^2.1.3",
     "print-js": "^1.6.0",
     "qs": "^6.11.2",
@@ -83,7 +82,9 @@
     "vditor": "^3.9.2",
     "vue": "3.3.4",
     "vue-i18n": "^9.2.2",
+    "vue-monoplasty-slide-verify": "^1.3.1",
     "vue-router": "^4.2.1",
+    "vue-slider-vertify": "^0.0.1",
     "vuedraggable": "^4.1.0",
     "wangeditor": "^4.7.15",
     "xgplayer": "^3.0.2"
@@ -99,25 +100,32 @@
     "@types/node": "20.2.1",
     "@types/qs": "^6.9.7",
     "@types/ua-parser-js": "^0.7.36",
+    "@types/vue": "^2.0.0",
     "@unocss/preset-uno": "^0.52.0",
     "@unocss/transformer-directives": "^0.52.0",
     "@unocss/vite": "^0.52.0",
+    "@vicons/fluent": "^0.12.0",
+    "@vicons/ionicons4": "^0.12.0",
     "@vitejs/plugin-vue": "^4.2.3",
     "@vitejs/plugin-vue-jsx": "^3.0.1",
     "conventional-changelog": "^3.1.25",
     "cross-env": "^7.0.3",
     "eslint": "^8.41.0",
     "eslint-config-soybeanjs": "^0.3.7",
+    "fs": "0.0.1-security",
     "lint-staged": "13.2.2",
     "mockjs": "^1.1.0",
+    "naive-ui": "2.34.4",
     "rollup-plugin-visualizer": "^5.9.0",
     "sass": "^1.62.1",
     "simple-git-hooks": "^2.8.1",
     "standard-version": "^9.5.0",
     "tsx": "^3.12.7",
     "typescript": "5.0.4",
+    "unocss": "^0.54.1",
     "unplugin-icons": "^0.16.1",
     "unplugin-vue-components": "0.24.1",
+    "vfonts": "^0.0.3",
     "vite": "^4.3.8",
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-mock": "2.9.8",

+ 447 - 26
pnpm-lock.yaml

@@ -1,5 +1,9 @@
 lockfileVersion: '6.0'
 
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
 patchedDependencies:
   mockjs@1.1.0:
     hash: zljuuegabo7mnbroxnwxab3e2u
@@ -57,12 +61,12 @@ dependencies:
   form-data:
     specifier: ^4.0.0
     version: 4.0.0
+  local-pkg:
+    specifier: ^0.4.3
+    version: 0.4.3
   lodash-es:
     specifier: ^4.17.21
     version: 4.17.21
-  naive-ui:
-    specifier: 2.34.4
-    version: 2.34.4(vue@3.3.4)
   pinia:
     specifier: ^2.1.3
     version: 2.1.3(typescript@5.0.4)(vue@3.3.4)
@@ -87,9 +91,15 @@ dependencies:
   vue-i18n:
     specifier: ^9.2.2
     version: 9.2.2(vue@3.3.4)
+  vue-monoplasty-slide-verify:
+    specifier: ^1.3.1
+    version: 1.3.1
   vue-router:
     specifier: ^4.2.1
     version: 4.2.1(vue@3.3.4)
+  vue-slider-vertify:
+    specifier: ^0.0.1
+    version: 0.0.1
   vuedraggable:
     specifier: ^4.1.0
     version: 4.1.0(vue@3.3.4)
@@ -131,6 +141,9 @@ devDependencies:
   '@types/ua-parser-js':
     specifier: ^0.7.36
     version: 0.7.36
+  '@types/vue':
+    specifier: ^2.0.0
+    version: 2.0.0
   '@unocss/preset-uno':
     specifier: ^0.52.0
     version: 0.52.0
@@ -140,6 +153,12 @@ devDependencies:
   '@unocss/vite':
     specifier: ^0.52.0
     version: 0.52.0(rollup@2.79.1)(vite@4.3.8)
+  '@vicons/fluent':
+    specifier: ^0.12.0
+    version: 0.12.0
+  '@vicons/ionicons4':
+    specifier: ^0.12.0
+    version: 0.12.0
   '@vitejs/plugin-vue':
     specifier: ^4.2.3
     version: 4.2.3(vite@4.3.8)(vue@3.3.4)
@@ -158,12 +177,18 @@ devDependencies:
   eslint-config-soybeanjs:
     specifier: ^0.3.7
     version: 0.3.7(eslint@8.41.0)(svelte@3.59.0)(typescript@5.0.4)
+  fs:
+    specifier: 0.0.1-security
+    version: 0.0.1-security
   lint-staged:
     specifier: 13.2.2
     version: 13.2.2
   mockjs:
     specifier: ^1.1.0
     version: 1.1.0(patch_hash=zljuuegabo7mnbroxnwxab3e2u)
+  naive-ui:
+    specifier: 2.34.4
+    version: 2.34.4(vue@3.3.4)
   rollup-plugin-visualizer:
     specifier: ^5.9.0
     version: 5.9.0(rollup@2.79.1)
@@ -182,12 +207,18 @@ devDependencies:
   typescript:
     specifier: 5.0.4
     version: 5.0.4
+  unocss:
+    specifier: ^0.54.1
+    version: 0.54.1(postcss@8.4.23)(rollup@2.79.1)(vite@4.3.8)
   unplugin-icons:
     specifier: ^0.16.1
     version: 0.16.1
   unplugin-vue-components:
     specifier: 0.24.1
     version: 0.24.1(rollup@2.79.1)(vue@3.3.4)
+  vfonts:
+    specifier: ^0.0.3
+    version: 0.0.3
   vite:
     specifier: ^4.3.8
     version: 4.3.8(@types/node@20.2.1)(sass@1.62.1)
@@ -259,6 +290,10 @@ packages:
     resolution: {integrity: sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==}
     dev: true
 
+  /@antfu/utils@0.7.5:
+    resolution: {integrity: sha512-dlR6LdS+0SzOAPx/TPRhnoi7hE251OVeT2Snw0RguNbBSbjUHdWr0l3vcUUDg26rEysT89kCbtw1lVorBXLLCg==}
+    dev: true
+
   /@antv/adjust@0.2.5:
     resolution: {integrity: sha512-MfWZOkD9CqXRES6MBGRNe27Q577a72EIwyMnE29wIlPliFvJfWwsrONddpGU7lilMpVKecS3WAzOoip3RfPTRQ==}
     dependencies:
@@ -2653,7 +2688,7 @@ packages:
       css-render: ~0.15.12
     dependencies:
       css-render: 0.15.12
-    dev: false
+    dev: true
 
   /@css-render/vue3-ssr@0.15.12(vue@3.3.4):
     resolution: {integrity: sha512-AQLGhhaE0F+rwybRCkKUdzBdTEM/5PZBYy+fSYe1T9z9+yxMuV/k7ZRqa4M69X+EI1W8pa4kc9Iq2VjQkZx4rg==}
@@ -2661,7 +2696,7 @@ packages:
       vue: ^3.0.11
     dependencies:
       vue: 3.3.4
-    dev: false
+    dev: true
 
   /@ctrl/tinycolor@3.6.0:
     resolution: {integrity: sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==}
@@ -2670,7 +2705,7 @@ packages:
 
   /@emotion/hash@0.8.0:
     resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
-    dev: false
+    dev: true
 
   /@esbuild-kit/cjs-loader@2.4.2:
     resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==}
@@ -3036,6 +3071,19 @@ packages:
       - supports-color
     dev: true
 
+  /@iconify/utils@2.1.7:
+    resolution: {integrity: sha512-P8S3z/L1LcV4Qem9AoCfVAaTFGySEMzFEY4CHZLkfRj0Fv9LiR+AwjDgrDrzyI93U2L2mg9JHsbTJ52mF8suNw==}
+    dependencies:
+      '@antfu/install-pkg': 0.1.1
+      '@antfu/utils': 0.7.5
+      '@iconify/types': 2.0.0
+      debug: 4.3.4
+      kolorist: 1.8.0
+      local-pkg: 0.4.3
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
   /@iconify/vue@4.1.1(vue@3.3.4):
     resolution: {integrity: sha512-RL85Bm/DAe8y6rT6pux7D2FJSiUEM/TPfyK7GrbAOfTSwrhvwJW+S5yijdGcmtXouA8MtuH9C7l4hiSE4mLMjg==}
     peerDependencies:
@@ -3137,7 +3185,7 @@ packages:
 
   /@juggle/resize-observer@3.4.0:
     resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
-    dev: false
+    dev: true
 
   /@nodelib/fs.scandir@2.1.5:
     resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
@@ -3615,17 +3663,17 @@ packages:
 
   /@types/katex@0.14.0:
     resolution: {integrity: sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==}
-    dev: false
+    dev: true
 
   /@types/lodash-es@4.17.7:
     resolution: {integrity: sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==}
     dependencies:
       '@types/lodash': 4.14.194
-    dev: false
+    dev: true
 
   /@types/lodash@4.14.194:
     resolution: {integrity: sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==}
-    dev: false
+    dev: true
 
   /@types/minimist@1.2.2:
     resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
@@ -3675,6 +3723,13 @@ packages:
     resolution: {integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==}
     dev: true
 
+  /@types/vue@2.0.0:
+    resolution: {integrity: sha512-WDElkBv/o4lVwu6wYHB06AXs4Xo2fwDjJUpvPRc1QQdzkUSiGFjrYuSCy8raxLE5FObgKq8ND7R5gSZTFLK60w==}
+    deprecated: This is a stub types definition for vuejs (https://github.com/vuejs/vue). vuejs provides its own type definitions, so you don't need @types/vue installed!
+    dependencies:
+      vue: 3.3.4
+    dev: true
+
   /@types/web-bluetooth@0.0.17:
     resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==}
     dev: false
@@ -3809,6 +3864,39 @@ packages:
       eslint-visitor-keys: 3.4.1
     dev: true
 
+  /@unocss/astro@0.54.1(rollup@2.79.1)(vite@4.3.8):
+    resolution: {integrity: sha512-TeY0ZCgJH/iKdswC83/axrJP+27l3D/VfNMVLvoBSiWN9LDR5V5iZqWq+A0Lqh9AHe4RI5ZaQQe2KS24BjOUeA==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      '@unocss/reset': 0.54.1
+      '@unocss/vite': 0.54.1(rollup@2.79.1)(vite@4.3.8)
+    transitivePeerDependencies:
+      - rollup
+      - vite
+    dev: true
+
+  /@unocss/cli@0.54.1(rollup@2.79.1):
+    resolution: {integrity: sha512-yfiRkCoEzuGg5qDl3h4vF4b33mnHhi925COL06X68ti24KbJAZU2ZQmuuyciSMePdf8uk+NWXQSnHg1P9PkaCw==}
+    engines: {node: '>=14'}
+    hasBin: true
+    dependencies:
+      '@ampproject/remapping': 2.2.1
+      '@rollup/pluginutils': 5.0.2(rollup@2.79.1)
+      '@unocss/config': 0.54.1
+      '@unocss/core': 0.54.1
+      '@unocss/preset-uno': 0.54.1
+      cac: 6.7.14
+      chokidar: 3.5.3
+      colorette: 2.0.20
+      consola: 3.2.3
+      fast-glob: 3.3.1
+      magic-string: 0.30.2
+      pathe: 1.1.1
+      perfect-debounce: 1.0.0
+    transitivePeerDependencies:
+      - rollup
+    dev: true
+
   /@unocss/config@0.52.0:
     resolution: {integrity: sha512-RbkFTAoPXPa0oXB/MuS+d0FOF4jXQHA7lm9D4zmKyrlTyPGBlzO/o4aPF9Z9tJUVjG0SRaSU3ZBQ2ZqTZK9P3Q==}
     engines: {node: '>=14'}
@@ -3817,16 +3905,34 @@ packages:
       unconfig: 0.3.7
     dev: true
 
+  /@unocss/config@0.54.1:
+    resolution: {integrity: sha512-g+Hiib2XKCMwu5YpBHeTcBWTW5VrX0glTVbRTmRWMCOHznuMZH0xqc/UMB3/4kfVAynEOszt2V9/RXSGx/iW5Q==}
+    engines: {node: '>=14'}
+    dependencies:
+      '@unocss/core': 0.54.1
+      unconfig: 0.3.10
+    dev: true
+
   /@unocss/core@0.52.0:
     resolution: {integrity: sha512-MGyG1LpiVtyrHmWmXiDRnf7j+JaJua14K058FGBAhNSLaG37dG6xIfwPuVDBOqEI8EgICmNTJs1T/ImQJYWxtw==}
     dev: true
 
+  /@unocss/core@0.54.1:
+    resolution: {integrity: sha512-lbwvGD91liMNEZs3jwXxLrIHIn/J4dkJpeKdosRdm1xObqrkg0+Zx1fVn6X+GOX74yvjQlzbu/ODZEXFQC3mGw==}
+    dev: true
+
   /@unocss/extractor-arbitrary-variants@0.52.0:
     resolution: {integrity: sha512-wJ7a9NWVywHwjWMeB8wN9PHl0fhwOcvAgmhDkyY7A9wXSazaecSMLbKrcnQe7q5bOFGvn5jyxYkk78XZqLWgyg==}
     dependencies:
       '@unocss/core': 0.52.0
     dev: true
 
+  /@unocss/extractor-arbitrary-variants@0.54.1:
+    resolution: {integrity: sha512-4bV0DbDxECihtUbP1UUIXkzSqOkDQ4vJG4VVmKcWbhSMXoRhuOCRkF7j+b9yaDJQtwTfnYgQws0kZFx6jlCVjg==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
   /@unocss/inspector@0.52.0:
     resolution: {integrity: sha512-oGMLht4hEBypglrLeNQWy8JBTvRyX3fdrtYChZpwjYTVsVC1SdF1m0ZjaPt7YQybZ+D4DG7bVCHYqxLgAFq5jw==}
     dependencies:
@@ -3834,6 +3940,43 @@ packages:
       sirv: 2.0.3
     dev: true
 
+  /@unocss/inspector@0.54.1:
+    resolution: {integrity: sha512-/7XIsSMPle6RGj2JR6/tP6rpsMy4+wIn4y3DwAda18apfKO2wDuNmcszCkrpc9ju7g3i0TRwvFzl9DAUCUWtDw==}
+    dependencies:
+      gzip-size: 6.0.0
+      sirv: 2.0.3
+    dev: true
+
+  /@unocss/postcss@0.54.1(postcss@8.4.23):
+    resolution: {integrity: sha512-6f1x/ZIRk6Q7olopWmdVVrVJZv5N45oFT4lSsrYJxbWnyk/D37chH8B+9Q9OrBcahLr7ImxL9DVMkGIBu6rpVw==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      postcss: ^8.4.21
+    dependencies:
+      '@unocss/config': 0.54.1
+      '@unocss/core': 0.54.1
+      css-tree: 2.3.1
+      fast-glob: 3.3.1
+      magic-string: 0.30.2
+      postcss: 8.4.23
+    dev: true
+
+  /@unocss/preset-attributify@0.54.1:
+    resolution: {integrity: sha512-DBQSHH6f7JmxOS49oaoDkxzsoChgeSfTsvoGOZHWN4PanjOalLfIUBst2Jwl15UBwEILokaWNuKTIhGkDtQcig==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
+  /@unocss/preset-icons@0.54.1:
+    resolution: {integrity: sha512-H3VloE4fAs9ufK7FDsG5mUEjNneboY2xgrtdOxDoN33NsapNKTaEmMRjV/9Tz9IdrT2WOEe+eb4qwDzwKpHJlw==}
+    dependencies:
+      '@iconify/utils': 2.1.7
+      '@unocss/core': 0.54.1
+      ofetch: 1.1.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
   /@unocss/preset-mini@0.52.0:
     resolution: {integrity: sha512-P4mQimuZ+yLba2FN3+hKA7anBvjypmEgNof/LdPhTydv138zlhDVly7KlYADISt7QPNIVaGD3U34HLKtgyfBmQ==}
     dependencies:
@@ -3841,6 +3984,26 @@ packages:
       '@unocss/extractor-arbitrary-variants': 0.52.0
     dev: true
 
+  /@unocss/preset-mini@0.54.1:
+    resolution: {integrity: sha512-hsoTkLk1WWS8cxteD7XR7yx3gaDUnTkrIdg9SAIseMeU2VPgzEem2iGpYMmEzJHGOGUREb8wGHyifKtOH+9LbA==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      '@unocss/extractor-arbitrary-variants': 0.54.1
+    dev: true
+
+  /@unocss/preset-tagify@0.54.1:
+    resolution: {integrity: sha512-OeBt+c9AxXiO+AXpHAPudQwkmenIoPGpkDk31Fw2/n4CKdw/bMLodBtQOY1119710h5XDlC0leW6w6xHAnZ8/g==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
+  /@unocss/preset-typography@0.54.1:
+    resolution: {integrity: sha512-wTPs+8XtIjnRy4m6X3n0C6Wem0vVxB1amamDG055SfGvqqvfVf5o6IOQ5mgsVXWAi4jsp0pLSMbtuVvaV4cVWQ==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      '@unocss/preset-mini': 0.54.1
+    dev: true
+
   /@unocss/preset-uno@0.52.0:
     resolution: {integrity: sha512-0pZH0gUJ4hug6B0xV03VNi74GjW49UlnSjwK3xBL6la7WzrgQ+E/mD6CVKxB9Qa0Sfc9qZg8IvVuI97/msdkOA==}
     dependencies:
@@ -3849,6 +4012,21 @@ packages:
       '@unocss/preset-wind': 0.52.0
     dev: true
 
+  /@unocss/preset-uno@0.54.1:
+    resolution: {integrity: sha512-osGEZjE96WeDVTFBGdO1mLqxfkQbrv/4tEK0Rr7x1Q2U+NxHiL8AMkyD8JJSn5EgXCTBFdTUPqXtk5C7IWwnoA==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      '@unocss/preset-mini': 0.54.1
+      '@unocss/preset-wind': 0.54.1
+    dev: true
+
+  /@unocss/preset-web-fonts@0.54.1:
+    resolution: {integrity: sha512-Z3R7KqF6WuIna0Wz5+KbwS7HXF1N+r/n31H4U+VphSdXcbeC8VLQxwgi+5fvxe1/aaQAyylHrVXPx9+bZfJ8NA==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      ofetch: 1.1.1
+    dev: true
+
   /@unocss/preset-wind@0.52.0:
     resolution: {integrity: sha512-y+x+MnXYwcKvPepjK9rbCwp3yiOiXv9XOO5T9YAHdzwrpfAOTjXOAhmW3XAFz2sODoy2xliLYQXsxthyzpf/7w==}
     dependencies:
@@ -3856,10 +4034,43 @@ packages:
       '@unocss/preset-mini': 0.52.0
     dev: true
 
+  /@unocss/preset-wind@0.54.1:
+    resolution: {integrity: sha512-t0wlGQ+YDx4ZsQqBXKKRMm0VpoX8mQk8gO73laALBtwoyECc6MmZApoOhpMvyRnUl5W4pcgtRxbXjeKwSlMSng==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      '@unocss/preset-mini': 0.54.1
+    dev: true
+
+  /@unocss/reset@0.54.1:
+    resolution: {integrity: sha512-qZcmybayQTX4QP7ya7jteN9IySU/ViK8HcCpixHA1ttUrsQeSURgdy01E74p+TsWDH0SY7vYmOy+HbYfQNycqQ==}
+    dev: true
+
   /@unocss/scope@0.52.0:
     resolution: {integrity: sha512-pGTBHdSWGzrcz/QnK4Dd8GUo0a1W3QbRNrIy8L0dgsI9QEBxSiAppiMMnnJZrQwUGDGy5DjkaCksOEArA28fCg==}
     dev: true
 
+  /@unocss/scope@0.54.1:
+    resolution: {integrity: sha512-hwDyv0DEW5ImXlKvr3LLJifli1m/eAnvlEBb2n4l5kgs3rZMGJquqy7LAdxFlZWi54LR586uFdc5zZm2YAWADw==}
+    dev: true
+
+  /@unocss/transformer-attributify-jsx-babel@0.54.1:
+    resolution: {integrity: sha512-/rB57mG2b8VSdcZUhd4L3plwJi2auJsir+Pty83QfR29w74/U5I6Q1DMP6arU1kFUHQtP7iB+Wgts+KX4d12gw==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
+  /@unocss/transformer-attributify-jsx@0.54.1:
+    resolution: {integrity: sha512-V0STWEUBmfN1HBwvPuj1d1MRyfFsmh3z8tahqaGfswb9SJBQcMLXQZ5h1wpUW74nqzCl0GNxon3jVwcwFYxnTQ==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
+  /@unocss/transformer-compile-class@0.54.1:
+    resolution: {integrity: sha512-vsxpTun8cOYx3TQJQ+/Ev0zRNykpE5fSn70oVj1gJuPDYdA76/MMJ/II2CbbfMk70dhu6NrJbXnBtO5y5Geadw==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
   /@unocss/transformer-directives@0.52.0:
     resolution: {integrity: sha512-Epi5Lt1rMl8RgR2InlRw7ddNcUXekiZl+qEEmb2rAHPnROWMNbJB5gCxk9YzczD+8vIgmFUqacMEqEzOUZdpSQ==}
     dependencies:
@@ -3867,6 +4078,19 @@ packages:
       css-tree: 2.3.1
     dev: true
 
+  /@unocss/transformer-directives@0.54.1:
+    resolution: {integrity: sha512-nNltKSo5dTKcjgehPV0o6hD3dJzCixnmsaLNwTtB3w7GUsESn4tl4JnDv0PCPbiuVmZFwLZlFA4aYOfZ/AzLsQ==}
+    dependencies:
+      '@unocss/core': 0.54.1
+      css-tree: 2.3.1
+    dev: true
+
+  /@unocss/transformer-variant-group@0.54.1:
+    resolution: {integrity: sha512-vWHYGmXA5BtVjKmBRxUmr0MumT081ixiGNFiHFIbIwTcnaRklehtTKCWWg0J5mxLe3G20oCPg5a52R4IdJGE2g==}
+    dependencies:
+      '@unocss/core': 0.54.1
+    dev: true
+
   /@unocss/vite@0.52.0(rollup@2.79.1)(vite@4.3.8):
     resolution: {integrity: sha512-Ip2Jyu7dywqEsy3EacnItE+VXB77R72mQ9oA6TyrZpov5ZKoS327kqQSzHS/lYXzZ2yomFq9EsqbKQWIEInH9Q==}
     peerDependencies:
@@ -3887,6 +4111,26 @@ packages:
       - rollup
     dev: true
 
+  /@unocss/vite@0.54.1(rollup@2.79.1)(vite@4.3.8):
+    resolution: {integrity: sha512-HM5kN3FRfXN+TlHvxfN7LJZ41k6KqsHM3l2ez/ImqwKFKCLaQugqDmDDGk0JSiXRNsNDqmTJT+ydTvp16wgTtg==}
+    peerDependencies:
+      vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
+    dependencies:
+      '@ampproject/remapping': 2.2.1
+      '@rollup/pluginutils': 5.0.2(rollup@2.79.1)
+      '@unocss/config': 0.54.1
+      '@unocss/core': 0.54.1
+      '@unocss/inspector': 0.54.1
+      '@unocss/scope': 0.54.1
+      '@unocss/transformer-directives': 0.54.1
+      chokidar: 3.5.3
+      fast-glob: 3.3.1
+      magic-string: 0.30.2
+      vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1)
+    transitivePeerDependencies:
+      - rollup
+    dev: true
+
   /@uppy/companion-client@2.2.2:
     resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
     dependencies:
@@ -3928,6 +4172,14 @@ packages:
       nanoid: 3.3.6
     dev: false
 
+  /@vicons/fluent@0.12.0:
+    resolution: {integrity: sha512-ATCiqPuiJ6RI5GBlD3BIpZ9Xw4MsCA4RpI5oR6MCti4quS4mX1Gp6N74FCzw7lgOj+80rV4HMKhZTVInwimpVQ==}
+    dev: true
+
+  /@vicons/ionicons4@0.12.0:
+    resolution: {integrity: sha512-i+7YwlpCrqD6m9esbZLy1bpVQlh4CKugtS3OzgfNw6BLTQQK6HT7drktaJgcESj/BTr4avdNbAtMQXx56wSVMg==}
+    dev: true
+
   /@vitejs/plugin-vue-jsx@3.0.1(vite@4.3.8)(vue@3.3.4):
     resolution: {integrity: sha512-+Jb7ggL48FSPS1uhPnJbJwWa9Sr90vQ+d0InW+AhBM22n+cfuYqJZDckBc+W3QSHe1WDvewMZfa4wZOtk5pRgw==}
     engines: {node: ^14.18.0 || >=16.0.0}
@@ -4035,6 +4287,14 @@ packages:
       '@vue/compiler-core': 3.3.4
       '@vue/shared': 3.3.4
 
+  /@vue/compiler-sfc@2.7.14:
+    resolution: {integrity: sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==}
+    dependencies:
+      '@babel/parser': 7.21.8
+      postcss: 8.4.23
+      source-map: 0.6.1
+    dev: false
+
   /@vue/compiler-sfc@3.3.4:
     resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==}
     dependencies:
@@ -4347,6 +4607,12 @@ packages:
     engines: {node: '>=0.4.0'}
     dev: false
 
+  /acorn@8.10.0:
+    resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+    dev: true
+
   /acorn@8.8.2:
     resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
     engines: {node: '>=0.4.0'}
@@ -4656,7 +4922,7 @@ packages:
 
   /async-validator@4.2.5:
     resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
-    dev: false
+    dev: true
 
   /async@3.2.4:
     resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
@@ -4873,6 +5139,11 @@ packages:
     engines: {node: '>= 0.8'}
     dev: false
 
+  /cac@6.7.14:
+    resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+    engines: {node: '>=8'}
+    dev: true
+
   /cacache@16.1.3:
     resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@@ -5253,6 +5524,11 @@ packages:
       - supports-color
     dev: true
 
+  /consola@3.2.3:
+    resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
+    engines: {node: ^14.18.0 || >=16.10.0}
+    dev: true
+
   /console-control-strings@1.1.0:
     resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
     dev: true
@@ -5521,7 +5797,7 @@ packages:
     dependencies:
       '@emotion/hash': 0.8.0
       csstype: 3.0.11
-    dev: false
+    dev: true
 
   /css-select@4.3.0:
     resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
@@ -5569,7 +5845,7 @@ packages:
 
   /csstype@3.0.11:
     resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
-    dev: false
+    dev: true
 
   /csstype@3.1.2:
     resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
@@ -5717,14 +5993,14 @@ packages:
       date-fns: '>=2.0.0'
     dependencies:
       date-fns: 2.30.0
-    dev: false
+    dev: true
 
   /date-fns@2.30.0:
     resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
     engines: {node: '>=0.11'}
     dependencies:
       '@babel/runtime': 7.21.5
-    dev: false
+    dev: true
 
   /dateformat@2.2.0:
     resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==}
@@ -5923,6 +6199,10 @@ packages:
     resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
     engines: {node: '>= 0.8'}
 
+  /destr@2.0.0:
+    resolution: {integrity: sha512-FJ9RDpf3GicEBvzI3jxc2XhHzbqD8p4ANw/1kPsFBfTvP1b7Gn/Lg1vO7R9J4IVgoMbyUmFrFGZafJ1hPZpvlg==}
+    dev: true
+
   /destroy@1.2.0:
     resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -7002,7 +7282,7 @@ packages:
 
   /evtd@0.2.4:
     resolution: {integrity: sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==}
-    dev: false
+    dev: true
 
   /execa@5.1.1:
     resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
@@ -7111,6 +7391,17 @@ packages:
       micromatch: 4.0.5
     dev: true
 
+  /fast-glob@3.3.1:
+    resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
+    engines: {node: '>=8.6.0'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.5
+    dev: true
+
   /fast-json-stable-stringify@2.1.0:
     resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
 
@@ -7354,6 +7645,10 @@ packages:
   /fs.realpath@1.0.0:
     resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
 
+  /fs@0.0.1-security:
+    resolution: {integrity: sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==}
+    dev: true
+
   /fsevents@2.3.2:
     resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
     engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -7785,7 +8080,7 @@ packages:
   /highlight.js@11.8.0:
     resolution: {integrity: sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==}
     engines: {node: '>=12.0.0'}
-    dev: false
+    dev: true
 
   /hosted-git-info@2.8.9:
     resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -7921,6 +8216,7 @@ packages:
   /iconv-lite@0.6.3:
     resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
     engines: {node: '>=0.10.0'}
+    requiresBuild: true
     dependencies:
       safer-buffer: 2.1.2
     dev: true
@@ -8454,6 +8750,11 @@ packages:
     hasBin: true
     dev: true
 
+  /jiti@1.19.1:
+    resolution: {integrity: sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==}
+    hasBin: true
+    dev: true
+
   /jju@1.4.0:
     resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
     dev: true
@@ -8557,6 +8858,10 @@ packages:
       semver: 7.5.0
     dev: true
 
+  /jsonc-parser@3.2.0:
+    resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
+    dev: true
+
   /jsoneditor@9.10.2:
     resolution: {integrity: sha512-sT9U8T9MB7We5uyCnofugqYPJtQ5rPJngFlvpdtyFTFKFjOMnlWE1jVhFwjTXwGBoFeiLS+S6rVuhIhJ35Jutw==}
     dependencies:
@@ -8774,7 +9079,6 @@ packages:
   /local-pkg@0.4.3:
     resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
     engines: {node: '>=14'}
-    dev: true
 
   /locate-path@2.0.0:
     resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
@@ -8808,7 +9112,6 @@ packages:
 
   /lodash-es@4.17.21:
     resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
-    dev: false
 
   /lodash.camelcase@4.3.0:
     resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
@@ -8919,6 +9222,13 @@ packages:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.4.15
 
+  /magic-string@0.30.2:
+    resolution: {integrity: sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==}
+    engines: {node: '>=12'}
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.4.15
+    dev: true
+
   /make-fetch-happen@10.2.1:
     resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@@ -9257,6 +9567,15 @@ packages:
     hasBin: true
     dev: true
 
+  /mlly@1.4.0:
+    resolution: {integrity: sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==}
+    dependencies:
+      acorn: 8.10.0
+      pathe: 1.1.1
+      pkg-types: 1.0.3
+      ufo: 1.2.0
+    dev: true
+
   /mobius1-selectr@2.4.13:
     resolution: {integrity: sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==}
     dev: false
@@ -9335,7 +9654,7 @@ packages:
       vooks: 0.2.12(vue@3.3.4)
       vue: 3.3.4
       vueuc: 0.4.51(vue@3.3.4)
-    dev: false
+    dev: true
 
   /namespace-emitter@2.0.1:
     resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
@@ -9391,6 +9710,10 @@ packages:
     resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
     dev: false
 
+  /node-fetch-native@1.2.0:
+    resolution: {integrity: sha512-5IAMBTl9p6PaAjYCnMv5FmqIF6GcZnawAVnzaCG0rX2aYZJ4CxEkZNtVPuTRug7fL7wyM5BQYTlAzcyMPi6oTQ==}
+    dev: true
+
   /node-gyp@9.3.1:
     resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==}
     engines: {node: ^12.13 || ^14.13 || >=16}
@@ -9679,6 +10002,14 @@ packages:
       es-abstract: 1.21.2
     dev: true
 
+  /ofetch@1.1.1:
+    resolution: {integrity: sha512-SSMoktrp9SNLi20BWfB/BnnKcL0RDigXThD/mZBeQxkIRv1xrd9183MtLdsqRYLYSqW0eTr5t8w8MqjNhvoOQQ==}
+    dependencies:
+      destr: 2.0.0
+      node-fetch-native: 1.2.0
+      ufo: 1.2.0
+    dev: true
+
   /on-finished@2.3.0:
     resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
     engines: {node: '>= 0.8'}
@@ -10008,12 +10339,20 @@ packages:
     resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==}
     dev: true
 
+  /pathe@1.1.1:
+    resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==}
+    dev: true
+
   /pause-stream@0.0.11:
     resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==}
     dependencies:
       through: 2.3.8
     dev: false
 
+  /perfect-debounce@1.0.0:
+    resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
+    dev: true
+
   /picocolors@1.0.0:
     resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
 
@@ -10060,6 +10399,14 @@ packages:
       vue-demi: 0.14.5(vue@3.3.4)
     dev: false
 
+  /pkg-types@1.0.3:
+    resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
+    dependencies:
+      jsonc-parser: 3.2.0
+      mlly: 1.4.0
+      pathe: 1.1.1
+    dev: true
+
   /platform@1.3.6:
     resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
     dev: false
@@ -10869,7 +11216,7 @@ packages:
 
   /seemly@0.3.6:
     resolution: {integrity: sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==}
-    dev: false
+    dev: true
 
   /select@1.1.2:
     resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==}
@@ -11608,7 +11955,7 @@ packages:
     hasBin: true
     dependencies:
       '@jridgewell/source-map': 0.3.3
-      acorn: 8.8.2
+      acorn: 8.10.0
       commander: 2.20.3
       source-map-support: 0.5.21
     dev: true
@@ -11733,7 +12080,7 @@ packages:
 
   /treemate@0.3.11:
     resolution: {integrity: sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==}
-    dev: false
+    dev: true
 
   /trim-newlines@3.0.1:
     resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
@@ -11879,6 +12226,10 @@ packages:
     resolution: {integrity: sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==}
     dev: false
 
+  /ufo@1.2.0:
+    resolution: {integrity: sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==}
+    dev: true
+
   /uglify-js@3.17.4:
     resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
     engines: {node: '>=0.8.0'}
@@ -11896,6 +12247,15 @@ packages:
       which-boxed-primitive: 1.0.2
     dev: true
 
+  /unconfig@0.3.10:
+    resolution: {integrity: sha512-tj317lhIq2iZF/NXrJnU1t2UaGUKKz1eL1sK2t63Oq66V9BxqvZV12m55fp/fpQJ+DDmVlLgo7cnLVOZkhlO/A==}
+    dependencies:
+      '@antfu/utils': 0.7.5
+      defu: 6.1.2
+      jiti: 1.19.1
+      mlly: 1.4.0
+    dev: true
+
   /unconfig@0.3.7:
     resolution: {integrity: sha512-1589b7oGa8ILBYpta7TndM5mLHLzHUqBfhszeZxuUBrjO/RoQ52VGVWsS3w0C0GLNxO9RPmqkf6BmIvBApaRdA==}
     dependencies:
@@ -11996,6 +12356,42 @@ packages:
     engines: {node: '>= 10.0.0'}
     dev: true
 
+  /unocss@0.54.1(postcss@8.4.23)(rollup@2.79.1)(vite@4.3.8):
+    resolution: {integrity: sha512-tT2hkDzjf2KV/neYKG/nVYxlpmgn36PGfrT3rE2zk+gaEMU+bU42CisiSkRQ7c2w4d/+zLeCmLz+dj71D8LhFA==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@unocss/webpack': 0.54.1
+    peerDependenciesMeta:
+      '@unocss/webpack':
+        optional: true
+    dependencies:
+      '@unocss/astro': 0.54.1(rollup@2.79.1)(vite@4.3.8)
+      '@unocss/cli': 0.54.1(rollup@2.79.1)
+      '@unocss/core': 0.54.1
+      '@unocss/extractor-arbitrary-variants': 0.54.1
+      '@unocss/postcss': 0.54.1(postcss@8.4.23)
+      '@unocss/preset-attributify': 0.54.1
+      '@unocss/preset-icons': 0.54.1
+      '@unocss/preset-mini': 0.54.1
+      '@unocss/preset-tagify': 0.54.1
+      '@unocss/preset-typography': 0.54.1
+      '@unocss/preset-uno': 0.54.1
+      '@unocss/preset-web-fonts': 0.54.1
+      '@unocss/preset-wind': 0.54.1
+      '@unocss/reset': 0.54.1
+      '@unocss/transformer-attributify-jsx': 0.54.1
+      '@unocss/transformer-attributify-jsx-babel': 0.54.1
+      '@unocss/transformer-compile-class': 0.54.1
+      '@unocss/transformer-directives': 0.54.1
+      '@unocss/transformer-variant-group': 0.54.1
+      '@unocss/vite': 0.54.1(rollup@2.79.1)(vite@4.3.8)
+    transitivePeerDependencies:
+      - postcss
+      - rollup
+      - supports-color
+      - vite
+    dev: true
+
   /unpipe@1.0.0:
     resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
     engines: {node: '>= 0.8'}
@@ -12209,7 +12605,7 @@ packages:
     dependencies:
       evtd: 0.2.4
       vue: 3.3.4
-    dev: false
+    dev: true
 
   /vditor@3.9.2:
     resolution: {integrity: sha512-Uei2HV1WACPE82FRkYLo3ys5E3KR7ucYgbMQNR8t33f2QxZMjwR6e5S/zoXccc9ru6ZWGi35DJE5vEW29hD4lQ==}
@@ -12217,6 +12613,10 @@ packages:
       diff-match-patch: 1.0.5
     dev: false
 
+  /vfonts@0.0.3:
+    resolution: {integrity: sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==}
+    dev: true
+
   /vite-plugin-compression@0.5.1(vite@4.3.8):
     resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
     peerDependencies:
@@ -12348,7 +12748,7 @@ packages:
     dependencies:
       evtd: 0.2.4
       vue: 3.3.4
-    dev: false
+    dev: true
 
   /vue-cropperjs@5.0.0(vue@3.3.4):
     resolution: {integrity: sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==}
@@ -12435,6 +12835,13 @@ packages:
       vue: 3.3.4
     dev: false
 
+  /vue-monoplasty-slide-verify@1.3.1:
+    resolution: {integrity: sha512-oMP9RdBo/2M2D8CcEE1IJCXKWOGPUyFNKFgMwj8+BMEA5Je4wF3jUbCnQe/hNNmV1cUBdeTNp0w/TdlP1A96SQ==}
+    engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
+    dependencies:
+      vue: 2.7.14
+    dev: false
+
   /vue-router@4.2.1(vue@3.3.4):
     resolution: {integrity: sha512-nW28EeifEp8Abc5AfmAShy5ZKGsGzjcnZ3L1yc2DYUo+MqbBClrRP9yda3dIekM4I50/KnEwo1wkBLf7kHH5Cw==}
     peerDependencies:
@@ -12444,6 +12851,13 @@ packages:
       vue: 3.3.4
     dev: false
 
+  /vue-slider-vertify@0.0.1:
+    resolution: {integrity: sha512-0nWYalhUKOX/FERDO/UIMHvJLnn+qffnecyrB0/NblCzc+AvECW1MA78kOvggx2AIOsqGGqTTlx/Nwwm86DAoA==}
+    dependencies:
+      prismjs: 1.29.0
+      vue: 3.3.4
+    dev: false
+
   /vue-template-compiler@2.7.14:
     resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
     dependencies:
@@ -12463,6 +12877,13 @@ packages:
       typescript: 5.0.4
     dev: true
 
+  /vue@2.7.14:
+    resolution: {integrity: sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==}
+    dependencies:
+      '@vue/compiler-sfc': 2.7.14
+      csstype: 3.1.2
+    dev: false
+
   /vue@3.3.4:
     resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
     dependencies:
@@ -12503,7 +12924,7 @@ packages:
       vdirs: 0.1.8(vue@3.3.4)
       vooks: 0.2.12(vue@3.3.4)
       vue: 3.3.4
-    dev: false
+    dev: true
 
   /wangeditor@4.7.15:
     resolution: {integrity: sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==}

+ 2 - 2
src/config/regexp.ts

@@ -6,8 +6,8 @@ export const REGEXP_PHONE =
 export const REGEXP_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
 
 /** 密码正则(密码为6-18位数字/字符/符号的组合) */
-export const REGEXP_PWD =
-  /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){6,18}$/;
+export const REGEXP_PWD = /^([0-9]{6,18}|[a-zA-Z]{6,18}|[^0-9a-zA-Z]{6,18})$/;
+  // /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){6,18}$/;
 
 /** 6位数字验证码正则 */
 export const REGEXP_CODE_SIX = /^\d{6}$/;

+ 1 - 1
src/config/service.ts

@@ -43,4 +43,4 @@ export const ERROR_STATUS = {
 export const NO_ERROR_MSG_CODE: (string | number)[] = [];
 
 /** token失效需要刷新token的code(这里的66666只是个例子,需要将后端表示token过期的code填进来) */
-export const REFRESH_TOKEN_CODE: (string | number)[] = [66666];
+export const REFRESH_TOKEN_CODE: (string | number)[] = ['token'];

+ 4 - 8
src/constants/business.ts

@@ -31,15 +31,11 @@ export const genderOptions: Common.OptionWithKey<UserManagement.GenderKey>[] = [
 
 /** 用户状态 */
 export const userStatusLabels: Record<UserManagement.UserStatusKey, string> = {
-  1: '启用',
-  2: '禁用',
-  3: '冻结',
-  4: '软删除'
+  Y: 'Y',
+  N: 'N',
 };
 
 export const userStatusOptions: Common.OptionWithKey<UserManagement.UserStatusKey>[] = [
-  { value: '1', label: userStatusLabels['1'] },
-  { value: '2', label: userStatusLabels['2'] },
-  { value: '3', label: userStatusLabels['3'] },
-  { value: '4', label: userStatusLabels['4'] }
+  { value: 'Y', label: userStatusLabels['Y'] },
+  { value: 'N', label: userStatusLabels['N'] },
 ];

+ 1 - 0
src/hooks/business/use-table.ts

@@ -32,6 +32,7 @@ type ApiFn<Params = ApiParams, TableData = Record<string, unknown>> = (
  */
 type TransformedTableData<TableData = Record<string, unknown>> = {
   data: TableData[];
+	status:boolean;
   pageNum: number;
   pageSize: number;
   total: number;

+ 3 - 2
src/locales/lang/zh-cn.ts

@@ -1,4 +1,4 @@
-import type { LocaleMessages } from 'vue-i18n';
+ import type { LocaleMessages } from 'vue-i18n';
 
 const locale: LocaleMessages<I18nType.Schema> = {
   message: {
@@ -75,7 +75,8 @@ const locale: LocaleMessages<I18nType.Schema> = {
         auth: '权限管理',
         role: '角色管理',
         route: '路由管理',
-        user: '用户管理'
+        user: '用户管理',
+        sort: '课程分类'
       },
       about: '关于'
     }

+ 11 - 0
src/router/modules/management.ts

@@ -36,6 +36,17 @@ const management: AuthRoute.Route = {
         icon: 'ic:round-manage-accounts'
       }
     },
+    {
+      name: 'management_sort',
+      path: '/management/sort',
+      component: 'self',
+      meta: {
+        title: '课程分类',
+        i18nTitle: 'message.routes.management.sort',
+        requiresAuth: true,
+        icon: 'material-symbols:sort'
+      }
+    },
     {
       name: 'management_route',
       path: '/management/route',

+ 28 - 5
src/service/api/auth.ts

@@ -1,4 +1,4 @@
-import { mockRequest } from '../request';
+import { request,mockRequest } from '../request';
 
 /**
  * 获取验证码
@@ -6,16 +6,39 @@ import { mockRequest } from '../request';
  * @returns - 返回boolean值表示是否发送成功
  */
 export function fetchSmsCode(phone: string) {
-  return mockRequest.post<boolean>('/getSmsCode', { phone });
+  return request.post<boolean>('/getSmsCode', { phone });
 }
 
+// 参数接口
+export interface AdminLoginParams {
+  username?: string;
+  passwd?: string;
+	captchaVerification?: string
+}
+
+// 响应接口
+export interface AdminLoginRes {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+/**
+ * 管理员登录
+ * @param {object} params AdminPojo
+ * @param {string} params.username
+ * @param {string} params.passwd
+ * @returns
+ */
+// export function adminLogin(params: AdminLoginParams) {
+//   return request.post(`/adminLogin`, params);
+// }
 /**
  * 登录
  * @param userName - 用户名
  * @param password - 密码
  */
-export function fetchLogin(userName: string, password: string) {
-  return mockRequest.post<ApiAuth.Token>('/login', { userName, password });
+export function fetchLogin(params: AdminLoginParams) {
+  return request.post<ApiAuth.Token>('/adminLogin',params);
 }
 
 /** 获取用户信息 */
@@ -37,5 +60,5 @@ export function fetchUserRoutes(userId: string) {
  * @param refreshToken
  */
 export function fetchUpdateToken(refreshToken: string) {
-  return mockRequest.post<ApiAuth.Token>('/updateToken', { refreshToken });
+  return request.post<ApiAuth.Token>('/refreshToken',  refreshToken );
 }

+ 0 - 0
src/service/api/login.ts


+ 0 - 0
src/service/api/man.ts


+ 166 - 0
src/service/api/sort.ts

@@ -0,0 +1,166 @@
+import { request } from '../request';
+
+
+// 查询全部课程类别
+// 响应接口
+export interface SelectAll_1Res {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+
+/**
+ * 查询全部课程类别
+ * @returns
+ */
+export function selectAll_1() {
+  return request.get(`/selectAll`);
+}
+
+
+// 添加课程类别
+// 参数接口
+export interface AddEasEduCategoryParams {
+  id?: number|null;
+  name?: string|null;
+  description?: string|null;
+  createTime?: string;
+  modifyTime?: string;
+  createUid?: number|null;
+  disabled?: string|null;
+}
+
+// 响应接口
+export interface AddEasEduCategoryRes {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+
+/**
+ * 添加课程类别
+ * @param {object} params EasEduCategory
+ * @param {number} params.id
+ * @param {string} params.name 学科名称
+ * @param {string} params.description 学科描述
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {number} params.createUid 创建用户ID
+ * @param {string} params.disabled 状态
+ * @returns
+ */
+export function addEasEduCategory(params: AddEasEduCategoryParams){
+  return request.post(`/addEasEduCategory`, params);
+}
+
+
+// 根据Id删除课程类别
+// 响应接口
+export interface DeleteByIdRes {
+  status: boolean;
+  msg: string;
+  data: string;
+}
+
+/**
+ * 根据Id删除课程类别
+ * @param {string} id
+  * @returns
+ */
+export function deleteById(id: number){
+  return request.delete(`/deleteById/${id}`);
+}
+
+
+
+// 课程类别更新
+// 参数接口
+export interface UpdateEasEduCategoryParams {
+  id?: number|null;
+  name?: string|null;
+  description?: string|null;
+  createTime?:  string;
+  modifyTime?: string;
+  createUid?: number|null;
+  disabled?: string|null;
+}
+
+// 响应接口
+export interface UpdateEasEduCategoryRes {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+
+/**
+ * 课程类别更新
+ * @param {object} params EasEduCategory
+ * @param {number} params.id
+ * @param {string} params.name 学科名称
+ * @param {string} params.description 学科描述
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {number} params.createUid 创建用户ID
+ * @param {string} params.disabled 状态
+ * @returns
+ */
+export function updateEasEduCategory(params: UpdateEasEduCategoryParams) {
+  return request.post(`/updateEasEduCategory`, params);
+}
+
+
+// 根据Id查询对应课程类别
+// 响应接口
+export interface SelectById_1Res {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+
+/**
+ * 根据Id查询对应课程类别
+ * @param {string} id
+  * @returns
+ */
+export function selectById_1(id: number) {
+  return request.get(`/selectById?id=${id}`);
+}
+
+
+// 根据条件进行查询课程类别
+// 参数接口
+export interface SelectByCondition_1Params {
+  id?: number;
+  name?: string;
+  description?: string;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+  disabled?: string;
+}
+
+// 响应接口
+export interface SelectByCondition_1Res {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+  total: number;
+}
+
+/**
+ * 根据条件进行查询课程类别
+ * @param {string} pageNum
+ * @param {string} pageSize
+ * @param {object} params EasEduCategory
+ * @param {number} params.id
+ * @param {string} params.name 学科名称
+ * @param {string} params.description 学科描述
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {number} params.createUid 创建用户ID
+ * @param {string} params.disabled 状态
+ * @returns
+ */
+export function selectByCondition_1(pageNum: number, pageSize: number, params: SelectByCondition_1Params){
+  return request.post(`/selectByCondition?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}

+ 116 - 0
src/service/api/user.ts

@@ -0,0 +1,116 @@
+import { request } from '../request';
+
+// 参数接口
+export interface UpdateParams {
+  id?: number;
+  name?: string;
+  isActive?: Record<string, unknown>;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+  disabled?: string;
+  description?: string;
+}
+// 响应接口
+export interface UpdateRes {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+
+/**
+ * 更新权限
+ * @param {object} params EasSysPermission
+ * @param {number} params.id ID
+ * @param {string} params.name 权限名称
+ * @param {object} params.isActive 是否激活
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {number} params.createUid 创建用户ID
+ * @param {string} params.disabled 状态
+ * @param {string} params.description 权限描述
+ * @returns
+ */
+export function update(params: UpdateParams) {
+  return request.put(`/permission/update`, params);
+}
+// 参数接口
+export interface QueryParams {
+  id?: number;
+  name?: string;
+  description?: string;
+  isActive?: string;
+  createTime?: string;
+  modifyTime?: string;
+  createUid?: number;
+  disabled?: string;
+}
+
+// 响应接口
+export interface QueryRes {
+  total: number;
+  data: Record<string, unknown>;
+}
+
+/**
+ * 查询权限
+ * @param {string} pageNum
+ * @param {string} pageSize
+ * @param {object} params EasSysPermission
+ * @param {number} params.id ID
+ * @param {string} params.name 权限名称
+ * @param {object} params.isActive 是否激活
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {number} params.createUid 创建用户ID
+ * @param {string} params.disabled 状态
+ * @param {string} params.description 权限描述
+ * @returns
+ */
+export function query(pageNum: number, pageSize: number, params: QueryParams) {
+  return request.post(`/permission/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}
+// 参数接口
+export interface Query_1Params {
+  id?: number;
+  depname?: string;
+  address?: string;
+  phone?: string;
+  email?: string;
+  manager?: string;
+  createTime?: string;
+  modifyTime?: string;
+  createUid?: number;
+  disabled?: string;
+}
+
+// 响应接口
+export interface Query_1Res {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+  total: number;
+}
+
+/**
+ * 查询部门
+ * @param {string} pageNum
+ * @param {string} pageSize
+ * @param {object} params EasSysDepartment
+ * @param {number} params.id
+ * @param {string} params.depname 部门名称
+ * @param {string} params.address 部门地址
+ * @param {string} params.phone 部门电话
+ * @param {string} params.email 部门电子邮箱
+ * @param {string} params.manager 部门负责人
+ * @param {object} params.createTime 创建时间
+ * @param {object} params.modifyTime 修改时间
+ * @param {number} params.createUid 创建用户ID
+ * @param {string} params.disabled 状态
+ * @returns
+ */
+export function query_1(pageNum: number, pageSize: number, params: Query_1Params) {
+  return request.post(`/department/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}
+
+

+ 6 - 1
src/service/request/index.ts

@@ -5,6 +5,11 @@ const { url, proxyPattern } = getServiceEnvConfig(import.meta.env);
 
 const isHttpProxy = import.meta.env.VITE_HTTP_PROXY === 'Y';
 
-export const request = createRequest({ baseURL: isHttpProxy ? proxyPattern : url });
+export const request = createRequest({ baseURL: isHttpProxy ? proxyPattern : url,
+	headers: {
+		'X-Requested-With': 'XMLHttpRequest',
+    'Content-Type': 'application/json; charset=UTF-8'
+	}
+});
 
 export const mockRequest = createRequest({ baseURL: '/mock' });

+ 7 - 4
src/service/request/instance.ts

@@ -43,14 +43,18 @@ export default class CustomAxiosInstance {
   setInterceptor() {
     this.instance.interceptors.request.use(
       async config => {
+				console.log("--------------------", config);
         const handleConfig = { ...config };
         if (handleConfig.headers) {
           // 数据转换
+					console.log(handleConfig.headers);
           const contentType = handleConfig.headers['Content-Type'] as UnionKey.ContentType;
+					// console.log(contentType);
           handleConfig.data = await transformRequestData(handleConfig.data, contentType);
           // 设置token
-          handleConfig.headers.Authorization = localStg.get('token') || '';
+          handleConfig.headers.Authorization = localStg.get('token') ||'';
         }
+				console.log(handleConfig);
         return handleConfig;
       },
       (axiosError: AxiosError) => {
@@ -61,14 +65,13 @@ export default class CustomAxiosInstance {
     this.instance.interceptors.response.use(
       (async response => {
         const { status } = response;
-        if (status === 200 || status < 300 || status === 304) {
+        if (status === 200 || status < 300 || status === 304 ) {
           const backend = response.data;
           const { codeKey, dataKey, successCode } = this.backendConfig;
           // 请求成功
-          if (backend[codeKey] === successCode) {
+          if (backend[codeKey] === successCode ) {
             return handleServiceResult(null, backend[dataKey]);
           }
-
           // token失效, 刷新token
           if (REFRESH_TOKEN_CODE.includes(backend[codeKey])) {
             const config = await handleRefreshToken(response.config);

+ 1 - 0
src/service/request/request.ts

@@ -19,6 +19,7 @@ interface RequestParam {
  * @param backendConfig - 后端接口字段配置
  */
 export function createRequest(axiosConfig: AxiosRequestConfig, backendConfig?: Service.BackendResultConfig) {
+	console.log( "axiosConfig",  axiosConfig )
   const customInstance = new CustomAxiosInstance(axiosConfig, backendConfig);
 
   /**

+ 30 - 28
src/store/modules/auth/index.ts

@@ -1,7 +1,7 @@
 import { unref, nextTick } from 'vue';
 import { defineStore } from 'pinia';
 import { router } from '@/router';
-import { fetchLogin, fetchUserInfo } from '@/service';
+import { fetchLogin, fetchUserInfo,AdminLoginParams } from '@/service';
 import { useRouterPush } from '@/composables';
 import { localStg } from '@/utils';
 import { useTabStore } from '../tab';
@@ -107,14 +107,16 @@ export const useAuthStore = defineStore('auth-store', {
 
       return successFlag;
     },
+		
     /**
      * 登录
      * @param userName - 用户名
      * @param password - 密码
      */
-    async login(userName: string, password: string) {
+
+    async login(params:AdminLoginParams) {
       this.loginLoading = true;
-      const { data } = await fetchLogin(userName, password);
+      const { data } = await fetchLogin(params);
       if (data) {
         await this.handleActionAfterLogin(data);
       }
@@ -124,30 +126,30 @@ export const useAuthStore = defineStore('auth-store', {
      * 更换用户权限(切换账号)
      * @param userRole
      */
-    async updateUserRole(userRole: Auth.RoleType) {
-      const { resetRouteStore, initAuthRoute } = useRouteStore();
-
-      const accounts: Record<Auth.RoleType, { userName: string; password: string }> = {
-        super: {
-          userName: 'Super',
-          password: 'super123'
-        },
-        admin: {
-          userName: 'Admin',
-          password: 'admin123'
-        },
-        user: {
-          userName: 'User01',
-          password: 'user01123'
-        }
-      };
-      const { userName, password } = accounts[userRole];
-      const { data } = await fetchLogin(userName, password);
-      if (data) {
-        await this.loginByToken(data);
-        resetRouteStore();
-        initAuthRoute();
-      }
-    }
+    // async updateUserRole(userRole: Auth.RoleType) {
+    //   const { resetRouteStore, initAuthRoute } = useRouteStore();
+
+    //   const accounts: Record<Auth.RoleType, { userName: string; password: string }> = {
+    //     super: {
+    //       userName: 'Super',
+    //       password: 'super123'
+    //     },
+    //     admin: {
+    //       userName: 'Admin',
+    //       password: 'admin123'
+    //     },
+    //     user: {
+    //       userName: 'User01',
+    //       password: 'user01123'
+    //     }
+    //   };
+    //   const { userName, password } = accounts[userRole];
+    //   const { data } = await fetchLogin(userName, password);
+    //   if (data) {
+    //     await this.loginByToken(data);
+    //     resetRouteStore();
+    //     initAuthRoute();
+    //   }
+    // }
   }
 });

+ 29 - 0
src/typings/api.copy.ts

@@ -0,0 +1,29 @@
+declare namespace ApiUserMa {
+	interface User {
+		/** 用户id */
+		id?: number;
+		name: number;
+		/** 用户名 */
+		description: string | null;
+		/** 用户年龄 */
+		createTime: number | null;
+		modifyTime: string | null;
+		createUid: number;
+		// /**
+		//  * 用户性别
+		//  * - 0: 女
+		//  * - 1: 男
+		//  */
+		// gender: '0' | '1' | null;
+		// /** 用户手机号码 */
+		// phone: string;
+		// /** 用户邮箱 */
+		// email: string | null;
+		/**
+		 * 用户状态
+		 * - N: 启用
+		 * - Y: 禁用
+		 */
+		disabled: "N" | "Y" | null;
+	}
+}

+ 9 - 16
src/typings/api.d.ts

@@ -25,28 +25,21 @@ declare namespace ApiRoute {
 declare namespace ApiUserManagement {
   interface User {
     /** 用户id */
-    id: string;
+    id: number | null;
     /** 用户名 */
-    userName: string | null;
+    name: string | null;
     /** 用户年龄 */
-    age: number | null;
-    /**
-     * 用户性别
-     * - 0: 女
-     * - 1: 男
-     */
-    gender: '0' | '1' | null;
+    description: string | null;
+    createTime: string;
     /** 用户手机号码 */
-    phone: string;
+    modifyTime: string;
     /** 用户邮箱 */
-    email: string | null;
+    createUid: number | null;
     /**
      * 用户状态
-     * - 1: 启用
-     * - 2: 禁用
-     * - 3: 冻结
-     * - 4: 软删除
+     * - Y: 启用
+     * - N: 禁用
      */
-    userStatus: '1' | '2' | '3' | '4' | null;
+    disabled: 'Y' | 'N'|null ;
   }
 }

+ 4 - 7
src/typings/business.d.ts

@@ -24,7 +24,7 @@ declare namespace UserManagement {
     /** 序号 */
     index: number;
     /** 表格的key(id) */
-    key: string;
+    key: number;
   }
 
   /**
@@ -32,14 +32,11 @@ declare namespace UserManagement {
    * - 0: 女
    * - 1: 男
    */
-  type GenderKey = NonNullable<User['gender']>;
+  // type GenderKey = NonNullable<User['gender']>;
 
   /**
    * 用户状态
-   * - 1: 启用
-   * - 2: 禁用
-   * - 3: 冻结
-   * - 4: 软删除
+
    */
-  type UserStatusKey = NonNullable<User['userStatus']>;
+  type UserStatusKey = NonNullable<User['disabled']>;
 }

+ 2 - 0
src/typings/page-route.d.ts

@@ -57,6 +57,7 @@ declare namespace PageRoute {
     | 'management_auth'
     | 'management_role'
     | 'management_route'
+    | 'management_sort'
     | 'management_user'
     | 'multi-menu'
     | 'multi-menu_first'
@@ -115,6 +116,7 @@ declare namespace PageRoute {
     | 'management_auth'
     | 'management_role'
     | 'management_route'
+    | 'management_sort'
     | 'management_user'
     | 'multi-menu_first_second-new_third'
     | 'multi-menu_first_second'

+ 22 - 0
src/typings/sort.ts

@@ -0,0 +1,22 @@
+declare namespace CourseSort {
+  interface User extends ApiUserMa.User {
+    /** 序号 */
+    index: number;
+    /** 表格的key(id) */
+    key: string;
+  }
+
+  /**
+   * 用户性别
+   * - 0: 女
+   * - 1: 男
+   */
+  // type GenderKey = NonNullable<User['gender']>;
+
+  /**
+   * 用户状态
+   * - 1: 启用
+   * - 2: 禁用
+   */
+  type UserStatusKey = NonNullable<User['disabled']>;
+}

+ 2 - 0
src/typings/system.d.ts

@@ -379,6 +379,8 @@ declare namespace I18nType {
         role: string;
         route: string;
         user: string;
+			  sort: string;
+				usdt:string;
       };
       about: string;
     };

+ 19 - 8
src/utils/crypto/index.ts

@@ -1,14 +1,23 @@
 import CryptoJS from 'crypto-js';
 
-const CryptoSecret = '__CryptoJS_Secret__';
+const keyword = 'eas-key-password';
 
 /**
  * 加密数据
  * @param data - 数据
  */
 export function encrypto(data: any) {
-  const newData = JSON.stringify(data);
-  return CryptoJS.AES.encrypt(newData, CryptoSecret).toString();
+	const time = Date.now();
+	 //转码
+	 const wordStr = CryptoJS.enc.Utf8.parse(time + "" + data);
+	 const key = CryptoJS.enc.Utf8.parse(keyword);
+  // const newData = JSON.stringify(data);
+	//加密
+  const cryptoStr = CryptoJS.AES.encrypt(wordStr, key, {
+    mode: CryptoJS.mode.ECB, //模式
+    padding: CryptoJS.pad.Pkcs7, //补零
+  });
+ return cryptoStr.toString();
 }
 
 /**
@@ -16,10 +25,12 @@ export function encrypto(data: any) {
  * @param cipherText - 密文
  */
 export function decrypto(cipherText: string) {
-  const bytes = CryptoJS.AES.decrypt(cipherText, CryptoSecret);
-  const originalText = bytes.toString(CryptoJS.enc.Utf8);
-  if (originalText) {
-    return JSON.parse(originalText);
-  }
+	const key = CryptoJS.enc.Utf8.parse(keyword);
+	//解密
+  const cryptoStr = CryptoJS.AES.decrypt(cipherText, key, {
+    mode: CryptoJS.mode.ECB, //模式
+    padding: CryptoJS.pad.Pkcs7, //补零
+  });
+  return CryptoJS.enc.Utf8.stringify(cryptoStr).toString();
   return null;
 }

+ 7 - 20
src/utils/form/rule.ts

@@ -1,6 +1,6 @@
 import type { Ref } from 'vue';
 import type { FormItemRule } from 'naive-ui';
-import { REGEXP_CODE_SIX, REGEXP_EMAIL, REGEXP_PHONE, REGEXP_PWD } from '@/config';
+import { REGEXP_PWD } from '@/config';
 
 /** 创建自定义错误信息的必填表单规则 */
 export const createRequiredFormRule = (message = '不能为空'): FormItemRule => ({ required: true, message });
@@ -10,30 +10,17 @@ export const requiredFormRule = createRequiredFormRule();
 /** 表单规则 */
 interface CustomFormRules {
   /** 手机号码 */
-  phone: FormItemRule[];
-  /** 密码 */
-  pwd: FormItemRule[];
-  /** 验证码 */
-  code: FormItemRule[];
-  /** 邮箱 */
-  email: FormItemRule[];
+  createTime: FormItemRule[];
+	pwd:FormItemRule[];
 }
 
 /** 表单规则 */
 export const formRules: CustomFormRules = {
-  phone: [
-    createRequiredFormRule('请输入手机号码'),
-    { pattern: REGEXP_PHONE, message: '手机号码格式错误', trigger: 'input' }
+  createTime: [
+    createRequiredFormRule('请输入创建时间'),
+    { pattern: '', message: '不能为空', trigger: 'input' }
   ],
-  pwd: [
-    createRequiredFormRule('请输入密码'),
-    { pattern: REGEXP_PWD, message: '密码为6-18位数字/字符/符号,至少2种组合', trigger: 'input' }
-  ],
-  code: [
-    createRequiredFormRule('请输入验证码'),
-    { pattern: REGEXP_CODE_SIX, message: '验证码格式错误', trigger: 'input' }
-  ],
-  email: [{ pattern: REGEXP_EMAIL, message: '邮箱格式错误', trigger: 'blur' }]
+	pwd: [{ pattern: REGEXP_PWD, message: '密码格式错误', trigger: 'blur' }]
 };
 
 /** 是否为空字符串 */

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 356 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/Verify.vue


+ 260 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/Verify/VerifyPoints.vue

@@ -0,0 +1,260 @@
+<template>
+    <div style="position: relative"
+        >
+        <div class="verify-img-out">
+            <div class="verify-img-panel" :style="{'width': setSize.imgWidth,
+                                                   'height': setSize.imgHeight,
+                                                   'background-size' : setSize.imgWidth + ' '+ setSize.imgHeight,
+                                                   'margin-bottom': vSpace + 'px'}"
+                                                    >
+                <div class="verify-refresh" style="z-index:3" @click="refresh" v-show="showRefresh">
+                    <i class="iconfont icon-refresh"></i>
+                </div>
+                <img :src="'data:image/png;base64,'+pointBackImgBase" 
+                ref="canvas"
+                alt=""  style="width:100%;height:100%;display:block"
+                @click="bindingClick?canvasClick($event):undefined">
+
+                <div v-for="(tempPoint, index) in tempPoints" :key="index" class="point-area"
+                     :style="{
+                        'background-color':'#1abd6c',
+                        color:'#fff',
+                        'z-index':9999,
+                        width:'20px',
+                        height:'20px',
+                        'text-align':'center',
+                        'line-height':'20px',
+                        'border-radius': '50%',
+                        position:'absolute',
+                        top:parseInt(tempPoint.y-10) + 'px',
+                        left:parseInt(tempPoint.x-10) + 'px'
+                     }">
+                    {{index + 1}}
+                </div>
+            </div>
+        </div>
+        <!-- 'height': this.barSize.height, -->
+        <div class="verify-bar-area"
+             :style="{'width': setSize.imgWidth,
+                      'color': this.barAreaColor,
+                      'border-color': this.barAreaBorderColor,
+                      'line-height':this.barSize.height}">
+            <span class="verify-msg">{{text}}</span>
+        </div>
+    </div>
+</template>
+<script type="text/babel">
+    /**
+     * VerifyPoints
+     * @description 点选
+     * */
+    import {resetSize, _code_chars, _code_color1, _code_color2} from './../utils/util'
+    import {aesEncrypt} from "./../utils/ase"
+    import {reqGet,reqCheck}  from "./../api/index"
+    import { computed, onMounted, reactive, ref,watch,nextTick,toRefs, watchEffect,getCurrentInstance} from 'vue';
+    export default {
+        name: 'VerifyPoints',
+        props: {
+            //弹出式pop,固定fixed
+            mode: {
+                type: String,
+                default: 'fixed'
+            },
+            captchaType:{
+                type:String,
+            },
+            //间隔
+            vSpace: {
+                type: Number,
+                default: 5
+            },
+            imgSize: {
+                type: Object,
+                default() {
+                    return {
+                        width: '310px',
+                        height: '155px'
+                    }
+                }
+            },
+            barSize: {
+                type: Object,
+                default() {
+                    return {
+                        width: '310px',
+                        height: '40px'
+                    }
+                }
+            }
+        },
+        setup(props,context){
+            const {mode,captchaType,vSpace,imgSize,barSize} = toRefs(props)
+            const { proxy } = getCurrentInstance();
+            let secretKey = ref(''),           //后端返回的ase加密秘钥
+                checkNum = ref(3),             //默认需要点击的字数
+                fontPos = reactive([]),            //选中的坐标信息
+                checkPosArr = reactive([]),        //用户点击的坐标
+                num = ref(1),                 //点击的记数
+                pointBackImgBase = ref(''),    //后端获取到的背景图片
+                poinTextList = reactive([]),        //后端返回的点击字体顺序
+                backToken = ref(''),           //后端返回的token值
+                setSize = reactive({
+                    imgHeight: 0,
+                    imgWidth: 0,
+                    barHeight: 0,
+                    barWidth: 0
+                }),
+                tempPoints = reactive([]),
+                text = ref(''),
+                barAreaColor = ref(undefined),
+                barAreaBorderColor = ref(undefined),
+                showRefresh = ref(true),
+                bindingClick = ref(true)
+
+                
+               
+
+                const init = ()=>{
+                    //加载页面
+                    fontPos.splice(0, fontPos.length)
+                    checkPosArr.splice(0, checkPosArr.length)
+                    num.value = 1
+                    getPictrue();
+                    nextTick(() => {
+                        let {imgHeight,imgWidth,barHeight,barWidth} = resetSize(proxy)
+                        setSize.imgHeight = imgHeight
+                        setSize.imgWidth = imgWidth
+                        setSize.barHeight = barHeight
+                        setSize.barWidth = barWidth
+                        proxy.$parent.$emit('ready', proxy)
+                    })
+                }
+                 onMounted(()=>{
+                    // 禁止拖拽
+                    init()
+                    proxy.$el.onselectstart = function () {
+                        return false
+                    }
+                })
+                const canvas = ref(null)
+                const canvasClick = (e)=>{
+                    checkPosArr.push(getMousePos(canvas, e));
+                    if (num.value == checkNum.value) {
+                        num.value = createPoint(getMousePos(canvas, e));
+                        //按比例转换坐标值
+                        let arr = pointTransfrom(checkPosArr,setSize)
+                        checkPosArr.length = 0
+                        checkPosArr.push(...arr);
+                        //等创建坐标执行完
+                        setTimeout(() => {
+                            // var flag = this.comparePos(this.fontPos, this.checkPosArr);
+                            //发送后端请求
+                            var captchaVerification = secretKey.value? aesEncrypt(backToken.value+'---'+JSON.stringify(checkPosArr),secretKey.value):backToken.value+'---'+JSON.stringify(checkPosArr)
+                            let data = {
+                                captchaType:captchaType.value,
+                                "pointJson":secretKey.value? aesEncrypt(JSON.stringify(checkPosArr),secretKey.value):JSON.stringify(checkPosArr),
+                                "token":backToken.value
+                            }
+                            reqCheck(data).then(res=>{
+                                if (res.repCode == "0000") {
+                                    barAreaColor.value = '#4cae4c'
+                                    barAreaBorderColor.value = '#5cb85c'
+                                    text.value = '验证成功'
+                                    bindingClick.value = false
+                                    if (mode.value=='pop') {
+                                        setTimeout(()=>{
+                                            proxy.$parent.clickShow = false;
+                                            refresh();
+                                        },1500)
+                                    }
+                                    proxy.$parent.$emit('success', {captchaVerification})
+                                }else{
+                                    proxy.$parent.$emit('error', proxy)
+                                    barAreaColor.value = '#d9534f'
+                                    barAreaBorderColor.value = '#d9534f'
+                                    text.value = '验证失败'
+                                    setTimeout(() => {
+                                        refresh();
+                                    }, 700);
+                                }
+                            })
+                        }, 400);
+                    }
+                    if (num.value < checkNum.value) {
+                        num.value = createPoint(getMousePos(canvas, e));
+                    }
+                }
+                 //获取坐标
+                const getMousePos = function (obj, e) {
+                    var x = e.offsetX 
+                    var y = e.offsetY 
+                    return {x, y}
+                }
+                //创建坐标点
+                const createPoint = function (pos) {
+                    tempPoints.push(Object.assign({}, pos))
+                    return num.value+1;
+                }
+                const refresh = function () {
+                    tempPoints.splice(0, tempPoints.length)
+                    barAreaColor.value = '#000'
+                    barAreaBorderColor.value = '#ddd'
+                    bindingClick.value = true
+                    fontPos.splice(0, fontPos.length)
+                    checkPosArr.splice(0, checkPosArr.length)
+                    num.value = 1
+                    getPictrue();
+                    text.value = '验证失败'
+                    showRefresh.value = true
+                }
+
+                // 请求背景图片和验证图片
+                function getPictrue() {
+                    let data = {
+                        captchaType:captchaType.value
+                    }
+                    reqGet(data).then(res=>{
+                        if (res.repCode == "0000") {
+                            pointBackImgBase.value = res.repData.originalImageBase64
+                            backToken.value = res.repData.token
+                            secretKey.value = res.repData.secretKey
+                            poinTextList.value = res.repData.wordList
+                            text.value = '请依次点击【' + poinTextList.value.join(",") + '】'
+                        }else{
+                            text.value = res.repMsg;
+                        }
+                    })
+                }
+                //坐标转换函数
+                const pointTransfrom = function(pointArr,imgSize){
+                    var newPointArr = pointArr.map(p=>{
+                        let x = Math.round(310 * p.x/parseInt(imgSize.imgWidth)) 
+                        let y =Math.round(155 * p.y/parseInt(imgSize.imgHeight)) 
+                        return {x,y}
+                    })
+                    return newPointArr
+                }
+                return {
+                    secretKey,
+                    checkNum,
+                    fontPos,
+                    checkPosArr,
+                    num,
+                    pointBackImgBase,
+                    poinTextList,
+                    backToken,
+                    setSize,
+                    tempPoints,
+                    text,
+                    barAreaColor,
+                    barAreaBorderColor,
+                    showRefresh,
+                    bindingClick,
+                    init,
+                    canvas,
+                    canvasClick,
+                    getMousePos,createPoint,refresh,getPictrue,pointTransfrom
+                }
+        },
+    }
+</script>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 550 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/Verify/VerifySlide.vue


+ 27 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/api/index.js

@@ -0,0 +1,27 @@
+/**
+ * 此处可直接引用自己项目封装好的 axios 配合后端联调
+ */
+
+
+import request from "./../utils/axios"  //组件内部封装的axios
+// import request from "@/api/axios.js"       //调用项目封装的axios
+
+//获取验证图片  以及token
+export function reqGet(data) {
+	return  request({
+        url: '/proxy-pattern/verify.get',
+        method: 'post',
+        data
+    })
+}
+
+//滑动或者点选验证
+export function reqCheck(data) {
+	return  request({
+        url: '/proxy-pattern/verify.check',
+        method: 'post',
+        data
+    })
+}
+
+

+ 11 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/utils/ase.js

@@ -0,0 +1,11 @@
+import CryptoJS from 'crypto-js'
+/**
+ * @word 要加密的内容
+ * @keyWord String  服务器随机返回的关键字
+ *  */
+export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
+  var key = CryptoJS.enc.Utf8.parse(keyWord);
+  var srcs = CryptoJS.enc.Utf8.parse(word);
+  var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
+  return encrypted.toString();
+}

+ 30 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/utils/axios.js

@@ -0,0 +1,30 @@
+import axios from 'axios';
+
+axios.defaults.baseURL = '/';
+
+const service = axios.create({
+  timeout: 40000,
+  headers: {
+    'X-Requested-With': 'XMLHttpRequest',
+    'Content-Type': 'application/json; charset=UTF-8'
+  },
+})
+service.interceptors.request.use(
+  config => {
+    return config
+  },
+  error => {
+    Promise.reject(error)
+  }
+)
+
+// response interceptor
+service.interceptors.response.use(
+  response => {
+    const res = response.data;
+    return res
+  },
+  error => {
+  }
+)
+export default service

+ 35 - 0
src/views/_builtin/login/components/pwd-login/components/verifition/utils/util.js

@@ -0,0 +1,35 @@
+export function resetSize(vm) {
+    var img_width, img_height, bar_width, bar_height;	//图片的宽度、高度,移动条的宽度、高度
+
+    var parentWidth = vm.$el.parentNode.offsetWidth || window.offsetWidth
+    var parentHeight = vm.$el.parentNode.offsetHeight || window.offsetHeight
+    if (vm.imgSize.width.indexOf('%') != -1) {
+        img_width = parseInt(vm.imgSize.width) / 100 * parentWidth + 'px'
+    } else {
+        img_width = vm.imgSize.width;
+    }
+
+    if (vm.imgSize.height.indexOf('%') != -1) {
+        img_height = parseInt(vm.imgSize.height) / 100 * parentHeight + 'px'
+    } else {
+        img_height = vm.imgSize.height
+    }
+
+    if (vm.barSize.width.indexOf('%') != -1) {
+        bar_width = parseInt(vm.barSize.width) / 100 * parentWidth + 'px'
+    } else {
+        bar_width = vm.barSize.width
+    }
+
+    if (vm.barSize.height.indexOf('%') != -1) {
+        bar_height = parseInt(vm.barSize.height) / 100 * parentHeight + 'px'
+    } else {
+        bar_height = vm.barSize.height
+    }
+
+    return {imgWidth: img_width, imgHeight: img_height, barWidth: bar_width, barHeight: bar_height}
+}
+
+export const _code_chars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
+export const _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0']
+export const _code_color2 = ['#FF0033', '#006699', '#993366', '#FF9900', '#66CC66', '#FF33CC']

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 143 - 51
src/views/_builtin/login/components/pwd-login/index.vue


+ 69 - 0
src/views/_builtin/login/components/pwd-login/indexCp.vue

@@ -0,0 +1,69 @@
+<template>
+  <div class="captcha-container">
+    <div class="captcha-wrapper" ref="wrapperRef">
+      <div class="slider" ref="sliderRef" :style="{ left: sliderLeft + 'px' }" @mousedown="startDrag"></div>
+      <div class="background">请拖动滑块完成验证</div>
+    </div>
+    <button class="verify-btn" @click="verify">验证</button>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, onUnmounted } from 'vue';
+
+const sliderLeft = ref(0);
+const isDragging = ref(false);
+let dragStartX = 0;
+const wrapperRef = ref<HTMLDivElement | null>(null); // 创建一个引用
+const sliderRef = ref<HTMLDivElement | null>(null); // 创建另一个引用
+
+const startDrag = (event: MouseEvent) => {
+  isDragging.value = true;
+  dragStartX = event.clientX;
+};
+
+const handleDrag = (event: MouseEvent) => {
+  if (!isDragging.value) return;
+
+  const sliderWidth = sliderRef.value?.offsetWidth ?? 0; // 使用引用获取宽度
+  const wrapperWidth = wrapperRef.value?.clientWidth ?? 0;
+  const maxSliderLeft = wrapperWidth - sliderWidth;
+
+  let newSliderLeft = event.clientX - dragStartX;
+  if (newSliderLeft < 0) newSliderLeft = 0;
+  if (newSliderLeft > maxSliderLeft) newSliderLeft = maxSliderLeft;
+
+  sliderLeft.value = newSliderLeft;
+};
+
+const endDrag = () => {
+  isDragging.value = false;
+};
+
+const verify = () => {
+  if (!wrapperRef.value || !sliderRef.value) return; // 检查引用是否存在
+
+  const maxSliderLeft = wrapperRef.value.clientWidth - sliderRef.value.clientWidth; // 计算最大滑块左侧位置
+  if (sliderLeft.value === maxSliderLeft) {
+    // 验证成功
+    console.log('验证成功');
+  } else {
+    // 验证失败
+    console.log('验证失败');
+  }
+};
+
+onMounted(() => {
+  window.addEventListener('mousemove', handleDrag);
+  window.addEventListener('mouseup', endDrag);
+});
+
+onUnmounted(() => {
+  window.removeEventListener('mousemove', handleDrag);
+  window.removeEventListener('mouseup', endDrag);
+});
+</script>
+
+<style scoped>
+/* 样式内容 */
+</style>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 224 - 0
src/views/_builtin/login/components/pwd-login/indexppp.vue


+ 0 - 1
src/views/crud/demo/crud.tsx

@@ -64,7 +64,6 @@ export default function createCrudOptions(): CreateCrudOptionsRet {
           }
         },
         select: {
-          title: '状态',
           search: { show: true },
           type: 'dict-select',
           dict: dict({

+ 1 - 0
src/views/index.ts

@@ -36,6 +36,7 @@ export const views: Record<
   management_auth: () => import('./management/auth/index.vue'),
   management_role: () => import('./management/role/index.vue'),
   management_route: () => import('./management/route/index.vue'),
+  management_sort: () => import('./management/sort/index.vue'),
   management_user: () => import('./management/user/index.vue'),
   'multi-menu_first_second-new_third': () => import('./multi-menu/first/second-new/third/index.vue'),
   'multi-menu_first_second': () => import('./multi-menu/first/second/index.vue'),

+ 88 - 3
src/views/management/auth/index.vue

@@ -1,7 +1,92 @@
 <template>
-  <div>权限管理</div>
+  <div class="h-full overflow-hidden">
+    <n-card title="权限管理" :bordered="false" class="rounded-16px shadow-sm">
+      <n-data-table :columns="columns" :data="tableData" :pagination="pagination" />
+    </n-card>
+  </div>
 </template>
 
-<script setup lang="tsx"></script>
+<script setup lang="ts">
+import { ref } from 'vue';
+import type { Ref } from 'vue';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { query } from '~/src/service/api/user';
+import type { QueryParams } from '~/src/service/api/user';
 
-<style scoped></style>
+const tableData = ref<QueryParams[]>([]);
+const pagination: PaginationProps = ref({
+  page: 1,
+  pageSize: 10,
+  showSizePicker: true,
+  pageSizes: [10, 20, 50]
+  // onChange: (page: number) => {
+  //   // 处理页码变化
+  // },
+  // onUpdatePageSize: (pageSize: number) => {
+  //   // 处理每页显示数量变化
+  // }
+}).value;
+
+async function getTableData() {
+  const pageNum = pagination.page as number;
+  const pageSize = pagination.pageSize as number;
+  const params: QueryParams = {};
+
+  query(pageNum, pageSize, params).then(res => {
+    // console.log(res);
+    tableData.value = res.data as [];
+  });
+}
+
+const columns: Ref<DataTableColumns<QueryParams>> = ref([
+  {
+    type: 'selection',
+    align: 'center'
+  },
+  {
+    key: 'name',
+    title: '部门名称',
+    align: 'center'
+  },
+  {
+    key: 'description',
+    title: '部门地址',
+    align: 'center'
+  },
+  {
+    key: 'isActive',
+    title: '是否激活',
+    align: 'center',
+    render: (row: QueryParams) => {
+      return row.isActive ? '是' : '否';
+    }
+  },
+  {
+    key: 'createTime',
+    title: '创建时间',
+    align: 'center'
+  },
+  {
+    key: 'modifyTime',
+    title: '修改时间',
+    align: 'center'
+  },
+  {
+    key: 'createUid',
+    title: '创建用户ID',
+    align: 'center'
+  },
+  {
+    key: 'disabled',
+    title: '状态',
+    align: 'center'
+  }
+]) as Ref<DataTableColumns<QueryParams>>;
+
+function init() {
+  getTableData();
+}
+
+// 初始化
+init();
+</script>

+ 88 - 3
src/views/management/role/index.vue

@@ -1,7 +1,92 @@
 <template>
-  <div>角色管理</div>
+  <div class="h-full overflow-hidden">
+    <n-card title="权限管理" :bordered="false" class="rounded-16px shadow-sm">
+      <n-data-table :columns="columns" :data="tableData" :pagination="pagination" />
+    </n-card>
+  </div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { ref } from 'vue';
+import type { Ref } from 'vue';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { query } from '~/src/service/api/user';
+import type { QueryParams } from '~/src/service/api/user';
 
-<style scoped></style>
+const tableData = ref<QueryParams[]>([]);
+const pagination: PaginationProps = ref({
+  page: 1,
+  pageSize: 10,
+  showSizePicker: true,
+  pageSizes: [10, 20, 50]
+  // onChange: (page: number) => {
+  //   // 处理页码变化
+  // },
+  // onUpdatePageSize: (pageSize: number) => {
+  //   // 处理每页显示数量变化
+  // }
+}).value;
+
+async function getTableData() {
+  const pageNum = pagination.page as number;//页码
+  const pageSize = pagination.pageSize as number;//当前所在数
+  const params: QueryParams = {};
+
+  query(pageNum, pageSize, params).then(res => {
+    // console.log(res);
+    tableData.value = res.data as [];
+  });
+}
+
+const columns: Ref<DataTableColumns<QueryParams>> = ref([
+  {
+    type: 'selection',
+    align: 'center'
+  },
+  {
+    key: 'name',
+    title: '部门名称',
+    align: 'center'
+  },
+  {
+    key: 'description',
+    title: '部门地址',
+    align: 'center'
+  },
+  {
+    key: 'isActive',
+    title: '是否激活',
+    align: 'center',
+    render: (row: QueryParams) => {
+      return row.isActive ? '是' : '否';
+    }
+  },
+  {
+    key: 'createTime',
+    title: '创建时间',
+    align: 'center'
+  },
+  {
+    key: 'modifyTime',
+    title: '修改时间',
+    align: 'center'
+  },
+  {
+    key: 'createUid',
+    title: '创建用户ID',
+    align: 'center'
+  },
+  {
+    key: 'disabled',
+    title: '状态',
+    align: 'center'
+  }
+]) as Ref<DataTableColumns<QueryParams>>;
+
+function init() {
+  getTableData();
+}
+
+// 初始化
+init();
+</script>

+ 110 - 0
src/views/management/role/queryUser.vue

@@ -0,0 +1,110 @@
+<template>
+  <div class="h-full overflow-hidden">
+    <n-card title="权限管理" :bordered="false" class="rounded-16px shadow-sm">
+      <n-data-table :columns="columns" :data="tableData" :pagination="pagination" />
+    </n-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import type { Ref } from 'vue';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { query } from '~/src/service/api/user';
+import type { QueryParams } from '~/src/service/api/user';
+
+const tableData = ref<QueryParams[]>([]);
+
+async function getTableData() {
+  const pageNum = pagination.page as number;
+  const pageSize = pagination.pageSize as number;
+
+  const params: QueryParams = {
+    name: '',
+    description: '',
+    isActive: '',
+    createTime: '',
+    modifyTime: "" ,
+    createUid: 0,
+    disabled: '',
+  };
+
+	query(pageNum, pageSize, params).then((res) => {
+			console.log(res);
+			tableData.value =  res.data as[]
+		})
+}
+
+const columns: Ref<DataTableColumns<QueryParams>> = ref([
+	{
+		type: 'selection',
+		align: 'center'
+	},
+	{
+		key: 'depname',
+		title: '部门名称',
+		align: 'center'
+	},
+	{
+		key: 'address',
+		title: '部门地址',
+		align: 'center'
+	},
+	{
+		key: 'phone',
+		title: '部门电话',
+		align: 'center'
+	},
+	{
+		key: 'email',
+		title: '部门电子邮箱',
+		align: 'center',
+	},
+	{
+		key: 'manager',
+		title: '部门负责人',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center'
+	},
+
+]) as Ref<DataTableColumns<QueryParams>>;
+
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+	}
+}).value;
+
+function init() {
+	getTableData();
+}
+
+// 初始化
+init();
+</script>

+ 38 - 0
src/views/management/role/userPa.vue

@@ -0,0 +1,38 @@
+<template>
+  <n-space vertical>
+    <n-pagination v-model:page="pageNum" :page-count="pageSize" />
+  </n-space>
+</template>
+
+<script lang="ts">
+import { reactive } from 'vue';
+import { defineComponent, ref } from 'vue';
+import type { QueryParams } from '~/src/service/api/user';
+
+export default defineComponent({
+  setup() {
+    const pageNum = ref(2);
+    const pageSize = ref<any>(10);
+    const queryData = reactive<QueryParams>({});
+    function queryList() {
+      console.log(1);
+
+      // query(1, 10, queryData).then(r => {
+      // 	console.log(r);
+      // });
+    }
+
+    return {
+      // 每页条数, 可自定义 page-size
+      pageNum,
+      // page-count
+      pageSize,
+      queryList,
+      queryData
+      // page: ref(2),
+      // pageSize: ref(20),
+      // queryData:reactive({})
+    };
+  }
+});
+</script>

+ 9 - 1
src/views/management/route/index.vue

@@ -2,6 +2,14 @@
   <div>路由管理</div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import type { QueryParams } from '~/src/service/api/user';
+import { query } from '~/src/service/api/user';
+const queryData: QueryParams = {};
+
+query(1, 20, queryData).then(r => {
+  console.log(r);
+});
+</script>
 
 <style scoped></style>

+ 49 - 0
src/views/management/sort/api.ts

@@ -0,0 +1,49 @@
+import type { UserPageQuery } from '@fast-crud/fast-crud';
+import { request } from '@/service/request';
+
+// 响应接口
+export interface SelectAll_1Res {
+  status: boolean;
+  msg: string;
+  data: Record<string, unknown>;
+}
+
+const apiPrefix = ``;
+
+export type HeaderGroupRecord = {
+  id: number;
+  [key: string]: any;
+};
+
+function resHandle(res: any) {
+  return res.data;
+}
+export async function selectAll_1(query: UserPageQuery) {
+  const res = await request.get(`/selectAll`, query);
+  return resHandle(res);
+}
+
+export async function AddObj(obj: HeaderGroupRecord) {
+  const res = await request.post(`${apiPrefix}/add`, obj);
+  return resHandle(res);
+}
+
+export async function UpdateObj(obj: HeaderGroupRecord) {
+  const res = await request.post(`${apiPrefix}/update`, obj);
+  return resHandle(res);
+}
+
+export async function DelObj(id: number) {
+  const res = await request.post(`${apiPrefix}/delete`, { id });
+  return resHandle(res);
+}
+
+export async function GetObj(id: number) {
+  const res = await request.get(`${apiPrefix}/info`, { params: { id } });
+  return resHandle(res);
+}
+
+export async function BatchDelete(ids: number[]) {
+  const res = await request.post(`${apiPrefix}/batchDelete`, { ids });
+  return resHandle(res);
+}

+ 88 - 0
src/views/management/sort/components/column-search.vue

@@ -0,0 +1,88 @@
+<template>
+	<n-space>
+		<n-input-group>
+			<n-input-group>
+				 <span class="w-80px mr-5px line-height-33.99px">学科名称</span> <n-input :style="{ width: '31%', marginRight: '2%' }"
+					clearable />
+				<span class="w-80px mr-5px line-height-33.99px">学科描述</span> <n-input :style="{ width: '31%' ,marginRight:'2%'}" clearable/>
+    		<span class="w-100px line-height-33.99px">创建用户ID</span> <n-input-number :style="{ width: '22%',marginRight:'10%' }" clearable />
+			</n-input-group>
+			<n-input-group>
+			  <span class="line-height-33.99px mr-5px w-70px">创建时间</span>
+				<n-date-picker :style="{ width: '13%' }" />
+				<n-time-picker :style="{ width: '14.2%', marginRight: '2%' }" />
+				<span class="line-height-33.99px mr-5px w-70px">修改时间</span>
+				<n-date-picker :style="{ width: '13%' }" />
+				<n-time-picker :style="{ width: '14.2%', marginRight: '2%' }" />
+				<span class="w-50px  line-height-33.99px">状态</span>
+				<n-select :options="selectOptions" :style="{ width: '21%', marginRight: '2%' }" clearable />
+			</n-input-group>
+			<span class="w-40px mr-5px line-height-33.99px">页码</span> <n-input-number :style="{ width: '48%', marginRight: '2%' }"
+				placeholder="请输入页码..." clearable v-model="pagination.page" @change="searchCondition" />
+			<span class="w-40px mr-5px line-height-33.99px">条数</span> <n-input-number :style="{ width: '48%' }"
+				placeholder="请输入数据条数..." clearable v-model="pagination.pageSize" @change="searchCondition" />
+			 <n-button type="primary" ghost @click="searchCondition()">
+				搜索
+			</n-button>
+		</n-input-group>
+	</n-space>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue'
+import { NButton, NSpace } from 'naive-ui';
+import type { PaginationProps } from 'naive-ui';
+
+import { selectByCondition_1 } from '~/src/service/api/sort';
+import type { SelectByCondition_1Params } from '~/src/service/api/sort';
+
+const searchData = ref<any[]>([]);
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+		pagination.page = page;
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+		pagination.pageSize = pageSize;
+		pagination.page = 1;
+	}
+}).value;
+
+function searchCondition() {
+	const pageNum = pagination.page as number;
+	const pageSize = pagination.pageSize as number;
+	const params: SelectByCondition_1Params = {};
+	console.log(pageNum, pageSize);
+
+	selectByCondition_1(pageNum, pageSize, params).then(res => {
+		// console.log(res);
+		searchData.value = res.data as [];
+		console.log(searchData.value);
+	});
+}
+
+export default defineComponent({
+	setup() {
+		return {
+			searchCondition,
+			searchData,
+			pagination,
+			selectOptions: ref([
+				{
+					label: 'Y',
+					value: 'Y'
+				},
+				{
+					label: 'N',
+					value: 'N'
+				}
+			]),
+		}
+	}
+})
+</script>

+ 214 - 0
src/views/management/sort/components/table-action-add.vue

@@ -0,0 +1,214 @@
+<template>
+	<n-modal v-model:show="modalVisible" preset="card" :title="title" class="w-700px">
+		<n-form ref="formRef" label-placement="left" :label-width="100" :model="formModel" :rules="rules">
+			<n-grid :cols="24" :x-gap="18">
+				<!-- <n-form-item-grid-item :span="12" label="ID" path="id">
+					<n-input-number v-model:value="formModel.id" />
+				</n-form-item-grid-item> -->
+				<n-form-item-grid-item :span="12" label="学科名称" path="name">
+					<n-input v-model:value="formModel.name" clearable />
+				</n-form-item-grid-item>
+				<!-- <n-form-item-grid-item :span="12" label="创建时间" path="createTime">
+					  <n-date-picker v-model:value="timestamp" type="datetime" clearable />
+					<n-input v-model:value="formModel.createTime" />
+				</n-form-item-grid-item> -->
+				<n-form-item-grid-item :span="12" label="学科描述" path="description">
+					<n-input v-model:value="formModel.description" clearable />
+					<!-- <n-radio-group v-model:value="formModel.description">
+						<n-radio v-for="item in genderOptions" :key="item.value" :value="item.value">{{ item.label }}</n-radio>
+					</n-radio-group> -->
+				</n-form-item-grid-item>
+				<!-- <n-form-item-grid-item :span="12" label="修改时间" path="email">
+					<n-date-picker v-show="props.type==='edit'" v-model:value="formModel.modifyTime" type="datetime" clearable />
+				</n-form-item-grid-item> -->
+				<n-form-item-grid-item :span="12" label="创建用户ID" path="createUid">
+					<n-input-number v-model:value="formModel.createUid" />
+				</n-form-item-grid-item>
+				<n-form-item-grid-item :span="12" label="状态" path="disabled">
+					<n-select v-model:value="formModel.disabled" :options="userStatusOptions" />
+				</n-form-item-grid-item>
+			</n-grid>
+			<n-space class="w-full pt-16px" :size="24" justify="end">
+				<n-button class="w-72px" @click="closeModal">取消</n-button>
+				<n-button class="w-72px" type="primary" @click="handleSubmit">确定</n-button>
+			</n-space>
+		</n-form>
+	</n-modal>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, reactive, watch } from 'vue';
+import type { FormInst, FormItemRule } from 'naive-ui';
+import { userStatusOptions } from '@/constants';
+import {createRequiredFormRule } from '@/utils';
+import dayjs from 'dayjs';
+import { addEasEduCategory, AddEasEduCategoryParams,updateEasEduCategory,UpdateEasEduCategoryParams } from '~/src/service/api/sort';
+import {getTableData} from '../index.vue'
+// const timestamp = ref(1483135260000)
+
+export interface Props {
+	/** 弹窗可见性 */
+	visible: boolean;
+	/**
+	 * 弹窗类型
+	 * add: 新增
+	 * edit: 编辑
+	 */
+	type?: 'add' | 'edit' ;
+	/** 编辑的表格行数据 */
+	editData?: UserManagement.User | null;
+}
+
+export type ModalType = NonNullable<Props['type']>;
+
+defineOptions({ name: 'TableActionAdd' });
+
+const props = withDefaults(defineProps<Props>(), {
+	type: 'add'||'edit',
+	editData: null,
+});
+
+interface Emits {
+	(e: 'update:visible', visible: boolean): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const modalVisible = computed({
+	get() {
+		return props.visible;
+	},
+	set(visible) {
+		emit('update:visible', visible);
+	}
+});
+
+const closeModal = () => {
+	modalVisible.value = false;
+};
+
+const title = computed(() => {
+	const titles: Record<ModalType, string> = {
+		add: '添加用户',
+		edit: '编辑用户',
+	};
+	// console.log(titles[props.type]);
+	return titles[props.type];
+
+});
+
+const formRef = ref<HTMLElement & FormInst>();
+
+
+interface FormModel extends Pick<UserManagement.User, 'id' |'name' | 'description' | 'createUid' | 'disabled'|'createTime'> {
+  modifyTime: string;
+}
+
+const formModel = reactive<FormModel>(createDefaultFormModel());
+
+const rules: Record<keyof FormModel, FormItemRule | FormItemRule[]> = {
+	id: createRequiredFormRule('请输入用户名'),
+	name: createRequiredFormRule('请输入学科名称'),
+	description: createRequiredFormRule('请进行部门描述'),
+	createTime:createRequiredFormRule('请输入创建时间'),
+	modifyTime:createRequiredFormRule('请输入修改时间'),
+	createUid: createRequiredFormRule('请输入创建用户ID'),
+	disabled: createRequiredFormRule('请选择用户状态')
+};
+// 'createTime' |'modifyTime'|
+function createDefaultFormModel(): FormModel {
+	return {
+		id: null,
+		name: '',
+		description: '',
+		createTime: '',
+		modifyTime:'',
+		createUid:null,
+		disabled: null,
+	};
+}
+
+function handleUpdateFormModel(model: Partial<FormModel>) {
+	Object.assign(formModel, model);
+	// console.log(	Object.assign(formModel, model));
+}
+
+function handleUpdateFormModelByModalType() {
+	const handlers: Record<ModalType, () => void> = {
+		add: () => {
+			const defaultFormModel = createDefaultFormModel();
+			handleUpdateFormModel(defaultFormModel);
+		},
+		edit: () => {
+			if (props.editData) {
+				console.log(props.editData);
+				handleUpdateFormModel(props.editData);
+			}
+		},
+	};
+
+	handlers[props.type]();
+}
+console.log(props.type);
+async function handleSubmit() {
+	await formRef.value?.validate()
+  if (props.type === 'add') {
+    const params: AddEasEduCategoryParams = {
+      // id: formModel.id,
+      name: formModel.name,
+      description: formModel.description,
+      // createTime: formModel.createTime,
+      createUid: formModel.createUid,
+      disabled: formModel.disabled
+    };
+    // 调用新增接口
+    addEasEduCategory(params)
+      .then(res => {
+        console.log(res);
+        window.$message?.success('新增成功!');
+				getTableData();
+        closeModal();
+      })
+      .catch(error => {
+        console.error(error);
+        window.$message?.error('新增失败!');
+      });
+  } else {
+	   const currentTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
+ 		 handleUpdateFormModel({ modifyTime: currentTime });
+     const params: UpdateEasEduCategoryParams = {
+				id: props.editData?.id, // 编辑数据的id
+				name: formModel.name,
+				description: formModel.description,
+				createTime: formModel.createTime,
+				modifyTime: formModel.modifyTime,
+				createUid: formModel.createUid,
+				disabled: formModel.disabled
+     };
+
+    // 调用更新接口
+    updateEasEduCategory(params)
+      .then(res => {
+        console.log(res);
+        window.$message?.success('更新成功!');
+        closeModal();
+        getTableData();
+      })
+      .catch(error => {
+        console.error(error);
+        window.$message?.error('更新失败!');
+      });
+  }
+}
+
+watch(
+	() => props.visible,
+	newValue => {
+		if (newValue) {
+			handleUpdateFormModelByModalType();
+		}
+	}
+);
+</script>
+
+<style scoped></style>

+ 181 - 0
src/views/management/sort/crud.tsx

@@ -0,0 +1,181 @@
+import type { AddReq, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from '@fast-crud/fast-crud';
+import { dict } from '@fast-crud/fast-crud';
+import dayjs from 'dayjs';
+import * as api from './api';
+import { selectAll_1 } from './api';
+export default function createCrudOptions(): CreateCrudOptionsRet {
+	const pageRequest = async (query: any): Promise<any> => {
+    // 调用你自己的函数从接口获取数据
+    const data = await selectAll_1(query);
+    return {
+      rows: data,
+      total: data.length
+    };
+  };
+  const editRequest = async (ctx: EditReq) => {
+    const { form, row } = ctx;
+    form.id = row.id;
+    return api.UpdateObj(form);
+  };
+  const delRequest = async (ctx: DelReq) => {
+    const { row } = ctx;
+    return api.DelObj(row.id);
+  };
+
+  const addRequest = async (req: AddReq) => {
+    const { form } = req;
+    return api.AddObj(form);
+  };
+  return {
+    crudOptions: {
+      container: {
+        is: 'fs-layout-card'
+      },
+      request: {
+        pageRequest,
+        addRequest,
+        editRequest,
+        delRequest
+      },
+      columns: {
+        id: {
+          title: 'ID',
+          key: 'id',
+          type: 'number',
+					search: { show: true },
+          column: {
+            width: 50,
+						align:'center',
+          },
+          form: {
+            show: false
+          }
+        },
+				name: {
+          title: '部门名称',
+					search: { show: true },
+          key: 'name',
+          type: 'text',
+          column: {
+            width: 150,
+						align:'center',
+          },
+          form: {
+            show: true
+          }
+        },
+        // select: {
+        //   title: '状态',
+        //   search: { show: true },
+        //   type: 'dict-select',
+				// 	align: 'center',
+        //   // dict: dict({
+        //   //   url: '/mock/crud/demo/dict'
+        //   // })
+        // },
+        description: {
+          title: '部门地址',
+					key: 'description',
+          type: 'text',
+          search: { show: true },
+					column: {
+            width: 200,
+						align:'center',
+          },
+        },
+        createTime: {
+					key: 'createTime',
+          title: '创建时间',
+					type: 'text',
+					column: {
+            width: 250,
+						align:'center',
+          },
+					search: { show: true },
+          // naive 默认仅支持数字类型时间戳作为日期输入与输出
+          // 字符串类型的时间需要转换格式
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              // naive 默认仅支持时间戳作为日期输入与输出
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+        modifyTime: {
+          title: '修改时间',
+					key: 'modifyTime',
+					type: 'text',
+					align: 'center',
+					column: {
+            width: 250,
+						align:'center',
+          },
+          // naive 默认仅支持数字类型时间戳作为日期输入与输出
+          // 字符串类型的时间需要转换格式
+          valueBuilder(context) {
+            const { value, row, key } = context;
+            if (value) {
+              // naive 默认仅支持时间戳作为日期输入与输出
+              row[key] = dayjs(value).valueOf();
+            }
+          },
+          valueResolve(context) {
+            const { value, form, key } = context;
+            if (value) {
+              form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
+            }
+          }
+        },
+				createUid: {
+          title: '创建用户ID',
+					key: 'createUid',
+          type: 'file-uploader',
+					column: {
+            width: 250,
+						align:'center',
+          },
+        },
+				disabled: {
+					key: 'disabled',
+					title: '状态',
+					type: 'dict-select',
+					column: {
+            width: 100,
+						align:'center',
+          },
+					dict: dict({
+            url: '/mock/crud/demo/dict'
+          }),
+          search: { show: true }
+        },
+        // richtext: {
+        //   title: '富文本',
+        //   type: 'editor-wang5',
+        //   column: {
+        //     // cell中不显示
+        //     show: false
+        //   },
+        //   form: {
+        //     col: {
+        //       // 横跨两列
+        //       span: 24
+        //     },
+        //     component: {
+        //       style: {
+        //         height: '300px'
+        //       }
+        //     }
+        //   }
+        // }
+      },
+
+    }
+  };
+}

+ 334 - 0
src/views/management/sort/index.vue

@@ -0,0 +1,334 @@
+<template>
+	<div class="h-full overflow-hidden">
+		<n-scrollbar>
+			<n-card title="课程分类" :bordered="false" class="rounded-16px shadow-sm">
+				<n-space class="pb-14px" justify="space-between">
+					<!-- 加入查询组件 -->
+					<n-space>
+						<n-button type="primary"  @click="addTableData">
+							<icon-ic-round-plus class="mr-4px text-20px" />
+							新增
+						</n-button>
+						<n-button type="error" @click="deleteTableData" @update:checked-row-keys="handleCheck">
+							<icon-ic-round-delete class="mr-4px text-20px" />
+							删除
+						</n-button>
+						<!-- 添加查询按钮 -->
+						<n-button type="primary" @click="handleOpenSearch">
+							<icon-simple-line-icons:magnifier class="mr-4px text-16px" />
+							查询
+						</n-button>
+						<n-input-group>
+							<n-input :style="{ width: '100%', }" placeholder="请输入id查询..." @clear="searchClear"  @change="handleChange"
+								@keyup.enter="handleSearch" v-model="searchId" clearable />
+							<n-button type="primary" ghost @click="handleSearch">
+								搜索
+							</n-button>
+						</n-input-group>
+						<div class="mr-5px"></div>
+						<n-input-group>
+							<span class="w-40px mr-5px line-height-33.99px">页码</span>
+							<n-input-number :style="{ width: '48%', marginRight: '2%' }" placeholder="请输入页码..." clearable v-model="pagination.page"
+								@update:value="searchPage"  @clear="searchConClear"/>
+							<span class="w-40px mr-5px line-height-33.99px">条数</span>
+							<n-input-number :style="{ width: '48%' }" placeholder="请输入数据条数..." clearable v-model="pagination.pageSize"
+								@update:value="searchSize"  @clear="searchConClear" />
+							<n-button type="primary" ghost @click="searchCondition">
+								搜索
+							</n-button>
+						</n-input-group>
+						<!-- <column-search v-if="showSearch" v-model:columns="columns" /> -->
+					</n-space>
+					<n-space align="center" :size="18">
+						<n-button size="small" type="primary" @click="getTableData">
+							<icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
+							刷新表格
+						</n-button>
+					</n-space>
+				</n-space>
+				<n-data-table v-if="searchForm.length > 0" :columns="createColumns" :data="searchForm" :loading="loading"
+					:pagination="pagination" :row-key="rowKey" @update:checked-row-keys="handleCheck" />
+				<n-data-table v-if="searchForm.length <= 0" :columns="createColumns" :data="tableData" :loading="loading"
+					:pagination="pagination" :row-key="rowKey" @update:checked-row-keys="handleCheck" />
+				<table-action-add v-model:visible="visible" :type="modalType" :edit-data="editData" />
+			</n-card>
+		</n-scrollbar>
+	</div>
+</template>
+
+<script setup lang="tsx" >
+import { ref } from 'vue'
+import { NButton, NSpace, NTag, NPopconfirm } from 'naive-ui';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { useBoolean, useLoading } from '@/hooks';
+import type { DataTableRowKey } from 'naive-ui'
+import TableActionAdd from './components/table-action-add.vue'
+import type { ModalType } from './components/table-action-add.vue';
+import { userStatusLabels } from '@/constants';
+import { selectAll_1, deleteById, selectById_1 } from '~/src/service/api/sort';
+import { selectByCondition_1 } from '~/src/service/api/sort';
+import type { SelectByCondition_1Params } from '~/src/service/api/sort';
+type RowData = {
+	key: number
+	id: number
+	name: string
+	description: string
+	createTime: string
+	modifyTime: string
+	createUid: number
+	disabled: string
+}
+const { loading, startLoading, endLoading } = useLoading(false);
+const { bool: visible, setTrue: openModal } = useBoolean();
+const tableData = ref<any[]>([]);
+const searchInput = ref([]) as any;
+const searchForm = ref([]) as any;
+const searchId = ref<number>(0); // 定义为数字类型,默认值为0
+// const searchData = ref<any[]>([]);
+const searchConData = ref<any[]>([]);
+const searchpagedata = ref<number>(0)
+const searchpagesize = ref<number>(0)
+
+function searchPage(v: number | null) {
+	searchpagedata.value = Number(v)
+}
+function searchSize(v: number | null) {
+	searchpagesize.value = Number(v)
+}
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+		pagination.page = page;
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+		pagination.pageSize = pageSize;
+		pagination.page = 1;
+	}
+}).value;
+
+function searchCondition() {
+	const pageNum = searchpagedata.value as number;
+	const pageSize = searchpagesize.value as number;
+	const params: SelectByCondition_1Params = {};
+	if(pageNum  &&  pageSize){
+		selectByCondition_1(pageNum, pageSize, params).then(res => {
+		searchConData.value = res.data as [];
+		pagination.page =searchpagedata.value
+		pagination.pageSize=searchpagesize.value
+		window.$message?.success('查询成功');
+		})
+	}
+	else if(!pageNum && !pageSize) {
+		searchpagedata.value =0;
+		searchpagesize.value=0;
+		window.$message?.warning('请输入页码和条数进行查询');
+	}
+}
+export async function getTableData() {
+	startLoading();
+	selectAll_1().then(res => {
+		setTimeout(() => {
+			tableData.value = res.data as [];
+			endLoading();
+		}, 1000);
+	});
+	checkedRowKeysRef.value=[]
+}
+function init() {
+	getTableData();
+}
+// 初始化
+init();
+
+function searchConClear(){
+	searchConData.value.length = 0
+	searchpagedata.value =0;
+	searchpagesize.value=0;
+	getTableData();
+}
+
+const showSearch = ref(false)
+function handleOpenSearch() {
+// 点击查询时显示搜索框
+	showSearch.value = !showSearch.value;
+}
+// 输入数据
+function handleChange(v: string) {
+	searchId.value = Number(v)
+}
+// 根据id查询数据
+async function handleSearch() {
+	if (searchId.value) {
+		await selectById_1(searchId.value)
+			.then(res => {
+				// 更新数据
+				searchInput.value = res.data as [];
+				const filteredItems = tableData.value.filter(item => item.id === searchInput.value.id)
+				searchForm.value = filteredItems;
+				window.$message?.success('查询成功');
+			})
+	}
+	else {
+		searchForm.value.length = 0
+		window.$message?.warning('请输入有效的ID进行查询');
+	}
+}
+
+function searchClear() {
+	searchForm.value.length = 0
+	getTableData();
+}
+
+const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+	const s = ref<DataTableRowKey[]>([])
+// 根据id进行删除
+async function deleteTableData() {
+	const ids = checkedRowKeysRef.value.filter((item)=>!s.value?.includes(item));
+	s.value=checkedRowKeysRef.value
+	if (ids.length !== 0) {
+		console.log(ids);
+		for (const id of ids) {
+			// 调用删除接口
+			await deleteById(id as number)
+				.then((res) => {
+						window.$message?.success('删除成功!');
+				})
+		}
+		getTableData(); // 删除完成后刷新表格数据
+	} else {
+		// 没有选择任何行时的操作
+		window.$message?.error('未选择要删除的行');
+	}
+}
+
+const modalType = ref<ModalType>('add' || 'edit');
+
+function setModalType(type: ModalType) {
+	modalType.value = type;
+}
+// 添加
+function addTableData() {
+	openModal();
+	setModalType('add');
+}
+
+const editData = ref<UserManagement.User | null>(null);
+function setEditData(data: UserManagement.User | null) {
+	editData.value = data;
+}
+console.log(tableData.value);
+function handleEditTable(rowId: number | null) {
+	const findItem = tableData.value.find(item => item.id === rowId);
+	setModalType('edit');
+	openModal();
+	if (findItem) {
+		setEditData(findItem);
+	}
+	getTableData(); // 编辑完成后刷新表格数据
+}
+
+function handleDeleteTable(rowId: number | null) {
+	const findItem = tableData.value.find(item => item.id === rowId);
+	if (findItem) {
+		deleteById(findItem.id).then((r) => {
+			getTableData(); // 编辑完成后刷新表格数据
+		})
+	}
+}
+
+const createColumns = (): DataTableColumns<UserManagement.User> => [
+	{
+		type: 'selection',
+		align: 'center',
+	},
+	{
+		key: 'id',
+		title: "ID",
+		align: 'center',
+
+	},
+	{
+		key: 'name',
+		title: '学科名称',
+		align: 'center'
+	},
+	{
+		key: 'description',
+		title: '学科描述',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center',
+
+		render: row => {
+			if (row.disabled) {
+				const tagTypes: Record<UserManagement.UserStatusKey, NaiveUI.ThemeColor> = {
+					'N': 'error',
+					'Y': 'success',
+				};
+				return <NTag type={tagTypes[row.disabled]}>{userStatusLabels[row.disabled]}</NTag>;
+			}
+			return
+		}
+	},
+	{
+		key: 'actions',
+		title: '操作',
+		align: 'center',
+		render: row => {
+			return (
+				<NSpace justify={'center'}>
+					<NButton size={'small'} onClick={() => handleEditTable(row.id)} >
+						编辑
+					</NButton>
+					<NPopconfirm onPositiveClick={() => handleDeleteTable(row.id)}>
+						{{
+							default: () => '确认删除',
+							trigger: () => <NButton size={'small'}>删除</NButton>
+						}}
+					</NPopconfirm>
+				</NSpace>
+			);
+		}
+
+	},
+]
+
+const	rowKey= (row: RowData) => row.id
+function handleCheck(rowKeys: DataTableRowKey[]) {
+	checkedRowKeysRef.value = rowKeys
+}
+		// handleKeyDown(event:KeyboardEvent) {
+    //   if (event.key === 'Backspace' && searchId.value===0) {
+    //     // 处理删除键按下且输入框为空的情况
+    //     // 执行刷新操作,例如调用 API 获取原来的列表数据
+		// 		getTableData()
+    //   }
+		// 	console.log(1);
+    // },
+
+
+
+</script>

+ 126 - 0
src/views/management/sort/index.vuebak

@@ -0,0 +1,126 @@
+<template>
+	<div class="h-full overflow-hidden">
+		<n-card title="用户管理" :bordered="false" class="rounded-16px shadow-sm">
+			<n-space class="pb-12px" justify="space-between">
+				<!-- <n-space>
+          <n-button type="primary" @click="handleAddTable">
+            <icon-ic-round-plus class="mr-4px text-20px" />
+            新增
+          </n-button>
+          <n-button type="error">
+            <icon-ic-round-delete class="mr-4px text-20px" />
+            删除
+          </n-button>
+          <n-button type="success">
+            <icon-uil:export class="mr-4px text-20px" />
+            导出Excel
+          </n-button>
+        </n-space> -->
+				<!-- <n-space align="center" :size="18">
+          <n-button size="small" type="primary" @click="getTableData">
+            <icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
+            刷新表格
+          </n-button>
+          <column-setting v-model:columns="columns" />
+        </n-space> -->
+			</n-space>
+			<n-data-table :columns="columns" :data="tableData" :pagination="pagination"  />
+
+			<!-- <table-action-modal v-model:visible="visible" :type="modalType" :edit-data="editData" /> -->
+		</n-card>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import type { Ref } from 'vue';
+// import type { SelectAll_1Res } from './api';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+// import { query } from '~/src/service/api/user';
+// import type { QueryParams } from '~/src/service/api/user';
+import { selectAll_1 } from '~/src/service/api/user';
+const tableData = ref<any[]>([]);
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50]
+	// onChange: (page: number) => {
+	//   // 处理页码变化
+	// },
+	// onUpdatePageSize: (pageSize: number) => {
+	//   // 处理每页显示数量变化
+	// }
+}).value;
+
+async function getTableData() {
+	// const pageNum = pagination.page as number;
+	// const pageSize = pagination.pageSize as number;
+	// const params: any = {};
+
+	selectAll_1().then(res => {
+		// console.log(res);
+		tableData.value = res.data as [];
+	});
+}
+
+type RowData = {
+	key: number
+	id: number
+	name: string
+	description: string
+	createTime: string
+	modifyTime: string
+	createUid: number
+	disabled: string
+}
+
+const columns: Ref<DataTableColumns<RowData>> = ref([
+	{
+		type: 'selection',
+		align: 'center',
+	},
+	{
+		key: 'id',
+		title: "ID",
+		align: 'center'
+	},
+	{
+		key: 'name',
+		title: '部门名称',
+		align: 'center'
+	},
+	{
+		key: 'description',
+		title: '部门地址',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center'
+	}
+]) as Ref<DataTableColumns<any>>;
+
+function init() {
+	getTableData();
+}
+
+// 初始化
+init();
+</script>

+ 317 - 0
src/views/management/sort/indexcopy.vue

@@ -0,0 +1,317 @@
+<template>
+	<div class="h-full overflow-hidden">
+		<n-card title="课程分类" :bordered="false" class="rounded-16px shadow-sm">
+			<n-space class="pb-12px" justify="space-between">
+				<!-- 加入查询组件 -->
+				<column-search v-if="showSearch" @close="handleCloseSearch" />
+				<n-space v-else>
+					<n-button type="primary" :data="addData" @click="addTableData">
+						<icon-ic-round-plus class="mr-4px text-20px" />
+						新增
+					</n-button>
+					<n-button type="error" @click="deleteTableData" @update:checked-row-keys="handleCheck">
+						<icon-ic-round-delete class="mr-4px text-20px" />
+						删除
+					</n-button>
+					<n-button type="success">
+						<icon-uil:export class="mr-4px text-20px" />
+						导出Excel
+					</n-button>
+					<!-- 添加查询按钮 -->
+					<n-button size="small" type="primary" @click="handleOpenSearch">
+						<icon-simple-line-icons:magnifier class="mr-4px text-16px" />
+						查询
+					</n-button>
+				</n-space>
+				<n-space align="center" :size="18">
+					<n-button size="small" type="primary" @click="getTableData">
+						<icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
+						刷新表格
+					</n-button>
+					<column-search v-model:columns="columns" />
+				</n-space>
+			</n-space>
+			<n-data-table :columns="columns" :data="tableData" :loading="loading" :pagination="pagination" :row-key="rowKey"
+				@update:checked-row-keys="handleCheck" />
+			<table-action-add v-model:visible="visible" :type="modalType" :edit-data="editData" />
+		</n-card>
+		<!-- <n-input-group>
+      <n-input :style="{ width: '100%' }" clearable/>
+    </n-input-group>
+		<n-input-group>
+			<span class="line-height-33.99px mr-5px w-70px">创建时间</span>
+      <n-date-picker :style="{ width: '13%' }"/>
+      <n-time-picker :style="{ width: '14.2%' ,marginRight:'2%'}"/>
+			<span class="line-height-33.99px mr-5px w-70px">修改时间</span>
+      <n-date-picker :style="{ width: '13%' }"/>
+      <n-time-picker :style="{ width: '14.2%' ,marginRight:'2%'}"/>
+				<span class="w-50px  line-height-33.99px">状态</span>
+				<n-select  :options="selectOptions" :style="{ width: '21%' ,marginRight:'2%'}"  clearable/>
+				<n-button type="primary" ghost>
+      	  搜索
+    		</n-button>
+    </n-input-group> -->
+	</div>
+</template>
+
+<script lang="tsx" >
+import { defineComponent, ref } from 'vue'
+import { NButton, NSpace, NTag, NPopconfirm } from 'naive-ui';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { useBoolean, useLoading } from '@/hooks';
+import type { DataTableRowKey } from 'naive-ui'
+import TableActionAdd from './components/table-action-add.vue'
+import type { ModalType } from './components/table-action-add.vue';
+// import {  userStatusLabels } from '@/constants';
+import { userStatusLabels } from '@/constants';
+import { selectAll_1, deleteById } from '~/src/service/api/sort';
+import type { AddEasEduCategoryParams } from '~/src/service/api/sort';
+import ColumnSearch from './components/column-search.vue';
+type RowData = {
+	key: number
+	id: number
+	name: string
+	description: string
+	createTime: string
+	modifyTime: string
+	createUid: number
+	disabled: string
+}
+const { loading, startLoading, endLoading } = useLoading(false);
+const { bool: visible, setTrue: openModal } = useBoolean();
+
+const tableData = ref<any[]>([]);
+
+// const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+		pagination.page = page;
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+		pagination.pageSize = pageSize;
+		pagination.page = 1;
+	}
+}).value;
+
+
+export async function getTableData() {
+	startLoading();
+	selectAll_1().then(res => {
+		setTimeout(() => {
+			// console.log(res);
+			tableData.value = res.data as [];
+			endLoading();
+		}, 1000);
+	});
+}
+
+
+const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+
+async function deleteTableData() {
+	const ids = checkedRowKeysRef.value;
+	// console.log(ids);
+	if (ids.length !== 0) {
+		console.log(ids);
+		for (let id of ids) {
+			// 调用删除接口
+			console.log(id);
+			await deleteById(id as number)
+				.then((res) => {
+					const deleteRes = res.data;
+					if (!deleteRes)
+						console.log(`成功删除课程,ID: ${id}`);
+					window.$message?.success('删除成功!');
+				})
+				.catch((error) => {
+					// 错误处理
+					console.error(`删除课程发生错误,ID: ${id}`, error);
+					window.$message?.error('删除失败!');
+				});
+		}
+		getTableData(); // 删除完成后刷新表格数据
+	} else {
+		// 没有选择任何行时的操作
+		console.warn('未选择要删除的行');
+	}
+}
+
+const createColumns = (): DataTableColumns<UserManagement.User> => [
+	{
+		type: 'selection',
+		align: 'center',
+	},
+	{
+		key: 'id',
+		title: "ID",
+		align: 'center'
+	},
+	{
+		key: 'name',
+		title: '学科名称',
+		align: 'center'
+	},
+	{
+		key: 'description',
+		title: '学科描述',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center',
+
+		render: row => {
+			if (row.disabled) {
+				const tagTypes: Record<UserManagement.UserStatusKey, NaiveUI.ThemeColor> = {
+					'N': 'error',
+					'Y': 'success',
+				};
+				return <NTag type={tagTypes[row.disabled]}>{userStatusLabels[row.disabled]}</NTag>;
+			}
+			return
+		}
+	},
+	{
+		key: 'actions',
+		title: '操作',
+		align: 'center',
+		render: row => {
+			return (
+				<NSpace justify={'center'}>
+					<NButton size={'small'} onClick={() => handleEditTable(row.id)} >
+						编辑
+					</NButton>
+					<NPopconfirm onPositiveClick={() => handleDeleteTable(row.id)}>
+						{{
+							default: () => '确认删除',
+							trigger: () => <NButton size={'small'}>删除</NButton>
+						}}
+					</NPopconfirm>
+				</NSpace>
+			);
+		}
+
+	},
+]
+
+const modalType = ref<ModalType>('add' || 'edit');
+
+function setModalType(type: ModalType) {
+	modalType.value = type;
+	// console.log(modalType.value);
+}
+
+const addData = ref<AddEasEduCategoryParams[]>([]);
+function addTableData() {
+	openModal();
+	setModalType('add');
+	getTableData(); // 删除完成后刷新表格数据
+	// const params: AddEasEduCategoryParams = {};
+	// addEasEduCategory(params).then(res => {
+	// 	console.log(res);
+	// 	addData.value = res.data as [];
+	// });
+}
+
+const editData = ref<UserManagement.User | null>(null);
+function setEditData(data: UserManagement.User | null) {
+	editData.value = data;
+}
+console.log(tableData.value);
+function handleEditTable(rowId: number | null) {
+	const findItem = tableData.value.find(item => item.id === rowId);
+	setModalType('edit');
+	openModal();
+	if (findItem) {
+		setEditData(findItem);
+	}
+	// console.log(findItem);
+	getTableData(); // 编辑完成后刷新表格数据
+}
+
+function handleDeleteTable(rowId: number | null) {
+	const findItem = tableData.value.find(item => item.id === rowId);
+	if (findItem) {
+		deleteById(findItem.id).then((r) => {
+			console.log(r);
+			getTableData(); // 编辑完成后刷新表格数据
+		})
+	}
+}
+
+const showSearch = ref(false)
+
+function handleOpenSearch() {
+	// 点击查询时显示搜索框
+	showSearch.value = true;
+}
+function handleCloseSearch() {
+	// 关闭搜索框,并重新显示主页面
+	showSearch.value = false;
+}
+
+
+function init() {
+	getTableData();
+}
+
+// 初始化
+init();
+
+export default defineComponent({
+	components: {
+		TableActionAdd,
+		ColumnSearch
+	},
+	setup() {
+		// const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+		return {
+			showSearch,
+			tableData,
+			addData,
+			loading,
+			modalType,
+			setEditData,
+			editData,
+			handleCloseSearch,
+			getTableData,
+			addTableData,
+			setModalType,
+			deleteTableData,
+			handleEditTable,
+			handleOpenSearch,
+			visible,
+			columns: createColumns(),
+			checkedRowKeys: checkedRowKeysRef,
+			pagination,
+			rowKey: (row: RowData) => row.id,
+			handleCheck(rowKeys: DataTableRowKey[]) {
+				checkedRowKeysRef.value = rowKeys
+				console.log(checkedRowKeysRef.value);
+			}
+		}
+	}
+})
+</script>

+ 251 - 0
src/views/management/sort/indexsss.vue

@@ -0,0 +1,251 @@
+<template>
+	<div class="h-full overflow-hidden">
+		<n-card title="课程分类" :bordered="false" class="rounded-16px shadow-sm">
+			<n-space class="pb-12px" justify="space-between">
+				<n-space>
+					<n-button type="primary" :data="addData" @click="addTableData">
+						<icon-ic-round-plus class="mr-4px text-20px" />
+						新增
+					</n-button>
+					<n-button type="error" @click="deleteTableData" @update:checked-row-keys="handleCheck">
+						<icon-ic-round-delete class="mr-4px text-20px" />
+						删除
+					</n-button>
+					<!-- <n-button type="success">
+            <icon-uil:export class="mr-4px text-20px" />
+            导出Excel
+          </n-button> -->
+				</n-space>
+				<n-space align="center" :size="18">
+					<n-button size="small" type="primary" @click="getTableData">
+						<icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
+						刷新表格
+					</n-button>
+					<column-setting v-model:columns="columns" />
+				</n-space>
+			</n-space>
+			<n-data-table :columns="columns" :data="tableData" :loading="loading" :pagination="pagination" :row-key="rowKey"
+				@update:checked-row-keys="handleCheck" />
+			<table-action-add v-model:visible="visible" :type="modalType" />
+		</n-card>
+	</div>
+</template>
+
+<script lang="tsx" >
+import { defineComponent, ref } from 'vue'
+import { NButton, NSpace,NTag ,NPopconfirm} from 'naive-ui';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { useBoolean, useLoading } from '@/hooks';
+import type { DataTableRowKey } from 'naive-ui'
+import TableActionAdd from './components/table-action-add.vue'
+import type { ModalType } from './components/table-action-add.vue';
+// import {  userStatusLabels } from '@/constants';
+import { userStatusLabels } from '@/constants';
+import { selectAll_1, deleteById } from '~/src/service/api/sort';
+import type { AddEasEduCategoryParams } from '~/src/service/api/sort';
+
+type RowData = {
+	key: number
+	id: number
+	name: string
+	description: string
+	createTime: string
+	modifyTime: string
+	createUid: number
+	disabled: string
+}
+const { loading, startLoading, endLoading } = useLoading(false);
+const { bool: visible, setTrue: openModal } = useBoolean();
+
+const tableData = ref<any[]>([]);
+
+// const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+		pagination.page = page;
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+		pagination.pageSize = pageSize;
+		pagination.page = 1;
+	}
+}).value;
+
+export async function getTableData() {
+	startLoading();
+	selectAll_1().then(res => {
+		setTimeout(() => {
+			// console.log(res);
+			tableData.value = res.data as [];
+			endLoading();
+		}, 1000);
+	});
+}
+
+
+const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+
+async function deleteTableData() {
+	const ids = checkedRowKeysRef.value;
+	// console.log(ids);
+	if (ids.length !== 0) {
+		console.log(ids);
+		for (let id of ids) {
+			// 调用删除接口
+			console.log(id);
+			await deleteById(id as number)
+				.then((res) => {
+					const deleteRes = res.data;
+					if (!deleteRes)
+						console.log(`成功删除课程,ID: ${id}`);
+					window.$message?.success('删除成功!');
+				})
+				.catch((error) => {
+					// 错误处理
+					console.error(`删除课程发生错误,ID: ${id}`, error);
+					window.$message?.error('删除失败!');
+				});
+		}
+		getTableData(); // 删除完成后刷新表格数据
+	} else {
+		// 没有选择任何行时的操作
+		console.warn('未选择要删除的行');
+	}
+
+}
+
+
+const modalType = ref<ModalType>('add');
+
+function setModalType(type: ModalType) {
+	modalType.value = type;
+}
+
+const addData = ref<AddEasEduCategoryParams[]>([]);
+function addTableData() {
+	openModal();
+	getTableData(); // 删除完成后刷新表格数据
+	setModalType('add');
+	// const params: AddEasEduCategoryParams = {};
+	// addEasEduCategory(params).then(res => {
+	// 	console.log(res);
+	// 	addData.value = res.data as [];
+	// });
+
+}
+
+function init() {
+	getTableData();
+}
+
+// 初始化
+init();
+
+const createColumns = (): DataTableColumns<UserManagement.User> => [
+	{
+		type: 'selection',
+		align: 'center',
+	},
+	{
+		key: 'id',
+		title: "ID",
+		align: 'center'
+	},
+	{
+		key: 'name',
+		title: '学科名称',
+		align: 'center'
+	},
+	{
+		key: 'description',
+		title: '学科描述',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center',
+
+		render: row => {
+			if (row.disabled) {
+				const tagTypes: Record<UserManagement.UserStatusKey, NaiveUI.ThemeColor> = {
+					'Y': 'success',
+					'N': 'error',
+				};
+				return <NTag type={tagTypes[row.disabled]}>{userStatusLabels[row.disabled]}</NTag>;
+		  }
+			return
+		}
+	},
+	{
+		key: 'actions',
+		title: '操作',
+		align: 'center',
+		render: row => {
+			return (
+				<NSpace justify={'center'}>
+					<NButton size={'small'} >
+						编辑
+					</NButton>
+					<NPopconfirm >
+						{{
+							default: () => '确认删除',
+							trigger: () => <NButton size={'small'}>删除</NButton>
+						}}
+					</NPopconfirm>
+				</NSpace>
+			);
+		}
+
+	},
+]
+
+export default defineComponent({
+	components: {
+		TableActionAdd,
+	},
+	setup() {
+		const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+
+		return {
+			tableData,
+			addData,
+			loading,
+			modalType,
+			getTableData,
+			addTableData,
+			setModalType,
+			deleteTableData,
+			visible,
+			columns:createColumns(),
+			checkedRowKeys: checkedRowKeysRef,
+			pagination,
+			rowKey: (row: RowData) => row.id,
+			handleCheck(rowKeys: DataTableRowKey[]) {
+				checkedRowKeysRef.value = rowKeys
+				console.log(checkedRowKeysRef.value);
+			}
+		}
+	}
+})
+</script>

+ 132 - 95
src/views/management/user/components/table-action-modal.vue

@@ -1,149 +1,186 @@
 <template>
-  <n-modal v-model:show="modalVisible" preset="card" :title="title" class="w-700px">
-    <n-form ref="formRef" label-placement="left" :label-width="80" :model="formModel" :rules="rules">
-      <n-grid :cols="24" :x-gap="18">
-        <n-form-item-grid-item :span="12" label="用户名" path="userName">
-          <n-input v-model:value="formModel.userName" />
-        </n-form-item-grid-item>
-        <n-form-item-grid-item :span="12" label="年龄" path="age">
-          <n-input-number v-model:value="formModel.age" clearable />
-        </n-form-item-grid-item>
-        <n-form-item-grid-item :span="12" label="性别" path="gender">
-          <n-radio-group v-model:value="formModel.gender">
-            <n-radio v-for="item in genderOptions" :key="item.value" :value="item.value">{{ item.label }}</n-radio>
-          </n-radio-group>
-        </n-form-item-grid-item>
-        <n-form-item-grid-item :span="12" label="手机号" path="phone">
-          <n-input v-model:value="formModel.phone" />
-        </n-form-item-grid-item>
-        <n-form-item-grid-item :span="12" label="邮箱" path="email">
-          <n-input v-model:value="formModel.email" />
-        </n-form-item-grid-item>
-        <n-form-item-grid-item :span="12" label="状态" path="userStatus">
-          <n-select v-model:value="formModel.userStatus" :options="userStatusOptions" />
-        </n-form-item-grid-item>
-      </n-grid>
-      <n-space class="w-full pt-16px" :size="24" justify="end">
-        <n-button class="w-72px" @click="closeModal">取消</n-button>
-        <n-button class="w-72px" type="primary" @click="handleSubmit">确定</n-button>
-      </n-space>
-    </n-form>
-  </n-modal>
+	<n-modal v-model:show="modalVisible" preset="card" :title="title" class="w-700px">
+		<n-form ref="formRef" label-placement="left" :label-width="100" :model="formModel" :rules="rules">
+			<n-grid :cols="24" :x-gap="18">
+				<!-- <n-form-item-grid-item :span="12" label="ID" path="id">
+					<n-input-number v-model:value="formModel.id" />
+				</n-form-item-grid-item> -->
+				<n-form-item-grid-item :span="12" label="学科名称" path="name">
+					<n-input v-model:value="formModel.name" clearable />
+				</n-form-item-grid-item>
+				<!-- <n-form-item-grid-item :span="12" label="创建时间" path="createTime">
+					  <n-date-picker v-model:value="timestamp" type="datetime" clearable />
+					<n-input v-model:value="formModel.createTime" />
+				</n-form-item-grid-item> -->
+				<n-form-item-grid-item :span="12" label="学科描述" path="description">
+					<n-input v-model:value="formModel.description" clearable />
+					<!-- <n-radio-group v-model:value="formModel.description">
+						<n-radio v-for="item in genderOptions" :key="item.value" :value="item.value">{{ item.label }}</n-radio>
+					</n-radio-group> -->
+				</n-form-item-grid-item>
+
+				<!-- <n-form-item-grid-item :span="12" label="修改时间" path="email">
+					<n-input />
+				</n-form-item-grid-item> -->
+				<n-form-item-grid-item :span="12" label="创建用户ID" path="createUid">
+					<n-input-number v-model:value="formModel.createUid" />
+				</n-form-item-grid-item>
+				<n-form-item-grid-item :span="12" label="状态" path="disabled">
+					<n-select v-model:value="formModel.disabled" :options="userStatusOptions" />
+				</n-form-item-grid-item>
+			</n-grid>
+			<n-space class="w-full pt-16px" :size="24" justify="end">
+				<n-button class="w-72px" @click="closeModal">取消</n-button>
+				<n-button class="w-72px" type="primary" @click="handleSubmit">确定</n-button>
+			</n-space>
+		</n-form>
+	</n-modal>
 </template>
 
 <script setup lang="ts">
 import { ref, computed, reactive, watch } from 'vue';
 import type { FormInst, FormItemRule } from 'naive-ui';
-import { genderOptions, userStatusOptions } from '@/constants';
-import { formRules, createRequiredFormRule } from '@/utils';
+import { userStatusOptions } from '@/constants';
+import {createRequiredFormRule } from '@/utils';
+import { addEasEduCategory, AddEasEduCategoryParams } from '~/src/service/api/sort';
+// import {getTableData} from '../index.vue'
+// const timestamp = ref(1483135260000)
+
 
 export interface Props {
-  /** 弹窗可见性 */
-  visible: boolean;
-  /**
-   * 弹窗类型
-   * add: 新增
-   * edit: 编辑
-   */
-  type?: 'add' | 'edit';
-  /** 编辑的表格行数据 */
-  editData?: UserManagement.User | null;
+	/** 弹窗可见性 */
+	visible: boolean;
+	/**
+	 * 弹窗类型
+	 * add: 新增
+	 * edit: 编辑
+	 * delete : 删除
+	 */
+	type?: 'add' | 'edit' ;
+	/** 编辑的表格行数据 */
+	editData?: UserManagement.User | null;
 }
 
 export type ModalType = NonNullable<Props['type']>;
 
-defineOptions({ name: 'TableActionModal' });
+defineOptions({ name: 'TableActionAdd' });
 
 const props = withDefaults(defineProps<Props>(), {
-  type: 'add',
-  editData: null
+	type: 'add',
+	editData: null,
 });
 
 interface Emits {
-  (e: 'update:visible', visible: boolean): void;
+	(e: 'update:visible', visible: boolean): void;
 }
 
 const emit = defineEmits<Emits>();
 
 const modalVisible = computed({
-  get() {
-    return props.visible;
-  },
-  set(visible) {
-    emit('update:visible', visible);
-  }
+	get() {
+		return props.visible;
+	},
+	set(visible) {
+		emit('update:visible', visible);
+	}
 });
 const closeModal = () => {
-  modalVisible.value = false;
+	modalVisible.value = false;
 };
 
 const title = computed(() => {
-  const titles: Record<ModalType, string> = {
-    add: '添加用户',
-    edit: '编辑用户'
-  };
-  return titles[props.type];
+	const titles: Record<ModalType, string> = {
+		add: '添加用户',
+		edit: '编辑用户',
+	};
+	return titles[props.type];
 });
 
 const formRef = ref<HTMLElement & FormInst>();
 
-type FormModel = Pick<UserManagement.User, 'userName' | 'age' | 'gender' | 'phone' | 'email' | 'userStatus'>;
+type FormModel = Pick<UserManagement.User,  | 'name' | 'description' |  'createUid' | 'disabled'>;
 
 const formModel = reactive<FormModel>(createDefaultFormModel());
 
 const rules: Record<keyof FormModel, FormItemRule | FormItemRule[]> = {
-  userName: createRequiredFormRule('请输入用户名'),
-  age: createRequiredFormRule('请输入年龄'),
-  gender: createRequiredFormRule('请选择性别'),
-  phone: formRules.phone,
-  email: formRules.email,
-  userStatus: createRequiredFormRule('请选择用户状态')
+	// id: createRequiredFormRule('请输入用户名'),
+	name: createRequiredFormRule('请输入学科名称'),
+	description: createRequiredFormRule('请进行部门描述'),
+	// createTime:formRules.createTime,
+	createUid: createRequiredFormRule('请输入创建用户ID'),
+	disabled: createRequiredFormRule('请选择用户状态')
+
 };
 
 function createDefaultFormModel(): FormModel {
-  return {
-    userName: '',
-    age: null,
-    gender: null,
-    phone: '',
-    email: null,
-    userStatus: null
-  };
+	return {
+		// id: null,
+		name: '',
+		description: '',
+		// createTime: '',
+		createUid:null,
+		disabled: null,
+	};
 }
 
+
 function handleUpdateFormModel(model: Partial<FormModel>) {
-  Object.assign(formModel, model);
+	Object.assign(formModel, model);
 }
 
 function handleUpdateFormModelByModalType() {
-  const handlers: Record<ModalType, () => void> = {
-    add: () => {
-      const defaultFormModel = createDefaultFormModel();
-      handleUpdateFormModel(defaultFormModel);
-    },
-    edit: () => {
-      if (props.editData) {
-        handleUpdateFormModel(props.editData);
-      }
-    }
-  };
-
-  handlers[props.type]();
+	const handlers: Record<ModalType, () => void> = {
+		add: () => {
+			const defaultFormModel = createDefaultFormModel();
+			handleUpdateFormModel(defaultFormModel);
+		},
+		edit: () => {
+			if (props.editData) {
+				handleUpdateFormModel(props.editData);
+			}
+		},
+	};
+
+	handlers[props.type]();
 }
 
+// async function handleSubmit() {
+// 	await formRef.value?.validate();
+// 	window.$message?.success('新增成功!');
+// 	closeModal();
+// }
+
+
 async function handleSubmit() {
   await formRef.value?.validate();
-  window.$message?.success('新增成功!');
-  closeModal();
+  const params: AddEasEduCategoryParams = {
+    // id: formModel.id,
+    name: formModel.name,
+    description: formModel.description,
+    // createTime: formModel.createTime,
+    createUid: formModel.createUid,
+    disabled: formModel.disabled
+  };
+  addEasEduCategory(params)
+    .then(res => {
+      window.$message?.success('新增成功!');
+      closeModal();
+			// getTableData();
+    })
+    .catch(error => {
+      console.error(error);
+      window.$message?.error('新增失败!');
+    });
+
 }
 
 watch(
-  () => props.visible,
-  newValue => {
-    if (newValue) {
-      handleUpdateFormModelByModalType();
-    }
-  }
+	() => props.visible,
+	newValue => {
+		if (newValue) {
+			handleUpdateFormModelByModalType();
+		}
+	}
 );
 </script>
 

+ 213 - 154
src/views/management/user/index.vue

@@ -1,199 +1,258 @@
 <template>
-  <div class="h-full overflow-hidden">
-    <n-card title="用户管理" :bordered="false" class="rounded-16px shadow-sm">
-      <n-space class="pb-12px" justify="space-between">
-        <n-space>
-          <n-button type="primary" @click="handleAddTable">
-            <icon-ic-round-plus class="mr-4px text-20px" />
-            新增
-          </n-button>
-          <n-button type="error">
-            <icon-ic-round-delete class="mr-4px text-20px" />
-            删除
-          </n-button>
-          <n-button type="success">
-            <icon-uil:export class="mr-4px text-20px" />
-            导出Excel
-          </n-button>
-        </n-space>
-        <n-space align="center" :size="18">
-          <n-button size="small" type="primary" @click="getTableData">
-            <icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
-            刷新表格
-          </n-button>
-          <column-setting v-model:columns="columns" />
-        </n-space>
-      </n-space>
-      <n-data-table :columns="columns" :data="tableData" :loading="loading" :pagination="pagination" />
-      <table-action-modal v-model:visible="visible" :type="modalType" :edit-data="editData" />
-    </n-card>
-  </div>
+	<div class="h-full overflow-hidden">
+		<n-card title="用户管理" :bordered="false" class="rounded-16px shadow-sm">
+			<n-space class="pb-12px" justify="space-between">
+				<n-space>
+					<n-button type="primary" @click="addTableData">
+						<icon-ic-round-plus class="mr-4px text-20px" />
+						新增
+					</n-button>
+					<n-button type="error" @click="deleteTableData">
+						<icon-ic-round-delete class="mr-4px text-20px" />
+						删除
+					</n-button>
+					<n-button type="success">
+						<icon-uil:export class="mr-4px text-20px" />
+						导出Excel
+					</n-button>
+				</n-space>
+				<n-space align="center" :size="18">
+					<n-button size="small" type="primary" @click="getTableData">
+						<icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
+						刷新表格
+					</n-button>
+					<column-setting v-model:columns="columns" />
+				</n-space>
+			</n-space>
+			<n-data-table :columns="columns" :data="tableData" :loading="loading" :pagination="pagination" :row-key="rowKey"
+				@update:checked-row-keys="handleCheck"/>
+			<table-action-modal v-model:visible="visible" :type="modalType" :edit-data="editData" />
+		</n-card>
+	</div>
 </template>
 
 <script setup lang="tsx">
-import { reactive, ref } from 'vue';
+import {  ref } from 'vue';
 import type { Ref } from 'vue';
 import { NButton, NPopconfirm, NSpace, NTag } from 'naive-ui';
 import type { DataTableColumns, PaginationProps } from 'naive-ui';
-import { genderLabels, userStatusLabels } from '@/constants';
-import { fetchUserList } from '@/service';
+import {  userStatusLabels } from '@/constants';
+// import { fetchUserList } from '@/service';
 import { useBoolean, useLoading } from '@/hooks';
+import type { DataTableRowKey } from 'naive-ui'
 import TableActionModal from './components/table-action-modal.vue';
 import type { ModalType } from './components/table-action-modal.vue';
 import ColumnSetting from './components/column-setting.vue';
-
+import { selectAll_1,deleteById } from '~/src/service/api/sort';
+// import type { AddEasEduCategoryParams } from '~/src/service/api/sort';
 const { loading, startLoading, endLoading } = useLoading(false);
 const { bool: visible, setTrue: openModal } = useBoolean();
 
 const tableData = ref<UserManagement.User[]>([]);
-function setTableData(data: UserManagement.User[]) {
-  tableData.value = data;
+// function setTableData(data: UserManagement.User[]) {
+// 	tableData.value = data;
+// }
+
+ async function getTableData() {
+	startLoading();
+	selectAll_1().then(res => {
+		setTimeout(() => {
+			// console.log(res);
+			tableData.value = res.data as [];
+			endLoading();
+		}, 1000);
+	});
 }
 
-async function getTableData() {
-  startLoading();
-  const { data } = await fetchUserList();
-  if (data) {
-    setTimeout(() => {
-      setTableData(data);
-      endLoading();
-    }, 1000);
-  }
+
+type RowData = {
+	key: number
+	id: number
+	name: string
+	description: string
+	createTime: string
+	modifyTime: string
+	createUid: number
+	disabled: string
 }
 
-const columns: Ref<DataTableColumns<UserManagement.User>> = ref([
-  {
-    type: 'selection',
-    align: 'center'
-  },
-  {
-    key: 'index',
-    title: '序号',
-    align: 'center'
-  },
-  {
-    key: 'userName',
-    title: '用户名',
-    align: 'center'
-  },
-  {
-    key: 'age',
-    title: '用户年龄',
-    align: 'center'
-  },
-  {
-    key: 'gender',
-    title: '性别',
-    align: 'center',
-    render: row => {
-      if (row.gender) {
-        const tagTypes: Record<UserManagement.GenderKey, NaiveUI.ThemeColor> = {
-          '0': 'success',
-          '1': 'warning'
-        };
-
-        return <NTag type={tagTypes[row.gender]}>{genderLabels[row.gender]}</NTag>;
-      }
-
-      return <span></span>;
-    }
-  },
-  {
-    key: 'phone',
-    title: '手机号码',
-    align: 'center'
-  },
-  {
-    key: 'email',
-    title: '邮箱',
-    align: 'center'
-  },
-  {
-    key: 'userStatus',
-    title: '状态',
-    align: 'center',
-    render: row => {
-      if (row.userStatus) {
-        const tagTypes: Record<UserManagement.UserStatusKey, NaiveUI.ThemeColor> = {
-          '1': 'success',
-          '2': 'error',
-          '3': 'warning',
-          '4': 'default'
-        };
-
-        return <NTag type={tagTypes[row.userStatus]}>{userStatusLabels[row.userStatus]}</NTag>;
-      }
-      return <span></span>;
-    }
-  },
-  {
-    key: 'actions',
-    title: '操作',
-    align: 'center',
-    render: row => {
-      return (
-        <NSpace justify={'center'}>
-          <NButton size={'small'} onClick={() => handleEditTable(row.id)}>
-            编辑
-          </NButton>
-          <NPopconfirm onPositiveClick={() => handleDeleteTable(row.id)}>
-            {{
-              default: () => '确认删除',
-              trigger: () => <NButton size={'small'}>删除</NButton>
-            }}
-          </NPopconfirm>
-        </NSpace>
-      );
+const rowKey= (row: RowData) => row.id
+
+function	handleCheck(rowKeys: DataTableRowKey[]) {
+	checkedRowKeysRef.value = rowKeys
+	console.log(checkedRowKeysRef.value);
+}
+
+
+const checkedRowKeysRef = ref<DataTableRowKey[]>([])
+
+async function deleteTableData() {
+  const ids = checkedRowKeysRef.value;
+	// console.log(ids);
+  if (ids.length !== 0) {
+		console.log(ids);
+    for (let id of ids) {
+      // 调用删除接口
+			console.log(id);
+      await deleteById(id as number)
+        .then((res) => {
+          const deleteRes = res.data;
+					if(!deleteRes)
+            console.log(`成功删除课程,ID: ${id}`);
+            window.$message?.success('删除成功!');
+        })
+        .catch((error) => {
+          // 错误处理
+          console.error(`删除课程发生错误,ID: ${id}`, error);
+          window.$message?.error('删除失败!');
+        });
     }
+    getTableData(); // 删除完成后刷新表格数据
+  } else {
+    // 没有选择任何行时的操作
+    console.warn('未选择要删除的行');
   }
+}
+
+const columns: Ref<DataTableColumns<UserManagement.User>> = ref([
+	{
+		type: 'selection',
+		align: 'center',
+	},
+	{
+		key: 'id',
+		title: "ID",
+		align: 'center'
+	},
+	{
+		key: 'name',
+		title: '学科名称',
+		align: 'center'
+	},
+	{
+		key: 'description',
+		title: '学科描述',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center',
+		render: row => {
+			if (row.disabled) {
+				const tagTypes: Record<UserManagement.UserStatusKey, NaiveUI.ThemeColor> = {
+					'Y': 'success',
+					'N': 'error',
+				};
+
+				return <NTag type={tagTypes[row.disabled]}>{userStatusLabels[row.disabled]}</NTag>;
+			}
+			return <span></span>;
+		}
+	},
+	{
+		key: 'actions',
+		title: '操作',
+		align: 'center',
+		render: row => {
+			return (
+				<NSpace justify={'center'}>
+					<NButton size={'small'} onClick={() => handleEditTable(row.id)}>
+						编辑
+					</NButton>
+					<NPopconfirm onPositiveClick={() => handleDeleteTable(row.id)}>
+						{{
+							default: () => '确认删除',
+							trigger: () => <NButton size={'small'}>删除</NButton>
+						}}
+					</NPopconfirm>
+				</NSpace>
+			);
+		}
+	}
 ]) as Ref<DataTableColumns<UserManagement.User>>;
 
 const modalType = ref<ModalType>('add');
 
 function setModalType(type: ModalType) {
-  modalType.value = type;
+	modalType.value = type;
 }
 
+
+// const addData = ref<AddEasEduCategoryParams[]>([]);
+function addTableData() {
+	openModal();
+	getTableData(); // 删除完成后刷新表格数据
+	setModalType('add');
+	// const params: AddEasEduCategoryParams = {};
+	// addEasEduCategory(params).then(res => {
+	// 	console.log(res);
+	// 	addData.value = res.data as [];
+	// });
+
+}
+
+
 const editData = ref<UserManagement.User | null>(null);
 
 function setEditData(data: UserManagement.User | null) {
-  editData.value = data;
+	editData.value = data;
 }
 
-function handleAddTable() {
-  openModal();
-  setModalType('add');
-}
+// function handleAddTable() {
+// 	openModal();
+// 	setModalType('add');
+// }
 
 function handleEditTable(rowId: string) {
-  const findItem = tableData.value.find(item => item.id === rowId);
-  if (findItem) {
-    setEditData(findItem);
-  }
-  setModalType('edit');
-  openModal();
+	const findItem = tableData.value.find(item => item.id === rowId);
+	if (findItem) {
+		setEditData(findItem);
+	}
+	setModalType('edit');
+	openModal();
 }
 
+
+
+
 function handleDeleteTable(rowId: string) {
-  window.$message?.info(`点击了删除,rowId为${rowId}`);
+	window.$message?.info(`点击了删除,rowId为${rowId}`);
 }
 
-const pagination: PaginationProps = reactive({
-  page: 1,
-  pageSize: 10,
-  showSizePicker: true,
-  pageSizes: [10, 15, 20, 25, 30],
-  onChange: (page: number) => {
-    pagination.page = page;
-  },
-  onUpdatePageSize: (pageSize: number) => {
-    pagination.pageSize = pageSize;
-    pagination.page = 1;
-  }
-});
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+		pagination.page = page;
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+		pagination.pageSize = pageSize;
+		pagination.page = 1;
+	}
+}).value;
 
 function init() {
-  getTableData();
+	getTableData();
 }
 
 // 初始化

+ 127 - 0
src/views/management/user/indexCopy.vue

@@ -0,0 +1,127 @@
+<template>
+	<div class="h-full overflow-hidden">
+		<n-card title="权限管理" :bordered="false" class="rounded-16px shadow-sm">
+			<n-data-table :columns="columns" :data="tableData" :pagination="pagination" />
+		</n-card>
+	</div>
+</template>
+
+<script setup lang="tsx">
+import { ref } from 'vue';
+import type { Ref } from 'vue';
+
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+
+import { query_1 } from '~/src/service/api/user';
+import type { Query_1Params } from '~/src/service/api/user';
+
+const tableData = ref<Query_1Params[]>([]);
+
+function setTableData(data: Query_1Params[]) {
+	tableData.value = data;
+}
+
+async function getTableData() {
+	const pageNum = pagination.page as number;
+	const pageSize = pagination.pageSize as number;
+
+	const params: Query_1Params = {
+		depname: '',
+		address: '',
+		phone: '',
+		email: '',
+		manager: '',
+		createTime: "",
+		modifyTime: "" ,
+		createUid: 0,
+		disabled: '',
+	};
+
+	query_1(pageNum, pageSize, params)
+		.then(response => {
+			console.log(response);
+
+			const data: Query_1Params[] = response.data as Query_1Params[]; // 使用类型断言
+			setTimeout(() => {
+				setTableData(data);
+			}, 1000);
+		})
+		.catch(error => {
+			// 处理错误情况
+		});
+
+}
+
+const columns: Ref<DataTableColumns<Query_1Params>> = ref([
+	{
+		type: 'selection',
+		align: 'center'
+	},
+	{
+		key: 'depname',
+		title: '部门名称',
+		align: 'center'
+	},
+	{
+		key: 'address',
+		title: '部门地址',
+		align: 'center'
+	},
+	{
+		key: 'phone',
+		title: '部门电话',
+		align: 'center'
+	},
+	{
+		key: 'email',
+		title: '部门电子邮箱',
+		align: 'center',
+	},
+	{
+		key: 'manager',
+		title: '部门负责人',
+		align: 'center'
+	},
+	{
+		key: 'createTime',
+		title: '创建时间',
+		align: 'center'
+	},
+	{
+		key: 'modifyTime',
+		title: '修改时间',
+		align: 'center'
+	},
+	{
+		key: 'createUid',
+		title: '创建用户ID',
+		align: 'center'
+	},
+	{
+		key: 'disabled',
+		title: '状态',
+		align: 'center'
+	},
+
+]) as Ref<DataTableColumns<Query_1Params>>;
+
+const pagination: PaginationProps = ref({
+	page: 1,
+	pageSize: 10,
+	showSizePicker: true,
+	pageSizes: [10, 20, 50],
+	onChange: (page: number) => {
+		// 处理页码变化
+	},
+	onUpdatePageSize: (pageSize: number) => {
+		// 处理每页显示数量变化
+	}
+}).value;
+
+function init() {
+	getTableData();
+}
+
+// 初始化
+init();
+</script>

+ 1 - 1
tsconfig.json

@@ -18,7 +18,7 @@
       "~/*": ["./*"],
       "@/*": ["./src/*"]
     },
-    "types": ["vite/client", "node", "unplugin-icons/types/vue", "naive-ui/volar"]
+    "types": ["vite/client", "node", "unplugin-icons/types/vue", "naive-ui/volar", "vue"]
   },
   "exclude": ["node_modules", "dist"]
 }

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels