Commit cb6a9a12822d5505b730441b027444c078d1f5f8

Authored by 芋道源码
Committed by Gitee
2 parents ee3ac7b6 77067a11

!288 修复vue3 部分bug 重构axios 完善vxe demo

Merge pull request !288 from xingyu/dev
Showing 68 changed files with 1352 additions and 1335 deletions
yudao-dependencies/pom.xml
... ... @@ -46,8 +46,8 @@
46 46 <jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
47 47 <lombok.version>1.18.24</lombok.version>
48 48 <mapstruct.version>1.5.3.Final</mapstruct.version>
49   - <hutool.version>5.8.8</hutool.version>
50   - <easyexcel.verion>3.1.1</easyexcel.verion>
  49 + <hutool.version>5.8.9</hutool.version>
  50 + <easyexcel.verion>3.1.2</easyexcel.verion>
51 51 <velocity.version>2.3</velocity.version>
52 52 <screw.version>1.0.5</screw.version>
53 53 <fastjson.version>1.2.83</fastjson.version>
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { ${simpleClassName}VO, ${simpleClassName}PageReqVO, ${simpleClassName}ExcelReqVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 #set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
7 5 // 查询${table.classComment}列表
8 6 export const get${simpleClassName}PageApi = async (params: ${simpleClassName}PageReqVO) => {
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
... ... @@ -6,9 +6,9 @@ import { DICT_TYPE } from &#39;@/utils/dict&#39;
6 6 import { useTable } from '@/hooks/web/useTable'
7 7 import { useI18n } from '@/hooks/web/useI18n'
8 8 import { FormExpose } from '@/components/Form'
9   -import type { ${simpleClassName}VO } from '@/api/${table.moduleName}/${simpleClassName}/types'
10   -import { rules, allSchemas } from './${simpleClassName}.data'
11   -import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${simpleClassName}'
  9 +import type { ${simpleClassName}VO } from '@/api/${table.moduleName}/${classNameVar}/types'
  10 +import { rules, allSchemas } from './${classNameVar}.data'
  11 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
12 12 const { t } = useI18n() // 国际化
13 13  
14 14 // ========== 列表相关 ==========
... ...
yudao-ui-admin-vue3/.env
... ... @@ -11,4 +11,4 @@ VITE_OPEN=true
11 11 VITE_APP_TENANT_ENABLE=true
12 12  
13 13 # 验证码的开关
14   -VITE_APP_CAPTCHA_ENABLE=false
  14 +VITE_APP_CAPTCHA_ENABLE=true
... ...
yudao-ui-admin-vue3/package.json
... ... @@ -36,9 +36,9 @@
36 36 "dayjs": "^1.11.6",
37 37 "echarts": "^5.4.0",
38 38 "echarts-wordcloud": "^2.0.0",
39   - "element-plus": "2.2.19",
  39 + "element-plus": "2.2.20",
40 40 "intro.js": "^6.0.0",
41   - "jsencrypt": "^3.3.0",
  41 + "jsencrypt": "^3.3.1",
42 42 "js-cookie": "^3.0.1",
43 43 "lodash-es": "^4.17.21",
44 44 "mitt": "^3.0.0",
... ... @@ -59,7 +59,7 @@
59 59 "devDependencies": {
60 60 "@commitlint/cli": "^17.2.0",
61 61 "@commitlint/config-conventional": "^17.2.0",
62   - "@iconify/json": "^2.1.131",
  62 + "@iconify/json": "^2.1.134",
63 63 "@intlify/vite-plugin-vue-i18n": "^6.0.3",
64 64 "@purge-icons/generated": "^0.9.0",
65 65 "@types/intro.js": "^5.1.0",
... ... @@ -73,7 +73,7 @@
73 73 "@vitejs/plugin-vue": "^3.2.0",
74 74 "@vitejs/plugin-vue-jsx": "^2.1.0",
75 75 "autoprefixer": "^10.4.13",
76   - "eslint": "^8.26.0",
  76 + "eslint": "^8.27.0",
77 77 "eslint-config-prettier": "^8.5.0",
78 78 "eslint-define-config": "^1.11.0",
79 79 "eslint-plugin-prettier": "^4.2.1",
... ... @@ -86,15 +86,15 @@
86 86 "postcss-less": "^6.0.0",
87 87 "prettier": "^2.7.1",
88 88 "rimraf": "^3.0.2",
89   - "rollup": "^2.79.1",
90   - "stylelint": "^14.14.0",
  89 + "rollup": "^3.2.5",
  90 + "stylelint": "^14.14.1",
91 91 "stylelint-config-html": "^1.1.0",
92 92 "stylelint-config-prettier": "^9.0.3",
93 93 "stylelint-config-recommended": "^9.0.0",
94 94 "stylelint-config-standard": "^29.0.0",
95 95 "stylelint-order": "^5.0.0",
96 96 "typescript": "4.8.4",
97   - "unplugin-vue-macros": "^0.15.2",
  97 + "unplugin-vue-macros": "^0.16.0",
98 98 "vite": "3.2.2",
99 99 "vite-plugin-compression": "^0.5.1",
100 100 "vite-plugin-eslint": "^1.8.1",
... ...
yudao-ui-admin-vue3/pnpm-lock.yaml
... ... @@ -4,7 +4,7 @@ specifiers:
4 4 '@commitlint/cli': ^17.2.0
5 5 '@commitlint/config-conventional': ^17.2.0
6 6 '@iconify/iconify': ^3.0.0
7   - '@iconify/json': ^2.1.131
  7 + '@iconify/json': ^2.1.134
8 8 '@intlify/vite-plugin-vue-i18n': ^6.0.3
9 9 '@purge-icons/generated': ^0.9.0
10 10 '@types/intro.js': ^5.1.0
... ... @@ -28,14 +28,15 @@ specifiers:
28 28 dayjs: ^1.11.6
29 29 echarts: ^5.4.0
30 30 echarts-wordcloud: ^2.0.0
31   - element-plus: 2.2.19
32   - eslint: ^8.26.0
  31 + element-plus: 2.2.20
  32 + eslint: ^8.27.0
33 33 eslint-config-prettier: ^8.5.0
34 34 eslint-define-config: ^1.11.0
35 35 eslint-plugin-prettier: ^4.2.1
36 36 eslint-plugin-vue: ^9.7.0
37 37 intro.js: ^6.0.0
38   - jsencrypt: ^3.3.0
  38 + js-cookie: ^3.0.1
  39 + jsencrypt: ^3.3.1
39 40 less: ^4.1.3
40 41 lint-staged: ^13.0.3
41 42 lodash-es: ^4.17.21
... ... @@ -50,15 +51,15 @@ specifiers:
50 51 qrcode: ^1.5.1
51 52 qs: ^6.11.0
52 53 rimraf: ^3.0.2
53   - rollup: ^2.79.1
54   - stylelint: ^14.14.0
  54 + rollup: ^3.2.5
  55 + stylelint: ^14.14.1
55 56 stylelint-config-html: ^1.1.0
56 57 stylelint-config-prettier: ^9.0.3
57 58 stylelint-config-recommended: ^9.0.0
58 59 stylelint-config-standard: ^29.0.0
59 60 stylelint-order: ^5.0.0
60 61 typescript: 4.8.4
61   - unplugin-vue-macros: ^0.15.2
  62 + unplugin-vue-macros: ^0.16.0
62 63 url: ^0.11.0
63 64 vite: 3.2.2
64 65 vite-plugin-compression: ^0.5.1
... ... @@ -91,9 +92,10 @@ dependencies:
91 92 dayjs: 1.11.6
92 93 echarts: 5.4.0
93 94 echarts-wordcloud: 2.0.0_echarts@5.4.0
94   - element-plus: 2.2.19_vue@3.2.41
  95 + element-plus: 2.2.20_vue@3.2.41
95 96 intro.js: 6.0.0
96   - jsencrypt: 3.3.0
  97 + js-cookie: 3.0.1
  98 + jsencrypt: 3.3.1
97 99 lodash-es: 4.17.21
98 100 mitt: 3.0.0
99 101 nprogress: 0.2.0
... ... @@ -113,7 +115,7 @@ dependencies:
113 115 devDependencies:
114 116 '@commitlint/cli': 17.2.0
115 117 '@commitlint/config-conventional': 17.2.0
116   - '@iconify/json': 2.1.131
  118 + '@iconify/json': 2.1.134
117 119 '@intlify/vite-plugin-vue-i18n': 6.0.3_vite@3.2.2+vue-i18n@9.2.2
118 120 '@purge-icons/generated': 0.9.0
119 121 '@types/intro.js': 5.1.0
... ... @@ -122,16 +124,16 @@ devDependencies:
122 124 '@types/nprogress': 0.2.0
123 125 '@types/qrcode': 1.5.0
124 126 '@types/qs': 6.9.7
125   - '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
126   - '@typescript-eslint/parser': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
  127 + '@typescript-eslint/eslint-plugin': 5.42.0_ofgjrzjuekeo7s3hdyz2yuzw34
  128 + '@typescript-eslint/parser': 5.42.0_rmayb2veg2btbq6mbmnyivgasy
127 129 '@vitejs/plugin-vue': 3.2.0_vite@3.2.2+vue@3.2.41
128 130 '@vitejs/plugin-vue-jsx': 2.1.0_vite@3.2.2+vue@3.2.41
129 131 autoprefixer: 10.4.13_postcss@8.4.18
130   - eslint: 8.26.0
131   - eslint-config-prettier: 8.5.0_eslint@8.26.0
  132 + eslint: 8.27.0
  133 + eslint-config-prettier: 8.5.0_eslint@8.27.0
132 134 eslint-define-config: 1.11.0
133   - eslint-plugin-prettier: 4.2.1_aniwkeyvlpmwkidetuytnokvcm
134   - eslint-plugin-vue: 9.7.0_eslint@8.26.0
  135 + eslint-plugin-prettier: 4.2.1_v7o5sx5x3wbs57ifz6wc4f76we
  136 + eslint-plugin-vue: 9.7.0_eslint@8.27.0
135 137 less: 4.1.3
136 138 lint-staged: 13.0.3
137 139 plop: 3.1.1
... ... @@ -140,18 +142,18 @@ devDependencies:
140 142 postcss-less: 6.0.0_postcss@8.4.18
141 143 prettier: 2.7.1
142 144 rimraf: 3.0.2
143   - rollup: 2.79.1
144   - stylelint: 14.14.0
145   - stylelint-config-html: 1.1.0_2wb2ag3ubchp7fdo72hd6rkeve
146   - stylelint-config-prettier: 9.0.3_stylelint@14.14.0
147   - stylelint-config-recommended: 9.0.0_stylelint@14.14.0
148   - stylelint-config-standard: 29.0.0_stylelint@14.14.0
149   - stylelint-order: 5.0.0_stylelint@14.14.0
  145 + rollup: 3.2.5
  146 + stylelint: 14.14.1
  147 + stylelint-config-html: 1.1.0_a4i6jbpfaxelx4fvjhtlgvxx6i
  148 + stylelint-config-prettier: 9.0.3_stylelint@14.14.1
  149 + stylelint-config-recommended: 9.0.0_stylelint@14.14.1
  150 + stylelint-config-standard: 29.0.0_stylelint@14.14.1
  151 + stylelint-order: 5.0.0_stylelint@14.14.1
150 152 typescript: 4.8.4
151   - unplugin-vue-macros: 0.15.2_mbqnf624zbi2ta2juc2wzs2gvm
  153 + unplugin-vue-macros: 0.16.0_f6zolwli45a6dkgzq5zhbk2c7e
152 154 vite: 3.2.2_less@4.1.3
153 155 vite-plugin-compression: 0.5.1_vite@3.2.2
154   - vite-plugin-eslint: 1.8.1_eslint@8.26.0+vite@3.2.2
  156 + vite-plugin-eslint: 1.8.1_eslint@8.27.0+vite@3.2.2
155 157 vite-plugin-html: 3.2.0_vite@3.2.2
156 158 vite-plugin-purge-icons: 0.9.1_vite@3.2.2
157 159 vite-plugin-style-import: 2.0.0_vite@3.2.2
... ... @@ -785,8 +787,8 @@ packages:
785 787 dependencies:
786 788 '@iconify/types': 2.0.0
787 789  
788   - /@iconify/json/2.1.131:
789   - resolution: {integrity: sha512-VUQLJ2IHEcB0Is9K/grtLEC0OuLV3Fj0h3t04fKMN9hXwJkn2SKounQr44w7LzcBlu2RRYA7/npGlovtWV0iXQ==}
  790 + /@iconify/json/2.1.134:
  791 + resolution: {integrity: sha512-vqz3quli1lcFogDyu3H7mHyPjub+bZv8dJaR1lRk1gzblKBPlKoHhC0VaAjSMiA5L6toqXQRp7osjulB4JkA5Q==}
790 792 dependencies:
791 793 '@iconify/types': 2.0.0
792 794 pathe: 0.3.9
... ... @@ -1118,7 +1120,7 @@ packages:
1118 1120 /@types/web-bluetooth/0.0.16:
1119 1121 resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
1120 1122  
1121   - /@typescript-eslint/eslint-plugin/5.42.0_6xw5wg2354iw4zujk2f3vyfrzu:
  1123 + /@typescript-eslint/eslint-plugin/5.42.0_ofgjrzjuekeo7s3hdyz2yuzw34:
1122 1124 resolution: {integrity: sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==}
1123 1125 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1124 1126 peerDependencies:
... ... @@ -1129,12 +1131,12 @@ packages:
1129 1131 typescript:
1130 1132 optional: true
1131 1133 dependencies:
1132   - '@typescript-eslint/parser': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
  1134 + '@typescript-eslint/parser': 5.42.0_rmayb2veg2btbq6mbmnyivgasy
1133 1135 '@typescript-eslint/scope-manager': 5.42.0
1134   - '@typescript-eslint/type-utils': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
1135   - '@typescript-eslint/utils': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
  1136 + '@typescript-eslint/type-utils': 5.42.0_rmayb2veg2btbq6mbmnyivgasy
  1137 + '@typescript-eslint/utils': 5.42.0_rmayb2veg2btbq6mbmnyivgasy
1136 1138 debug: 4.3.4
1137   - eslint: 8.26.0
  1139 + eslint: 8.27.0
1138 1140 ignore: 5.2.0
1139 1141 natural-compare-lite: 1.4.0
1140 1142 regexpp: 3.2.0
... ... @@ -1145,7 +1147,7 @@ packages:
1145 1147 - supports-color
1146 1148 dev: true
1147 1149  
1148   - /@typescript-eslint/parser/5.42.0_wyqvi574yv7oiwfeinomdzmc3m:
  1150 + /@typescript-eslint/parser/5.42.0_rmayb2veg2btbq6mbmnyivgasy:
1149 1151 resolution: {integrity: sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==}
1150 1152 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1151 1153 peerDependencies:
... ... @@ -1159,7 +1161,7 @@ packages:
1159 1161 '@typescript-eslint/types': 5.42.0
1160 1162 '@typescript-eslint/typescript-estree': 5.42.0_typescript@4.8.4
1161 1163 debug: 4.3.4
1162   - eslint: 8.26.0
  1164 + eslint: 8.27.0
1163 1165 typescript: 4.8.4
1164 1166 transitivePeerDependencies:
1165 1167 - supports-color
... ... @@ -1173,7 +1175,7 @@ packages:
1173 1175 '@typescript-eslint/visitor-keys': 5.42.0
1174 1176 dev: true
1175 1177  
1176   - /@typescript-eslint/type-utils/5.42.0_wyqvi574yv7oiwfeinomdzmc3m:
  1178 + /@typescript-eslint/type-utils/5.42.0_rmayb2veg2btbq6mbmnyivgasy:
1177 1179 resolution: {integrity: sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==}
1178 1180 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1179 1181 peerDependencies:
... ... @@ -1184,9 +1186,9 @@ packages:
1184 1186 optional: true
1185 1187 dependencies:
1186 1188 '@typescript-eslint/typescript-estree': 5.42.0_typescript@4.8.4
1187   - '@typescript-eslint/utils': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
  1189 + '@typescript-eslint/utils': 5.42.0_rmayb2veg2btbq6mbmnyivgasy
1188 1190 debug: 4.3.4
1189   - eslint: 8.26.0
  1191 + eslint: 8.27.0
1190 1192 tsutils: 3.21.0_typescript@4.8.4
1191 1193 typescript: 4.8.4
1192 1194 transitivePeerDependencies:
... ... @@ -1219,7 +1221,7 @@ packages:
1219 1221 - supports-color
1220 1222 dev: true
1221 1223  
1222   - /@typescript-eslint/utils/5.42.0_wyqvi574yv7oiwfeinomdzmc3m:
  1224 + /@typescript-eslint/utils/5.42.0_rmayb2veg2btbq6mbmnyivgasy:
1223 1225 resolution: {integrity: sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==}
1224 1226 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1225 1227 peerDependencies:
... ... @@ -1230,9 +1232,9 @@ packages:
1230 1232 '@typescript-eslint/scope-manager': 5.42.0
1231 1233 '@typescript-eslint/types': 5.42.0
1232 1234 '@typescript-eslint/typescript-estree': 5.42.0_typescript@4.8.4
1233   - eslint: 8.26.0
  1235 + eslint: 8.27.0
1234 1236 eslint-scope: 5.1.1
1235   - eslint-utils: 3.0.0_eslint@8.26.0
  1237 + eslint-utils: 3.0.0_eslint@8.27.0
1236 1238 semver: 7.3.8
1237 1239 transitivePeerDependencies:
1238 1240 - supports-color
... ... @@ -1355,26 +1357,26 @@ packages:
1355 1357 '@volar/vue-language-core': 1.0.9
1356 1358 dev: true
1357 1359  
1358   - /@vue-macros/api/0.1.1:
1359   - resolution: {integrity: sha512-SZHwR1zsmgTi3HmqvcjUEiI+pdSLSOj1pW2g1rdXK8s2hpI9EdxPRPv+r3MSb+513rBZ8ZRsIs8HkDYszqi3vg==}
  1360 + /@vue-macros/api/0.1.2:
  1361 + resolution: {integrity: sha512-NuhWgOmxwmdHtGVhucLaRSJPymmr8Phabw2PuV8mLp7pRmjibp+99+RWF6IwXCNqVnEDYt3MwcEzTvPSzRcqjA==}
1360 1362 engines: {node: '>=14.19.0'}
1361 1363 dependencies:
1362 1364 '@babel/types': 7.20.0
1363   - '@vue-macros/common': 0.13.2
  1365 + '@vue-macros/common': 0.13.3
1364 1366 dev: true
1365 1367  
1366   - /@vue-macros/better-define/0.0.3:
1367   - resolution: {integrity: sha512-X3J6PEC2iNps1TCs1g/po15UMfW/6HG8VvRbDbGPCzjZ7MyQCYJE/aZ1vF5aqrU/+1xiGCCXkJv+5no6RAmq0Q==}
  1368 + /@vue-macros/better-define/0.0.4:
  1369 + resolution: {integrity: sha512-wp4C7Oom1P80oKvCtrpEDtotdIsTHXt0OqgBn47xUqdj4S/baG7Ji6qQ3MUtHxBTQ+nyC+7g9nxSADl+s1Px/Q==}
1368 1370 engines: {node: '>=14.19.0'}
1369 1371 dependencies:
1370 1372 '@rollup/pluginutils': 4.2.1
1371   - '@vue-macros/api': 0.1.1
1372   - '@vue-macros/common': 0.13.2
  1373 + '@vue-macros/api': 0.1.2
  1374 + '@vue-macros/common': 0.13.3
1373 1375 unplugin: 0.10.2
1374 1376 dev: true
1375 1377  
1376   - /@vue-macros/common/0.13.2:
1377   - resolution: {integrity: sha512-2pv9aUIw21IzdcROpo4FgMjEFR4zdV0ikHVF/kE/HX0xHcCteG4Pm7rHYK/JvIBhtiLDLWrcD31Y0B0XBaE0PQ==}
  1378 + /@vue-macros/common/0.13.3:
  1379 + resolution: {integrity: sha512-pV9UFwGZs7ddbAmJI5PZvNA2ZlNESQD81jOJM1wmwLnta66K8m0RQuJK2X/tdy7Avpm/p62M8opwbWyfXsBk4w==}
1378 1380 engines: {node: '>=14.19.0'}
1379 1381 dependencies:
1380 1382 '@babel/types': 7.20.0
... ... @@ -1382,8 +1384,8 @@ packages:
1382 1384 magic-string: 0.26.7
1383 1385 dev: true
1384 1386  
1385   - /@vue-macros/define-model/0.13.7_@vueuse+core@9.4.0:
1386   - resolution: {integrity: sha512-nJXeeh94C49to6k6eGiSnaQGwWVqVpdLxHGFnJynzGCUIbaDAsrVfLWZWG1sbKNlGHHJRAFam4VqBavvqR7zAg==}
  1387 + /@vue-macros/define-model/0.13.8_@vueuse+core@9.4.0:
  1388 + resolution: {integrity: sha512-B/cV6n8wRRxwY4GLNo2q/YUzwYDR3Kbt2cI7Bxb51VRCxZexRqOazn5ZB8I9LdBwBLEenOX/3gRrHW3FApkRww==}
1387 1389 engines: {node: '>=14.19.0'}
1388 1390 peerDependencies:
1389 1391 '@vueuse/core': ^9.0.0
... ... @@ -1392,55 +1394,67 @@ packages:
1392 1394 optional: true
1393 1395 dependencies:
1394 1396 '@rollup/pluginutils': 4.2.1
1395   - '@vue-macros/common': 0.13.2
  1397 + '@vue-macros/common': 0.13.3
1396 1398 '@vueuse/core': 9.4.0_vue@3.2.41
1397 1399 ast-walker-scope: 0.3.0
1398 1400 unplugin: 0.10.2
1399 1401 dev: true
1400 1402  
1401   - /@vue-macros/define-render/0.13.7_vue@3.2.41:
1402   - resolution: {integrity: sha512-7+9PDVVwKp9wtxFhsYDKIBTyr1qJYPOg5aMeG5btJ9zN2zVtNVVO+tx7yAE0xQBkHI7ml2bwy2PG3dFK/phmrQ==}
  1403 + /@vue-macros/define-props/0.0.1_vue@3.2.41:
  1404 + resolution: {integrity: sha512-LyB8k4JSwyBmjlVicxogD3N6+qGgpm7KJOeONNQJnHDo0bkdyssVXDIOEnqfgo+RdqJiqXKdFuBpw/lSvMp0KQ==}
  1405 + engines: {node: '>=14.19.0'}
  1406 + peerDependencies:
  1407 + vue: ^3.2.25
  1408 + dependencies:
  1409 + '@rollup/pluginutils': 4.2.1
  1410 + '@vue-macros/common': 0.13.3
  1411 + unplugin: 0.10.2
  1412 + vue: 3.2.41
  1413 + dev: true
  1414 +
  1415 + /@vue-macros/define-render/0.13.8_vue@3.2.41:
  1416 + resolution: {integrity: sha512-a1FIGgTuvLN5gfbh7/dtYLSaXPBYLu33l2sc0auc55uNXqB6qXGzxu/12bEskONhYcx1BBwsqjWiSFbSJ3yLbg==}
1403 1417 engines: {node: '>=14.19.0'}
1404 1418 peerDependencies:
1405 1419 vue: ^2.7.0 || ^3.0.0
1406 1420 dependencies:
1407 1421 '@rollup/pluginutils': 4.2.1
1408   - '@vue-macros/common': 0.13.2
  1422 + '@vue-macros/common': 0.13.3
1409 1423 unplugin: 0.10.2
1410 1424 vue: 3.2.41
1411 1425 dev: true
1412 1426  
1413   - /@vue-macros/define-slots/0.0.4_vue@3.2.41:
1414   - resolution: {integrity: sha512-AAUz85J1ZL9Lsq3omhwkBe1p95L/VHixdcBonmt1jTCpjpCMmDWUmzl4iPh5pRMkk0D1lfvm5V/m0D68YqKZIg==}
  1427 + /@vue-macros/define-slots/0.0.5_vue@3.2.41:
  1428 + resolution: {integrity: sha512-+CS2MTH1fBeHbiZzThn6aXmrcbPRiuG29yWI6ugMarpIxwvVWXrPcvrWSE2BK/FSwcCR9Xfz7rETIo+BSjdo6A==}
1415 1429 engines: {node: '>=14.19.0'}
1416 1430 peerDependencies:
1417 1431 vue: ^2.7.0 || ^3.0.0
1418 1432 dependencies:
1419 1433 '@rollup/pluginutils': 4.2.1
1420   - '@vue-macros/common': 0.13.2
  1434 + '@vue-macros/common': 0.13.3
1421 1435 unplugin: 0.10.2
1422 1436 vue: 3.2.41
1423 1437 dev: true
1424 1438  
1425   - /@vue-macros/hoist-static/0.12.6:
1426   - resolution: {integrity: sha512-TeF6Dbug2PHaDuHd4VaiL+wPx58yJwaZyPhHA7IvGeo7xHh/nyXSj64aRMj3g5ovi38zXHHLvSb+yMNc3PYhBg==}
  1439 + /@vue-macros/hoist-static/0.12.7:
  1440 + resolution: {integrity: sha512-YRQ1zcy/sH13dgURk4PtazrLzMMnRDwg2N5xyeozaUWNczJmC65OWA5W9wK60WcxHu4pHRR/p7x+jive/bui9w==}
1427 1441 engines: {node: '>=14.19.0'}
1428 1442 dependencies:
1429 1443 '@rollup/pluginutils': 4.2.1
1430   - '@vue-macros/common': 0.13.2
  1444 + '@vue-macros/common': 0.13.3
1431 1445 unplugin: 0.10.2
1432 1446 dev: true
1433 1447  
1434   - /@vue-macros/named-template/0.0.4_4bxfdhtj34q3f6vjmpq7dc2fyi:
1435   - resolution: {integrity: sha512-Hq2QSfglJD73boibJvKXUyiQyI/Gd5bSIF74mzY1Ec1CXhoUO4nupZE+0Ue/qk8Fq5XjUXYDGd2c/SCckBlK9w==}
  1448 + /@vue-macros/named-template/0.0.5_kfit4shdbw4ah6piqfzpu53piy:
  1449 + resolution: {integrity: sha512-bZRUljNyvOOqeE9dyqXvKPQCLUCcPt1EkThmXqSbxagV29ohyviF8+CCs/8OdmNygLTBIChjP8DexQ3nUIFzUg==}
1436 1450 engines: {node: '>=14.19.0'}
1437 1451 dependencies:
1438 1452 '@rollup/pluginutils': 4.2.1
1439 1453 '@vitejs/plugin-vue': 3.2.0_vite@3.2.2+vue@3.2.41
1440   - '@vue-macros/common': 0.13.2
  1454 + '@vue-macros/common': 0.13.3
1441 1455 '@vue/compiler-dom': 3.2.41
1442 1456 unplugin: 0.10.2
1443   - unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.2
  1457 + unplugin-combine: 0.2.8_rollup@3.2.5+vite@3.2.2
1444 1458 transitivePeerDependencies:
1445 1459 - esbuild
1446 1460 - rollup
... ... @@ -1449,14 +1463,14 @@ packages:
1449 1463 - webpack
1450 1464 dev: true
1451 1465  
1452   - /@vue-macros/setup-component/0.12.6_rollup@2.79.1+vite@3.2.2:
1453   - resolution: {integrity: sha512-oYknsBrC13HzZI9xvFz51KeQ8eOzCuki8wpT7BFOub33d9gJuvynpmqLl45FHSw2AJo8UA6vaKi6ef74JMukRg==}
  1466 + /@vue-macros/setup-component/0.12.7_rollup@3.2.5+vite@3.2.2:
  1467 + resolution: {integrity: sha512-L0WkJgw0QDwZh4tOjjKIDR0DMIybiOunsaxVqkJjicTb2YaiRUSLq4Wadl8Ttrsd0IEfI51CSlg7Sx0/dKLrlQ==}
1454 1468 engines: {node: '>=14.19.0'}
1455 1469 dependencies:
1456 1470 '@rollup/pluginutils': 4.2.1
1457   - '@vue-macros/common': 0.13.2
  1471 + '@vue-macros/common': 0.13.3
1458 1472 unplugin: 0.10.2
1459   - unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.2
  1473 + unplugin-combine: 0.2.8_rollup@3.2.5+vite@3.2.2
1460 1474 transitivePeerDependencies:
1461 1475 - esbuild
1462 1476 - rollup
... ... @@ -1464,21 +1478,21 @@ packages:
1464 1478 - webpack
1465 1479 dev: true
1466 1480  
1467   - /@vue-macros/setup-sfc/0.12.6:
1468   - resolution: {integrity: sha512-V7jXQ2sTTcxE4c+BTaWExd2kMi5w5qnJMjyzRPbQUTDf/KWNtPznTCxcmb9wVyJQRrrKfg61VYqpQ1jAtiDFoQ==}
  1481 + /@vue-macros/setup-sfc/0.12.7:
  1482 + resolution: {integrity: sha512-2RyeAEanl2MLeIoyfBKWSpJgXHjAazubF02hO7nbDCf2FgKqWB0Vu8NwyMZaQPNCWJuE4azLEodg8XBMJxyUKg==}
1469 1483 engines: {node: '>=14.19.0'}
1470 1484 dependencies:
1471 1485 '@rollup/pluginutils': 4.2.1
1472   - '@vue-macros/common': 0.13.2
  1486 + '@vue-macros/common': 0.13.3
1473 1487 unplugin: 0.10.2
1474 1488 dev: true
1475 1489  
1476   - /@vue-macros/short-emits/0.12.7:
1477   - resolution: {integrity: sha512-CGy7Za/caP3WejNsHg4Si2bHeqxl2piv7Bf7TAMI/+948FuizQUFI8dRiv6dEQ8rGvegsU2BuTYH8JNDyzAK1A==}
  1490 + /@vue-macros/short-emits/0.12.8:
  1491 + resolution: {integrity: sha512-av/dqgPtU4EomWHHJPbGeuoYavCX2QTE0cd7Ka0dSuXuGgMhTN7feOv+sqsN8003yfOaPSBt6R+N/fy+T99GMA==}
1478 1492 engines: {node: '>=14.19.0'}
1479 1493 dependencies:
1480 1494 '@rollup/pluginutils': 4.2.1
1481   - '@vue-macros/common': 0.13.2
  1495 + '@vue-macros/common': 0.13.3
1482 1496 unplugin: 0.10.2
1483 1497 dev: true
1484 1498  
... ... @@ -2951,8 +2965,8 @@ packages:
2951 2965 resolution: {integrity: sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==}
2952 2966 dev: true
2953 2967  
2954   - /element-plus/2.2.19_vue@3.2.41:
2955   - resolution: {integrity: sha512-uN0gt9lUus/IHzu5J6vkbYoYJgUtU05osdtFv9RO27bHKOG5GN7dH6uA3OKfkQQ6R2sV8ZxY1rc9PH1X8Dgrow==}
  2968 + /element-plus/2.2.20_vue@3.2.41:
  2969 + resolution: {integrity: sha512-ludShd3f5kNRY4FLzeoNitLcwZ4qs2M/zwKeyeE7rUzZJAQ0BZtcT3SvZoEoBLmgxw9jHoonl4WIwon4UzhyRA==}
2956 2970 peerDependencies:
2957 2971 vue: ^3.2.0
2958 2972 dependencies:
... ... @@ -3278,13 +3292,13 @@ packages:
3278 3292 engines: {node: '>=10'}
3279 3293 dev: true
3280 3294  
3281   - /eslint-config-prettier/8.5.0_eslint@8.26.0:
  3295 + /eslint-config-prettier/8.5.0_eslint@8.27.0:
3282 3296 resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==}
3283 3297 hasBin: true
3284 3298 peerDependencies:
3285 3299 eslint: '>=7.0.0'
3286 3300 dependencies:
3287   - eslint: 8.26.0
  3301 + eslint: 8.27.0
3288 3302 dev: true
3289 3303  
3290 3304 /eslint-define-config/1.11.0:
... ... @@ -3292,7 +3306,7 @@ packages:
3292 3306 engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13', pnpm: '>= 7.0.0'}
3293 3307 dev: true
3294 3308  
3295   - /eslint-plugin-prettier/4.2.1_aniwkeyvlpmwkidetuytnokvcm:
  3309 + /eslint-plugin-prettier/4.2.1_v7o5sx5x3wbs57ifz6wc4f76we:
3296 3310 resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
3297 3311 engines: {node: '>=12.0.0'}
3298 3312 peerDependencies:
... ... @@ -3303,25 +3317,25 @@ packages:
3303 3317 eslint-config-prettier:
3304 3318 optional: true
3305 3319 dependencies:
3306   - eslint: 8.26.0
3307   - eslint-config-prettier: 8.5.0_eslint@8.26.0
  3320 + eslint: 8.27.0
  3321 + eslint-config-prettier: 8.5.0_eslint@8.27.0
3308 3322 prettier: 2.7.1
3309 3323 prettier-linter-helpers: 1.0.0
3310 3324 dev: true
3311 3325  
3312   - /eslint-plugin-vue/9.7.0_eslint@8.26.0:
  3326 + /eslint-plugin-vue/9.7.0_eslint@8.27.0:
3313 3327 resolution: {integrity: sha512-DrOO3WZCZEwcLsnd3ohFwqCoipGRSTKTBTnLwdhqAbYZtzWl0o7D+D8ZhlmiZvABKTEl8AFsqH1GHGdybyoQmw==}
3314 3328 engines: {node: ^14.17.0 || >=16.0.0}
3315 3329 peerDependencies:
3316 3330 eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
3317 3331 dependencies:
3318   - eslint: 8.26.0
3319   - eslint-utils: 3.0.0_eslint@8.26.0
  3332 + eslint: 8.27.0
  3333 + eslint-utils: 3.0.0_eslint@8.27.0
3320 3334 natural-compare: 1.4.0
3321 3335 nth-check: 2.1.1
3322 3336 postcss-selector-parser: 6.0.10
3323 3337 semver: 7.3.8
3324   - vue-eslint-parser: 9.1.0_eslint@8.26.0
  3338 + vue-eslint-parser: 9.1.0_eslint@8.27.0
3325 3339 xml-name-validator: 4.0.0
3326 3340 transitivePeerDependencies:
3327 3341 - supports-color
... ... @@ -3350,13 +3364,13 @@ packages:
3350 3364 eslint-visitor-keys: 1.3.0
3351 3365 dev: true
3352 3366  
3353   - /eslint-utils/3.0.0_eslint@8.26.0:
  3367 + /eslint-utils/3.0.0_eslint@8.27.0:
3354 3368 resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
3355 3369 engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
3356 3370 peerDependencies:
3357 3371 eslint: '>=5'
3358 3372 dependencies:
3359   - eslint: 8.26.0
  3373 + eslint: 8.27.0
3360 3374 eslint-visitor-keys: 2.1.0
3361 3375 dev: true
3362 3376  
... ... @@ -3375,8 +3389,8 @@ packages:
3375 3389 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
3376 3390 dev: true
3377 3391  
3378   - /eslint/8.26.0:
3379   - resolution: {integrity: sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==}
  3392 + /eslint/8.27.0:
  3393 + resolution: {integrity: sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==}
3380 3394 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
3381 3395 hasBin: true
3382 3396 dependencies:
... ... @@ -3391,7 +3405,7 @@ packages:
3391 3405 doctrine: 3.0.0
3392 3406 escape-string-regexp: 4.0.0
3393 3407 eslint-scope: 7.1.1
3394   - eslint-utils: 3.0.0_eslint@8.26.0
  3408 + eslint-utils: 3.0.0_eslint@8.27.0
3395 3409 eslint-visitor-keys: 3.3.0
3396 3410 espree: 9.4.0
3397 3411 esquery: 1.4.0
... ... @@ -4471,6 +4485,11 @@ packages:
4471 4485 resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
4472 4486 dev: true
4473 4487  
  4488 + /js-cookie/3.0.1:
  4489 + resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==}
  4490 + engines: {node: '>=12'}
  4491 + dev: false
  4492 +
4474 4493 /js-sdsl/4.1.5:
4475 4494 resolution: {integrity: sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==}
4476 4495 dev: true
... ... @@ -4490,8 +4509,8 @@ packages:
4490 4509 argparse: 2.0.1
4491 4510 dev: true
4492 4511  
4493   - /jsencrypt/3.3.0:
4494   - resolution: {integrity: sha512-OPfQMUU3pJ6KKTvKzr83jePHfyD1zWiWeLtRU9yIWjcbaRWm8MuXIu1/eQlDXPwDZrUjZy+9HVamS2Kmwrvz/Q==}
  4512 + /jsencrypt/3.3.1:
  4513 + resolution: {integrity: sha512-dVvV54GdFuJgmEKn+oBiaifDMen4p6o6j/lJh0OVMcouME8sST0bJ7bldIgKBQk4za0zyGn0/pm4vOznR25mLw==}
4495 4514 dev: false
4496 4515  
4497 4516 /jsesc/2.5.2:
... ... @@ -4577,8 +4596,8 @@ packages:
4577 4596 engines: {node: '>=0.10.0'}
4578 4597 dev: true
4579 4598  
4580   - /known-css-properties/0.25.0:
4581   - resolution: {integrity: sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==}
  4599 + /known-css-properties/0.26.0:
  4600 + resolution: {integrity: sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==}
4582 4601 dev: true
4583 4602  
4584 4603 /kolorist/1.6.0:
... ... @@ -5940,6 +5959,14 @@ packages:
5940 5959 fsevents: 2.3.2
5941 5960 dev: true
5942 5961  
  5962 + /rollup/3.2.5:
  5963 + resolution: {integrity: sha512-/Ha7HhVVofduy+RKWOQJrxe4Qb3xyZo+chcpYiD8SoQa4AG7llhupUtyfKSSrdBM2mWJjhM8wZwmbY23NmlIYw==}
  5964 + engines: {node: '>=14.18.0', npm: '>=8.0.0'}
  5965 + hasBin: true
  5966 + optionalDependencies:
  5967 + fsevents: 2.3.2
  5968 + dev: true
  5969 +
5943 5970 /run-async/2.4.1:
5944 5971 resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
5945 5972 engines: {node: '>=0.12.0'}
... ... @@ -6325,7 +6352,7 @@ packages:
6325 6352 resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
6326 6353 dev: true
6327 6354  
6328   - /stylelint-config-html/1.1.0_2wb2ag3ubchp7fdo72hd6rkeve:
  6355 + /stylelint-config-html/1.1.0_a4i6jbpfaxelx4fvjhtlgvxx6i:
6329 6356 resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==}
6330 6357 engines: {node: ^12 || >=14}
6331 6358 peerDependencies:
... ... @@ -6333,48 +6360,48 @@ packages:
6333 6360 stylelint: '>=14.0.0'
6334 6361 dependencies:
6335 6362 postcss-html: 1.5.0
6336   - stylelint: 14.14.0
  6363 + stylelint: 14.14.1
6337 6364 dev: true
6338 6365  
6339   - /stylelint-config-prettier/9.0.3_stylelint@14.14.0:
  6366 + /stylelint-config-prettier/9.0.3_stylelint@14.14.1:
6340 6367 resolution: {integrity: sha512-5n9gUDp/n5tTMCq1GLqSpA30w2sqWITSSEiAWQlpxkKGAUbjcemQ0nbkRvRUa0B1LgD3+hCvdL7B1eTxy1QHJg==}
6341 6368 engines: {node: '>= 12'}
6342 6369 hasBin: true
6343 6370 peerDependencies:
6344 6371 stylelint: '>=11.0.0'
6345 6372 dependencies:
6346   - stylelint: 14.14.0
  6373 + stylelint: 14.14.1
6347 6374 dev: true
6348 6375  
6349   - /stylelint-config-recommended/9.0.0_stylelint@14.14.0:
  6376 + /stylelint-config-recommended/9.0.0_stylelint@14.14.1:
6350 6377 resolution: {integrity: sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==}
6351 6378 peerDependencies:
6352 6379 stylelint: ^14.10.0
6353 6380 dependencies:
6354   - stylelint: 14.14.0
  6381 + stylelint: 14.14.1
6355 6382 dev: true
6356 6383  
6357   - /stylelint-config-standard/29.0.0_stylelint@14.14.0:
  6384 + /stylelint-config-standard/29.0.0_stylelint@14.14.1:
6358 6385 resolution: {integrity: sha512-uy8tZLbfq6ZrXy4JKu3W+7lYLgRQBxYTUUB88vPgQ+ZzAxdrvcaSUW9hOMNLYBnwH+9Kkj19M2DHdZ4gKwI7tg==}
6359 6386 peerDependencies:
6360 6387 stylelint: ^14.14.0
6361 6388 dependencies:
6362   - stylelint: 14.14.0
6363   - stylelint-config-recommended: 9.0.0_stylelint@14.14.0
  6389 + stylelint: 14.14.1
  6390 + stylelint-config-recommended: 9.0.0_stylelint@14.14.1
6364 6391 dev: true
6365 6392  
6366   - /stylelint-order/5.0.0_stylelint@14.14.0:
  6393 + /stylelint-order/5.0.0_stylelint@14.14.1:
6367 6394 resolution: {integrity: sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw==}
6368 6395 peerDependencies:
6369 6396 stylelint: ^14.0.0
6370 6397 dependencies:
6371 6398 postcss: 8.4.18
6372 6399 postcss-sorting: 7.0.1_postcss@8.4.18
6373   - stylelint: 14.14.0
  6400 + stylelint: 14.14.1
6374 6401 dev: true
6375 6402  
6376   - /stylelint/14.14.0:
6377   - resolution: {integrity: sha512-yUI+4xXfPHVnueYddSQ/e1GuEA/2wVhWQbGj16AmWLtQJtn28lVxfS4b0CsWyVRPgd3Auzi0NXOthIEUhtQmmA==}
  6403 + /stylelint/14.14.1:
  6404 + resolution: {integrity: sha512-Jnftu+lSD8cSpcV/+Z2nfgfgFpTIS1FcujezXPngtoIQ6wtwutL22MsNE0dJuMiM1h1790g2qIjAyUZCMrX4sw==}
6378 6405 engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
6379 6406 hasBin: true
6380 6407 dependencies:
... ... @@ -6395,7 +6422,7 @@ packages:
6395 6422 import-lazy: 4.0.0
6396 6423 imurmurhash: 0.1.4
6397 6424 is-plain-object: 5.0.0
6398   - known-css-properties: 0.25.0
  6425 + known-css-properties: 0.26.0
6399 6426 mathml-tag-names: 2.1.3
6400 6427 meow: 9.0.0
6401 6428 micromatch: 4.0.5
... ... @@ -6413,7 +6440,7 @@ packages:
6413 6440 style-search: 0.1.0
6414 6441 supports-hyperlinks: 2.3.0
6415 6442 svg-tags: 1.0.0
6416   - table: 6.8.0
  6443 + table: 6.8.1
6417 6444 v8-compile-cache: 2.3.0
6418 6445 write-file-atomic: 4.0.2
6419 6446 transitivePeerDependencies:
... ... @@ -6497,8 +6524,8 @@ packages:
6497 6524 stable: 0.1.8
6498 6525 dev: true
6499 6526  
6500   - /table/6.8.0:
6501   - resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==}
  6527 + /table/6.8.1:
  6528 + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==}
6502 6529 engines: {node: '>=10.0.0'}
6503 6530 dependencies:
6504 6531 ajv: 8.11.0
... ... @@ -6730,7 +6757,7 @@ packages:
6730 6757 engines: {node: '>= 10.0.0'}
6731 6758 dev: true
6732 6759  
6733   - /unplugin-combine/0.2.8_rollup@2.79.1+vite@3.2.2:
  6760 + /unplugin-combine/0.2.8_rollup@3.2.5+vite@3.2.2:
6734 6761 resolution: {integrity: sha512-Z38AC/TEjXbVyZ5HjVqo+lADj0/dcfwWC0Z4y0LNhybJzJQwmcMxm+ZsqHY3faauj4YigmlRMdptR5JEW9RuLg==}
6735 6762 engines: {node: '>=14.19.0'}
6736 6763 peerDependencies:
... ... @@ -6749,40 +6776,41 @@ packages:
6749 6776 optional: true
6750 6777 dependencies:
6751 6778 '@antfu/utils': 0.6.0
6752   - rollup: 2.79.1
  6779 + rollup: 3.2.5
6753 6780 unplugin: 0.10.2
6754 6781 vite: 3.2.2_less@4.1.3
6755 6782 dev: true
6756 6783  
6757   - /unplugin-vue-define-options/0.12.6:
6758   - resolution: {integrity: sha512-uD4JTJVTDTRUTwLaT39VZkQ3gMlCba166oweU3jZJeIk8ku4Fh7N7UFazVzRch4THHFBVQ6dHvqvs4oPuCcJjg==}
  6784 + /unplugin-vue-define-options/0.12.7:
  6785 + resolution: {integrity: sha512-relFORVPLDs4dd3ogEti5YyAqQ62XEieRgLu/OrDIRZdSZQ942pydf9ilfLFiFwCUt+EES/2Xl4EERtgP1T/og==}
6759 6786 engines: {node: '>=14.19.0'}
6760 6787 dependencies:
6761 6788 '@rollup/pluginutils': 4.2.1
6762   - '@vue-macros/common': 0.13.2
  6789 + '@vue-macros/common': 0.13.3
6763 6790 ast-walker-scope: 0.3.0
6764 6791 unplugin: 0.10.2
6765 6792 dev: true
6766 6793  
6767   - /unplugin-vue-macros/0.15.2_mbqnf624zbi2ta2juc2wzs2gvm:
6768   - resolution: {integrity: sha512-hFtUJRk9JE534S+mflAFh8QITOspACNCshVgn21NhdECRDAjyrp4xu+CzSIgKAob/xOgS7J2flLaOHSyqePSCQ==}
  6794 + /unplugin-vue-macros/0.16.0_f6zolwli45a6dkgzq5zhbk2c7e:
  6795 + resolution: {integrity: sha512-GdSJT+8Anc5zrGtZTvEnya2XVOneG0MEyyRrWWhVtn5xYEsUkrB0IxsHiT/mGjR5U+tjyQ/9sNL+FhhC54NFnQ==}
6769 6796 engines: {node: '>=14.19.0'}
6770 6797 peerDependencies:
6771 6798 vue: ^2.7.0 || ^3.2.25
6772 6799 dependencies:
6773 6800 '@rollup/pluginutils': 4.2.1
6774   - '@vue-macros/better-define': 0.0.3
6775   - '@vue-macros/define-model': 0.13.7_@vueuse+core@9.4.0
6776   - '@vue-macros/define-render': 0.13.7_vue@3.2.41
6777   - '@vue-macros/define-slots': 0.0.4_vue@3.2.41
6778   - '@vue-macros/hoist-static': 0.12.6
6779   - '@vue-macros/named-template': 0.0.4_4bxfdhtj34q3f6vjmpq7dc2fyi
6780   - '@vue-macros/setup-component': 0.12.6_rollup@2.79.1+vite@3.2.2
6781   - '@vue-macros/setup-sfc': 0.12.6
6782   - '@vue-macros/short-emits': 0.12.7
  6801 + '@vue-macros/better-define': 0.0.4
  6802 + '@vue-macros/define-model': 0.13.8_@vueuse+core@9.4.0
  6803 + '@vue-macros/define-props': 0.0.1_vue@3.2.41
  6804 + '@vue-macros/define-render': 0.13.8_vue@3.2.41
  6805 + '@vue-macros/define-slots': 0.0.5_vue@3.2.41
  6806 + '@vue-macros/hoist-static': 0.12.7
  6807 + '@vue-macros/named-template': 0.0.5_kfit4shdbw4ah6piqfzpu53piy
  6808 + '@vue-macros/setup-component': 0.12.7_rollup@3.2.5+vite@3.2.2
  6809 + '@vue-macros/setup-sfc': 0.12.7
  6810 + '@vue-macros/short-emits': 0.12.8
6783 6811 local-pkg: 0.4.2
6784   - unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.2
6785   - unplugin-vue-define-options: 0.12.6
  6812 + unplugin-combine: 0.2.8_rollup@3.2.5+vite@3.2.2
  6813 + unplugin-vue-define-options: 0.12.7
6786 6814 vue: 3.2.41
6787 6815 transitivePeerDependencies:
6788 6816 - '@vueuse/core'
... ... @@ -6897,7 +6925,7 @@ packages:
6897 6925 - supports-color
6898 6926 dev: true
6899 6927  
6900   - /vite-plugin-eslint/1.8.1_eslint@8.26.0+vite@3.2.2:
  6928 + /vite-plugin-eslint/1.8.1_eslint@8.27.0+vite@3.2.2:
6901 6929 resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==}
6902 6930 peerDependencies:
6903 6931 eslint: '>=7'
... ... @@ -6905,7 +6933,7 @@ packages:
6905 6933 dependencies:
6906 6934 '@rollup/pluginutils': 4.2.1
6907 6935 '@types/eslint': 8.4.6
6908   - eslint: 8.26.0
  6936 + eslint: 8.27.0
6909 6937 rollup: 2.79.1
6910 6938 vite: 3.2.2_less@4.1.3
6911 6939 dev: true
... ... @@ -7041,14 +7069,14 @@ packages:
7041 7069 dependencies:
7042 7070 vue: 3.2.41
7043 7071  
7044   - /vue-eslint-parser/9.1.0_eslint@8.26.0:
  7072 + /vue-eslint-parser/9.1.0_eslint@8.27.0:
7045 7073 resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
7046 7074 engines: {node: ^14.17.0 || >=16.0.0}
7047 7075 peerDependencies:
7048 7076 eslint: '>=6.0.0'
7049 7077 dependencies:
7050 7078 debug: 4.3.4
7051   - eslint: 8.26.0
  7079 + eslint: 8.27.0
7052 7080 eslint-scope: 7.1.1
7053 7081 eslint-visitor-keys: 3.3.0
7054 7082 espree: 9.4.0
... ...
yudao-ui-admin-vue3/src/api/bpm/form/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { FormVO } from './types'
3   -const request = useAxios()
4 3  
5 4 // 创建工作流的表单定义
6 5 export const createFormApi = async (data: FormVO) => {
... ...
yudao-ui-admin-vue3/src/api/bpm/leave/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { LeaveVO } from './types'
3   -const request = useAxios()
4 3  
5 4 // 创建请假申请
6 5 export const createLeaveApi = async (data: LeaveVO) => {
... ...
yudao-ui-admin-vue3/src/api/bpm/model/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { ModelVO } from './types'
3   -const request = useAxios()
4 3  
5 4 export const getModelPageApi = async (params) => {
6 5 return await request.get({ url: '/bpm/model/page', params })
... ...
yudao-ui-admin-vue3/src/api/bpm/processInstance/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { ProcessInstanceVO } from './types'
3   -const request = useAxios()
4 3  
5 4 export const getMyProcessInstancePageApi = async (params) => {
6 5 return await request.get({ url: '/bpm/process-instance/my-page', params })
... ...
yudao-ui-admin-vue3/src/api/bpm/task/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 export const getTodoTaskPage = async (params) => {
6 4 return await request.get({ url: '/bpm/task/todo-page', params })
... ...
yudao-ui-admin-vue3/src/api/bpm/taskAssignRule/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { TaskAssignVO } from './types'
3   -const request = useAxios()
4 3  
5 4 export const getTaskAssignRuleList = async (params) => {
6 5 return await request.get({ url: '/bpm/task-assign-rule/list', params })
... ...
yudao-ui-admin-vue3/src/api/bpm/userGroup/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { UserGroupVO } from './types'
3   -const request = useAxios()
4 3  
5 4 // 创建用户组
6 5 export const createUserGroupApi = async (data: UserGroupVO) => {
... ...
yudao-ui-admin-vue3/src/api/infra/apiAccessLog/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询列表API 访问日志
6 4 export const getApiAccessLogPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/infra/apiErrorLog/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询列表API 访问日志
6 4 export const getApiErrorLogPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/infra/codegen/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { CodegenUpdateReqVO, CodegenCreateListReqVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询列表代码生成表定义
7 5 export const getCodegenTablePageApi = (params) => {
8 6 return request.get({ url: '/infra/codegen/table/page', params })
... ...
yudao-ui-admin-vue3/src/api/infra/config/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { ConfigVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询参数列表
7 5 export const getConfigPageApi = (params) => {
8 6 return request.get({ url: '/infra/config/page', params })
... ...
yudao-ui-admin-vue3/src/api/infra/dataSourceConfig/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { DataSourceConfigVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询数据源配置列表
7 5 export const getDataSourceConfigListApi = () => {
8 6 return request.get({ url: '/infra/data-source-config/list' })
... ...
yudao-ui-admin-vue3/src/api/infra/dbDoc/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 导出Html
6 4 export const exportHtmlApi = () => {
... ...
yudao-ui-admin-vue3/src/api/infra/fileConfig/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { FileConfigVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询文件配置列表
7 5 export const getFileConfigPageApi = (params) => {
8 6 return request.get({ url: '/infra/file-config/page', params })
... ...
yudao-ui-admin-vue3/src/api/infra/fileList/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询文件列表
6 4 export const getFilePageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/infra/job/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { JobVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 任务列表
7 5 export const getJobPageApi = (params) => {
8 6 return request.get({ url: '/infra/job/page', params })
... ...
yudao-ui-admin-vue3/src/api/infra/jobLog/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 任务日志列表
6 4 export const getJobLogPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/infra/redis/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 /**
6 4 * 获取redis 监控信息
... ...
yudao-ui-admin-vue3/src/api/login/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { getRefreshToken } from '@/utils/auth'
3 3 import type { UserLoginVO } from './types'
4 4  
5   -const request = useAxios()
6   -
7 5 export interface CodeImgResult {
8 6 captchaOnOff: boolean
9 7 img: string
... ...
yudao-ui-admin-vue3/src/api/pay/app/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { AppVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询列表支付应用
7 5 export const getAppPageApi = (params) => {
8 6 return request.get({ url: '/pay/app/page', params })
... ...
yudao-ui-admin-vue3/src/api/pay/channel/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { ChannelVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询列表支付渠道
7 5 export const getChannelPageApi = (params) => {
8 6 return request.get({ url: '/pay/channel/page', params })
... ...
yudao-ui-admin-vue3/src/api/pay/merchant/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { MerchantVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询列表支付商户
7 5 export const getMerchantPageApi = (params) => {
8 6 return request.get({ url: '/pay/merchant/page', params })
... ...
yudao-ui-admin-vue3/src/api/pay/order/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { OrderVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询列表支付订单
7 5 export const getOrderPageApi = async (params) => {
8 6 return await request.get({ url: '/pay/order/page', params })
... ...
yudao-ui-admin-vue3/src/api/pay/refund/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { RefundVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询列表退款订单
7 5 export const getRefundPageApi = (params) => {
8 6 return request.get({ url: '/pay/refund/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/dept/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { DeptVO, DeptListReqVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询部门(精简)列表
7 5 export const listSimpleDeptApi = () => {
8 6 return request.get({ url: '/system/dept/list-all-simple' })
... ...
yudao-ui-admin-vue3/src/api/system/dict/dict.data.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { DictDataVO, DictDataPageReqVO, DictDataExportReqVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询字典数据(精简)列表
7 5 export const listSimpleDictDataApi = () => {
8 6 return request.get({ url: '/system/dict-data/list-all-simple' })
... ...
yudao-ui-admin-vue3/src/api/system/dict/dict.type.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { DictTypeVO, DictTypePageReqVO, DictTypeExportReqVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询字典(精简)列表
7 5 export const listSimpleDictTypeApi = () => {
8 6 return request.get({ url: '/system/dict-type/list-all-simple' })
... ...
yudao-ui-admin-vue3/src/api/system/errorCode/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { ErrorCodeVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询错误码列表
7 5 export const getErrorCodePageApi = (params) => {
8 6 return request.get({ url: '/system/error-code/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/loginLog/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询登录日志列表
6 4 export const getLoginLogPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/system/menu/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { MenuVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询菜单(精简)列表
7 5 export const listSimpleMenusApi = () => {
8 6 return request.get({ url: '/system/menu/list-all-simple' })
... ...
yudao-ui-admin-vue3/src/api/system/notice/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { NoticeVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询公告列表
7 5 export const getNoticePageApi = (params) => {
8 6 return request.get({ url: '/system/notice/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/oauth2/client.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import { OAuth2ClientVo } from './client.types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询 OAuth2列表
7 5 export const getOAuth2ClientPageApi = (params) => {
8 6 return request.get({ url: '/system/oauth2-client/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/oauth2/token.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询 token列表
6 4 export const getAccessTokenPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/system/operatelog/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询操作日志列表
6 4 export const getOperateLogPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/system/permission/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type {
3 3 PermissionAssignRoleDataScopeReqVO,
4 4 PermissionAssignRoleMenuReqVO,
5 5 PermissionAssignUserRoleReqVO
6 6 } from './types'
7 7  
8   -const request = useAxios()
9   -
10 8 // 查询角色拥有的菜单权限
11 9 export const listRoleMenusApi = async (roleId: number) => {
12 10 return await request.get({ url: '/system/permission/list-role-resources?roleId=' + roleId })
... ...
yudao-ui-admin-vue3/src/api/system/post/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { PostVO, PostPageReqVO, PostExportReqVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询岗位列表
7 5 export const getPostPageApi = async (params: PostPageReqVO) => {
8 6 return await request.get({ url: '/system/post/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/role/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { RoleVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询角色列表
7 5 export const getRolePageApi = async (params) => {
8 6 return await request.get({ url: '/system/role/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/sensitiveWord/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { SensitiveWordVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询敏感词列表
7 5 export const getSensitiveWordPageApi = (params) => {
8 6 return request.get({ url: '/system/sensitive-word/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/sms/smsChannel/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { SmsChannelVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询短信渠道列表
7 5 export const getSmsChannelPageApi = (params) => {
8 6 return request.get({ url: '/system/sms-channel/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/sms/smsLog/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询短信日志列表
6 4 export const getSmsLogPageApi = (params) => {
... ...
yudao-ui-admin-vue3/src/api/system/sms/smsTemplate/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { SmsTemplateVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询短信模板列表
7 5 export const getSmsTemplatePageApi = (params) => {
8 6 return request.get({ url: '/system/sms-template/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/tenant/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { TenantVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询租户列表
7 5 export const getTenantPageApi = (params) => {
8 6 return request.get({ url: '/system/tenant/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/tenantPackage/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { TenantPackageVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询租户套餐列表
7 5 export const getTenantPackageTypePageApi = (params) => {
8 6 return request.get({ url: '/system/tenant-package/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/user/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
  1 +import request from '@/config/axios'
2 2 import type { UserVO } from './types'
3 3  
4   -const request = useAxios()
5   -
6 4 // 查询用户管理列表
7 5 export const getUserPageApi = (params) => {
8 6 return request.get({ url: '/system/user/page', params })
... ...
yudao-ui-admin-vue3/src/api/system/user/profile/index.ts
1   -import { useAxios } from '@/hooks/web/useAxios'
2   -
3   -const request = useAxios()
  1 +import request from '@/config/axios'
4 2  
5 3 // 查询用户个人信息
6 4 export const getUserProfileApi = () => {
... ...
yudao-ui-admin-vue3/src/components/XButton/index.ts 0 → 100644
  1 +import XButton from './src/XButton.vue'
  2 +
  3 +export { XButton }
... ...
yudao-ui-admin-vue3/src/components/XButton/src/XButton.vue 0 → 100644
  1 +<script setup lang="ts">
  2 +import { propTypes } from '@/utils/propTypes'
  3 +import { computed, useAttrs, PropType } from 'vue'
  4 +
  5 +const props = defineProps({
  6 + modelValue: propTypes.bool.def(false),
  7 + loading: propTypes.bool.def(false),
  8 + preIcon: propTypes.string.def(''),
  9 + postIcon: propTypes.string.def(''),
  10 + title: propTypes.string.def('按钮'),
  11 + type: propTypes.oneOf(['', 'primary', 'success', 'warning', 'danger', 'info']).def(''),
  12 + link: propTypes.bool.def(false),
  13 + circle: propTypes.bool.def(false),
  14 + round: propTypes.bool.def(false),
  15 + plain: propTypes.bool.def(false),
  16 + onClick: { type: Function as PropType<(...args) => any>, default: null }
  17 +})
  18 +const getBindValue = computed(() => {
  19 + const delArr: string[] = ['title', 'preIcon', 'postIcon', 'onClick']
  20 + const attrs = useAttrs()
  21 + const obj = { ...attrs, ...props }
  22 + for (const key in obj) {
  23 + if (delArr.indexOf(key) !== -1) {
  24 + delete obj[key]
  25 + }
  26 + }
  27 + return obj
  28 +})
  29 +</script>
  30 +
  31 +<template>
  32 + <el-button v-bind="getBindValue" @click="onClick">
  33 + <Icon :icon="preIcon" v-if="preIcon" class="mr-1px" />
  34 + {{ title }}
  35 + <Icon :icon="postIcon" v-if="postIcon" class="mr-1px" />
  36 + </el-button>
  37 +</template>
... ...
yudao-ui-admin-vue3/src/components/XModal/index.ts 0 → 100644
  1 +import XModal from './src/XModal.vue'
  2 +
  3 +export { XModal }
... ...
yudao-ui-admin-vue3/src/components/XModal/src/XModal.vue 0 → 100644
  1 +<script setup lang="ts">
  2 +import { propTypes } from '@/utils/propTypes'
  3 +import { computed, useAttrs, useSlots } from 'vue'
  4 +
  5 +const slots = useSlots()
  6 +
  7 +const props = defineProps({
  8 + id: propTypes.string.def('model_1'),
  9 + modelValue: propTypes.bool.def(false),
  10 + fullscreen: propTypes.bool.def(false),
  11 + loading: propTypes.bool.def(false),
  12 + title: propTypes.string.def('弹窗'),
  13 + width: propTypes.string.def('800'),
  14 + height: propTypes.string.def('480'),
  15 + minWidth: propTypes.string.def('460'),
  16 + minHeight: propTypes.string.def('320'),
  17 + showFooter: propTypes.bool.def(true)
  18 +})
  19 +
  20 +const getBindValue = computed(() => {
  21 + const attrs = useAttrs()
  22 + const obj = { ...attrs, ...props }
  23 + return obj
  24 +})
  25 +</script>
  26 +
  27 +<template>
  28 + <vxe-modal v-bind="getBindValue" destroy-on-close show-zoom resize transfer>
  29 + <template v-if="slots.header" #header>
  30 + <slot name="header"></slot>
  31 + </template>
  32 + <template v-if="slots.default" #default>
  33 + <slot name="default"></slot>
  34 + </template>
  35 + <template v-if="slots.corner" #corner>
  36 + <slot name="corner"></slot>
  37 + </template>
  38 + <template v-if="slots.footer" #footer>
  39 + <slot name="footer"></slot>
  40 + </template>
  41 + </vxe-modal>
  42 +</template>
... ...
yudao-ui-admin-vue3/src/components/index.ts
... ... @@ -4,6 +4,8 @@ import { Form } from &#39;@/components/Form&#39;
4 4 import { Table } from '@/components/Table'
5 5 import { Search } from '@/components/Search'
6 6 import { Dialog } from '@/components/Dialog'
  7 +import { XModal } from '@/components/XModal'
  8 +import { XButton } from '@/components/XButton'
7 9 import { DictTag } from '@/components/DictTag'
8 10 import { ContentWrap } from '@/components/ContentWrap'
9 11 import { Descriptions } from '@/components/Descriptions'
... ... @@ -14,6 +16,8 @@ export const setupGlobCom = (app: App&lt;Element&gt;): void =&gt; {
14 16 app.component('Table', Table)
15 17 app.component('Search', Search)
16 18 app.component('Dialog', Dialog)
  19 + app.component('XModal', XModal)
  20 + app.component('XButton', XButton)
17 21 app.component('DictTag', DictTag)
18 22 app.component('ContentWrap', ContentWrap)
19 23 app.component('Descriptions', Descriptions)
... ...
yudao-ui-admin-vue3/src/config/axios/index.ts
1   -import axios, {
2   - AxiosInstance,
3   - AxiosRequestConfig,
4   - AxiosRequestHeaders,
5   - AxiosResponse,
6   - AxiosError
7   -} from 'axios'
8   -import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
9   -import qs from 'qs'
10   -import { config } from '@/config/axios/config'
11   -import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
12   -import errorCode from './errorCode'
13   -import { useI18n } from '@/hooks/web/useI18n'
14   -import { resetRouter } from '@/router'
15   -import { useCache } from '@/hooks/web/useCache'
  1 +import { service } from './service'
16 2  
17   -const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
18   -const { result_code, base_url, request_timeout } = config
  3 +import { config } from './config'
19 4  
20   -// 需要忽略的提示。忽略后,自动 Promise.reject('error')
21   -const ignoreMsgs = [
22   - '无效的刷新令牌', // 刷新令牌被删除时,不用提示
23   - '刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401,无法跳转到登出界面
24   -]
25   -// 是否显示重新登录
26   -export const isRelogin = { show: false }
27   -// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
28   -// 请求队列
29   -let requestList: any[] = []
30   -// 是否正在刷新中
31   -let isRefreshToken = false
  5 +const { default_headers } = config
32 6  
33   -// 创建axios实例
34   -const service: AxiosInstance = axios.create({
35   - baseURL: base_url, // api 的 base_url
36   - timeout: request_timeout, // 请求超时时间
37   - withCredentials: false // 禁用 Cookie 等信息
38   -})
39   -
40   -// request拦截器
41   -service.interceptors.request.use(
42   - (config: AxiosRequestConfig) => {
43   - // 是否需要设置 token
44   - const isToken = (config!.headers || {}).isToken === false
45   - if (getAccessToken() && !isToken) {
46   - ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
47   - }
48   - // 设置租户
49   - if (tenantEnable) {
50   - const tenantId = getTenantId()
51   - if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId
52   - }
53   - const params = config.params || {}
54   - const data = config.data || false
55   - if (
56   - config.method?.toUpperCase() === 'POST' &&
57   - (config.headers as AxiosRequestHeaders)['Content-Type'] ===
58   - 'application/x-www-form-urlencoded'
59   - ) {
60   - config.data = qs.stringify(data)
61   - }
62   - // get参数编码
63   - if (config.method?.toUpperCase() === 'GET' && params) {
64   - let url = config.url + '?'
65   - for (const propName of Object.keys(params)) {
66   - const value = params[propName]
67   - if (value !== void 0 && value !== null && typeof value !== 'undefined') {
68   - if (typeof value === 'object') {
69   - for (const val of Object.keys(value)) {
70   - const params = propName + '[' + val + ']'
71   - const subPart = encodeURIComponent(params) + '='
72   - url += subPart + encodeURIComponent(value[val]) + '&'
73   - }
74   - } else {
75   - url += `${propName}=${encodeURIComponent(value)}&`
76   - }
77   - }
78   - }
79   - // 给 get 请求加上时间戳参数,避免从缓存中拿数据
80   - // const now = new Date().getTime()
81   - // params = params.substring(0, url.length - 1) + `?_t=${now}`
82   - url = url.slice(0, -1)
83   - config.params = {}
84   - config.url = url
85   - }
86   - return config
  7 +const request = (option: any) => {
  8 + const { url, method, params, data, headersType, responseType } = option
  9 + return service({
  10 + url: url,
  11 + method,
  12 + params,
  13 + data,
  14 + responseType: responseType,
  15 + headers: {
  16 + 'Content-Type': headersType || default_headers
  17 + }
  18 + })
  19 +}
  20 +export default {
  21 + get: async <T = any>(option: any) => {
  22 + const res = await request({ method: 'GET', ...option })
  23 + return res.data as unknown as T
87 24 },
88   - (error: AxiosError) => {
89   - // Do something with request error
90   - console.log(error) // for debug
91   - Promise.reject(error)
92   - }
93   -)
94   -
95   -// response 拦截器
96   -service.interceptors.response.use(
97   - async (response: AxiosResponse<Recordable>) => {
98   - const { data } = response
99   - const config = response.config
100   - if (!data) {
101   - // 返回“[HTTP]请求没有返回值”;
102   - throw new Error()
103   - }
104   - const { t } = useI18n()
105   - // 未设置状态码则默认成功状态
106   - const code = data.code || result_code
107   - // 二进制数据则直接返回
108   - if (
109   - response.request.responseType === 'blob' ||
110   - response.request.responseType === 'arraybuffer'
111   - ) {
112   - return response.data
113   - }
114   - // 获取错误信息
115   - const msg = data.msg || errorCode[code] || errorCode['default']
116   - if (ignoreMsgs.indexOf(msg) !== -1) {
117   - // 如果是忽略的错误码,直接返回 msg 异常
118   - return Promise.reject(msg)
119   - } else if (code === 401) {
120   - // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
121   - if (!isRefreshToken) {
122   - isRefreshToken = true
123   - // 1. 如果获取不到刷新令牌,则只能执行登出操作
124   - if (!getRefreshToken()) {
125   - return handleAuthorized()
126   - }
127   - // 2. 进行刷新访问令牌
128   - try {
129   - const refreshTokenRes = await refreshToken()
130   - // 2.1 刷新成功,则回放队列的请求 + 当前请求
131   - setToken(refreshTokenRes.data.data)
132   - config.headers!.Authorization = 'Bearer ' + getAccessToken()
133   - requestList.forEach((cb: any) => {
134   - cb()
135   - })
136   - requestList = []
137   - return service(config)
138   - } catch (e) {
139   - // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
140   - // 2.2 刷新失败,只回放队列的请求
141   - requestList.forEach((cb: any) => {
142   - cb()
143   - })
144   - // 提示是否要登出。即不回放当前请求!不然会形成递归
145   - return handleAuthorized()
146   - } finally {
147   - requestList = []
148   - isRefreshToken = false
149   - }
150   - } else {
151   - // 添加到队列,等待刷新获取到新的令牌
152   - return new Promise((resolve) => {
153   - requestList.push(() => {
154   - config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
155   - resolve(service(config))
156   - })
157   - })
158   - }
159   - } else if (code === 500) {
160   - ElMessage.error(t('sys.api.errMsg500'))
161   - return Promise.reject(new Error(msg))
162   - } else if (code === 901) {
163   - ElMessage.error(
164   - '<div>' +
165   - t('sys.api.errMsg901') +
166   - '</div>' +
167   - '<div> &nbsp; </div>' +
168   - '<div>参考 https://doc.iocoder.cn/ 教程</div>' +
169   - '<div> &nbsp; </div>' +
170   - '<div>5 分钟搭建本地环境</div>'
171   - )
172   - return Promise.reject(new Error(msg))
173   - } else if (code !== 200) {
174   - if (msg === '无效的刷新令牌') {
175   - // hard coding:忽略这个提示,直接登出
176   - console.log(msg)
177   - } else {
178   - ElNotification.error({
179   - title: msg
180   - })
181   - }
182   - return Promise.reject('error')
183   - } else {
184   - return data
185   - }
  25 + post: async <T = any>(option: any) => {
  26 + const res = await request({ method: 'POST', ...option })
  27 + return res.data as unknown as T
186 28 },
187   - (error: AxiosError) => {
188   - console.log('err' + error) // for debug
189   - let { message } = error
190   - const { t } = useI18n()
191   - if (message === 'Network Error') {
192   - message = t('sys.api.errorMessage')
193   - } else if (message.includes('timeout')) {
194   - message = t('sys.api.apiTimeoutMessage')
195   - } else if (message.includes('Request failed with status code')) {
196   - message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
197   - }
198   - ElMessage.error(message)
199   - return Promise.reject(error)
200   - }
201   -)
202   -
203   -const refreshToken = async () => {
204   - return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
205   -}
206   -const handleAuthorized = () => {
207   - const { t } = useI18n()
208   - if (!isRelogin.show) {
209   - isRelogin.show = true
210   - ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
211   - confirmButtonText: t('login.relogin'),
212   - cancelButtonText: t('common.cancel'),
213   - type: 'warning'
214   - })
215   - .then(() => {
216   - const { wsCache } = useCache()
217   - resetRouter() // 重置静态路由表
218   - wsCache.clear()
219   - removeToken()
220   - isRelogin.show = false
221   - window.location.href = '/'
222   - })
223   - .catch(() => {
224   - isRelogin.show = false
225   - })
  29 + delete: async <T = any>(option: any) => {
  30 + const res = await request({ method: 'DELETE', ...option })
  31 + return res.data as unknown as T
  32 + },
  33 + put: async <T = any>(option: any) => {
  34 + const res = await request({ method: 'PUT', ...option })
  35 + return res.data as unknown as T
  36 + },
  37 + download: async <T = any>(option: any) => {
  38 + const res = await request({ method: 'GET', responseType: 'blob', ...option })
  39 + return res as unknown as Promise<T>
  40 + },
  41 + upload: async <T = any>(option: any) => {
  42 + option.headersType = 'multipart/form-data'
  43 + const res = await request({ method: 'PUT', ...option })
  44 + return res as unknown as Promise<T>
226 45 }
227   - return Promise.reject(t('sys.api.timeoutMessage'))
228 46 }
229   -export { service }
... ...
yudao-ui-admin-vue3/src/config/axios/service.ts 0 → 100644
  1 +import axios, {
  2 + AxiosInstance,
  3 + AxiosRequestConfig,
  4 + AxiosRequestHeaders,
  5 + AxiosResponse,
  6 + AxiosError
  7 +} from 'axios'
  8 +import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
  9 +import qs from 'qs'
  10 +import { config } from '@/config/axios/config'
  11 +import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
  12 +import errorCode from './errorCode'
  13 +import { useI18n } from '@/hooks/web/useI18n'
  14 +import { resetRouter } from '@/router'
  15 +import { useCache } from '@/hooks/web/useCache'
  16 +
  17 +const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
  18 +const { result_code, base_url, request_timeout } = config
  19 +
  20 +// 需要忽略的提示。忽略后,自动 Promise.reject('error')
  21 +const ignoreMsgs = [
  22 + '无效的刷新令牌', // 刷新令牌被删除时,不用提示
  23 + '刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401,无法跳转到登出界面
  24 +]
  25 +// 是否显示重新登录
  26 +export const isRelogin = { show: false }
  27 +// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
  28 +// 请求队列
  29 +let requestList: any[] = []
  30 +// 是否正在刷新中
  31 +let isRefreshToken = false
  32 +
  33 +// 创建axios实例
  34 +const service: AxiosInstance = axios.create({
  35 + baseURL: base_url, // api 的 base_url
  36 + timeout: request_timeout, // 请求超时时间
  37 + withCredentials: false // 禁用 Cookie 等信息
  38 +})
  39 +
  40 +// request拦截器
  41 +service.interceptors.request.use(
  42 + (config: AxiosRequestConfig) => {
  43 + // 是否需要设置 token
  44 + const isToken = (config!.headers || {}).isToken === false
  45 + if (getAccessToken() && !isToken) {
  46 + ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
  47 + }
  48 + // 设置租户
  49 + if (tenantEnable) {
  50 + const tenantId = getTenantId()
  51 + if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId
  52 + }
  53 + const params = config.params || {}
  54 + const data = config.data || false
  55 + if (
  56 + config.method?.toUpperCase() === 'POST' &&
  57 + (config.headers as AxiosRequestHeaders)['Content-Type'] ===
  58 + 'application/x-www-form-urlencoded'
  59 + ) {
  60 + config.data = qs.stringify(data)
  61 + }
  62 + // get参数编码
  63 + if (config.method?.toUpperCase() === 'GET' && params) {
  64 + let url = config.url + '?'
  65 + for (const propName of Object.keys(params)) {
  66 + const value = params[propName]
  67 + if (value !== void 0 && value !== null && typeof value !== 'undefined') {
  68 + if (typeof value === 'object') {
  69 + for (const val of Object.keys(value)) {
  70 + const params = propName + '[' + val + ']'
  71 + const subPart = encodeURIComponent(params) + '='
  72 + url += subPart + encodeURIComponent(value[val]) + '&'
  73 + }
  74 + } else {
  75 + url += `${propName}=${encodeURIComponent(value)}&`
  76 + }
  77 + }
  78 + }
  79 + // 给 get 请求加上时间戳参数,避免从缓存中拿数据
  80 + // const now = new Date().getTime()
  81 + // params = params.substring(0, url.length - 1) + `?_t=${now}`
  82 + url = url.slice(0, -1)
  83 + config.params = {}
  84 + config.url = url
  85 + }
  86 + return config
  87 + },
  88 + (error: AxiosError) => {
  89 + // Do something with request error
  90 + console.log(error) // for debug
  91 + Promise.reject(error)
  92 + }
  93 +)
  94 +
  95 +// response 拦截器
  96 +service.interceptors.response.use(
  97 + async (response: AxiosResponse<Recordable>) => {
  98 + const { data } = response
  99 + const config = response.config
  100 + if (!data) {
  101 + // 返回“[HTTP]请求没有返回值”;
  102 + throw new Error()
  103 + }
  104 + const { t } = useI18n()
  105 + // 未设置状态码则默认成功状态
  106 + const code = data.code || result_code
  107 + // 二进制数据则直接返回
  108 + if (
  109 + response.request.responseType === 'blob' ||
  110 + response.request.responseType === 'arraybuffer'
  111 + ) {
  112 + return response.data
  113 + }
  114 + // 获取错误信息
  115 + const msg = data.msg || errorCode[code] || errorCode['default']
  116 + if (ignoreMsgs.indexOf(msg) !== -1) {
  117 + // 如果是忽略的错误码,直接返回 msg 异常
  118 + return Promise.reject(msg)
  119 + } else if (code === 401) {
  120 + // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
  121 + if (!isRefreshToken) {
  122 + isRefreshToken = true
  123 + // 1. 如果获取不到刷新令牌,则只能执行登出操作
  124 + if (!getRefreshToken()) {
  125 + return handleAuthorized()
  126 + }
  127 + // 2. 进行刷新访问令牌
  128 + try {
  129 + const refreshTokenRes = await refreshToken()
  130 + // 2.1 刷新成功,则回放队列的请求 + 当前请求
  131 + setToken(refreshTokenRes.data.data)
  132 + config.headers!.Authorization = 'Bearer ' + getAccessToken()
  133 + requestList.forEach((cb: any) => {
  134 + cb()
  135 + })
  136 + requestList = []
  137 + return service(config)
  138 + } catch (e) {
  139 + // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
  140 + // 2.2 刷新失败,只回放队列的请求
  141 + requestList.forEach((cb: any) => {
  142 + cb()
  143 + })
  144 + // 提示是否要登出。即不回放当前请求!不然会形成递归
  145 + return handleAuthorized()
  146 + } finally {
  147 + requestList = []
  148 + isRefreshToken = false
  149 + }
  150 + } else {
  151 + // 添加到队列,等待刷新获取到新的令牌
  152 + return new Promise((resolve) => {
  153 + requestList.push(() => {
  154 + config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
  155 + resolve(service(config))
  156 + })
  157 + })
  158 + }
  159 + } else if (code === 500) {
  160 + ElMessage.error(t('sys.api.errMsg500'))
  161 + return Promise.reject(new Error(msg))
  162 + } else if (code === 901) {
  163 + ElMessage.error(
  164 + '<div>' +
  165 + t('sys.api.errMsg901') +
  166 + '</div>' +
  167 + '<div> &nbsp; </div>' +
  168 + '<div>参考 https://doc.iocoder.cn/ 教程</div>' +
  169 + '<div> &nbsp; </div>' +
  170 + '<div>5 分钟搭建本地环境</div>'
  171 + )
  172 + return Promise.reject(new Error(msg))
  173 + } else if (code !== 200) {
  174 + if (msg === '无效的刷新令牌') {
  175 + // hard coding:忽略这个提示,直接登出
  176 + console.log(msg)
  177 + } else {
  178 + ElNotification.error({
  179 + title: msg
  180 + })
  181 + }
  182 + return Promise.reject('error')
  183 + } else {
  184 + return data
  185 + }
  186 + },
  187 + (error: AxiosError) => {
  188 + console.log('err' + error) // for debug
  189 + let { message } = error
  190 + const { t } = useI18n()
  191 + if (message === 'Network Error') {
  192 + message = t('sys.api.errorMessage')
  193 + } else if (message.includes('timeout')) {
  194 + message = t('sys.api.apiTimeoutMessage')
  195 + } else if (message.includes('Request failed with status code')) {
  196 + message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
  197 + }
  198 + ElMessage.error(message)
  199 + return Promise.reject(error)
  200 + }
  201 +)
  202 +
  203 +const refreshToken = async () => {
  204 + return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
  205 +}
  206 +const handleAuthorized = () => {
  207 + const { t } = useI18n()
  208 + if (!isRelogin.show) {
  209 + isRelogin.show = true
  210 + ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
  211 + confirmButtonText: t('login.relogin'),
  212 + cancelButtonText: t('common.cancel'),
  213 + type: 'warning'
  214 + })
  215 + .then(() => {
  216 + const { wsCache } = useCache()
  217 + resetRouter() // 重置静态路由表
  218 + wsCache.clear()
  219 + removeToken()
  220 + isRelogin.show = false
  221 + window.location.href = '/'
  222 + })
  223 + .catch(() => {
  224 + isRelogin.show = false
  225 + })
  226 + }
  227 + return Promise.reject(t('sys.api.timeoutMessage'))
  228 +}
  229 +export { service }
... ...
yudao-ui-admin-vue3/src/hooks/web/useAxios.ts deleted
1   -import { service } from '@/config/axios'
2   -
3   -import { config } from '@/config/axios/config'
4   -
5   -const { default_headers } = config
6   -
7   -const request = (option: AxiosConfig) => {
8   - const { url, method, params, data, headersType, responseType } = option
9   - return service({
10   - url: url,
11   - method,
12   - params,
13   - data,
14   - responseType: responseType,
15   - headers: {
16   - 'Content-Type': headersType || default_headers
17   - }
18   - })
19   -}
20   -
21   -async function getFn<T = any>(option: AxiosConfig): Promise<T> {
22   - const res = await request({ method: 'GET', ...option })
23   - return res.data
24   -}
25   -
26   -async function postFn<T = any>(option: AxiosConfig): Promise<T> {
27   - const res = await request({ method: 'POST', ...option })
28   - return res.data
29   -}
30   -
31   -async function deleteFn<T = any>(option: AxiosConfig): Promise<T> {
32   - const res = await request({ method: 'DELETE', ...option })
33   - return res.data
34   -}
35   -
36   -async function putFn<T = any>(option: AxiosConfig): Promise<T> {
37   - const res = await request({ method: 'PUT', ...option })
38   - return res.data
39   -}
40   -async function downloadFn<T = any>(option: AxiosConfig): Promise<T> {
41   - const res = await request({ method: 'GET', responseType: 'blob', ...option })
42   - return res as unknown as Promise<T>
43   -}
44   -
45   -async function uploadFn<T = any>(option: AxiosConfig): Promise<T> {
46   - option.headersType = 'multipart/form-data'
47   - const res = await request({ method: 'PUT', ...option })
48   - return res as unknown as Promise<T>
49   -}
50   -
51   -export const useAxios = () => {
52   - return {
53   - get: getFn,
54   - post: postFn,
55   - delete: deleteFn,
56   - put: putFn,
57   - download: downloadFn,
58   - upload: uploadFn
59   - }
60   -}
yudao-ui-admin-vue3/src/hooks/web/useVxeCrudSchemas.ts 0 → 100644
  1 +import { DescriptionsSchema } from '@/types/descriptions'
  2 +import { getIntDictOptions } from '@/utils/dict'
  3 +import { reactive } from 'vue'
  4 +import {
  5 + FormItemRenderOptions,
  6 + VxeFormItemProps,
  7 + VxeGridPropTypes,
  8 + VxeTableDefines
  9 +} from 'vxe-table'
  10 +import { eachTree } from 'xe-utils'
  11 +import { useI18n } from '@/hooks/web/useI18n'
  12 +import { VxeTableColumn } from '@/types/table'
  13 +
  14 +export type VxeCrudSchema = Omit<VxeTableColumn, 'children'> & {
  15 + field: string
  16 + title?: string
  17 + search?: CrudSearchParams
  18 + table?: CrudTableParams
  19 + form?: CrudFormParams
  20 + detail?: CrudDescriptionsParams
  21 + print?: boolean
  22 + children?: VxeCrudSchema[]
  23 + dictType?: string
  24 +}
  25 +type CrudSearchParams = {
  26 + // 是否显示在查询项
  27 + show?: boolean
  28 +} & Omit<VxeFormItemProps, 'field'>
  29 +
  30 +type CrudTableParams = {
  31 + // 是否显示表头
  32 + show?: boolean
  33 +} & Omit<VxeTableDefines.ColumnOptions, 'field'>
  34 +
  35 +type CrudFormParams = {
  36 + // 是否显示表单项
  37 + show?: boolean
  38 +} & Omit<VxeFormItemProps, 'field'>
  39 +
  40 +type CrudDescriptionsParams = {
  41 + // 是否显示表单项
  42 + show?: boolean
  43 +} & Omit<DescriptionsSchema, 'field'>
  44 +
  45 +interface VxeAllSchemas {
  46 + searchSchema: VxeFormItemProps[]
  47 + tableSchema: VxeGridPropTypes.Columns
  48 + formSchema: VxeFormItemProps[]
  49 + detailSchema: DescriptionsSchema[]
  50 + printSchema: VxeTableDefines.ColumnInfo[]
  51 +}
  52 +
  53 +// 过滤所有结构
  54 +export const useVxeCrudSchemas = (
  55 + crudSchema: VxeCrudSchema[]
  56 +): {
  57 + allSchemas: VxeAllSchemas
  58 +} => {
  59 + // 所有结构数据
  60 + const allSchemas = reactive<VxeAllSchemas>({
  61 + searchSchema: [],
  62 + tableSchema: [],
  63 + formSchema: [],
  64 + detailSchema: [],
  65 + printSchema: []
  66 + })
  67 +
  68 + const searchSchema = filterSearchSchema(crudSchema)
  69 + allSchemas.searchSchema = searchSchema || []
  70 +
  71 + const tableSchema = filterTableSchema(crudSchema)
  72 + allSchemas.tableSchema = tableSchema || []
  73 +
  74 + const formSchema = filterFormSchema(crudSchema)
  75 + allSchemas.formSchema = formSchema
  76 +
  77 + const detailSchema = filterDescriptionsSchema(crudSchema)
  78 + allSchemas.detailSchema = detailSchema
  79 +
  80 + const printSchema = filterPrintSchema(crudSchema)
  81 + allSchemas.printSchema = printSchema
  82 +
  83 + return {
  84 + allSchemas
  85 + }
  86 +}
  87 +
  88 +// 过滤 Search 结构
  89 +const filterSearchSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] => {
  90 + const searchSchema: VxeFormItemProps[] = []
  91 + const { t } = useI18n()
  92 + eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
  93 + // 判断是否显示
  94 + if (schemaItem?.search?.show) {
  95 + let itemRenderName = schemaItem?.search?.itemRender?.name || '$input'
  96 + const options: any[] = []
  97 + let itemRender: FormItemRenderOptions = {
  98 + name: itemRenderName,
  99 + props: { placeholder: t('common.inputText') }
  100 + }
  101 + if (schemaItem.dictType) {
  102 + const allOptions = { label: '全部', value: '' }
  103 + options.push(allOptions)
  104 + getIntDictOptions(schemaItem.dictType).forEach((dict) => {
  105 + options.push(dict)
  106 + })
  107 + itemRender.options = options
  108 + if (!schemaItem.search.itemRender?.name) itemRenderName = '$select'
  109 + itemRender = {
  110 + name: itemRenderName,
  111 + options: options,
  112 + props: { placeholder: t('common.selectText') }
  113 + }
  114 + }
  115 +
  116 + const searchSchemaItem = {
  117 + // 默认为 input
  118 + span: 6,
  119 + itemRender: itemRender,
  120 + ...schemaItem.search,
  121 + field: schemaItem.field,
  122 + title: schemaItem.search?.title || schemaItem.title
  123 + }
  124 + // 删除不必要的字段
  125 + delete searchSchemaItem.show
  126 +
  127 + searchSchema.push(searchSchemaItem)
  128 + }
  129 + })
  130 + // 添加搜索按钮
  131 + const buttons: VxeFormItemProps = {
  132 + span: 24,
  133 + align: 'center',
  134 + collapseNode: true,
  135 + itemRender: {
  136 + name: '$buttons',
  137 + children: [
  138 + { props: { type: 'submit', content: t('common.query'), status: 'primary' } },
  139 + { props: { type: 'reset', content: t('common.reset') } }
  140 + ]
  141 + }
  142 + }
  143 + searchSchema.push(buttons)
  144 + return searchSchema
  145 +}
  146 +
  147 +// 过滤 table 结构
  148 +const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Columns => {
  149 + const tableSchema: VxeGridPropTypes.Columns = []
  150 + eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
  151 + // 判断是否显示
  152 + if (schemaItem?.table?.show !== false) {
  153 + const tableSchemaItem = {
  154 + ...schemaItem.table,
  155 + field: schemaItem.field,
  156 + title: schemaItem.table?.title || schemaItem.title
  157 + }
  158 +
  159 + // 删除不必要的字段
  160 + delete tableSchemaItem.show
  161 +
  162 + tableSchema.push(tableSchemaItem)
  163 + }
  164 + })
  165 + return tableSchema
  166 +}
  167 +
  168 +// 过滤 form 结构
  169 +const filterFormSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] => {
  170 + const formSchema: VxeFormItemProps[] = []
  171 + const { t } = useI18n()
  172 + eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
  173 + // 判断是否显示
  174 + if (schemaItem?.form?.show !== false) {
  175 + let itemRenderName = schemaItem?.form?.itemRender?.name || '$input'
  176 + let itemRender: FormItemRenderOptions = {
  177 + name: itemRenderName,
  178 + props: { placeholder: t('common.inputText') }
  179 + }
  180 + if (schemaItem.dictType) {
  181 + if (!(schemaItem.form && schemaItem.form.itemRender?.name)) itemRenderName = '$select'
  182 + itemRender = {
  183 + name: itemRenderName,
  184 + options: getIntDictOptions(schemaItem.dictType),
  185 + props: { placeholder: t('common.selectText') }
  186 + }
  187 + }
  188 + const formSchemaItem = {
  189 + // 默认为 input
  190 + itemRender: itemRender,
  191 + ...schemaItem.form,
  192 + span: schemaItem.form?.span || 12,
  193 + field: schemaItem.field,
  194 + title: schemaItem.form?.title || schemaItem.title
  195 + }
  196 +
  197 + // 删除不必要的字段
  198 + delete formSchemaItem.show
  199 +
  200 + formSchema.push(formSchemaItem)
  201 + }
  202 + })
  203 +
  204 + return formSchema
  205 +}
  206 +
  207 +// 过滤 descriptions 结构
  208 +const filterDescriptionsSchema = (crudSchema: VxeCrudSchema[]): DescriptionsSchema[] => {
  209 + const descriptionsSchema: DescriptionsSchema[] = []
  210 +
  211 + eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
  212 + // 判断是否显示
  213 + if (schemaItem?.detail?.show !== false) {
  214 + const descriptionsSchemaItem = {
  215 + ...schemaItem.detail,
  216 + field: schemaItem.field,
  217 + label: schemaItem.detail?.label || schemaItem.title
  218 + }
  219 +
  220 + // 删除不必要的字段
  221 + delete descriptionsSchemaItem.show
  222 +
  223 + descriptionsSchema.push(descriptionsSchemaItem)
  224 + }
  225 + })
  226 +
  227 + return descriptionsSchema
  228 +}
  229 +
  230 +// 过滤 打印 结构
  231 +const filterPrintSchema = (crudSchema: VxeCrudSchema[]): any[] => {
  232 + const printSchema: any[] = []
  233 +
  234 + eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
  235 + // 判断是否显示
  236 + if (schemaItem?.detail?.show !== false) {
  237 + const printSchemaItem = {
  238 + field: schemaItem.field
  239 + }
  240 +
  241 + printSchema.push(printSchemaItem)
  242 + }
  243 + })
  244 +
  245 + return printSchema
  246 +}
... ...
yudao-ui-admin-vue3/src/hooks/web/useVxeGrid.ts 0 → 100644
  1 +import { reactive } from 'vue'
  2 +import { VxeGridProps } from 'vxe-table'
  3 +
  4 +export const useVxeGrid = (allSchemas, getPageApi) => {
  5 + const gridOptions = reactive<VxeGridProps>({
  6 + loading: false,
  7 + height: 800,
  8 + rowConfig: {
  9 + keyField: 'id',
  10 + isHover: true
  11 + },
  12 + toolbarConfig: {
  13 + custom: true,
  14 + slots: { buttons: 'toolbar_buttons' }
  15 + },
  16 + printConfig: {
  17 + columns: allSchemas.printSchema
  18 + },
  19 + formConfig: {
  20 + titleWidth: 100,
  21 + titleAlign: 'right',
  22 + items: allSchemas.searchSchema
  23 + },
  24 + columns: allSchemas.tableSchema,
  25 + pagerConfig: {
  26 + border: false,
  27 + background: false,
  28 + perfect: true,
  29 + pageSize: 10,
  30 + pagerCount: 7,
  31 + pageSizes: [5, 10, 15, 20, 50, 100, 200, 500],
  32 + layouts: [
  33 + 'PrevJump',
  34 + 'PrevPage',
  35 + 'Jump',
  36 + 'PageCount',
  37 + 'NextPage',
  38 + 'NextJump',
  39 + 'Sizes',
  40 + 'Total'
  41 + ]
  42 + },
  43 + proxyConfig: {
  44 + seq: true, // 启用动态序号代理(分页之后索引自动计算为当前页的起始序号)
  45 + form: true, // 启用表单代理,当点击表单提交按钮时会自动触发 reload 行为
  46 + props: { result: 'list', total: 'total' },
  47 + ajax: {
  48 + query: ({ page, form }) => {
  49 + const queryParams = Object.assign({}, form)
  50 + queryParams.pageSize = page.pageSize
  51 + queryParams.pageNo = page.currentPage
  52 + return new Promise(async (resolve) => {
  53 + resolve(await getPageApi(queryParams))
  54 + })
  55 + }
  56 + }
  57 + }
  58 + })
  59 + return gridOptions
  60 +}
... ...
yudao-ui-admin-vue3/src/plugins/vxeTable/index.ts
... ... @@ -60,7 +60,14 @@ VXETable.setup({
60 60 autoResize: true, // 自动监听父元素的变化去重新计算表格
61 61 resizable: true, // 列是否允许拖动列宽调整大小
62 62 emptyText: '暂无数据', // 空表单
63   - highlightHoverRow: true // 自动监听父元素的变化去重新计算表格
  63 + highlightHoverRow: true, // 自动监听父元素的变化去重新计算表格
  64 + treeConfig: {
  65 + rowField: 'id',
  66 + parentField: 'parentId',
  67 + children: 'children',
  68 + indent: 20,
  69 + showIcon: true
  70 + }
64 71 },
65 72 grid: {
66 73 toolbarConfig: {
... ... @@ -107,8 +114,10 @@ VXETable.setup({
107 114 titleColon: true // 是否显示标题冒号
108 115 },
109 116 modal: {
110   - width: 600, // 窗口的宽度
111   - height: 400, // 窗口的高度
  117 + width: 800, // 窗口的宽度
  118 + height: 600, // 窗口的高度
  119 + minWidth: 460,
  120 + minHeight: 320,
112 121 showZoom: true, // 标题是否标显示最大化与还原按钮
113 122 resize: true, // 是否允许窗口边缘拖动调整窗口大小
114 123 marginSize: 0, // 只对 resize 启用后有效,用于设置可拖动界限范围,如果为负数则允许拖动超出屏幕边界
... ... @@ -127,13 +136,28 @@ VXETable.setup({
127 136 : XEUtils.toFormatString(XEUtils.get(enUS, key), args)
128 137 }
129 138 })
130   -// 格式金额,默认2位数
131   -VXETable.formats.add('formatAmount', ({ cellValue }, digits = 2) => {
132   - return XEUtils.commafy(XEUtils.toNumber(cellValue), { digits })
133   -})
134   -// 格式日期,默认 yyyy-MM-dd HH:mm:ss
135   -VXETable.formats.add('formatDate', ({ cellValue }, format = 'yyyy-MM-dd HH:mm:ss') => {
136   - return XEUtils.toDateString(cellValue, format)
  139 +// 自定义全局的格式化处理函数
  140 +VXETable.formats.mixin({
  141 + // 格式日期,默认 yyyy-MM-dd HH:mm:ss
  142 + formatDate({ cellValue }, format) {
  143 + return XEUtils.toDateString(cellValue, format || 'yyyy-MM-dd HH:mm:ss')
  144 + },
  145 + // 四舍五入金额,每隔3位逗号分隔,默认2位数
  146 + formatAmount({ cellValue }, digits = 2) {
  147 + return XEUtils.commafy(Number(cellValue), { digits })
  148 + },
  149 + // 格式化银行卡,默认每4位空格隔开
  150 + formatBankcard({ cellValue }) {
  151 + return XEUtils.commafy(XEUtils.toValueString(cellValue), { spaceNumber: 4, separator: ' ' })
  152 + },
  153 + // 四舍五入,默认两位数
  154 + formatFixedNumber({ cellValue }, digits = 2) {
  155 + return XEUtils.toFixed(XEUtils.round(cellValue, digits), digits)
  156 + },
  157 + // 向下舍入,默认两位数
  158 + formatCutNumber({ cellValue }, digits = 2) {
  159 + return XEUtils.toFixed(XEUtils.floor(cellValue, digits), digits)
  160 + }
137 161 })
138 162 export const setupVxeTable = (app: App<Element>) => {
139 163 // 表格功能
... ...
yudao-ui-admin-vue3/src/router/index.ts
... ... @@ -10,7 +10,7 @@ import { usePermissionStoreWithOut } from &#39;@/store/modules/permission&#39;
10 10 import { useDictStoreWithOut } from '@/store/modules/dict'
11 11 import { useUserStoreWithOut } from '@/store/modules/user'
12 12 import { listSimpleDictDataApi } from '@/api/system/dict/dict.data'
13   -import { isRelogin } from '@/config/axios'
  13 +import { isRelogin } from '@/config/axios/service'
14 14 import { getInfoApi } from '@/api/login'
15 15  
16 16 const { start, done } = useNProgress()
... ...
yudao-ui-admin-vue3/src/types/table.d.ts
... ... @@ -4,6 +4,12 @@ export type TableColumn = {
4 4 children?: TableColumn[]
5 5 } & Recordable
6 6  
  7 +export type VxeTableColumn = {
  8 + field: string
  9 + title?: string
  10 + children?: TableColumn[]
  11 +} & Recordable
  12 +
7 13 export type TableSlotDefault = {
8 14 row: Recordable
9 15 column: TableColumn
... ...
yudao-ui-admin-vue3/src/views/system/menu/index.vue
  1 +<template>
  2 + <ContentWrap>
  3 + <el-form :model="queryParams" ref="queryForm" :inline="true">
  4 + <el-form-item label="菜单名称" prop="name">
  5 + <el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
  6 + </el-form-item>
  7 + <el-form-item label="状态" prop="status">
  8 + <el-select v-model="queryParams.status" placeholder="请选择菜单状态">
  9 + <el-option
  10 + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
  11 + :key="dict.value"
  12 + :label="dict.label"
  13 + :value="dict.value"
  14 + />
  15 + </el-select>
  16 + </el-form-item>
  17 + <el-form-item>
  18 + <XButton
  19 + type="primary"
  20 + preIcon="ep:search"
  21 + :title="t('common.query')"
  22 + @click="handleQuery()"
  23 + />
  24 + <XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" />
  25 + </el-form-item>
  26 + </el-form>
  27 + <vxe-toolbar>
  28 + <template #buttons>
  29 + <XButton
  30 + type="primary"
  31 + preIcon="ep:zoom-in"
  32 + :title="t('action.add')"
  33 + v-hasPermi="['system:menu:create']"
  34 + @click="handleCreate()"
  35 + />
  36 + <XButton title="展开所有" @click="xTable?.setAllTreeExpand(true)" />
  37 + <XButton title="关闭所有" @click="xTable?.clearTreeExpand()" />
  38 + </template>
  39 + </vxe-toolbar>
  40 + <vxe-table
  41 + show-overflow
  42 + keep-source
  43 + ref="xTable"
  44 + :loading="tableLoading"
  45 + :row-config="{ keyField: 'id' }"
  46 + :column-config="{ resizable: true }"
  47 + :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
  48 + :print-config="{}"
  49 + :export-config="{}"
  50 + :data="tableData"
  51 + class="xtable"
  52 + >
  53 + <vxe-column title="菜单名称" field="name" width="200" tree-node>
  54 + <template #default="{ row }">
  55 + <Icon :icon="row.icon" />
  56 + <span class="ml-3">{{ row.name }}</span>
  57 + </template>
  58 + </vxe-column>
  59 + <vxe-column title="菜单类型" field="type">
  60 + <template #default="{ row }">
  61 + <DictTag :type="DICT_TYPE.SYSTEM_MENU_TYPE" :value="row.type" />
  62 + </template>
  63 + </vxe-column>
  64 + <vxe-column title="路由地址" field="path" />
  65 + <vxe-column title="组件路径" field="component" />
  66 + <vxe-column title="权限标识" field="permission" />
  67 + <vxe-column title="排序" field="sort" />
  68 + <vxe-column title="状态" field="status">
  69 + <template #default="{ row }">
  70 + <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  71 + </template>
  72 + </vxe-column>
  73 + <vxe-column title="创建时间" field="createTime" formatter="formatDate" />
  74 + <vxe-column title="操作" width="200">
  75 + <template #default="{ row }">
  76 + <XButton
  77 + link
  78 + type="primary"
  79 + preIcon="ep:edit"
  80 + :title="t('action.edit')"
  81 + v-hasPermi="['system:menu:update']"
  82 + @click="handleUpdate(row.id)"
  83 + />
  84 + <XButton
  85 + link
  86 + type="primary"
  87 + preIcon="ep:delete"
  88 + :title="t('action.del')"
  89 + v-hasPermi="['system:menu:delete']"
  90 + @click="handleDelete(row)"
  91 + />
  92 + </template>
  93 + </vxe-column>
  94 + </vxe-table>
  95 + </ContentWrap>
  96 + <XModal v-model="dialogVisible" id="menuModel" :title="dialogTitle">
  97 + <template #default>
  98 + <!-- 对话框(添加 / 修改) -->
  99 + <el-form
  100 + :model="menuForm"
  101 + :rules="rules"
  102 + :inline="true"
  103 + label-width="120px"
  104 + label-position="right"
  105 + >
  106 + <el-row :gutter="24">
  107 + <el-col :span="24">
  108 + <el-form-item label="上级菜单">
  109 + <el-tree-select
  110 + node-key="id"
  111 + v-model="menuForm.parentId"
  112 + :props="menuProps"
  113 + :data="menuOptions"
  114 + check-strictly
  115 + />
  116 + </el-form-item>
  117 + </el-col>
  118 + <el-col :span="12">
  119 + <el-form-item label="菜单类型" prop="type">
  120 + <el-radio-group v-model="menuForm.type">
  121 + <el-radio-button
  122 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)"
  123 + :key="dict.value"
  124 + :label="dict.value"
  125 + >
  126 + {{ dict.label }}
  127 + </el-radio-button>
  128 + </el-radio-group>
  129 + </el-form-item>
  130 + </el-col>
  131 + <el-col :span="12">
  132 + <el-form-item label="菜单名称" prop="name">
  133 + <el-input v-model="menuForm.name" placeholder="请输入菜单名称" clearable />
  134 + </el-form-item>
  135 + </el-col>
  136 + <template v-if="menuForm.type !== 3">
  137 + <el-col :span="12">
  138 + <el-form-item label="菜单图标">
  139 + <IconSelect v-model="menuForm.icon" clearable />
  140 + </el-form-item>
  141 + </el-col>
  142 + <el-col :span="12">
  143 + <el-form-item label="路由地址" prop="path">
  144 + <template #label>
  145 + <Tooltip
  146 + titel="路由地址"
  147 + message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
  148 + />
  149 + </template>
  150 + <el-input v-model="menuForm.path" placeholder="请输入路由地址" clearable />
  151 + </el-form-item>
  152 + </el-col>
  153 + </template>
  154 + <template v-if="menuForm.type === 2">
  155 + <el-col :span="12">
  156 + <el-form-item label="路由地址" prop="component">
  157 + <el-input v-model="menuForm.component" placeholder="请输入组件地址" clearable />
  158 + </el-form-item>
  159 + </el-col>
  160 + </template>
  161 + <template v-if="menuForm.type !== 1">
  162 + <el-col :span="12">
  163 + <el-form-item label="权限标识" prop="permission">
  164 + <template #label>
  165 + <Tooltip
  166 + titel="权限标识"
  167 + message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
  168 + />
  169 + </template>
  170 + <el-input v-model="menuForm.permission" placeholder="请输入权限标识" clearable />
  171 + </el-form-item>
  172 + </el-col>
  173 + </template>
  174 + <el-col :span="12">
  175 + <el-form-item label="显示排序" prop="sort">
  176 + <el-input-number
  177 + v-model="menuForm.sort"
  178 + controls-position="right"
  179 + :min="0"
  180 + clearable
  181 + />
  182 + </el-form-item>
  183 + </el-col>
  184 + <el-col :span="12">
  185 + <el-form-item label="菜单状态" prop="status">
  186 + <el-radio-group v-model="menuForm.status">
  187 + <el-radio-button
  188 + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
  189 + :key="dict.value"
  190 + :label="dict.value"
  191 + >
  192 + {{ dict.label }}
  193 + </el-radio-button>
  194 + </el-radio-group>
  195 + </el-form-item>
  196 + </el-col>
  197 + <template v-if="menuForm.type !== 3">
  198 + <el-col :span="12">
  199 + <el-form-item label="显示状态" prop="status">
  200 + <template #label>
  201 + <Tooltip
  202 + titel="显示状态"
  203 + message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问"
  204 + />
  205 + </template>
  206 + <el-radio-group v-model="menuForm.visible">
  207 + <el-radio-button key="true" :label="true">显示</el-radio-button>
  208 + <el-radio-button key="false" :label="false">隐藏</el-radio-button>
  209 + </el-radio-group>
  210 + </el-form-item>
  211 + </el-col>
  212 + </template>
  213 + <template v-if="menuForm.type === 2">
  214 + <el-col :span="12">
  215 + <el-form-item label="缓存状态" prop="keepAlive">
  216 + <template #label>
  217 + <Tooltip
  218 + titel="缓存状态"
  219 + message="选择缓存时,则会被 `keep-alive` 缓存,需要匹配组件的 `name` 和路由地址保持一致"
  220 + />
  221 + </template>
  222 + <el-radio-group v-model="menuForm.keepAlive">
  223 + <el-radio-button key="true" :label="true">缓存</el-radio-button>
  224 + <el-radio-button key="false" :label="false">不缓存</el-radio-button>
  225 + </el-radio-group>
  226 + </el-form-item>
  227 + </el-col>
  228 + </template>
  229 + </el-row>
  230 + </el-form>
  231 + </template>
  232 + <template #footer>
  233 + <!-- 操作按钮 -->
  234 + <XButton
  235 + v-if="['create', 'update'].includes(actionType)"
  236 + type="primary"
  237 + :loading="actionLoading"
  238 + @click="submitForm"
  239 + :title="t('action.save')"
  240 + />
  241 + <XButton :loading="actionLoading" @click="dialogVisible = false" :title="t('dialog.close')" />
  242 + </template>
  243 + </XModal>
  244 +</template>
1 245 <script setup lang="ts">
2   -import { ref, reactive, onMounted } from 'vue'
3   -import { handleTree } from '@/utils/tree'
4   -import dayjs from 'dayjs'
5   -import { IconSelect } from '@/components/Icon'
6   -import { Tooltip } from '@/components/Tooltip'
7 246 import * as MenuApi from '@/api/system/menu'
  247 +import { MenuVO } from '@/api/system/menu/types'
8 248 import { useI18n } from '@/hooks/web/useI18n'
  249 +import { useMessage } from '@/hooks/web/useMessage'
  250 +import { IconSelect } from '@/components/Icon'
  251 +import { Tooltip } from '@/components/Tooltip'
  252 +import { required } from '@/utils/formRules.js'
  253 +import { onMounted, reactive, ref } from 'vue'
  254 +import { VxeTableInstance } from 'vxe-table'
  255 +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  256 +import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
9 257 import {
10 258 ElRow,
11 259 ElCol,
12   - ElTable,
13   - ElTableColumn,
14 260 ElForm,
15 261 ElFormItem,
16 262 ElInput,
... ... @@ -21,21 +267,32 @@ import {
21 267 ElRadioGroup,
22 268 ElRadioButton
23 269 } from 'element-plus'
24   -import { MenuVO } from '@/api/system/menu/types'
25   -import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
26   -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
27   -import { useMessage } from '@/hooks/web/useMessage'
28   -import { required } from '@/utils/formRules.js'
29   -const message = useMessage()
  270 +import { handleTree } from '@/utils/tree'
30 271 const { t } = useI18n() // 国际化
31   -// ========== 创建菜单树结构 ==========
32   -const loading = ref(true)
33   -const menuData = ref<any[]>([]) // 树形结构
34   -const getList = async () => {
35   - const res = await MenuApi.getMenuListApi(queryParams)
36   - menuData.value = handleTree(res)
37   - loading.value = false
38   -}
  272 +const message = useMessage()
  273 +const xTable = ref<VxeTableInstance>()
  274 +const tableLoading = ref(false)
  275 +const tableData = ref()
  276 +const actionLoading = ref(false) // 遮罩层
  277 +const actionType = ref('') // 操作按钮的类型
  278 +const dialogVisible = ref(false) // 是否显示弹出层
  279 +const dialogTitle = ref('edit') // 弹出层标题
  280 +const statusOption = ref() // 状态选项
  281 +const menuForm = ref<MenuVO>({
  282 + id: 0,
  283 + name: '',
  284 + permission: '',
  285 + type: SystemMenuTypeEnum.DIR,
  286 + sort: 1,
  287 + parentId: 0,
  288 + path: '',
  289 + icon: '',
  290 + component: '',
  291 + status: CommonStatusEnum.ENABLE,
  292 + visible: true,
  293 + keepAlive: true,
  294 + createTime: ''
  295 +})
39 296 const menuProps = {
40 297 checkStrictly: true,
41 298 children: 'children',
... ... @@ -57,46 +314,16 @@ const getTree = async () =&gt; {
57 314 }
58 315 // ========== 查询 ==========
59 316 const queryParams = reactive({
60   - name: undefined,
61   - status: undefined
  317 + name: null,
  318 + status: null
62 319 })
63   -// 查询操作
64   -const handleQuery = async () => {
65   - await getList()
66   -}
67   -// 重置操作
68   -const resetQuery = async () => {
69   - queryParams.name = undefined
70   - queryParams.status = undefined
71   - await getList()
  320 +const getList = async () => {
  321 + statusOption.value = getIntDictOptions(DICT_TYPE.COMMON_STATUS)
  322 + tableLoading.value = true
  323 + const res = await MenuApi.getMenuListApi(queryParams)
  324 + tableData.value = res
  325 + tableLoading.value = false
72 326 }
73   -// ========== CRUD 相关 ==========
74   -const actionLoading = ref(false) // 遮罩层
75   -const actionType = ref('') // 操作按钮的类型
76   -const dialogVisible = ref(false) // 是否显示弹出层
77   -const dialogTitle = ref('edit') // 弹出层标题
78   -const menuForm = ref<MenuVO>({
79   - id: 0,
80   - name: '',
81   - permission: '',
82   - type: SystemMenuTypeEnum.DIR,
83   - sort: 1,
84   - parentId: 0,
85   - path: '',
86   - icon: '',
87   - component: '',
88   - status: CommonStatusEnum.ENABLE,
89   - visible: true,
90   - keepAlive: true,
91   - createTime: ''
92   -})
93   -// 表单校验
94   -const rules = reactive({
95   - name: [required],
96   - sort: [required],
97   - path: [required],
98   - status: [required]
99   -})
100 327 // 设置标题
101 328 const setDialogTile = (type: string) => {
102 329 dialogTitle.value = t('action.' + type)
... ... @@ -105,25 +332,39 @@ const setDialogTile = (type: string) =&gt; {
105 332 }
106 333 // 新建操作
107 334 const handleCreate = () => {
108   - // 重置表单
109 335 setDialogTile('create')
110 336 }
111 337 // 修改操作
112 338 const handleUpdate = async (row: MenuVO) => {
113 339 // 设置数据
114 340 const res = await MenuApi.getMenuApi(row.id)
  341 + console.log(res)
115 342 menuForm.value = res
116 343 setDialogTile('update')
117 344 }
118 345 // 删除操作
119 346 const handleDelete = async (row: MenuVO) => {
120   - message
121   - .confirm(t('common.delDataMessage'), t('common.confirmTitle'))
122   - .then(async () => {
123   - await MenuApi.deleteMenuApi(row.id)
124   - message.success(t('common.delSuccess'))
125   - })
126   - .catch(() => {})
  347 + message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {
  348 + await MenuApi.deleteMenuApi(row.id)
  349 + message.success(t('common.delSuccess'))
  350 + await getList()
  351 + })
  352 +}
  353 +// 表单校验
  354 +const rules = reactive({
  355 + name: [required],
  356 + sort: [required],
  357 + path: [required],
  358 + status: [required]
  359 +})
  360 +// 查询操作
  361 +const handleQuery = async () => {
  362 + await getList()
  363 +}
  364 +// 重置操作
  365 +const resetQuery = async () => {
  366 + queryParams.name = null
  367 + queryParams.status = null
127 368 await getList()
128 369 }
129 370 // 保存操作
... ... @@ -162,248 +403,8 @@ const submitForm = async () =&gt; {
162 403 actionLoading.value = false
163 404 }
164 405 }
165   -// ========== 初始化 ==========
166 406 onMounted(async () => {
167 407 await getList()
168 408 getTree()
169 409 })
170 410 </script>
171   -<template>
172   - <!-- 搜索工作区 -->
173   - <ContentWrap>
174   - <el-form :model="queryParams" ref="queryForm" :inline="true">
175   - <el-form-item label="菜单名称" prop="name">
176   - <el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
177   - </el-form-item>
178   - <el-form-item label="状态" prop="status">
179   - <el-select v-model="queryParams.status" placeholder="请选择菜单状态">
180   - <el-option
181   - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
182   - :key="dict.value"
183   - :label="dict.label"
184   - :value="dict.value"
185   - />
186   - </el-select>
187   - </el-form-item>
188   - <el-form-item>
189   - <el-button type="primary" @click="handleQuery">
190   - <Icon icon="ep:search" class="mr-5px" />
191   - {{ t('common.query') }}
192   - </el-button>
193   - <el-button @click="resetQuery">
194   - <Icon icon="ep:refresh-right" class="mr-5px" />
195   - {{ t('common.reset') }}
196   - </el-button>
197   - </el-form-item>
198   - </el-form>
199   - </ContentWrap>
200   - <!-- 列表 -->
201   - <ContentWrap>
202   - <div class="mb-10px">
203   - <el-button type="primary" v-hasPermi="['system:notice:create']" @click="handleCreate">
204   - <Icon icon="ep:zoom-in" class="mr-1px" /> {{ t('action.add') }}
205   - </el-button>
206   - </div>
207   - <el-table
208   - v-loading="loading"
209   - table-layout="auto"
210   - row-key="id"
211   - :data="menuData"
212   - :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
213   - >
214   - <el-table-column label="菜单名称" prop="name" width="240px">
215   - <template #default="scope">
216   - <Icon :icon="scope.row.icon" />
217   - <span class="ml-3">{{ scope.row.name }}</span>
218   - </template>
219   - </el-table-column>
220   - <el-table-column label="菜单类型" prop="type">
221   - <template #default="scope">
222   - <DictTag :type="DICT_TYPE.SYSTEM_MENU_TYPE" :value="scope.row.type" />
223   - </template>
224   - </el-table-column>
225   - <el-table-column label="路由地址" prop="path" />
226   - <el-table-column label="组件路径" prop="component" />
227   - <el-table-column label="权限标识" prop="permission" />
228   - <el-table-column label="排序" prop="sort" />
229   - <el-table-column label="状态" prop="status">
230   - <template #default="scope">
231   - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
232   - </template>
233   - </el-table-column>
234   - <el-table-column label="创建时间" prop="createTime">
235   - <template #default="scope">
236   - <span>{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
237   - </template>
238   - </el-table-column>
239   - <el-table-column label="操作">
240   - <template #default="scope">
241   - <el-button
242   - link
243   - type="primary"
244   - v-hasPermi="['system:menu:update']"
245   - @click="handleUpdate(scope.row)"
246   - >
247   - <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
248   - </el-button>
249   - <el-button
250   - link
251   - type="primary"
252   - v-hasPermi="['system:menu:delete']"
253   - @click="handleDelete(scope.row)"
254   - >
255   - <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
256   - </el-button>
257   - </template>
258   - </el-table-column>
259   - </el-table>
260   - </ContentWrap>
261   - <!-- 添加或修改菜单对话框 -->
262   - <Dialog v-model="dialogVisible" :title="dialogTitle" maxHeight="400px" width="45%">
263   - <el-form
264   - :model="menuForm"
265   - :rules="rules"
266   - :inline="true"
267   - label-width="120px"
268   - label-position="right"
269   - >
270   - <el-row :gutter="24">
271   - <el-col :span="24">
272   - <el-form-item label="上级菜单">
273   - <el-tree-select
274   - node-key="id"
275   - v-model="menuForm.parentId"
276   - :props="menuProps"
277   - :data="menuOptions"
278   - check-strictly
279   - />
280   - </el-form-item>
281   - </el-col>
282   - <el-col :span="12">
283   - <el-form-item label="菜单类型" prop="type">
284   - <el-radio-group v-model="menuForm.type">
285   - <el-radio-button
286   - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)"
287   - :key="dict.value"
288   - :label="dict.value"
289   - >
290   - {{ dict.label }}
291   - </el-radio-button>
292   - </el-radio-group>
293   - </el-form-item>
294   - </el-col>
295   - <el-col :span="12">
296   - <el-form-item label="菜单名称" prop="name">
297   - <el-input v-model="menuForm.name" placeholder="请输入菜单名称" clearable />
298   - </el-form-item>
299   - </el-col>
300   - <template v-if="menuForm.type !== 3">
301   - <el-col :span="12">
302   - <el-form-item label="菜单图标">
303   - <IconSelect v-model="menuForm.icon" clearable />
304   - </el-form-item>
305   - </el-col>
306   - <el-col :span="12">
307   - <el-form-item label="路由地址" prop="path">
308   - <template #label>
309   - <Tooltip
310   - titel="路由地址"
311   - message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
312   - />
313   - </template>
314   - <el-input v-model="menuForm.path" placeholder="请输入路由地址" clearable />
315   - </el-form-item>
316   - </el-col>
317   - </template>
318   - <template v-if="menuForm.type === 2">
319   - <el-col :span="12">
320   - <el-form-item label="路由地址" prop="component">
321   - <el-input v-model="menuForm.component" placeholder="请输入组件地址" clearable />
322   - </el-form-item>
323   - </el-col>
324   - </template>
325   - <template v-if="menuForm.type !== 1">
326   - <el-col :span="12">
327   - <el-form-item label="权限标识" prop="permission">
328   - <template #label>
329   - <Tooltip
330   - titel="权限标识"
331   - message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
332   - />
333   - </template>
334   - <el-input v-model="menuForm.permission" placeholder="请输入权限标识" clearable />
335   - </el-form-item>
336   - </el-col>
337   - </template>
338   - <el-col :span="12">
339   - <el-form-item label="显示排序" prop="sort">
340   - <el-input-number v-model="menuForm.sort" controls-position="right" :min="0" clearable />
341   - </el-form-item>
342   - </el-col>
343   - <el-col :span="12">
344   - <el-form-item label="菜单状态" prop="status">
345   - <el-radio-group v-model="menuForm.status">
346   - <el-radio-button
347   - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
348   - :key="dict.value"
349   - :label="dict.value"
350   - >
351   - {{ dict.label }}
352   - </el-radio-button>
353   - </el-radio-group>
354   - </el-form-item>
355   - </el-col>
356   - <template v-if="menuForm.type !== 3">
357   - <el-col :span="12">
358   - <el-form-item label="显示状态" prop="status">
359   - <template #label>
360   - <Tooltip
361   - titel="显示状态"
362   - message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问"
363   - />
364   - </template>
365   - <el-radio-group v-model="menuForm.visible">
366   - <el-radio-button key="true" :label="true">显示</el-radio-button>
367   - <el-radio-button key="false" :label="false">隐藏</el-radio-button>
368   - </el-radio-group>
369   - </el-form-item>
370   - </el-col>
371   - </template>
372   - <template v-if="menuForm.type === 2">
373   - <el-col :span="12">
374   - <el-form-item label="缓存状态" prop="keepAlive">
375   - <template #label>
376   - <Tooltip
377   - titel="缓存状态"
378   - message="选择缓存时,则会被 `keep-alive` 缓存,需要匹配组件的 `name` 和路由地址保持一致"
379   - />
380   - </template>
381   - <el-radio-group v-model="menuForm.keepAlive">
382   - <el-radio-button key="true" :label="true">缓存</el-radio-button>
383   - <el-radio-button key="false" :label="false">不缓存</el-radio-button>
384   - </el-radio-group>
385   - </el-form-item>
386   - </el-col>
387   - </template>
388   - </el-row>
389   - </el-form>
390   - <!-- 操作按钮 -->
391   - <template #footer>
392   - <el-button
393   - v-if="['create', 'update'].includes(actionType)"
394   - type="primary"
395   - :loading="actionLoading"
396   - @click="submitForm"
397   - >
398   - {{ t('action.save') }}
399   - </el-button>
400   - <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
401   - </template>
402   - </Dialog>
403   -</template>
404   -<style lang="less" scoped>
405   -:deep(.el-button.is-text) {
406   - margin-left: 0;
407   - padding: 8px 10px;
408   -}
409   -</style>
... ...
yudao-ui-admin-vue3/src/views/system/post/index.vue
  1 +<template>
  2 + <ContentWrap>
  3 + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  4 + <template #toolbar_buttons>
  5 + <XButton
  6 + type="primary"
  7 + preIcon="ep:zoom-in"
  8 + :title="t('action.add')"
  9 + v-hasPermi="['system:post:create']"
  10 + @click="handleCreate()"
  11 + />
  12 + </template>
  13 + <template #status_default="{ row }">
  14 + <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  15 + </template>
  16 + <template #action_default="{ row }">
  17 + <XButton
  18 + link
  19 + type="primary"
  20 + preIcon="ep:edit"
  21 + :title="t('action.edit')"
  22 + v-hasPermi="['system:post:update']"
  23 + @click="handleUpdate(row.id)"
  24 + />
  25 + <XButton
  26 + link
  27 + type="primary"
  28 + preIcon="ep:view"
  29 + :title="t('action.detail')"
  30 + v-hasPermi="['system:post:update']"
  31 + @click="handleDetail(row)"
  32 + />
  33 + <XButton
  34 + link
  35 + type="primary"
  36 + preIcon="ep:delete"
  37 + :title="t('action.del')"
  38 + v-hasPermi="['system:post:delete']"
  39 + @click="handleDelete(row.id)"
  40 + />
  41 + </template>
  42 + </vxe-grid>
  43 + </ContentWrap>
  44 + <XModal id="postModel" v-model="dialogVisible" :title="dialogTitle">
  45 + <template #default>
  46 + <!-- 对话框(添加 / 修改) -->
  47 + <vxe-form
  48 + ref="xForm"
  49 + v-if="['create', 'update'].includes(actionType)"
  50 + :data="formData"
  51 + :items="formItems"
  52 + :rules="rules"
  53 + />
  54 + <Descriptions
  55 + v-if="actionType === 'detail'"
  56 + :schema="allSchemas.detailSchema"
  57 + :data="detailRef"
  58 + >
  59 + <template #status="{ row }">
  60 + <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  61 + </template>
  62 + <template #createTime="{ row }">
  63 + <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  64 + </template>
  65 + </Descriptions>
  66 + </template>
  67 + <template #footer>
  68 + <XButton
  69 + v-if="['create', 'update'].includes(actionType)"
  70 + :loading="actionLoading"
  71 + :title="t('action.save')"
  72 + @click="submitForm"
  73 + />
  74 + <XButton
  75 + v-if="['create', 'update'].includes(actionType)"
  76 + :loading="actionLoading"
  77 + :title="t('dialog.close')"
  78 + @click="dialogVisible = false"
  79 + />
  80 + </template>
  81 + </XModal>
  82 +</template>
1 83 <script setup lang="ts">
2   -import { reactive, ref } from 'vue'
  84 +import { ref } from 'vue'
3 85 import dayjs from 'dayjs'
4 86 import { useI18n } from '@/hooks/web/useI18n'
5   -import {
6   - VxeFormEvents,
7   - VxeFormInstance,
8   - VxeFormItemProps,
9   - VxeGrid,
10   - VxeGridInstance,
11   - VxeGridProps
12   -} from 'vxe-table'
  87 +import { VxeFormEvents, VxeFormInstance, VxeFormItemProps, VxeGridInstance } from 'vxe-table'
13 88 import * as PostApi from '@/api/system/post'
14   -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  89 +import { DICT_TYPE } from '@/utils/dict'
15 90 import { ContentWrap } from '@/components/ContentWrap'
16   -import { PostPageReqVO, PostVO } from '@/api/system/post/types'
  91 +import { PostVO } from '@/api/system/post/types'
17 92 import { rules, allSchemas } from './post.data'
18   -import { ElMessage, ElMessageBox } from 'element-plus'
  93 +import { useMessage } from '@/hooks/web/useMessage'
  94 +import { useVxeGrid } from '@/hooks/web/useVxeGrid'
19 95  
20 96 const { t } = useI18n() // 国际化
21   -
  97 +const message = useMessage()
22 98 const xGrid = ref<VxeGridInstance>()
23 99 const xForm = ref<VxeFormInstance>()
24 100 const dialogVisible = ref(false) // 是否显示弹出层
... ... @@ -26,158 +102,9 @@ const dialogTitle = ref(&#39;edit&#39;) // 弹出层标题
26 102 const actionType = ref('') // 操作按钮的类型
27 103 const actionLoading = ref(false) // 遮罩层
28 104  
29   -const gridOptions = reactive<VxeGridProps>({
30   - loading: false,
31   - rowConfig: {
32   - keyField: 'id',
33   - isHover: true
34   - },
35   - toolbarConfig: {
36   - custom: true,
37   - slots: { buttons: 'toolbar_buttons' }
38   - },
39   - printConfig: {
40   - columns: [
41   - { field: 'name' },
42   - { field: 'code' },
43   - { field: 'sort' },
44   - { field: 'status' },
45   - { field: 'createTime' }
46   - ]
47   - },
48   - formConfig: {
49   - titleWidth: 100,
50   - titleAlign: 'right',
51   - items: [
52   - {
53   - field: 'name',
54   - title: '岗位名称',
55   - span: 6,
56   - itemRender: { name: '$input', props: { placeholder: '请输入岗位名称' } }
57   - },
58   - {
59   - field: 'code',
60   - title: '岗位编码',
61   - span: 6,
62   - itemRender: { name: '$input', props: { placeholder: '请输入岗位编码' } }
63   - },
64   - {
65   - field: 'status',
66   - title: t('common.status'),
67   - span: 6,
68   - itemRender: { name: '$select', options: getIntDictOptions(DICT_TYPE.COMMON_STATUS) }
69   - },
70   - {
71   - span: 24,
72   - align: 'center',
73   - collapseNode: true,
74   - itemRender: {
75   - name: '$buttons',
76   - children: [
77   - { props: { type: 'submit', content: t('common.query'), status: 'primary' } },
78   - { props: { type: 'reset', content: t('common.reset') } }
79   - ]
80   - }
81   - }
82   - ]
83   - },
84   - columns: [
85   - { type: 'seq', title: t('common.index'), width: 100 },
86   - { field: 'name', title: '岗位名称' },
87   - { field: 'code', title: '岗位编码' },
88   - { field: 'sort', title: '岗位顺序' },
89   - {
90   - field: 'status',
91   - title: t('common.status'),
92   - slots: {
93   - default: 'status_default'
94   - }
95   - },
96   - {
97   - field: 'createTime',
98   - title: t('common.createTime'),
99   - width: 160,
100   - sortable: true,
101   - formatter: 'formatDate'
102   - },
103   - {
104   - field: 'action',
105   - title: t('table.action'),
106   - width: '240px',
107   - showOverflow: true,
108   - slots: {
109   - default: 'action_default'
110   - }
111   - }
112   - ],
113   - pagerConfig: {
114   - border: false,
115   - background: false,
116   - perfect: true,
117   - pageSize: 10,
118   - pagerCount: 7,
119   - pageSizes: [5, 10, 15, 20, 50, 100, 200, 500],
120   - layouts: ['PrevJump', 'PrevPage', 'Jump', 'PageCount', 'NextPage', 'NextJump', 'Sizes', 'Total']
121   - },
122   - proxyConfig: {
123   - seq: true, // 启用动态序号代理(分页之后索引自动计算为当前页的起始序号)
124   - form: true, // 启用表单代理,当点击表单提交按钮时会自动触发 reload 行为
125   - props: { result: 'list', total: 'total' },
126   - ajax: {
127   - query: ({ page, form }) => {
128   - const queryParams: PostPageReqVO = Object.assign({}, form)
129   - queryParams.pageSize = page.pageSize
130   - queryParams.pageNo = page.currentPage
131   - return new Promise(async (resolve) => {
132   - resolve(await PostApi.getPostPageApi(queryParams))
133   - })
134   - }
135   - }
136   - }
137   -})
  105 +const gridOptions = useVxeGrid(allSchemas, PostApi.getPostPageApi)
138 106 const formData = ref<PostVO>()
139   -const formItems = ref<VxeFormItemProps[]>([
140   - { field: 'id', title: 'id', visible: false },
141   - {
142   - field: 'name',
143   - title: '岗位名称',
144   - span: 12,
145   - itemRender: { name: '$input', props: { placeholder: '请输入岗位名称' } }
146   - },
147   - {
148   - field: 'code',
149   - title: '岗位编码',
150   - span: 12,
151   - itemRender: { name: '$input', props: { placeholder: '请输入岗位编码' } }
152   - },
153   - {
154   - field: 'sort',
155   - title: '岗位顺序',
156   - span: 12,
157   - itemRender: { name: '$input', props: { type: 'number', placeholder: '请输入岗位顺序' } }
158   - },
159   - {
160   - field: 'status',
161   - title: t('common.status'),
162   - span: 12,
163   - itemRender: {
164   - name: '$select',
165   - options: getIntDictOptions(DICT_TYPE.COMMON_STATUS),
166   - props: { placeholder: '请选择' }
167   - }
168   - },
169   - {
170   - align: 'center',
171   - span: 24,
172   - itemRender: {
173   - name: '$buttons',
174   - children: [
175   - { props: { type: 'submit', content: t('action.save'), status: 'primary' } },
176   - { props: { type: 'reset', content: t('common.reset') } }
177   - ]
178   - }
179   - }
180   -])
  107 +const formItems = ref<VxeFormItemProps[]>(allSchemas.formSchema)
181 108 // 设置标题
182 109 const setDialogTile = (type: string) => {
183 110 dialogTitle.value = t('action.' + type)
... ... @@ -194,7 +121,7 @@ const handleDetail = (row: PostVO) =&gt; {
194 121 // 新增操作
195 122 const handleCreate = () => {
196 123 setDialogTile('create')
197   - xForm.value?.reset()
  124 + formData.value = undefined
198 125 }
199 126  
200 127 // 修改操作
... ... @@ -206,16 +133,13 @@ const handleUpdate = async (rowId: number) =&gt; {
206 133 }
207 134 // 删除操作
208 135 const handleDelete = (rowId: number) => {
209   - ElMessageBox.confirm(t('common.delMessage'), t('common.confirmTitle'), {
210   - confirmButtonText: t('common.ok'),
211   - cancelButtonText: t('common.cancel'),
212   - type: 'warning'
213   - })
  136 + message
  137 + .confirm(t('common.delMessage'), t('common.confirmTitle'))
214 138 .then(async () => {
215 139 await PostApi.deletePostApi(rowId)
  140 + message.success(t('common.delSuccess'))
216 141 })
217 142 .finally(() => {
218   - ElMessage.success(t('common.delSuccess'))
219 143 xGrid.value?.commitProxy('query')
220 144 })
221 145 }
... ... @@ -227,10 +151,10 @@ const submitForm: VxeFormEvents.Submit = async () =&gt; {
227 151 const data = formData.value as PostVO
228 152 if (actionType.value === 'create') {
229 153 await PostApi.createPostApi(data)
230   - ElMessage.success(t('common.createSuccess'))
  154 + message.success(t('common.createSuccess'))
231 155 } else {
232 156 await PostApi.updatePostApi(data)
233   - ElMessage.success(t('common.updateSuccess'))
  157 + message.success(t('common.updateSuccess'))
234 158 }
235 159 // 操作成功,重新加载列表
236 160 dialogVisible.value = false
... ... @@ -240,82 +164,3 @@ const submitForm: VxeFormEvents.Submit = async () =&gt; {
240 164 }
241 165 }
242 166 </script>
243   -<template>
244   - <ContentWrap>
245   - <vxe-grid ref="xGrid" v-bind="gridOptions">
246   - <template #toolbar_buttons>
247   - <el-button type="primary" v-hasPermi="['system:post:create']" @click="handleCreate">
248   - <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
249   - </el-button>
250   - </template>
251   - <template #status_default="{ row }">
252   - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
253   - </template>
254   - <template #action_default="{ row }">
255   - <el-button
256   - link
257   - type="primary"
258   - v-hasPermi="['system:post:update']"
259   - @click="handleUpdate(row.id)"
260   - >
261   - <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
262   - </el-button>
263   - <el-button
264   - link
265   - type="primary"
266   - v-hasPermi="['system:post:update']"
267   - @click="handleDetail(row)"
268   - >
269   - <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
270   - </el-button>
271   - <el-button
272   - link
273   - type="primary"
274   - v-hasPermi="['system:post:delete']"
275   - @click="handleDelete(row.id)"
276   - >
277   - <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
278   - </el-button>
279   - </template>
280   - </vxe-grid>
281   - </ContentWrap>
282   - <vxe-modal
283   - v-model="dialogVisible"
284   - id="myModal6"
285   - :title="dialogTitle"
286   - width="800"
287   - height="400"
288   - min-width="460"
289   - min-height="320"
290   - show-zoom
291   - resize
292   - remember
293   - storage
294   - transfer
295   - show-footer
296   - >
297   - <template #default>
298   - <!-- 对话框(添加 / 修改) -->
299   - <vxe-form
300   - ref="xForm"
301   - v-if="['create', 'update'].includes(actionType)"
302   - :data="formData"
303   - :items="formItems"
304   - :rules="rules"
305   - @submit="submitForm"
306   - />
307   - <Descriptions
308   - v-if="actionType === 'detail'"
309   - :schema="allSchemas.detailSchema"
310   - :data="detailRef"
311   - >
312   - <template #status="{ row }">
313   - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
314   - </template>
315   - <template #createTime="{ row }">
316   - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
317   - </template>
318   - </Descriptions>
319   - </template>
320   - </vxe-modal>
321   -</template>
... ...
yudao-ui-admin-vue3/src/views/system/post/indexd.vue deleted
1   -<script setup lang="ts">
2   -import { ref, unref } from 'vue'
3   -import dayjs from 'dayjs'
4   -import { ElMessage } from 'element-plus'
5   -import { DICT_TYPE } from '@/utils/dict'
6   -import { useTable } from '@/hooks/web/useTable'
7   -import { useI18n } from '@/hooks/web/useI18n'
8   -import { FormExpose } from '@/components/Form'
9   -import type { PostVO } from '@/api/system/post/types'
10   -import { rules, allSchemas } from './post.data'
11   -import * as PostApi from '@/api/system/post'
12   -const { t } = useI18n() // 国际化
13   -
14   -// ========== 列表相关 ==========
15   -const { register, tableObject, methods } = useTable<PostVO>({
16   - getListApi: PostApi.getPostPageApi,
17   - delListApi: PostApi.deletePostApi,
18   - exportListApi: PostApi.exportPostApi
19   -})
20   -const { getList, setSearchParams, delList, exportList } = methods
21   -
22   -// ========== CRUD 相关 ==========
23   -const actionLoading = ref(false) // 遮罩层
24   -const actionType = ref('') // 操作按钮的类型
25   -const dialogVisible = ref(false) // 是否显示弹出层
26   -const dialogTitle = ref('edit') // 弹出层标题
27   -const formRef = ref<FormExpose>() // 表单 Ref
28   -
29   -// 设置标题
30   -const setDialogTile = (type: string) => {
31   - dialogTitle.value = t('action.' + type)
32   - actionType.value = type
33   - dialogVisible.value = true
34   -}
35   -
36   -// 新增操作
37   -const handleCreate = () => {
38   - setDialogTile('create')
39   - // 重置表单
40   - unref(formRef)?.getElFormRef()?.resetFields()
41   -}
42   -
43   -// 修改操作
44   -const handleUpdate = async (rowId: number) => {
45   - setDialogTile('update')
46   - // 设置数据
47   - const res = await PostApi.getPostApi(rowId)
48   - unref(formRef)?.setValues(res)
49   -}
50   -
51   -// 提交按钮
52   -const submitForm = async () => {
53   - const elForm = unref(formRef)?.getElFormRef()
54   - if (!elForm) return
55   - elForm.validate(async (valid) => {
56   - if (valid) {
57   - actionLoading.value = true
58   - // 提交请求
59   - try {
60   - const data = unref(formRef)?.formModel as PostVO
61   - if (actionType.value === 'create') {
62   - await PostApi.createPostApi(data)
63   - ElMessage.success(t('common.createSuccess'))
64   - } else {
65   - await PostApi.updatePostApi(data)
66   - ElMessage.success(t('common.updateSuccess'))
67   - }
68   - // 操作成功,重新加载列表
69   - dialogVisible.value = false
70   - await getList()
71   - } finally {
72   - actionLoading.value = false
73   - }
74   - }
75   - })
76   -}
77   -
78   -// ========== 详情相关 ==========
79   -const detailRef = ref() // 详情 Ref
80   -
81   -// 详情操作
82   -const handleDetail = async (row: PostVO) => {
83   - // 设置数据
84   - detailRef.value = row
85   - setDialogTile('detail')
86   -}
87   -
88   -// ========== 初始化 ==========
89   -getList()
90   -</script>
91   -
92   -<template>
93   - <!-- 搜索工作区 -->
94   - <ContentWrap>
95   - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
96   - </ContentWrap>
97   - <ContentWrap>
98   - <!-- 操作工具栏 -->
99   - <div class="mb-10px">
100   - <el-button type="primary" v-hasPermi="['system:post:create']" @click="handleCreate">
101   - <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
102   - </el-button>
103   - <el-button
104   - type="warning"
105   - v-hasPermi="['system:post:export']"
106   - :loading="tableObject.exportLoading"
107   - @click="exportList('岗位数据.xls')"
108   - >
109   - <Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
110   - </el-button>
111   - </div>
112   - <!-- 列表 -->
113   - <Table
114   - :columns="allSchemas.tableColumns"
115   - :selection="false"
116   - :data="tableObject.tableList"
117   - :loading="tableObject.loading"
118   - :pagination="{
119   - total: tableObject.total
120   - }"
121   - v-model:pageSize="tableObject.pageSize"
122   - v-model:currentPage="tableObject.currentPage"
123   - @register="register"
124   - >
125   - <template #status="{ row }">
126   - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
127   - </template>
128   - <template #createTime="{ row }">
129   - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
130   - </template>
131   - <template #action="{ row }">
132   - <el-button
133   - link
134   - type="primary"
135   - v-hasPermi="['system:post:update']"
136   - @click="handleUpdate(row.id)"
137   - >
138   - <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
139   - </el-button>
140   - <el-button
141   - link
142   - type="primary"
143   - v-hasPermi="['system:post:update']"
144   - @click="handleDetail(row)"
145   - >
146   - <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
147   - </el-button>
148   - <el-button
149   - link
150   - type="primary"
151   - v-hasPermi="['system:post:delete']"
152   - @click="delList(row.id, false)"
153   - >
154   - <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
155   - </el-button>
156   - </template>
157   - </Table>
158   - </ContentWrap>
159   -
160   - <Dialog v-model="dialogVisible" :title="dialogTitle">
161   - <!-- 对话框(添加 / 修改) -->
162   - <Form
163   - v-if="['create', 'update'].includes(actionType)"
164   - :schema="allSchemas.formSchema"
165   - :rules="rules"
166   - ref="formRef"
167   - />
168   - <!-- 对话框(详情) -->
169   - <Descriptions
170   - v-if="actionType === 'detail'"
171   - :schema="allSchemas.detailSchema"
172   - :data="detailRef"
173   - >
174   - <template #status="{ row }">
175   - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
176   - </template>
177   - <template #createTime="{ row }">
178   - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
179   - </template>
180   - </Descriptions>
181   - <!-- 操作按钮 -->
182   - <template #footer>
183   - <el-button
184   - v-if="['create', 'update'].includes(actionType)"
185   - type="primary"
186   - :loading="actionLoading"
187   - @click="submitForm"
188   - >
189   - {{ t('action.save') }}
190   - </el-button>
191   - <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
192   - </template>
193   - </Dialog>
194   -</template>
yudao-ui-admin-vue3/src/views/system/post/post.data.ts
1 1 import { reactive } from 'vue'
2 2 import { useI18n } from '@/hooks/web/useI18n'
3 3 import { required } from '@/utils/formRules'
4   -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
  4 +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
5 5 import { DICT_TYPE } from '@/utils/dict'
6 6 const { t } = useI18n() // 国际化
7 7  
... ... @@ -13,9 +13,9 @@ export const rules = reactive({
13 13 })
14 14  
15 15 // CrudSchema
16   -const crudSchemas = reactive<CrudSchema[]>([
  16 +const crudSchemas = reactive<VxeCrudSchema[]>([
17 17 {
18   - label: t('common.index'),
  18 + title: t('common.index'),
19 19 field: 'id',
20 20 type: 'index',
21 21 form: {
... ... @@ -26,42 +26,54 @@ const crudSchemas = reactive&lt;CrudSchema[]&gt;([
26 26 }
27 27 },
28 28 {
29   - label: '岗位名称',
  29 + title: '岗位名称',
30 30 field: 'name',
31 31 search: {
32 32 show: true
33 33 }
34 34 },
35 35 {
36   - label: '岗位编码',
  36 + title: '岗位编码',
37 37 field: 'code',
38 38 search: {
39 39 show: true
40 40 }
41 41 },
42 42 {
43   - label: '岗位顺序',
  43 + title: '岗位顺序',
44 44 field: 'sort'
45 45 },
46 46 {
47   - label: t('common.status'),
  47 + title: t('common.status'),
48 48 field: 'status',
49 49 dictType: DICT_TYPE.COMMON_STATUS,
  50 + table: {
  51 + slots: {
  52 + default: 'status_default'
  53 + }
  54 + },
50 55 search: {
51 56 show: true
52 57 }
53 58 },
54 59 {
55   - label: t('common.createTime'),
  60 + title: t('common.createTime'),
56 61 field: 'createTime',
57 62 form: {
58 63 show: false
59 64 }
60 65 },
61 66 {
62   - label: t('table.action'),
  67 + title: t('table.action'),
63 68 field: 'action',
64 69 width: '240px',
  70 + table: {
  71 + width: '240px',
  72 + showOverflow: true,
  73 + slots: {
  74 + default: 'action_default'
  75 + }
  76 + },
65 77 form: {
66 78 show: false
67 79 },
... ... @@ -70,4 +82,4 @@ const crudSchemas = reactive&lt;CrudSchema[]&gt;([
70 82 }
71 83 }
72 84 ])
73   -export const { allSchemas } = useCrudSchemas(crudSchemas)
  85 +export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
... ...