Prechádzať zdrojové kódy

!299 refactor vue3 vxe crud
Merge pull request !299 from xingyu/feature/vue3

芋道源码 2 rokov pred
rodič
commit
29cd9b79de

+ 95 - 92
yudao-ui-admin-vue3/pnpm-lock.yaml

@@ -1,4 +1,4 @@
-lockfileVersion: 5.3
+lockfileVersion: 5.4
 
 specifiers:
   '@commitlint/cli': ^17.2.0
@@ -84,7 +84,7 @@ dependencies:
   '@iconify/iconify': 3.0.0
   '@vueuse/core': 9.5.0_vue@3.2.44
   '@wangeditor/editor': 5.1.22
-  '@wangeditor/editor-for-vue': 5.1.12_95363b7c2c964a937bf2a01c911df30e
+  '@wangeditor/editor-for-vue': 5.1.12_su3dw7bmszfjg67suaojchptby
   '@zxcvbn-ts/core': 2.1.0
   animate.css: 4.1.1
   axios: 0.27.2
@@ -99,7 +99,7 @@ dependencies:
   lodash-es: 4.17.21
   mitt: 3.0.0
   nprogress: 0.2.0
-  pinia: 2.0.23_typescript@4.8.4+vue@3.2.44
+  pinia: 2.0.23_d45o5shxrtvj6wh4y524t7cqnm
   qrcode: 1.5.1
   qs: 6.11.0
   url: 0.11.0
@@ -124,15 +124,15 @@ devDependencies:
   '@types/nprogress': 0.2.0
   '@types/qrcode': 1.5.0
   '@types/qs': 6.9.7
-  '@typescript-eslint/eslint-plugin': 5.42.1_d506b9be61cb4ac2646ecbc6e0680464
-  '@typescript-eslint/parser': 5.42.1_eslint@8.27.0+typescript@4.8.4
+  '@typescript-eslint/eslint-plugin': 5.42.1_2udltptbznfmezdozpdoa2aemq
+  '@typescript-eslint/parser': 5.42.1_rmayb2veg2btbq6mbmnyivgasy
   '@vitejs/plugin-vue': 3.2.0_vite@3.2.3+vue@3.2.44
   '@vitejs/plugin-vue-jsx': 2.1.1_vite@3.2.3+vue@3.2.44
   autoprefixer: 10.4.13_postcss@8.4.18
   eslint: 8.27.0
   eslint-config-prettier: 8.5.0_eslint@8.27.0
   eslint-define-config: 1.12.0
-  eslint-plugin-prettier: 4.2.1_afddd95fb7dd832efd05cfac2e17feb1
+  eslint-plugin-prettier: 4.2.1_v7o5sx5x3wbs57ifz6wc4f76we
   eslint-plugin-vue: 9.7.0_eslint@8.27.0
   less: 4.1.3
   lint-staged: 13.0.3
@@ -144,14 +144,14 @@ devDependencies:
   rimraf: 3.0.2
   rollup: 3.2.5
   stylelint: 14.14.1
-  stylelint-config-html: 1.1.0_0711e485e505c8bbf0b549e6b356f7f2
+  stylelint-config-html: 1.1.0_a4i6jbpfaxelx4fvjhtlgvxx6i
   stylelint-config-prettier: 9.0.4_stylelint@14.14.1
   stylelint-config-recommended: 9.0.0_stylelint@14.14.1
   stylelint-config-standard: 29.0.0_stylelint@14.14.1
   stylelint-order: 5.0.0_stylelint@14.14.1
   typescript: 4.8.4
-  unplugin-vue-macros: 0.16.2_688fcac82e974ec4fd5c071d8de5a7a5
-  vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+  unplugin-vue-macros: 0.16.2_nch4vsbos5hmj7k4a4oy3znhuu
+  vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
   vite-plugin-compression: 0.5.1_vite@3.2.3
   vite-plugin-eslint: 1.8.1_eslint@8.27.0+vite@3.2.3
   vite-plugin-html: 3.2.0_vite@3.2.3
@@ -574,10 +574,10 @@ packages:
       '@types/node': 14.18.31
       chalk: 4.1.2
       cosmiconfig: 7.0.1
-      cosmiconfig-typescript-loader: 4.1.1_33d7b64ae90e9bb80d48469351c457b9
+      cosmiconfig-typescript-loader: 4.1.1_gpl3msxjb2n3qdkii2jvdrcxxe
       lodash: 4.17.21
       resolve-from: 5.0.0
-      ts-node: 10.9.1_2abc08acbb4fe741ae8218df9aa74f5c
+      ts-node: 10.9.1_fk6arlf3j7tudlucddpzvj2plq
       typescript: 4.8.4
     transitivePeerDependencies:
       - '@swc/core'
@@ -658,7 +658,7 @@ packages:
       '@jridgewell/trace-mapping': 0.3.9
     dev: true
 
-  /@csstools/selector-specificity/2.0.2_1d546e2941f6b4ca889831b9fbdc79d8:
+  /@csstools/selector-specificity/2.0.2_dvkg4kkb622mvceygg47xxdz3a:
     resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==}
     engines: {node: ^12 || ^14 || >=16}
     peerDependencies:
@@ -798,14 +798,12 @@ packages:
       '@intlify/message-compiler': 9.2.2
       '@intlify/shared': 9.2.2
       '@intlify/vue-devtools': 9.2.2
-    dev: false
 
   /@intlify/devtools-if/9.2.2:
     resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
     engines: {node: '>= 14'}
     dependencies:
       '@intlify/shared': 9.2.2
-    dev: false
 
   /@intlify/message-compiler/9.2.2:
     resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
@@ -813,7 +811,6 @@ packages:
     dependencies:
       '@intlify/shared': 9.2.2
       source-map: 0.6.1
-    dev: false
 
   /@intlify/message-compiler/9.3.0-beta.6:
     resolution: {integrity: sha512-3PJqRJoqvFHExA9DCkf7fZYKbvYne1tYQ0fptJAhUOZsELarh8wr4aPLKWCkQSRuutdrtZ/n5CcPgJgUmVthDw==}
@@ -826,7 +823,6 @@ packages:
   /@intlify/shared/9.2.2:
     resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
     engines: {node: '>= 14'}
-    dev: false
 
   /@intlify/shared/9.3.0-beta.6:
     resolution: {integrity: sha512-ITA1R4tvJYwZXT5x6QCSwxcwQ4dU52zrzVm/EUbgsp8oWzYS1xexBrxyNM80PSQudYvL2rvcZJKQ7yBh7b0LkQ==}
@@ -854,7 +850,7 @@ packages:
       debug: 4.3.4
       fast-glob: 3.2.12
       source-map: 0.6.1
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
       vue-i18n: 9.2.2_vue@3.2.44
     transitivePeerDependencies:
       - supports-color
@@ -866,7 +862,6 @@ packages:
     dependencies:
       '@intlify/core-base': 9.2.2
       '@intlify/shared': 9.2.2
-    dev: false
 
   /@jridgewell/gen-mapping/0.1.1:
     resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
@@ -1097,9 +1092,8 @@ packages:
 
   /@types/web-bluetooth/0.0.16:
     resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
-    dev: false
 
-  /@typescript-eslint/eslint-plugin/5.42.1_d506b9be61cb4ac2646ecbc6e0680464:
+  /@typescript-eslint/eslint-plugin/5.42.1_2udltptbznfmezdozpdoa2aemq:
     resolution: {integrity: sha512-LyR6x784JCiJ1j6sH5Y0K6cdExqCCm8DJUTcwG5ThNXJj/G8o5E56u5EdG4SLy+bZAwZBswC+GYn3eGdttBVCg==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1110,10 +1104,10 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 5.42.1_eslint@8.27.0+typescript@4.8.4
+      '@typescript-eslint/parser': 5.42.1_rmayb2veg2btbq6mbmnyivgasy
       '@typescript-eslint/scope-manager': 5.42.1
-      '@typescript-eslint/type-utils': 5.42.1_eslint@8.27.0+typescript@4.8.4
-      '@typescript-eslint/utils': 5.42.1_eslint@8.27.0+typescript@4.8.4
+      '@typescript-eslint/type-utils': 5.42.1_rmayb2veg2btbq6mbmnyivgasy
+      '@typescript-eslint/utils': 5.42.1_rmayb2veg2btbq6mbmnyivgasy
       debug: 4.3.4
       eslint: 8.27.0
       ignore: 5.2.0
@@ -1126,7 +1120,7 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/parser/5.42.1_eslint@8.27.0+typescript@4.8.4:
+  /@typescript-eslint/parser/5.42.1_rmayb2veg2btbq6mbmnyivgasy:
     resolution: {integrity: sha512-kAV+NiNBWVQDY9gDJDToTE/NO8BHi4f6b7zTsVAJoTkmB/zlfOpiEVBzHOKtlgTndCKe8vj9F/PuolemZSh50Q==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1154,7 +1148,7 @@ packages:
       '@typescript-eslint/visitor-keys': 5.42.1
     dev: true
 
-  /@typescript-eslint/type-utils/5.42.1_eslint@8.27.0+typescript@4.8.4:
+  /@typescript-eslint/type-utils/5.42.1_rmayb2veg2btbq6mbmnyivgasy:
     resolution: {integrity: sha512-WWiMChneex5w4xPIX56SSnQQo0tEOy5ZV2dqmj8Z371LJ0E+aymWD25JQ/l4FOuuX+Q49A7pzh/CGIQflxMVXg==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1165,7 +1159,7 @@ packages:
         optional: true
     dependencies:
       '@typescript-eslint/typescript-estree': 5.42.1_typescript@4.8.4
-      '@typescript-eslint/utils': 5.42.1_eslint@8.27.0+typescript@4.8.4
+      '@typescript-eslint/utils': 5.42.1_rmayb2veg2btbq6mbmnyivgasy
       debug: 4.3.4
       eslint: 8.27.0
       tsutils: 3.21.0_typescript@4.8.4
@@ -1200,7 +1194,7 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/utils/5.42.1_eslint@8.27.0+typescript@4.8.4:
+  /@typescript-eslint/utils/5.42.1_rmayb2veg2btbq6mbmnyivgasy:
     resolution: {integrity: sha512-Gxvf12xSp3iYZd/fLqiQRD4uKZjDNR01bQ+j8zvhPjpsZ4HmvEFL/tC4amGNyxN9Rq+iqvpHLhlqx6KTxz9ZyQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1279,7 +1273,7 @@ packages:
       '@babel/core': 7.19.6
       '@babel/plugin-transform-typescript': 7.20.2_@babel+core@7.19.6
       '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.19.6
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
       vue: 3.2.44
     transitivePeerDependencies:
       - supports-color
@@ -1292,7 +1286,7 @@ packages:
       vite: ^3.0.0
       vue: ^3.2.25
     dependencies:
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
       vue: 3.2.44
     dev: true
 
@@ -1424,7 +1418,7 @@ packages:
       unplugin: 0.10.2
     dev: true
 
-  /@vue-macros/named-template/0.0.5_aaae75a03f99901122a33a7412c8cd0a:
+  /@vue-macros/named-template/0.0.5_vkxhlib7tgibcivdhj2bfsgnbi:
     resolution: {integrity: sha512-bZRUljNyvOOqeE9dyqXvKPQCLUCcPt1EkThmXqSbxagV29ohyviF8+CCs/8OdmNygLTBIChjP8DexQ3nUIFzUg==}
     engines: {node: '>=14.19.0'}
     dependencies:
@@ -1521,7 +1515,6 @@ packages:
       '@vue/shared': 3.2.44
       estree-walker: 2.0.2
       source-map: 0.6.1
-    dev: false
 
   /@vue/compiler-dom/3.2.41:
     resolution: {integrity: sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==}
@@ -1542,7 +1535,6 @@ packages:
     dependencies:
       '@vue/compiler-core': 3.2.44
       '@vue/shared': 3.2.44
-    dev: false
 
   /@vue/compiler-sfc/3.2.41:
     resolution: {integrity: sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==}
@@ -1587,7 +1579,6 @@ packages:
       magic-string: 0.25.9
       postcss: 8.4.18
       source-map: 0.6.1
-    dev: false
 
   /@vue/compiler-ssr/3.2.41:
     resolution: {integrity: sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==}
@@ -1608,11 +1599,9 @@ packages:
     dependencies:
       '@vue/compiler-dom': 3.2.44
       '@vue/shared': 3.2.44
-    dev: false
 
   /@vue/devtools-api/6.4.3:
     resolution: {integrity: sha512-9WCRwdROJvWcHAdyrR7SZMM/qUvllDZnpndHXokThkUsjnJ2xe4/pvsH9FZrxFe22L+JmDKczL79HjLJ7DK9rg==}
-    dev: false
 
   /@vue/devtools-api/6.4.4:
     resolution: {integrity: sha512-Ku31WzpOV/8cruFaXaEZKF81WkNnvCSlBY4eOGtz5WMSdJvX1v1WWlSMGZeqUwPtQ27ZZz7B62erEMq8JDjcXw==}
@@ -1650,7 +1639,6 @@ packages:
       '@vue/shared': 3.2.44
       estree-walker: 2.0.2
       magic-string: 0.25.9
-    dev: false
 
   /@vue/reactivity/3.2.41:
     resolution: {integrity: sha512-9JvCnlj8uc5xRiQGZ28MKGjuCoPhhTwcoAdv3o31+cfGgonwdPNuvqAXLhlzu4zwqavFEG5tvaoINQEfxz+l6g==}
@@ -1662,14 +1650,12 @@ packages:
     resolution: {integrity: sha512-Fe0s52fTsPl+RSdvoqUZ3HRKlaVsKhIh1mea5EWOedFvZCjnymzlj3YC1wZMxi89qXRFSdEASVA/BWUGypk0Ig==}
     dependencies:
       '@vue/shared': 3.2.44
-    dev: false
 
   /@vue/runtime-core/3.2.44:
     resolution: {integrity: sha512-uwEV1cttL33k2dC+CNGYhKEYqGejT9KmgQ+4n/LmYUfZ1Gorl8F32DlIX+1pANyGHL1tBAisqHDxKyQBp2oBNA==}
     dependencies:
       '@vue/reactivity': 3.2.44
       '@vue/shared': 3.2.44
-    dev: false
 
   /@vue/runtime-dom/3.2.44:
     resolution: {integrity: sha512-LDzNwXpU/nSpxrLk5jS0bfStgt88msgsgFzj6vHrl7es3QktIrCGybQS5CB/p/TO0q98iAiYtEVmi+Lej7Vgjg==}
@@ -1677,7 +1663,6 @@ packages:
       '@vue/runtime-core': 3.2.44
       '@vue/shared': 3.2.44
       csstype: 2.6.21
-    dev: false
 
   /@vue/server-renderer/3.2.44_vue@3.2.44:
     resolution: {integrity: sha512-3+ArN07UgOAdbGKIp3uVqeC3bnR3J324QNjPR6vxHbLrTlkibFv8QNled/ux3fVq0KDCkVVKGOKB2V4sCIYOgg==}
@@ -1687,7 +1672,6 @@ packages:
       '@vue/compiler-ssr': 3.2.44
       '@vue/shared': 3.2.44
       vue: 3.2.44
-    dev: false
 
   /@vue/shared/3.2.41:
     resolution: {integrity: sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==}
@@ -1699,7 +1683,6 @@ packages:
 
   /@vue/shared/3.2.44:
     resolution: {integrity: sha512-mGZ44bnn0zpZ36nXtxbrBPno43yr96wjQE1dBEKS1Sieugt27HS4OGZVBRIgsdGzosB7vqZAvu0ttu1FDVdolA==}
-    dev: false
 
   /@vueuse/core/9.5.0_vue@3.2.44:
     resolution: {integrity: sha512-6GsWBsJHEb3sYw15mbLrcbslAVY45pkzjJYTKYKCXv88z7srAF0VEW0q+oXKsl58tCbqooplInahXFg8Yo1m4w==}
@@ -1711,11 +1694,9 @@ packages:
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
-    dev: false
 
   /@vueuse/metadata/9.5.0:
     resolution: {integrity: sha512-4M1AyPZmIv41pym+K5+4wup3bKuYebbH8w8BROY1hmT7rIwcyS4tEL+UsGz0Hiu1FCOxcoBrwtAizc0YmBJjyQ==}
-    dev: false
 
   /@vueuse/shared/9.5.0_vue@3.2.44:
     resolution: {integrity: sha512-HnnCWU1Vg9CVWRCcI8ohDKDRB2Sc4bTgT1XAIaoLSfVHHn+TKbrox6pd3klCSw4UDxkhDfOk8cAdcK+Z5KleCA==}
@@ -1724,9 +1705,8 @@ packages:
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
-    dev: false
 
-  /@wangeditor/basic-modules/1.1.6_77a30faf19af486fa77beec27d9e830b:
+  /@wangeditor/basic-modules/1.1.6_o6rq7lyzv5eg7j3353bh3hudbm:
     resolution: {integrity: sha512-wckcFm/kEAHpTn7dTmN0+7POFoygqt9bZdNHJUkdKObXtAerml8RdjrkHRcwJFCkSELbrNK63fvkwS0+FsabfA==}
     peerDependencies:
       '@wangeditor/core': 1.x
@@ -1736,7 +1716,7 @@ packages:
       slate: ^0.72.0
       snabbdom: ^3.1.0
     dependencies:
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
       dom7: 3.0.0
       is-url: 1.2.4
       lodash.throttle: 4.1.1
@@ -1745,7 +1725,7 @@ packages:
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/code-highlight/1.0.3_5fc334405e4d9219aba9f66fdd32274f:
+  /@wangeditor/code-highlight/1.0.3_l7btiqc6jwjbtk5j6zx52mrhj4:
     resolution: {integrity: sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==}
     peerDependencies:
       '@wangeditor/core': 1.x
@@ -1753,14 +1733,14 @@ packages:
       slate: ^0.72.0
       snabbdom: ^3.1.0
     dependencies:
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
       dom7: 3.0.0
       prismjs: 1.29.0
       slate: 0.72.8
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/core/1.1.18_83942e33b1d7a7a6aab922626cc5c0f9:
+  /@wangeditor/core/1.1.18_qokc4m5r26t2nkvzejrgzroa7e:
     resolution: {integrity: sha512-GZsW/8tm2Hc2hZKX8BZP9PO7vTZll9YXsOt+jKck3D2bj9nk4T0FZymuE5fq9ZHdo+MwLiXBHXS/D1SIGlVnGQ==}
     peerDependencies:
       '@uppy/core': ^2.1.1
@@ -1800,7 +1780,7 @@ packages:
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/editor-for-vue/5.1.12_95363b7c2c964a937bf2a01c911df30e:
+  /@wangeditor/editor-for-vue/5.1.12_su3dw7bmszfjg67suaojchptby:
     resolution: {integrity: sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==}
     peerDependencies:
       '@wangeditor/editor': '>=5.1.0'
@@ -1815,13 +1795,13 @@ packages:
     dependencies:
       '@uppy/core': 2.3.4
       '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
-      '@wangeditor/basic-modules': 1.1.6_77a30faf19af486fa77beec27d9e830b
-      '@wangeditor/code-highlight': 1.0.3_5fc334405e4d9219aba9f66fdd32274f
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
-      '@wangeditor/list-module': 1.0.5_5fc334405e4d9219aba9f66fdd32274f
-      '@wangeditor/table-module': 1.1.4_5d8cd29e73aad229850928ebedfb04b7
-      '@wangeditor/upload-image-module': 1.0.2_7a9aad2bf3b86405f1f37087d2b924a4
-      '@wangeditor/video-module': 1.1.4_47db22f98847f2d6b6569a7e95c5dcf5
+      '@wangeditor/basic-modules': 1.1.6_o6rq7lyzv5eg7j3353bh3hudbm
+      '@wangeditor/code-highlight': 1.0.3_l7btiqc6jwjbtk5j6zx52mrhj4
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
+      '@wangeditor/list-module': 1.0.5_l7btiqc6jwjbtk5j6zx52mrhj4
+      '@wangeditor/table-module': 1.1.4_lwgnfhttvljctbijfdv636yew4
+      '@wangeditor/upload-image-module': 1.0.2_pknk2k7txbsal4ptocd5fojeuq
+      '@wangeditor/video-module': 1.1.4_i7nsf6mii7znnnswtj7jlro46u
       dom7: 3.0.0
       is-hotkey: 0.2.0
       lodash.camelcase: 4.3.0
@@ -1836,7 +1816,7 @@ packages:
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/list-module/1.0.5_5fc334405e4d9219aba9f66fdd32274f:
+  /@wangeditor/list-module/1.0.5_l7btiqc6jwjbtk5j6zx52mrhj4:
     resolution: {integrity: sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==}
     peerDependencies:
       '@wangeditor/core': 1.x
@@ -1844,13 +1824,13 @@ packages:
       slate: ^0.72.0
       snabbdom: ^3.1.0
     dependencies:
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
       dom7: 3.0.0
       slate: 0.72.8
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/table-module/1.1.4_5d8cd29e73aad229850928ebedfb04b7:
+  /@wangeditor/table-module/1.1.4_lwgnfhttvljctbijfdv636yew4:
     resolution: {integrity: sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==}
     peerDependencies:
       '@wangeditor/core': 1.x
@@ -1861,7 +1841,7 @@ packages:
       slate: ^0.72.0
       snabbdom: ^3.1.0
     dependencies:
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
       dom7: 3.0.0
       lodash.isequal: 4.5.0
       lodash.throttle: 4.1.1
@@ -1870,7 +1850,7 @@ packages:
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/upload-image-module/1.0.2_7a9aad2bf3b86405f1f37087d2b924a4:
+  /@wangeditor/upload-image-module/1.0.2_pknk2k7txbsal4ptocd5fojeuq:
     resolution: {integrity: sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==}
     peerDependencies:
       '@uppy/core': ^2.0.3
@@ -1884,15 +1864,15 @@ packages:
     dependencies:
       '@uppy/core': 2.3.4
       '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
-      '@wangeditor/basic-modules': 1.1.6_77a30faf19af486fa77beec27d9e830b
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
+      '@wangeditor/basic-modules': 1.1.6_o6rq7lyzv5eg7j3353bh3hudbm
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
       dom7: 3.0.0
       lodash.foreach: 4.5.0
       slate: 0.72.8
       snabbdom: 3.5.1
     dev: false
 
-  /@wangeditor/video-module/1.1.4_47db22f98847f2d6b6569a7e95c5dcf5:
+  /@wangeditor/video-module/1.1.4_i7nsf6mii7znnnswtj7jlro46u:
     resolution: {integrity: sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==}
     peerDependencies:
       '@uppy/core': ^2.1.4
@@ -1905,7 +1885,7 @@ packages:
     dependencies:
       '@uppy/core': 2.3.4
       '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
-      '@wangeditor/core': 1.1.18_83942e33b1d7a7a6aab922626cc5c0f9
+      '@wangeditor/core': 1.1.18_qokc4m5r26t2nkvzejrgzroa7e
       dom7: 3.0.0
       nanoid: 3.3.4
       slate: 0.72.8
@@ -2269,6 +2249,8 @@ packages:
       snapdragon-node: 2.1.1
       split-string: 3.1.0
       to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /braces/3.0.2:
@@ -2652,8 +2634,8 @@ packages:
     engines: {node: '>=10'}
     hasBin: true
     dependencies:
-      is-text-path: 1.0.1
       JSONStream: 1.3.5
+      is-text-path: 1.0.1
       lodash: 4.17.21
       meow: 8.1.2
       split2: 3.2.2
@@ -2685,7 +2667,7 @@ packages:
       vary: 1.1.2
     dev: true
 
-  /cosmiconfig-typescript-loader/4.1.1_33d7b64ae90e9bb80d48469351c457b9:
+  /cosmiconfig-typescript-loader/4.1.1_gpl3msxjb2n3qdkii2jvdrcxxe:
     resolution: {integrity: sha512-9DHpa379Gp0o0Zefii35fcmuuin6q92FnLDffzdZ0l9tVd3nEobG3O+MZ06+kuBvFTSVScvNb/oHA13Nd4iipg==}
     engines: {node: '>=12', npm: '>=6'}
     peerDependencies:
@@ -2696,7 +2678,7 @@ packages:
     dependencies:
       '@types/node': 14.18.31
       cosmiconfig: 7.0.1
-      ts-node: 10.9.1_2abc08acbb4fe741ae8218df9aa74f5c
+      ts-node: 10.9.1_fk6arlf3j7tudlucddpzvj2plq
       typescript: 4.8.4
     dev: true
 
@@ -2779,7 +2761,6 @@ packages:
 
   /csstype/2.6.21:
     resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
-    dev: false
 
   /d/1.0.1:
     resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
@@ -2803,12 +2784,22 @@ packages:
 
   /debug/2.6.9:
     resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
     dependencies:
       ms: 2.0.0
     dev: true
 
   /debug/3.2.7:
     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
     dependencies:
       ms: 2.1.3
     dev: true
@@ -3074,7 +3065,7 @@ packages:
       escape-html: 1.0.3
       lodash: 4.17.21
       lodash-es: 4.17.21
-      lodash-unified: 1.0.2_da03a4540fbd16bbaafbb96724306afd
+      lodash-unified: 1.0.2_3ib2ivapxullxkx3xftsimdk7u
       memoize-one: 6.0.0
       normalize-wheel-es: 1.2.0
       vue: 3.2.44
@@ -3398,7 +3389,7 @@ packages:
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13', pnpm: '>= 7.0.0'}
     dev: true
 
-  /eslint-plugin-prettier/4.2.1_afddd95fb7dd832efd05cfac2e17feb1:
+  /eslint-plugin-prettier/4.2.1_v7o5sx5x3wbs57ifz6wc4f76we:
     resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
     engines: {node: '>=12.0.0'}
     peerDependencies:
@@ -3632,6 +3623,8 @@ packages:
       regex-not: 1.0.2
       snapdragon: 0.8.2
       to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /expand-tilde/2.0.2:
@@ -3687,6 +3680,8 @@ packages:
       regex-not: 1.0.2
       snapdragon: 0.8.2
       to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /fast-deep-equal/3.1.3:
@@ -4708,6 +4703,8 @@ packages:
       mime: 1.6.0
       needle: 3.1.0
       source-map: 0.6.1
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /levn/0.4.1:
@@ -4814,7 +4811,7 @@ packages:
     resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
     dev: false
 
-  /lodash-unified/1.0.2_da03a4540fbd16bbaafbb96724306afd:
+  /lodash-unified/1.0.2_3ib2ivapxullxkx3xftsimdk7u:
     resolution: {integrity: sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g==}
     peerDependencies:
       '@types/lodash-es': '*'
@@ -5043,6 +5040,8 @@ packages:
       regex-not: 1.0.2
       snapdragon: 0.8.2
       to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /micromatch/4.0.5:
@@ -5183,6 +5182,8 @@ packages:
       regex-not: 1.0.2
       snapdragon: 0.8.2
       to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /natural-compare-lite/1.4.0:
@@ -5202,6 +5203,8 @@ packages:
       debug: 3.2.7
       iconv-lite: 0.6.3
       sax: 1.2.4
+    transitivePeerDependencies:
+      - supports-color
     dev: true
     optional: true
 
@@ -5602,7 +5605,7 @@ packages:
     dev: true
     optional: true
 
-  /pinia/2.0.23_typescript@4.8.4+vue@3.2.44:
+  /pinia/2.0.23_d45o5shxrtvj6wh4y524t7cqnm:
     resolution: {integrity: sha512-N15hFf4o5STrxpNrib1IEb1GOArvPYf1zPvQVRGOO1G1d74Ak0J0lVyalX/SmrzdT4Q0nlEFjbURsmBmIGUR5Q==}
     peerDependencies:
       '@vue/composition-api': ^1.4.0
@@ -6258,6 +6261,8 @@ packages:
       source-map: 0.5.7
       source-map-resolve: 0.5.3
       use: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /source-map-js/1.0.2:
@@ -6430,7 +6435,7 @@ packages:
     resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
     dev: true
 
-  /stylelint-config-html/1.1.0_0711e485e505c8bbf0b549e6b356f7f2:
+  /stylelint-config-html/1.1.0_a4i6jbpfaxelx4fvjhtlgvxx6i:
     resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==}
     engines: {node: ^12 || >=14}
     peerDependencies:
@@ -6483,7 +6488,7 @@ packages:
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     hasBin: true
     dependencies:
-      '@csstools/selector-specificity': 2.0.2_1d546e2941f6b4ca889831b9fbdc79d8
+      '@csstools/selector-specificity': 2.0.2_dvkg4kkb622mvceygg47xxdz3a
       balanced-match: 2.0.0
       colord: 2.9.3
       cosmiconfig: 7.0.1
@@ -6580,6 +6585,8 @@ packages:
       posthtml-svg-mode: 1.0.3
       query-string: 4.3.4
       traverse: 0.6.6
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /svg-tags/1.0.0:
@@ -6707,7 +6714,7 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
-  /ts-node/10.9.1_2abc08acbb4fe741ae8218df9aa74f5c:
+  /ts-node/10.9.1_fk6arlf3j7tudlucddpzvj2plq:
     resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
     hasBin: true
     peerDependencies:
@@ -6804,7 +6811,6 @@ packages:
     resolution: {integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==}
     engines: {node: '>=4.2.0'}
     hasBin: true
-    dev: true
 
   /uglify-js/3.17.3:
     resolution: {integrity: sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==}
@@ -6855,7 +6861,7 @@ packages:
       '@antfu/utils': 0.6.0
       rollup: 3.2.5
       unplugin: 0.10.2
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     dev: true
 
   /unplugin-vue-define-options/0.12.7:
@@ -6868,7 +6874,7 @@ packages:
       unplugin: 0.10.2
     dev: true
 
-  /unplugin-vue-macros/0.16.2_688fcac82e974ec4fd5c071d8de5a7a5:
+  /unplugin-vue-macros/0.16.2_nch4vsbos5hmj7k4a4oy3znhuu:
     resolution: {integrity: sha512-uNfjIXVUYBujbjJUcjXreE6zipZlPAIEMsx6bc/5qygwTfdvkJeHCAvvxrl0c8hdcT5/18OV2VDdwI60vCh56g==}
     engines: {node: '>=14.19.0'}
     peerDependencies:
@@ -6881,7 +6887,7 @@ packages:
       '@vue-macros/define-render': 0.13.8_vue@3.2.44
       '@vue-macros/define-slots': 0.0.5_vue@3.2.44
       '@vue-macros/hoist-static': 0.12.7
-      '@vue-macros/named-template': 0.0.5_aaae75a03f99901122a33a7412c8cd0a
+      '@vue-macros/named-template': 0.0.5_vkxhlib7tgibcivdhj2bfsgnbi
       '@vue-macros/setup-component': 0.12.7_rollup@3.2.5+vite@3.2.3
       '@vue-macros/setup-sfc': 0.12.7
       '@vue-macros/short-emits': 0.12.8
@@ -6997,7 +7003,7 @@ packages:
       chalk: 4.1.2
       debug: 4.3.4
       fs-extra: 10.1.0
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -7012,7 +7018,7 @@ packages:
       '@types/eslint': 8.4.6
       eslint: 8.27.0
       rollup: 2.79.1
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     dev: true
 
   /vite-plugin-html/3.2.0_vite@3.2.3:
@@ -7032,7 +7038,7 @@ packages:
       html-minifier-terser: 6.1.0
       node-html-parser: 5.4.2
       pathe: 0.2.0
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     dev: true
 
   /vite-plugin-purge-icons/0.9.1_vite@3.2.3:
@@ -7044,7 +7050,7 @@ packages:
       '@purge-icons/core': 0.9.1
       '@purge-icons/generated': 0.9.0
       rollup-plugin-purge-icons: 0.9.1
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     transitivePeerDependencies:
       - encoding
       - supports-color
@@ -7062,7 +7068,7 @@ packages:
       fs-extra: 10.1.0
       magic-string: 0.25.9
       pathe: 0.2.0
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     dev: true
 
   /vite-plugin-svg-icons/2.0.1_vite@3.2.3:
@@ -7078,7 +7084,7 @@ packages:
       pathe: 0.2.0
       svg-baker: 1.7.0
       svgo: 2.8.0
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -7091,13 +7097,13 @@ packages:
       '@windicss/plugin-utils': 1.8.8
       debug: 4.3.4
       kolorist: 1.6.0
-      vite: 3.2.3_@types+node@18.11.9+less@4.1.3
+      vite: 3.2.3_mp5lu76ee5qtwstsyca37sdhqi
       windicss: 3.5.6
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /vite/3.2.3_@types+node@18.11.9+less@4.1.3:
+  /vite/3.2.3_mp5lu76ee5qtwstsyca37sdhqi:
     resolution: {integrity: sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==}
     engines: {node: ^14.18.0 || >=16.0.0}
     hasBin: true
@@ -7149,7 +7155,6 @@ packages:
         optional: true
     dependencies:
       vue: 3.2.44
-    dev: false
 
   /vue-eslint-parser/9.1.0_eslint@8.27.0:
     resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
@@ -7180,7 +7185,6 @@ packages:
       '@intlify/vue-devtools': 9.2.2
       '@vue/devtools-api': 6.4.3
       vue: 3.2.44
-    dev: false
 
   /vue-router/4.1.6_vue@3.2.44:
     resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==}
@@ -7227,7 +7231,6 @@ packages:
       '@vue/runtime-dom': 3.2.44
       '@vue/server-renderer': 3.2.44_vue@3.2.44
       '@vue/shared': 3.2.44
-    dev: false
 
   /vxe-table/4.3.5_vue@3.2.44+xe-utils@3.5.7:
     resolution: {integrity: sha512-JEvGAs7SBN1rWn5f2tkoRiXd/rAT7RfnDTTlFsHsTtASiUTKNTISI2WBsVeLkkNRTs0SXh6FgrYsIPO2soSBXA==}

+ 2 - 1
yudao-ui-admin-vue3/src/api/system/menu/index.ts

@@ -1,10 +1,11 @@
 import request from '@/config/axios'
 import type { MenuVO } from './types'
 
-// 查询菜单(精简)列表
+// 查询菜单(精简列表
 export const listSimpleMenusApi = () => {
   return request.get({ url: '/system/menu/list-all-simple' })
 }
+
 // 查询菜单列表
 export const getMenuListApi = (params) => {
   return request.get({ url: '/system/menu/list', params })

+ 1 - 0
yudao-ui-admin-vue3/src/api/system/post/index.ts

@@ -31,6 +31,7 @@ export const deletePostApi = async (id: number) => {
 }
 
 // 导出岗位
+// TODO @星语:导出这块,咱怎么弄哈
 export const exportPostApi = async (params: PostExportReqVO) => {
   return await request.download({ url: '/system/post/export', params })
 }

+ 1 - 0
yudao-ui-admin-vue3/src/api/system/post/types.ts

@@ -8,6 +8,7 @@ export type PostVO = {
   createTime?: string
 }
 
+// TODO @星语:要不要搞个 Page 基类呀?和后端对应
 export type PostPageReqVO = {
   code: string
   name: string

+ 8 - 1
yudao-ui-admin-vue3/src/components/Descriptions/src/Descriptions.vue

@@ -1,4 +1,5 @@
 <script setup lang="ts">
+import dayjs from 'dayjs'
 import { ElCollapseTransition, ElDescriptions, ElDescriptionsItem, ElTooltip } from 'element-plus'
 import { useDesign } from '@/hooks/web/useDesign'
 import { propTypes } from '@/utils/propTypes'
@@ -111,7 +112,13 @@ const toggleClick = () => {
             </template>
 
             <template #default>
-              <slot :name="item.field" :row="data">{{ data[item.field] }}</slot>
+              <slot v-if="item.dateFormat">
+                {{ dayjs(data[item.field]).format(item.dateFormat) }}
+              </slot>
+              <slot v-else-if="item.dictType">
+                <DictTag :type="item.dictType" :value="data[item.field]" />
+              </slot>
+              <slot v-else :name="item.field" :row="data">{{ data[item.field] }}</slot>
             </template>
           </ElDescriptionsItem>
         </ElDescriptions>

+ 27 - 17
yudao-ui-admin-vue3/src/config/axios/service.ts

@@ -5,7 +5,7 @@ import axios, {
   AxiosResponse,
   AxiosError
 } from 'axios'
-import { useMessage } from '@/hooks/web/useMessage'
+import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
 import qs from 'qs'
 import { config } from '@/config/axios/config'
 import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
@@ -17,7 +17,6 @@ import { useCache } from '@/hooks/web/useCache'
 const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
 const { result_code, base_url, request_timeout } = config
 
-const message = useMessage()
 // 需要忽略的提示。忽略后,自动 Promise.reject('error')
 const ignoreMsgs = [
   '无效的刷新令牌', // 刷新令牌被删除时,不用提示
@@ -30,6 +29,8 @@ export const isRelogin = { show: false }
 let requestList: any[] = []
 // 是否正在刷新中
 let isRefreshToken = false
+// 请求白名单,无须token的接口
+const whiteList: string[] = ['/login', '/refresh-token']
 
 // 创建axios实例
 const service: AxiosInstance = axios.create({
@@ -42,14 +43,20 @@ const service: AxiosInstance = axios.create({
 service.interceptors.request.use(
   (config: AxiosRequestConfig) => {
     // 是否需要设置 token
-    const isToken = (config!.headers || {}).isToken === false
+    let isToken = (config!.headers || {}).isToken === false
+    whiteList.some((v) => {
+      if (config.url) {
+        config.url.indexOf(v) > -1
+        return (isToken = false)
+      }
+    })
     if (getAccessToken() && !isToken) {
       ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
     }
     // 设置租户
     if (tenantEnable && tenantEnable === 'true') {
       const tenantId = getTenantId()
-      if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId
+      if (tenantId) (config as Recordable).headers['tenant-id'] = tenantId
     }
     const params = config.params || {}
     const data = config.data || false
@@ -157,10 +164,10 @@ service.interceptors.response.use(
         })
       }
     } else if (code === 500) {
-      message.error(t('sys.api.errMsg500'))
+      ElMessage.error(t('sys.api.errMsg500'))
       return Promise.reject(new Error(msg))
     } else if (code === 901) {
-      message.error(
+      ElMessage.error(
         '<div>' +
           t('sys.api.errMsg901') +
           '</div>' +
@@ -175,7 +182,7 @@ service.interceptors.response.use(
         // hard coding:忽略这个提示,直接登出
         console.log(msg)
       } else {
-        message.notifyError(msg)
+        ElNotification.error({ title: msg })
       }
       return Promise.reject('error')
     } else {
@@ -184,16 +191,16 @@ service.interceptors.response.use(
   },
   (error: AxiosError) => {
     console.log('err' + error) // for debug
-    let { message: msg } = error
+    let { message } = error
     const { t } = useI18n()
-    if (msg === 'Network Error') {
-      msg = t('sys.api.errorMessage')
-    } else if (msg.includes('timeout')) {
-      msg = t('sys.api.apiTimeoutMessage')
-    } else if (msg.includes('Request failed with status code')) {
-      msg = t('sys.api.apiRequestFailed') + msg.substr(msg.length - 3)
+    if (message === 'Network Error') {
+      message = t('sys.api.errorMessage')
+    } else if (message.includes('timeout')) {
+      message = t('sys.api.apiTimeoutMessage')
+    } else if (message.includes('Request failed with status code')) {
+      message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
     }
-    message.error(msg)
+    ElMessage.error(message)
     return Promise.reject(error)
   }
 )
@@ -205,8 +212,11 @@ const handleAuthorized = () => {
   const { t } = useI18n()
   if (!isRelogin.show) {
     isRelogin.show = true
-    message
-      .confirm(t('sys.api.timeoutMessage'))
+    ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
+      confirmButtonText: t('login.relogin'),
+      cancelButtonText: t('common.cancel'),
+      type: 'warning'
+    })
       .then(() => {
         const { wsCache } = useCache()
         resetRouter() // 重置静态路由表

+ 74 - 34
yudao-ui-admin-vue3/src/hooks/web/useVxeCrudSchemas.ts

@@ -14,18 +14,31 @@ import { VxeTableColumn } from '@/types/table'
 import { FormSchema } from '@/types/form'
 import { ComponentOptions } from '@/types/components'
 
-export type VxeCrudSchema = Omit<VxeTableColumn, 'children'> & {
+export type VxeCrudSchema = {
+  // 主键ID
+  primaryKey?: string
+  primaryType?: VxeColumnPropTypes.Type
+  // 是否开启操作栏插槽
+  action?: boolean
+  columns: VxeCrudColumns[]
+}
+type VxeCrudColumns = Omit<VxeTableColumn, 'children'> & {
   field: string
   title?: string
   formatter?: VxeColumnPropTypes.Formatter
+  isSearch?: boolean
   search?: CrudSearchParams
+  isTable?: boolean
   table?: CrudTableParams
+  isForm?: boolean
   form?: CrudFormParams
+  isDetail?: boolean
   detail?: CrudDescriptionsParams
   print?: CrudPrintParams
-  children?: VxeCrudSchema[]
+  children?: VxeCrudColumns[]
   dictType?: string
 }
+
 type CrudSearchParams = {
   // 是否显示在查询项
   show?: boolean
@@ -61,7 +74,7 @@ export type VxeAllSchemas = {
 
 // 过滤所有结构
 export const useVxeCrudSchemas = (
-  crudSchema: VxeCrudSchema[]
+  crudSchema: VxeCrudSchema
 ): {
   allSchemas: VxeAllSchemas
 } => {
@@ -95,12 +108,12 @@ export const useVxeCrudSchemas = (
 }
 
 // 过滤 Search 结构
-const filterSearchSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] => {
-  const searchSchema: VxeFormItemProps[] = []
+const filterSearchSchema = (crudSchema: VxeCrudSchema): VxeFormItemProps[] => {
   const { t } = useI18n()
-  eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
+  const searchSchema: VxeFormItemProps[] = []
+  eachTree(crudSchema.columns, (schemaItem: VxeCrudColumns) => {
     // 判断是否显示
-    if (schemaItem?.search?.show) {
+    if (schemaItem?.isSearch) {
       let itemRenderName = schemaItem?.search?.itemRender?.name || '$input'
       const options: any[] = []
       let itemRender: FormItemRenderOptions = {
@@ -114,7 +127,7 @@ const filterSearchSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] =>
           options.push(dict)
         })
         itemRender.options = options
-        if (!schemaItem.search.itemRender?.name) itemRenderName = '$select'
+        if (!schemaItem?.search?.itemRender?.name) itemRenderName = '$select'
         itemRender = {
           name: itemRenderName,
           options: options,
@@ -123,15 +136,12 @@ const filterSearchSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] =>
       }
       const searchSchemaItem = {
         // 默认为 input
-        span: 8,
         folding: searchSchema.length > 2,
-        itemRender: itemRender,
-        ...schemaItem.search,
+        itemRender: schemaItem.itemRender ? schemaItem.itemRender : itemRender,
         field: schemaItem.field,
-        title: schemaItem.search?.title || schemaItem.title
+        title: schemaItem.search?.title || schemaItem.title,
+        span: 8
       }
-      // 删除不必要的字段
-      delete searchSchemaItem.show
 
       searchSchema.push(searchSchemaItem)
     }
@@ -154,36 +164,63 @@ const filterSearchSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] =>
 }
 
 // 过滤 table 结构
-const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Columns => {
+const filterTableSchema = (crudSchema: VxeCrudSchema): VxeGridPropTypes.Columns => {
+  const { t } = useI18n()
   const tableSchema: VxeGridPropTypes.Columns = []
-  eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
+  // 主键ID
+  if (crudSchema.primaryKey) {
+    const tableSchemaItem = {
+      title: t('common.index'),
+      field: crudSchema.primaryKey,
+      type: crudSchema.primaryType ? crudSchema.primaryType : 'seq',
+      width: '50px'
+    }
+    tableSchema.push(tableSchemaItem)
+  }
+  eachTree(crudSchema.columns, (schemaItem: VxeCrudColumns) => {
     // 判断是否显示
-    if (schemaItem?.table?.show !== false) {
+    if (schemaItem?.isTable !== false) {
       const tableSchemaItem = {
         ...schemaItem.table,
         field: schemaItem.field,
         title: schemaItem.table?.title || schemaItem.title
       }
+      tableSchemaItem.showOverflow = 'tooltip'
       if (schemaItem?.formatter) {
         tableSchemaItem.formatter = schemaItem.formatter
       }
-
-      // 删除不必要的字段
-      delete tableSchemaItem.show
+      if (schemaItem?.dictType) {
+        tableSchemaItem.cellRender = {
+          name: 'XDict',
+          content: schemaItem.dictType
+        }
+      }
 
       tableSchema.push(tableSchemaItem)
     }
   })
+  // 操作栏插槽
+  if (crudSchema.action && crudSchema.action == true) {
+    const tableSchemaItem = {
+      title: t('table.action'),
+      field: 'actionbtns',
+      width: '240px',
+      slots: {
+        default: 'actionbtns_default'
+      }
+    }
+    tableSchema.push(tableSchemaItem)
+  }
   return tableSchema
 }
 
 // 过滤 form 结构
-const filterFormSchema = (crudSchema: VxeCrudSchema[]): FormSchema[] => {
+const filterFormSchema = (crudSchema: VxeCrudSchema): FormSchema[] => {
   const formSchema: FormSchema[] = []
 
-  eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
+  eachTree(crudSchema.columns, (schemaItem: VxeCrudColumns) => {
     // 判断是否显示
-    if (schemaItem?.form?.show !== false) {
+    if (schemaItem?.isForm !== false) {
       let component = schemaItem?.form?.component || 'Input'
       const options: ComponentOptions[] = []
       let comonentProps = {}
@@ -205,9 +242,6 @@ const filterFormSchema = (crudSchema: VxeCrudSchema[]): FormSchema[] => {
         label: schemaItem.form?.label || schemaItem.title
       }
 
-      // 删除不必要的字段
-      delete formSchemaItem.show
-
       formSchema.push(formSchemaItem)
     }
   })
@@ -216,20 +250,26 @@ const filterFormSchema = (crudSchema: VxeCrudSchema[]): FormSchema[] => {
 }
 
 // 过滤 descriptions 结构
-const filterDescriptionsSchema = (crudSchema: VxeCrudSchema[]): DescriptionsSchema[] => {
+const filterDescriptionsSchema = (crudSchema: VxeCrudSchema): DescriptionsSchema[] => {
   const descriptionsSchema: DescriptionsSchema[] = []
 
-  eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
+  eachTree(crudSchema.columns, (schemaItem: VxeCrudColumns) => {
     // 判断是否显示
-    if (schemaItem?.detail?.show !== false) {
+    if (schemaItem?.isDetail !== false) {
       const descriptionsSchemaItem = {
         ...schemaItem.detail,
         field: schemaItem.field,
         label: schemaItem.detail?.label || schemaItem.title
       }
-
-      // 删除不必要的字段
-      delete descriptionsSchemaItem.show
+      if (schemaItem.dictType) {
+        descriptionsSchemaItem.dictType = schemaItem.dictType
+      }
+      if (schemaItem.detail?.dateFormat || schemaItem.formatter == 'formatDate') {
+        // descriptionsSchemaItem.dateFormat = schemaItem.detail.dateFormat
+        //   ? schemaItem?.detail?.dateFormat
+        //   : 'YYYY-MM-DD HH:mm:ss'
+        descriptionsSchemaItem.dateFormat = 'YYYY-MM-DD HH:mm:ss'
+      }
 
       descriptionsSchema.push(descriptionsSchemaItem)
     }
@@ -239,10 +279,10 @@ const filterDescriptionsSchema = (crudSchema: VxeCrudSchema[]): DescriptionsSche
 }
 
 // 过滤 打印 结构
-const filterPrintSchema = (crudSchema: VxeCrudSchema[]): any[] => {
+const filterPrintSchema = (crudSchema: VxeCrudSchema): any[] => {
   const printSchema: any[] = []
 
-  eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
+  eachTree(crudSchema.columns, (schemaItem: VxeCrudColumns) => {
     // 判断是否显示
     if (schemaItem?.print?.show !== false) {
       const printSchemaItem = {

+ 1 - 5
yudao-ui-admin-vue3/src/hooks/web/useVxeGrid.ts

@@ -43,10 +43,6 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
       isCurrent: true, // 当鼠标点击行时,是否要高亮当前行
       isHover: true // 当鼠标移到行时,是否要高亮当前行
     },
-    showOverflow: 'tooltip', // 当内容溢出时显示为省略号
-    tooltipConfig: {
-      showAll: true // 开启全表工具提示
-    },
     toolbarConfig: {
       custom: true,
       slots: { buttons: 'toolbar_buttons' }
@@ -85,7 +81,7 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
       props: { result: 'list', total: 'total' },
       ajax: {
         query: ({ page, form }) => {
-          const queryParams = Object.assign({}, form)
+          const queryParams = Object.assign({}, JSON.parse(JSON.stringify(form)))
           queryParams.pageSize = page.pageSize
           queryParams.pageNo = page.currentPage
           gridOptions.loading = false

+ 5 - 0
yudao-ui-admin-vue3/src/plugins/vxeTable/index.ts

@@ -1,6 +1,7 @@
 import { App, unref } from 'vue'
 import 'xe-utils'
 import XEUtils from 'xe-utils'
+import './renderer'
 import { i18n } from '@/plugins/vueI18n'
 import zhCN from 'vxe-table/es/locale/lang/zh-CN'
 import enUS from 'vxe-table/lib/locale/lang/en-US'
@@ -138,6 +139,10 @@ VXETable.formats.mixin({
   formatDate({ cellValue }, format) {
     return XEUtils.toDateString(cellValue, format || 'yyyy-MM-dd HH:mm:ss')
   },
+  // 格式字典
+  formatDict() {
+    return 'cellValue 123'
+  },
   // 四舍五入金额,每隔3位逗号分隔,默认2位数
   formatAmount({ cellValue }, digits = 2) {
     return XEUtils.commafy(Number(cellValue), { digits })

+ 23 - 0
yudao-ui-admin-vue3/src/plugins/vxeTable/renderer/dataTimePicker.tsx

@@ -0,0 +1,23 @@
+import { useI18n } from '@/hooks/web/useI18n'
+import { ElDatePicker } from 'element-plus'
+import { VXETable } from 'vxe-table'
+
+// 日期区间选择渲染
+VXETable.renderer.add('XDataTimePicker', {
+  // 默认显示模板
+  renderItemContent(renderOpts, params) {
+    const { t } = useI18n()
+    const { data, field } = params
+    const { content } = renderOpts
+    return (
+      <ElDatePicker
+        v-model={data[field]}
+        type={content ? (content as any) : 'datetimerange'}
+        value-format="YYYY-MM-DD HH:mm:ss"
+        range-separator="-"
+        start-placeholder={t('common.startTimeText')}
+        end-placeholder={t('common.endTimeText')}
+      ></ElDatePicker>
+    )
+  }
+})

+ 12 - 0
yudao-ui-admin-vue3/src/plugins/vxeTable/renderer/dict.tsx

@@ -0,0 +1,12 @@
+import { DictTag } from '@/components/DictTag'
+import { VXETable } from 'vxe-table'
+
+// 字典渲染
+VXETable.renderer.add('XDict', {
+  // 默认显示模板
+  renderDefault(renderOpts, params) {
+    const { row, column } = params
+    const { content } = renderOpts
+    return <DictTag type={content as unknown as string} value={row[column.field]}></DictTag>
+  }
+})

+ 2 - 0
yudao-ui-admin-vue3/src/plugins/vxeTable/renderer/index.tsx

@@ -0,0 +1,2 @@
+import './dataTimePicker'
+import './dict'

+ 2 - 0
yudao-ui-admin-vue3/src/types/descriptions.d.ts

@@ -8,4 +8,6 @@ export interface DescriptionsSchema {
   labelAlign?: 'left' | 'center' | 'right'
   className?: string
   labelClassName?: string
+  dateFormat?: string
+  dictType?: string
 }

+ 38 - 67
yudao-ui-admin-vue3/src/views/system/errorCode/errorCode.data.ts

@@ -2,9 +2,8 @@ import { reactive } from 'vue'
 import { required } from '@/utils/formRules'
 import { useI18n } from '@/hooks/web/useI18n'
 import { DICT_TYPE } from '@/utils/dict'
-import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
-// 国际化
-const { t } = useI18n()
+import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
+const { t } = useI18n() // 国际化
 // 表单校验
 export const rules = reactive({
   applicationName: [required],
@@ -12,71 +11,43 @@ export const rules = reactive({
   message: [required]
 })
 // 新增 + 修改
-const crudSchemas = reactive<CrudSchema[]>([
-  {
-    label: t('common.index'),
-    field: 'id',
-    type: 'index',
-    form: {
-      show: false
+const crudSchemas = reactive<VxeCrudSchema>({
+  primaryKey: 'id',
+  primaryType: 'seq',
+  action: true,
+  columns: [
+    {
+      title: '错误码类型',
+      field: 'type',
+      dictType: DICT_TYPE.SYSTEM_ERROR_CODE_TYPE,
+      isSearch: true
     },
-    detail: {
-      show: false
-    }
-  },
-  {
-    label: '错误码类型',
-    field: 'type',
-    component: 'InputNumber',
-    dictType: DICT_TYPE.SYSTEM_ERROR_CODE_TYPE,
-    search: {
-      show: true
-    }
-  },
-  {
-    label: '应用名',
-    field: 'applicationName',
-    search: {
-      show: true
-    }
-  },
-  {
-    label: '错误码编码',
-    field: 'code',
-    search: {
-      show: true
-    }
-  },
-  {
-    label: '错误码错误提示',
-    field: 'message'
-  },
-  {
-    label: t('common.createTime'),
-    field: 'createTime',
-    form: {
-      show: false
+    {
+      title: '应用名',
+      field: 'applicationName',
+      isSearch: true
     },
-    search: {
-      show: true,
-      component: 'DatePicker',
-      componentProps: {
-        type: 'daterange',
-        valueFormat: 'YYYY-MM-DD HH:mm:ss',
-        defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]
-      }
-    }
-  },
-  {
-    field: 'action',
-    width: '240px',
-    label: t('table.action'),
-    form: {
-      show: false
+    {
+      title: '错误码编码',
+      field: 'code',
+      isSearch: true
+    },
+    {
+      title: '错误码错误提示',
+      field: 'message'
     },
-    detail: {
-      show: false
+    {
+      title: t('common.createTime'),
+      field: 'createTime',
+      formatter: 'formatDate',
+      isForm: false,
+      isSearch: true,
+      search: {
+        itemRender: {
+          name: 'XDataTimePicker'
+        }
+      }
     }
-  }
-])
-export const { allSchemas } = useCrudSchemas(crudSchemas)
+  ]
+})
+export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

+ 106 - 134
yudao-ui-admin-vue3/src/views/system/errorCode/index.vue

@@ -1,30 +1,92 @@
+<template>
+  <ContentWrap>
+    <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
+      <template #toolbar_buttons>
+        <XButton
+          type="primary"
+          preIcon="ep:zoom-in"
+          :title="t('action.add')"
+          v-hasPermi="['system:error-code:create']"
+          @click="handleCreate()"
+        />
+      </template>
+      <template #actionbtns_default="{ row }">
+        <XTextButton
+          preIcon="ep:edit"
+          :title="t('action.edit')"
+          v-hasPermi="['system:error-code:update']"
+          @click="handleUpdate(row.id)"
+        />
+        <XTextButton
+          preIcon="ep:view"
+          :title="t('action.detail')"
+          v-hasPermi="['system:error-code:update']"
+          @click="handleDetail(row)"
+        />
+        <XTextButton
+          preIcon="ep:delete"
+          :title="t('action.del')"
+          v-hasPermi="['system:error-code:delete']"
+          @click="handleDelete(row.id)"
+        />
+      </template>
+    </vxe-grid>
+  </ContentWrap>
+  <XModal id="errorCodeModel" v-model="dialogVisible" :title="dialogTitle">
+    <template #default>
+      <!-- 对话框(添加 / 修改) -->
+      <Form
+        v-if="['create', 'update'].includes(actionType)"
+        :schema="allSchemas.formSchema"
+        :rules="rules"
+        ref="formRef"
+      />
+      <!-- 对话框(详情) -->
+      <Descriptions
+        v-if="actionType === 'detail'"
+        :schema="allSchemas.detailSchema"
+        :data="detailRef"
+      />
+    </template>
+    <!-- 操作按钮 -->
+    <template #footer>
+      <XButton
+        v-if="['create', 'update'].includes(actionType)"
+        type="primary"
+        :title="t('action.save')"
+        :loading="actionLoading"
+        @click="submitForm"
+      />
+      <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
+    </template>
+  </XModal>
+</template>
+
 <script setup lang="ts">
 import { ref, unref } from 'vue'
-import dayjs from 'dayjs'
-import { ElMessage } from 'element-plus'
-import { DICT_TYPE } from '@/utils/dict'
-import { useTable } from '@/hooks/web/useTable'
-import { useI18n } from '@/hooks/web/useI18n'
-import { FormExpose } from '@/components/Form'
 import type { ErrorCodeVO } from '@/api/system/errorCode/types'
 import { rules, allSchemas } from './errorCode.data'
 import * as ErrorCodeApi from '@/api/system/errorCode'
-const { t } = useI18n() // 国际化
-
-// ========== 列表相关 ==========
-const { register, tableObject, methods } = useTable<ErrorCodeVO>({
-  getListApi: ErrorCodeApi.getErrorCodePageApi,
-  delListApi: ErrorCodeApi.deleteErrorCodeApi
-})
-const { getList, setSearchParams, delList } = methods
+import { useI18n } from '@/hooks/web/useI18n'
+import { useMessage } from '@/hooks/web/useMessage'
+import { useVxeGrid } from '@/hooks/web/useVxeGrid'
+import { VxeGridInstance } from 'vxe-table'
+import { FormExpose } from '@/components/Form'
 
-// ========== CRUD 相关 ==========
-const loading = ref(false) // 遮罩层
-const actionType = ref('') // 操作按钮的类型
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
+const actionType = ref('') // 操作按钮的类型
+const actionLoading = ref(false) // 按钮Loading
+const xGrid = ref<VxeGridInstance>() // grid Ref
 const formRef = ref<FormExpose>() // 表单 Ref
+const detailRef = ref() // 详情 Ref
 
+const { gridOptions } = useVxeGrid<ErrorCodeVO>({
+  allSchemas: allSchemas,
+  getListApi: ErrorCodeApi.getErrorCodePageApi
+})
 // 设置标题
 const setDialogTile = (type: string) => {
   dialogTitle.value = t('action.' + type)
@@ -39,147 +101,57 @@ const handleCreate = () => {
   unref(formRef)?.getElFormRef()?.resetFields()
 }
 
+// 详情操作
+const handleDetail = async (row: ErrorCodeVO) => {
+  // 设置数据
+  detailRef.value = row
+  setDialogTile('detail')
+}
+
 // 修改操作
-const handleUpdate = async (row: ErrorCodeVO) => {
+const handleUpdate = async (rowId: number) => {
   setDialogTile('update')
   // 设置数据
-  const res = await ErrorCodeApi.getErrorCodeApi(row.id)
+  const res = await ErrorCodeApi.getErrorCodeApi(rowId)
   unref(formRef)?.setValues(res)
 }
 
+// 删除操作
+const handleDelete = async (rowId: number) => {
+  message
+    .delConfirm()
+    .then(async () => {
+      await ErrorCodeApi.deleteErrorCodeApi(rowId)
+      message.success(t('common.delSuccess'))
+    })
+    .finally(() => {
+      xGrid.value?.commitProxy('query')
+    })
+}
+
 // 提交按钮
 const submitForm = async () => {
   const elForm = unref(formRef)?.getElFormRef()
   if (!elForm) return
   elForm.validate(async (valid) => {
     if (valid) {
-      loading.value = true
+      actionLoading.value = true
       // 提交请求
       try {
         const data = unref(formRef)?.formModel as ErrorCodeVO
         if (actionType.value === 'create') {
           await ErrorCodeApi.createErrorCodeApi(data)
-          ElMessage.success(t('common.createSuccess'))
+          message.success(t('common.createSuccess'))
         } else {
           await ErrorCodeApi.updateErrorCodeApi(data)
-          ElMessage.success(t('common.updateSuccess'))
+          message.success(t('common.updateSuccess'))
         }
-        // 操作成功,重新加载列表
         dialogVisible.value = false
-        await getList()
       } finally {
-        loading.value = false
+        actionLoading.value = false
+        xGrid.value?.commitProxy('query')
       }
     }
   })
 }
-
-// ========== 详情相关 ==========
-const detailRef = ref() // 详情 Ref
-
-// 详情操作
-const handleDetail = async (row: ErrorCodeVO) => {
-  // 设置数据
-  detailRef.value = row
-  setDialogTile('detail')
-}
-
-// ========== 初始化 ==========
-getList()
 </script>
-
-<template>
-  <!-- 搜索工作区 -->
-  <ContentWrap>
-    <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
-  </ContentWrap>
-  <ContentWrap>
-    <!-- 操作工具栏 -->
-    <div class="mb-10px">
-      <el-button v-hasPermi="['system:error-code:create']" type="primary" @click="handleCreate">
-        <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
-      </el-button>
-    </div>
-    <!-- 列表 -->
-    <Table
-      :columns="allSchemas.tableColumns"
-      :selection="false"
-      :data="tableObject.tableList"
-      :loading="tableObject.loading"
-      :pagination="{
-        total: tableObject.total
-      }"
-      v-model:pageSize="tableObject.pageSize"
-      v-model:currentPage="tableObject.currentPage"
-      @register="register"
-    >
-      <template #type="{ row }">
-        <DictTag :type="DICT_TYPE.SYSTEM_ERROR_CODE_TYPE" :value="row.type" />
-      </template>
-      <template #createTime="{ row }">
-        <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
-      </template>
-      <template #action="{ row }">
-        <el-button
-          link
-          type="primary"
-          v-hasPermi="['system:error-code:update']"
-          @click="handleUpdate(row)"
-        >
-          <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
-        </el-button>
-        <el-button
-          link
-          type="primary"
-          v-hasPermi="['system:error-code:update']"
-          @click="handleDetail(row)"
-        >
-          <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
-        </el-button>
-        <el-button
-          link
-          type="primary"
-          v-hasPermi="['system:error-code:delete']"
-          @click="delList(row.id, false)"
-        >
-          <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
-        </el-button>
-      </template>
-    </Table>
-  </ContentWrap>
-
-  <Dialog v-model="dialogVisible" :title="dialogTitle">
-    <!-- 对话框(添加 / 修改) -->
-    <Form
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-      ref="formRef"
-    />
-    <!-- 对话框(详情) -->
-    <Descriptions
-      v-if="actionType === 'detail'"
-      :schema="allSchemas.detailSchema"
-      :data="detailRef"
-    >
-      <template #type="{ row }">
-        <DictTag :type="DICT_TYPE.SYSTEM_ERROR_CODE_TYPE" :value="row.type" />
-      </template>
-      <template #createTime="{ row }">
-        <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
-      </template>
-    </Descriptions>
-    <!-- 操作按钮 -->
-    <template #footer>
-      <el-button
-        v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :loading="loading"
-        @click="submitForm"
-      >
-        {{ t('action.save') }}
-      </el-button>
-      <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
-    </template>
-  </Dialog>
-</template>

+ 83 - 46
yudao-ui-admin-vue3/src/views/system/menu/index.vue

@@ -1,5 +1,6 @@
 <template>
   <ContentWrap>
+    <!-- 搜索工作栏 -->
     <el-form :model="queryParams" ref="queryForm" :inline="true">
       <el-form-item label="菜单名称" prop="name">
         <el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
@@ -15,17 +16,20 @@
         </el-select>
       </el-form-item>
       <el-form-item>
+        <!-- 操作:搜索 -->
         <XButton
           type="primary"
           preIcon="ep:search"
           :title="t('common.query')"
           @click="handleQuery()"
         />
+        <!-- 操作:重置 -->
         <XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" />
       </el-form-item>
     </el-form>
     <vxe-toolbar>
       <template #buttons>
+        <!-- 操作:新增 -->
         <XButton
           type="primary"
           preIcon="ep:zoom-in"
@@ -37,6 +41,8 @@
         <XButton title="关闭所有" @click="xTable?.clearTreeExpand()" />
       </template>
     </vxe-toolbar>
+    <!-- 列表 -->
+    <!-- TODO 星语:是不是也搞成 grid 会好点,后续代码就统一走 grid 风格? -->
     <vxe-table
       show-overflow
       keep-source
@@ -73,12 +79,14 @@
       <vxe-column title="创建时间" field="createTime" formatter="formatDate" />
       <vxe-column title="操作" width="200">
         <template #default="{ row }">
+          <!-- 操作:修改 -->
           <XTextButton
             preIcon="ep:edit"
             :title="t('action.edit')"
             v-hasPermi="['system:menu:update']"
             @click="handleUpdate(row)"
           />
+          <!-- 操作:删除 -->
           <XTextButton
             preIcon="ep:delete"
             :title="t('action.del')"
@@ -89,6 +97,7 @@
       </vxe-column>
     </vxe-table>
   </ContentWrap>
+  <!-- 添加或修改菜单对话框 -->
   <XModal v-model="dialogVisible" id="menuModel" :title="dialogTitle">
     <template #default>
       <!-- 对话框(添加 / 修改) -->
@@ -107,6 +116,7 @@
                 v-model="menuForm.parentId"
                 :props="menuProps"
                 :data="menuOptions"
+                :default-expanded-keys="[0]"
                 check-strictly
               />
             </el-form-item>
@@ -226,7 +236,7 @@
       </el-form>
     </template>
     <template #footer>
-      <!-- 操作按钮 -->
+      <!-- 按钮:保存 -->
       <XButton
         v-if="['create', 'update'].includes(actionType)"
         type="primary"
@@ -234,22 +244,17 @@
         @click="submitForm"
         :title="t('action.save')"
       />
+      <!-- 按钮:关闭 -->
       <XButton :loading="actionLoading" @click="dialogVisible = false" :title="t('dialog.close')" />
     </template>
   </XModal>
 </template>
 <script setup lang="ts">
-import * as MenuApi from '@/api/system/menu'
-import { MenuVO } from '@/api/system/menu/types'
+// 全局相关的 import
+import { onMounted, reactive, ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
-import { IconSelect } from '@/components/Icon'
-import { Tooltip } from '@/components/Tooltip'
-import { required } from '@/utils/formRules.js'
-import { onMounted, reactive, ref } from 'vue'
-import { VxeTableInstance } from 'vxe-table'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
+// TODO @星语:是不是 'element-plus' 和 '@/components/Tooltip' 和 '@/components/Icon' 全局直接引入
 import {
   ElRow,
   ElCol,
@@ -263,17 +268,29 @@ import {
   ElRadioGroup,
   ElRadioButton
 } from 'element-plus'
+import { Tooltip } from '@/components/Tooltip'
+import { IconSelect } from '@/components/Icon'
+import { VxeTableInstance } from 'vxe-table'
+// 业务相关的 import
+import * as MenuApi from '@/api/system/menu'
+import { MenuVO } from '@/api/system/menu/types'
+import { required } from '@/utils/formRules.js'
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
 import { handleTree } from '@/utils/tree'
+
 const { t } = useI18n() // 国际化
-const message = useMessage()
+const message = useMessage() // 消息弹窗
+// 列表相关的变量
 const xTable = ref<VxeTableInstance>()
 const tableLoading = ref(false)
 const tableData = ref()
-const actionLoading = ref(false) // 遮罩层
-const actionType = ref('') // 操作按钮的类型
+// 弹窗相关的变量
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
-const statusOption = ref() // 状态选项
+const actionType = ref('') // 操作按钮的类型
+const actionLoading = ref(false) // 遮罩层
+// 新增和修改的表单值
 const menuForm = ref<MenuVO>({
   id: 0,
   name: '',
@@ -289,12 +306,24 @@ const menuForm = ref<MenuVO>({
   keepAlive: true,
   createTime: ''
 })
+// 新增和修改的表单校验
+const rules = reactive({
+  name: [required],
+  sort: [required],
+  path: [required],
+  status: [required]
+})
+
+// ========== 下拉框[上级菜单] ==========
+// 下拉框[上级菜单]的配置项目
+// TODO @星语:menuProps 貌似也可以抽到全局?
 const menuProps = {
   checkStrictly: true,
   children: 'children',
   label: 'name',
   value: 'id'
 }
+// TODO @星语:Tree 可以是全局的
 interface Tree {
   id: number
   name: string
@@ -308,6 +337,7 @@ const getTree = async () => {
   menu.children = handleTree(res)
   menuOptions.value.push(menu)
 }
+
 // ========== 查询 ==========
 const queryParams = reactive({
   name: null,
@@ -315,58 +345,47 @@ const queryParams = reactive({
 })
 const getList = async () => {
   tableLoading.value = true
-  statusOption.value = getIntDictOptions(DICT_TYPE.COMMON_STATUS)
   const res = await MenuApi.getMenuListApi(queryParams)
   tableData.value = res
   tableLoading.value = false
 }
+
+// 查询操作
+const handleQuery = async () => {
+  await getList()
+}
+
+// 重置操作
+const resetQuery = async () => {
+  queryParams.name = null
+  queryParams.status = null
+  await getList()
+}
+
+// ========== 新增/修改 ==========
+
 // 设置标题
 const setDialogTile = (type: string) => {
   dialogTitle.value = t('action.' + type)
   actionType.value = type
   dialogVisible.value = true
 }
+
 // 新建操作
 const handleCreate = () => {
   setDialogTile('create')
+  // TODO @星语:重置表单
 }
+
 // 修改操作
 const handleUpdate = async (row: MenuVO) => {
+  setDialogTile('update')
   // 设置数据
   const res = await MenuApi.getMenuApi(row.id)
-  console.log(res)
   menuForm.value = res
-  setDialogTile('update')
-}
-// 删除操作
-const handleDelete = async (row: MenuVO) => {
-  message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {
-    await MenuApi.deleteMenuApi(row.id)
-    message.success(t('common.delSuccess'))
-    await getList()
-  })
-}
-// 表单校验
-const rules = reactive({
-  name: [required],
-  sort: [required],
-  path: [required],
-  status: [required]
-})
-// 查询操作
-const handleQuery = async () => {
-  await getList()
-}
-// 重置操作
-const resetQuery = async () => {
-  queryParams.name = null
-  queryParams.status = null
-  await getList()
-}
-// 保存操作
-const isExternal = (path: string) => {
-  return /^(https?:|mailto:|tel:)/.test(path)
 }
+
+// 提交新增/修改的表单
 const submitForm = async () => {
   actionLoading.value = true
   // 提交请求
@@ -399,8 +418,26 @@ const submitForm = async () => {
     actionLoading.value = false
   }
 }
+
+// 判断 path 是不是外部的 HTTP 等链接
+const isExternal = (path: string) => {
+  return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+// ========== 删除 ==========
+// 删除操作
+const handleDelete = async (row: MenuVO) => {
+  message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {
+    await MenuApi.deleteMenuApi(row.id)
+    message.success(t('common.delSuccess'))
+    await getList()
+  })
+}
+
+// ========== 初始化 ==========
 onMounted(async () => {
   await getList()
+  // TODO @星语:这个告警解决下;是不是改成新增和修改点击的时候,去加载下好一点哈?
   getTree()
 })
 </script>

+ 104 - 138
yudao-ui-admin-vue3/src/views/system/notice/index.vue

@@ -1,28 +1,91 @@
+<template>
+  <ContentWrap>
+    <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
+      <template #toolbar_buttons>
+        <XButton
+          type="primary"
+          preIcon="ep:zoom-in"
+          :title="t('action.add')"
+          v-hasPermi="['system:notice:create']"
+          @click="handleCreate()"
+        />
+      </template>
+      <template #actionbtns_default="{ row }">
+        <XTextButton
+          preIcon="ep:edit"
+          :title="t('action.edit')"
+          v-hasPermi="['system:notice:update']"
+          @click="handleUpdate(row.id)"
+        />
+        <XTextButton
+          preIcon="ep:view"
+          :title="t('action.detail')"
+          v-hasPermi="['system:notice:update']"
+          @click="handleDetail(row)"
+        />
+        <XTextButton
+          preIcon="ep:delete"
+          :title="t('action.del')"
+          v-hasPermi="['system:notice:delete']"
+          @click="handleDelete(row.id)"
+        />
+      </template>
+    </vxe-grid>
+  </ContentWrap>
+  <XModal id="noticeModel" v-model="dialogVisible" :title="dialogTitle">
+    <template #default>
+      <!-- 对话框(添加 / 修改) -->
+      <Form
+        v-if="['create', 'update'].includes(actionType)"
+        :schema="allSchemas.formSchema"
+        :rules="rules"
+        ref="formRef"
+      />
+      <!-- 对话框(详情) -->
+      <Descriptions
+        v-if="actionType === 'detail'"
+        :schema="allSchemas.detailSchema"
+        :data="detailRef"
+      />
+    </template>
+    <!-- 操作按钮 -->
+    <template #footer>
+      <XButton
+        v-if="['create', 'update'].includes(actionType)"
+        type="primary"
+        :title="t('action.save')"
+        :loading="actionLoading"
+        @click="submitForm"
+      />
+      <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
+    </template>
+  </XModal>
+</template>
 <script setup lang="ts">
 import { ref, unref } from 'vue'
-import dayjs from 'dayjs'
-import { ElMessage } from 'element-plus'
-import { DICT_TYPE } from '@/utils/dict'
-import { useTable } from '@/hooks/web/useTable'
+import * as NoticeApi from '@/api/system/notice'
+import { NoticeVO } from '@/api/system/notice/types'
+import { rules, allSchemas } from './notice.data'
 import { useI18n } from '@/hooks/web/useI18n'
+import { useMessage } from '@/hooks/web/useMessage'
+import { useVxeGrid } from '@/hooks/web/useVxeGrid'
+import { VxeGridInstance } from 'vxe-table'
 import { FormExpose } from '@/components/Form'
-import type { NoticeVO } from '@/api/system/notice/types'
-import { rules, allSchemas } from './notice.data'
-import * as NoticeApi from '@/api/system/notice'
-const { t } = useI18n() // 国际化
-// ========== 列表相关 ==========
-const { register, tableObject, methods } = useTable<NoticeVO>({
-  getListApi: NoticeApi.getNoticePageApi,
-  delListApi: NoticeApi.deleteNoticeApi
-})
-const { getList, setSearchParams, delList } = methods
 
-// ========== CRUD 相关 ==========
-const actionLoading = ref(false) // 遮罩层
-const actionType = ref('') // 操作按钮的类型
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
+const actionType = ref('') // 操作按钮的类型
+const actionLoading = ref(false) // 按钮Loading
+const xGrid = ref<VxeGridInstance>() // grid Ref
 const formRef = ref<FormExpose>() // 表单 Ref
+const detailRef = ref() // 详情 Ref
+
+const { gridOptions } = useVxeGrid<NoticeVO>({
+  allSchemas: allSchemas,
+  getListApi: NoticeApi.getNoticePageApi
+})
 
 // 设置标题
 const setDialogTile = (type: string) => {
@@ -39,13 +102,32 @@ const handleCreate = () => {
 }
 
 // 修改操作
-const handleUpdate = async (row: NoticeVO) => {
+const handleUpdate = async (rowId: number) => {
   setDialogTile('update')
   // 设置数据
-  const res = await NoticeApi.getNoticeApi(row.id)
+  const res = await NoticeApi.getNoticeApi(rowId)
   unref(formRef)?.setValues(res)
 }
 
+// 详情操作
+const handleDetail = (row: NoticeVO) => {
+  setDialogTile('detail')
+  detailRef.value = row
+}
+
+// 删除操作
+const handleDelete = async (rowId: number) => {
+  message
+    .delConfirm()
+    .then(async () => {
+      await NoticeApi.deleteNoticeApi(rowId)
+      message.success(t('common.delSuccess'))
+    })
+    .finally(() => {
+      xGrid.value?.commitProxy('query')
+    })
+}
+
 // 提交按钮
 const submitForm = async () => {
   const elForm = unref(formRef)?.getElFormRef()
@@ -58,133 +140,17 @@ const submitForm = async () => {
         const data = unref(formRef)?.formModel as NoticeVO
         if (actionType.value === 'create') {
           await NoticeApi.createNoticeApi(data)
-          ElMessage.success(t('common.createSuccess'))
+          message.success(t('common.createSuccess'))
         } else {
           await NoticeApi.updateNoticeApi(data)
-          ElMessage.success(t('common.updateSuccess'))
+          message.success(t('common.updateSuccess'))
         }
-        // 操作成功,重新加载列表
         dialogVisible.value = false
-        await getList()
       } finally {
         actionLoading.value = false
+        xGrid.value?.commitProxy('query')
       }
     }
   })
 }
-
-// ========== 详情相关 ==========
-const detailRef = ref() // 详情 Ref
-
-// 详情操作
-const handleDetail = async (row: NoticeVO) => {
-  // 设置数据
-  detailRef.value = row
-  setDialogTile('detail')
-}
-
-// ========== 初始化 ==========
-getList()
 </script>
-
-<template>
-  <!-- 搜索工作区 -->
-  <ContentWrap>
-    <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
-  </ContentWrap>
-  <ContentWrap>
-    <!-- 操作工具栏 -->
-    <div class="mb-10px">
-      <el-button type="primary" v-hasPermi="['system:notice:create']" @click="handleCreate">
-        <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
-      </el-button>
-    </div>
-    <!-- 列表 -->
-    <Table
-      :columns="allSchemas.tableColumns"
-      :selection="false"
-      :data="tableObject.tableList"
-      :loading="tableObject.loading"
-      :pagination="{
-        total: tableObject.total
-      }"
-      v-model:pageSize="tableObject.pageSize"
-      v-model:currentPage="tableObject.currentPage"
-      @register="register"
-    >
-      <template #type="{ row }">
-        <DictTag :type="DICT_TYPE.SYSTEM_NOTICE_TYPE" :value="row.type" />
-      </template>
-      <template #status="{ row }">
-        <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
-      </template>
-      <template #createTime="{ row }">
-        <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
-      </template>
-      <template #action="{ row }">
-        <el-button
-          link
-          type="primary"
-          v-hasPermi="['system:notice:update']"
-          @click="handleUpdate(row)"
-        >
-          <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
-        </el-button>
-        <el-button
-          link
-          type="primary"
-          v-hasPermi="['system:notice:update']"
-          @click="handleDetail(row)"
-        >
-          <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
-        </el-button>
-        <el-button
-          link
-          type="primary"
-          v-hasPermi="['system:notice:delete']"
-          @click="delList(row.id, false)"
-        >
-          <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
-        </el-button>
-      </template>
-    </Table>
-  </ContentWrap>
-
-  <Dialog v-model="dialogVisible" :title="dialogTitle" maxHeight="500px" width="50%">
-    <!-- 对话框(添加 / 修改) -->
-    <Form
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-      ref="formRef"
-    />
-    <!-- 对话框(详情) -->
-    <Descriptions
-      v-if="actionType === 'detail'"
-      :schema="allSchemas.detailSchema"
-      :data="detailRef"
-    >
-      <template #type="{ row }">
-        <DictTag :type="DICT_TYPE.SYSTEM_NOTICE_TYPE" :value="row.type" />
-      </template>
-      <template #status="{ row }">
-        <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
-      </template>
-      <template #createTime="{ row }">
-        <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
-      </template>
-    </Descriptions>
-    <!-- 操作按钮 -->
-    <template #footer>
-      <el-button
-        v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :loading="actionLoading"
-        @click="submitForm"
-      >
-        {{ t('action.save') }}
-      </el-button>
-      <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
-    </template>
-  </Dialog>
-</template>

+ 40 - 67
yudao-ui-admin-vue3/src/views/system/notice/notice.data.ts

@@ -2,7 +2,7 @@ import { reactive } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { required } from '@/utils/formRules'
 import { DICT_TYPE } from '@/utils/dict'
-import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
+import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
 const { t } = useI18n() // 国际化
 
 // 表单校验
@@ -12,74 +12,47 @@ export const rules = reactive({
 })
 
 // CrudSchema
-const crudSchemas = reactive<CrudSchema[]>([
-  {
-    label: t('common.index'),
-    field: 'id',
-    type: 'index',
-    form: {
-      show: false
+const crudSchemas = reactive<VxeCrudSchema>({
+  primaryKey: 'id',
+  primaryType: 'seq',
+  action: true,
+  columns: [
+    {
+      title: '公告标题',
+      field: 'title',
+      isSearch: true
     },
-    detail: {
-      show: false
-    }
-  },
-  {
-    label: '公告标题',
-    field: 'title',
-    search: {
-      show: true
-    }
-  },
-  {
-    label: '公告类型',
-    field: 'type',
-    dictType: DICT_TYPE.SYSTEM_NOTICE_TYPE,
-    search: {
-      show: true
-    }
-  },
-  {
-    label: t('common.status'),
-    field: 'status',
-    dictType: DICT_TYPE.COMMON_STATUS,
-    search: {
-      show: true
+    {
+      title: '公告类型',
+      field: 'type',
+      dictType: DICT_TYPE.SYSTEM_NOTICE_TYPE,
+      isSearch: true
     },
-    form: {
-      component: 'RadioButton'
-    }
-  },
-  {
-    label: '公告内容',
-    field: 'content',
-    form: {
-      component: 'Editor',
-      colProps: {
-        span: 24
-      },
-      componentProps: {
-        valueHtml: ''
+    {
+      title: t('common.status'),
+      field: 'status',
+      dictType: DICT_TYPE.COMMON_STATUS,
+      isSearch: true
+    },
+    {
+      title: '公告内容',
+      field: 'content',
+      form: {
+        component: 'Editor',
+        colProps: {
+          span: 24
+        },
+        componentProps: {
+          valueHtml: ''
+        }
       }
-    }
-  },
-  {
-    label: t('common.createTime'),
-    field: 'createTime',
-    form: {
-      show: false
-    }
-  },
-  {
-    label: t('table.action'),
-    field: 'action',
-    width: '240px',
-    form: {
-      show: false
     },
-    detail: {
-      show: false
+    {
+      title: t('common.createTime'),
+      field: 'createTime',
+      formatter: 'formatDate',
+      isForm: false
     }
-  }
-])
-export const { allSchemas } = useCrudSchemas(crudSchemas)
+  ]
+})
+export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

+ 36 - 32
yudao-ui-admin-vue3/src/views/system/post/index.vue

@@ -1,6 +1,8 @@
 <template>
   <ContentWrap>
+    <!-- 列表 -->
     <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
+      <!-- 操作:新增 -->
       <template #toolbar_buttons>
         <XButton
           type="primary"
@@ -10,22 +12,22 @@
           @click="handleCreate()"
         />
       </template>
-      <template #status_default="{ row }">
-        <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
-      </template>
-      <template #action_default="{ row }">
+      <template #actionbtns_default="{ row }">
+        <!-- 操作:修改 -->
         <XTextButton
           preIcon="ep:edit"
           :title="t('action.edit')"
           v-hasPermi="['system:post:update']"
           @click="handleUpdate(row.id)"
         />
+        <!-- 操作:详情 -->
         <XTextButton
           preIcon="ep:view"
           :title="t('action.detail')"
           v-hasPermi="['system:post:update']"
           @click="handleDetail(row)"
         />
+        <!-- 操作:删除 -->
         <XTextButton
           preIcon="ep:delete"
           :title="t('action.del')"
@@ -35,29 +37,25 @@
       </template>
     </vxe-grid>
   </ContentWrap>
+  <!-- 弹窗 -->
   <XModal id="postModel" v-model="dialogVisible" :title="dialogTitle">
     <template #default>
-      <!-- 对话框(添加 / 修改) -->
+      <!-- 表单:添加/修改 -->
       <Form
         v-if="['create', 'update'].includes(actionType)"
         :schema="allSchemas.formSchema"
         :rules="rules"
         ref="formRef"
       />
+      <!-- 表单:详情 -->
       <Descriptions
         v-if="actionType === 'detail'"
         :schema="allSchemas.detailSchema"
         :data="detailRef"
-      >
-        <template #status="{ row }">
-          <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
-        </template>
-        <template #createTime="{ row }">
-          <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
-        </template>
-      </Descriptions>
+      />
     </template>
     <template #footer>
+      <!-- 按钮:保存 -->
       <XButton
         v-if="['create', 'update'].includes(actionType)"
         type="primary"
@@ -65,38 +63,40 @@
         :loading="actionLoading"
         @click="submitForm"
       />
+      <!-- 按钮:关闭 -->
       <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
     </template>
   </XModal>
 </template>
 <script setup lang="ts">
+// 全局相关的 import
 import { ref, unref } from 'vue'
-import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import * as PostApi from '@/api/system/post'
-import { PostVO } from '@/api/system/post/types'
-import { rules, allSchemas } from './post.data'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
 import { useVxeGrid } from '@/hooks/web/useVxeGrid'
 import { VxeGridInstance } from 'vxe-table'
 import { FormExpose } from '@/components/Form'
+// 业务相关的 import
+import * as PostApi from '@/api/system/post'
+import { PostVO } from '@/api/system/post/types'
+import { rules, allSchemas } from './post.data'
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
+// 列表相关的变量
+const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
+const { gridOptions } = useVxeGrid<PostVO>({
+  allSchemas: allSchemas,
+  getListApi: PostApi.getPostPageApi
+})
+// 弹窗相关的变量
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
 const actionType = ref('') // 操作按钮的类型
-const actionLoading = ref(false) // 按钮Loading
-const xGrid = ref<VxeGridInstance>() // grid Ref
+const actionLoading = ref(false) // 按钮 Loading
 const formRef = ref<FormExpose>() // 表单 Ref
 const detailRef = ref() // 详情 Ref
 
-const { gridOptions } = useVxeGrid<PostVO>({
-  allSchemas: allSchemas,
-  getListApi: PostApi.getPostPageApi
-})
-
 // 设置标题
 const setDialogTile = (type: string) => {
   dialogTitle.value = t('action.' + type)
@@ -111,12 +111,6 @@ const handleCreate = () => {
   unref(formRef)?.getElFormRef()?.resetFields()
 }
 
-// 详情操作
-const handleDetail = (row: PostVO) => {
-  setDialogTile('detail')
-  detailRef.value = row
-}
-
 // 修改操作
 const handleUpdate = async (rowId: number) => {
   setDialogTile('update')
@@ -125,6 +119,13 @@ const handleUpdate = async (rowId: number) => {
   unref(formRef)?.setValues(res)
 }
 
+// 详情操作
+const handleDetail = (row: PostVO) => {
+  setDialogTile('detail')
+  // TODO @星语:要不读取下后端?
+  detailRef.value = row
+}
+
 // 删除操作
 const handleDelete = async (rowId: number) => {
   message
@@ -134,14 +135,16 @@ const handleDelete = async (rowId: number) => {
       message.success(t('common.delSuccess'))
     })
     .finally(() => {
+      // 刷新列表
       xGrid.value?.commitProxy('query')
     })
 }
 
-// 提交按钮
+// 提交新增/修改的表单
 const submitForm = async () => {
   const elForm = unref(formRef)?.getElFormRef()
   if (!elForm) return
+  // TODO @星语:这个告警,要不要解决下?
   elForm.validate(async (valid) => {
     if (valid) {
       actionLoading.value = true
@@ -158,6 +161,7 @@ const submitForm = async () => {
         dialogVisible.value = false
       } finally {
         actionLoading.value = false
+        // 刷新列表
         xGrid.value?.commitProxy('query')
       }
     }

+ 33 - 70
yudao-ui-admin-vue3/src/views/system/post/post.data.ts

@@ -13,79 +13,42 @@ export const rules = reactive({
 })
 
 // CrudSchema
-const crudSchemas = reactive<VxeCrudSchema[]>([
-  {
-    title: t('common.index'),
-    field: 'id',
-    type: 'seq',
-    form: {
-      show: false
+const crudSchemas = reactive<VxeCrudSchema>({
+  primaryKey: 'id',
+  primaryType: 'seq',
+  action: true,
+  columns: [
+    {
+      title: '岗位名称',
+      field: 'name',
+      isSearch: true
     },
-    detail: {
-      show: false
-    }
-  },
-  {
-    title: '岗位名称',
-    field: 'name',
-    search: {
-      show: true
-    }
-  },
-  {
-    title: '岗位编码',
-    field: 'code',
-    search: {
-      show: true
-    }
-  },
-  {
-    title: '岗位顺序',
-    field: 'sort'
-  },
-  {
-    title: t('common.status'),
-    field: 'status',
-    dictType: DICT_TYPE.COMMON_STATUS,
-    table: {
-      slots: {
-        default: 'status_default'
-      }
+    {
+      title: '岗位编码',
+      field: 'code',
+      isSearch: true
     },
-    search: {
-      show: true
-    }
-  },
-  {
-    title: '备注',
-    field: 'remark',
-    table: {
-      show: false
-    }
-  },
-  {
-    title: t('common.createTime'),
-    field: 'createTime',
-    formatter: 'formatDate',
-    form: {
-      show: false
-    }
-  },
-  {
-    title: t('table.action'),
-    field: 'action',
-    table: {
-      width: '240px',
-      slots: {
-        default: 'action_default'
-      }
+    {
+      title: '岗位顺序',
+      field: 'sort'
     },
-    form: {
-      show: false
+    {
+      title: t('common.status'),
+      field: 'status',
+      dictType: DICT_TYPE.COMMON_STATUS,
+      isSearch: true
     },
-    detail: {
-      show: false
+    {
+      title: '备注',
+      field: 'remark',
+      isTable: false
+    },
+    {
+      title: t('common.createTime'),
+      field: 'createTime',
+      formatter: 'formatDate',
+      isForm: false
     }
-  }
-])
+  ]
+})
 export const { allSchemas } = useVxeCrudSchemas(crudSchemas)