Przeglądaj źródła

!271 升级后端及 vue3部分依赖
Merge pull request !271 from xingyu/dev

芋道源码 2 lat temu
rodzic
commit
d1736af6da
100 zmienionych plików z 993 dodań i 614 usunięć
  1. 29 29
      README.md
  2. 2 2
      pom.xml
  3. 23 23
      yudao-dependencies/pom.xml
  4. 1 1
      yudao-example/yudao-sso-demo-by-code/pom.xml
  5. 1 1
      yudao-example/yudao-sso-demo-by-password/pom.xml
  6. 2 2
      yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
  7. 2 2
      yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml
  8. 4 3
      yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java
  9. 5 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java
  10. 22 16
      yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
  11. 2 3
      yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/app/banner/AppBannerController.java
  12. 0 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java
  13. 10 10
      yudao-ui-admin-vue3/README.md
  14. 41 41
      yudao-ui-admin-vue3/package.json
  15. 2 0
      yudao-ui-admin-vue3/src/api/system/tenant/types.ts
  16. 2 1
      yudao-ui-admin-vue3/src/components/ConfigGlobal/src/ConfigGlobal.vue
  17. 2 1
      yudao-ui-admin-vue3/src/components/ContextMenu/src/ContextMenu.vue
  18. 1 1
      yudao-ui-admin-vue3/src/components/CountTo/src/CountTo.vue
  19. 1 1
      yudao-ui-admin-vue3/src/components/Crontab/src/Crontab.vue
  20. 1 0
      yudao-ui-admin-vue3/src/components/Descriptions/src/Descriptions.vue
  21. 1 1
      yudao-ui-admin-vue3/src/components/Dialog/src/Dialog.vue
  22. 1 1
      yudao-ui-admin-vue3/src/components/Editor/src/Editor.vue
  23. 1 0
      yudao-ui-admin-vue3/src/components/Error/src/Error.vue
  24. 1 0
      yudao-ui-admin-vue3/src/components/Form/index.ts
  25. 1 0
      yudao-ui-admin-vue3/src/components/Form/src/Form.vue
  26. 1 0
      yudao-ui-admin-vue3/src/components/Form/src/componentMap.ts
  27. 1 0
      yudao-ui-admin-vue3/src/components/Form/src/components/useRenderCheckbox.tsx
  28. 1 0
      yudao-ui-admin-vue3/src/components/Form/src/components/useRenderRadio.tsx
  29. 10 1
      yudao-ui-admin-vue3/src/components/Form/src/components/useRenderSelect.tsx
  30. 2 0
      yudao-ui-admin-vue3/src/components/Form/src/helper.ts
  31. 2 0
      yudao-ui-admin-vue3/src/components/Form/src/types.ts
  32. 1 1
      yudao-ui-admin-vue3/src/components/Icon/src/IconSelect.vue
  33. 3 2
      yudao-ui-admin-vue3/src/components/Infotip/src/Infotip.vue
  34. 1 1
      yudao-ui-admin-vue3/src/components/InputPassword/src/InputPassword.vue
  35. 1 1
      yudao-ui-admin-vue3/src/components/Menu/src/Menu.vue
  36. 2 1
      yudao-ui-admin-vue3/src/components/Qrcode/src/Qrcode.vue
  37. 2 1
      yudao-ui-admin-vue3/src/components/Search/src/Search.vue
  38. 1 1
      yudao-ui-admin-vue3/src/components/Setting/src/Setting.vue
  39. 1 1
      yudao-ui-admin-vue3/src/components/Setting/src/components/ColorRadioPicker.vue
  40. 26 1
      yudao-ui-admin-vue3/src/components/Setting/src/components/InterfaceDisplay.vue
  41. 2 1
      yudao-ui-admin-vue3/src/components/SizeDropdown/src/SizeDropdown.vue
  42. 36 9
      yudao-ui-admin-vue3/src/components/TabMenu/src/TabMenu.vue
  43. 4 4
      yudao-ui-admin-vue3/src/components/TabMenu/src/helper.ts
  44. 3 0
      yudao-ui-admin-vue3/src/components/Table/index.ts
  45. 1 0
      yudao-ui-admin-vue3/src/components/Table/src/Table.vue
  46. 2 0
      yudao-ui-admin-vue3/src/components/Table/src/types.ts
  47. 2 2
      yudao-ui-admin-vue3/src/components/UserInfo/src/UserInfo.vue
  48. 0 104
      yudao-ui-admin-vue3/src/config/app.ts
  49. 18 8
      yudao-ui-admin-vue3/src/config/axios/index.ts
  50. 0 32
      yudao-ui-admin-vue3/src/config/locale.ts
  51. 1 0
      yudao-ui-admin-vue3/src/hooks/web/useConfigGlobal.ts
  52. 4 0
      yudao-ui-admin-vue3/src/hooks/web/useCrudSchemas.ts
  53. 1 0
      yudao-ui-admin-vue3/src/hooks/web/useForm.ts
  54. 1 0
      yudao-ui-admin-vue3/src/hooks/web/useIcon.ts
  55. 8 3
      yudao-ui-admin-vue3/src/hooks/web/useTable.ts
  56. 16 3
      yudao-ui-admin-vue3/src/layout/components/useRenderLayout.tsx
  57. 4 1
      yudao-ui-admin-vue3/src/locales/en.ts
  58. 4 1
      yudao-ui-admin-vue3/src/locales/zh-CN.ts
  59. 0 3
      yudao-ui-admin-vue3/src/store/index.ts
  60. 100 11
      yudao-ui-admin-vue3/src/store/modules/app.ts
  61. 1 5
      yudao-ui-admin-vue3/src/store/modules/dict.ts
  62. 31 7
      yudao-ui-admin-vue3/src/store/modules/locale.ts
  63. 1 5
      yudao-ui-admin-vue3/src/store/modules/permission.ts
  64. 1 2
      yudao-ui-admin-vue3/src/store/modules/tagsView.ts
  65. 1 2
      yudao-ui-admin-vue3/src/store/modules/user.ts
  66. 52 0
      yudao-ui-admin-vue3/src/types/components.d.ts
  67. 4 0
      yudao-ui-admin-vue3/src/types/configGlobal.d.ts
  68. 7 0
      yudao-ui-admin-vue3/src/types/contextMenu.d.ts
  69. 1 1
      yudao-ui-admin-vue3/src/types/descriptions.d.ts
  70. 3 0
      yudao-ui-admin-vue3/src/types/elementPlus.d.ts
  71. 45 0
      yudao-ui-admin-vue3/src/types/form.d.ts
  72. 1 1
      yudao-ui-admin-vue3/src/types/icon.d.ts
  73. 1 1
      yudao-ui-admin-vue3/src/types/infoTip.d.ts
  74. 1 0
      yudao-ui-admin-vue3/src/types/layout.d.ts
  75. 2 2
      yudao-ui-admin-vue3/src/types/localeDropdown.d.ts
  76. 1 1
      yudao-ui-admin-vue3/src/types/qrcode.d.ts
  77. 4 4
      yudao-ui-admin-vue3/src/types/table.d.ts
  78. 16 0
      yudao-ui-admin-vue3/src/types/theme.d.ts
  79. 1 0
      yudao-ui-admin-vue3/src/utils/dict.ts
  80. 17 12
      yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue
  81. 1 0
      yudao-ui-admin-vue3/src/views/Login/components/RegisterForm.vue
  82. 22 16
      yudao-ui-admin-vue3/src/views/bpm/form/index.vue
  83. 23 17
      yudao-ui-admin-vue3/src/views/bpm/group/index.vue
  84. 22 16
      yudao-ui-admin-vue3/src/views/bpm/model/index.vue
  85. 10 1
      yudao-ui-admin-vue3/src/views/infra/codegen/EditTable.vue
  86. 2 0
      yudao-ui-admin-vue3/src/views/infra/codegen/components/BasicInfoForm.vue
  87. 45 5
      yudao-ui-admin-vue3/src/views/infra/codegen/components/GenInfoForm.vue
  88. 1 1
      yudao-ui-admin-vue3/src/views/infra/codegen/components/ImportTable.vue
  89. 22 16
      yudao-ui-admin-vue3/src/views/infra/config/index.vue
  90. 22 16
      yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/index.vue
  91. 22 16
      yudao-ui-admin-vue3/src/views/infra/fileConfig/index.vue
  92. 23 17
      yudao-ui-admin-vue3/src/views/infra/job/index.vue
  93. 22 16
      yudao-ui-admin-vue3/src/views/pay/app/index.vue
  94. 22 16
      yudao-ui-admin-vue3/src/views/pay/merchant/index.vue
  95. 22 16
      yudao-ui-admin-vue3/src/views/pay/order/index.vue
  96. 2 0
      yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts
  97. 21 15
      yudao-ui-admin-vue3/src/views/system/dept/index.vue
  98. 45 33
      yudao-ui-admin-vue3/src/views/system/dict/index.vue
  99. 22 16
      yudao-ui-admin-vue3/src/views/system/errorCode/index.vue
  100. 11 5
      yudao-ui-admin-vue3/src/views/system/menu/index.vue

+ 29 - 29
README.md

@@ -174,29 +174,29 @@ ps:核心功能已经实现,正在对接微信小程序中...
 
 ### 后端
 
-| 框架                                                                                         | 说明                   | 版本      | 学习指南                                                           |
-|---------------------------------------------------------------------------------------------|-----------------------|---------|----------------------------------------------------------------|
-| [Spring Boot](https://spring.io/projects/spring-boot)                                       | 应用开发框架             | 2.6.10  | [文档](https://github.com/YunaiV/SpringBoot-Labs)                |
-| [MySQL](https://www.mysql.com/cn/)                                                          | 数据库服务器             | 5.7     |                                                                |
-| [Druid](https://github.com/alibaba/druid)                                                   | JDBC 连接池、监控组件     | 1.2.11  | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [MyBatis Plus](https://mp.baomidou.com/)                                                    | MyBatis 增强工具包       | 3.5.2   | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao)         |
-| [Dynamic Datasource](https://dynamic-datasource.com/)                                       | 动态数据源               | 3.5.0   | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [Redis](https://redis.io/)                                                                  | key-value 数据库        | 5.0     |                                                                |
-| [Redisson](https://github.com/redisson/redisson)                                            | Redis 客户端            | 3.17.4  | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao)           |
-| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架               | 5.3.20  | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao)               |
-| [Spring Security](https://github.com/spring-projects/spring-security)                       | Spring 安全框架         | 5.6.5   | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
-| [Hibernate Validator](https://github.com/hibernate/hibernate-validator)                     | 参数校验组件             | 6.2.3   | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao)      |
-| [Flowable](https://github.com/flowable/flowable-engine)                                     | 工作流引擎               | 6.7.2   | [文档](https://doc.iocoder.cn/bpm/)                                                     |
-| [Quartz](https://github.com/quartz-scheduler)                                               | 任务调度组件             | 2.3.2   | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao)             |
-| [Knife4j](https://gitee.com/xiaoym/knife4j)                                                 | Swagger 增强 UI 实现    | 3.0.3   | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao)         |
-| [Resilience4j](https://github.com/resilience4j/resilience4j)                                | 服务保障组件             | 1.7.1   | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao)    |
-| [SkyWalking](https://skywalking.apache.org/)                                                | 分布式应用追踪系统        | 8.5.0   | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao)      |
-| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin)                       | Spring Boot 监控平台    | 2.6.7   | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao)           |
-| [Jackson](https://github.com/FasterXML/jackson)                                             | JSON 工具库             | 2.13.3  |                                                                |
-| [MapStruct](https://mapstruct.org/)                                                         | Java Bean 转换         | 1.4.1   | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao)       |
-| [Lombok](https://projectlombok.org/)                                                        | 消除冗长的 Java 代码     | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao)          |
-| [JUnit](https://junit.org/junit5/)                                                          | Java 单元测试框架        | 5.8.2   | -                                                              |
-| [Mockito](https://github.com/mockito/mockito)                                               | Java Mock 框架         | 4.0.0   | -                                                              |
+| 框架                                                                                         | 说明                   | 版本               | 学习指南                                                           |
+|---------------------------------------------------------------------------------------------|-----------------------|------------------|----------------------------------------------------------------|
+| [Spring Boot](https://spring.io/projects/spring-boot)                                       | 应用开发框架             | 2.6.12           | [文档](https://github.com/YunaiV/SpringBoot-Labs)                |
+| [MySQL](https://www.mysql.com/cn/)                                                          | 数据库服务器             | 5.7 / 8.0+       |                                                                |
+| [Druid](https://github.com/alibaba/druid)                                                   | JDBC 连接池、监控组件     | 1.2.13-SNSAPSHOT | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [MyBatis Plus](https://mp.baomidou.com/)                                                    | MyBatis 增强工具包       | 3.5.2            | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao)         |
+| [Dynamic Datasource](https://dynamic-datasource.com/)                                       | 动态数据源               | 3.5.2            | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [Redis](https://redis.io/)                                                                  | key-value 数据库        | 5.0              |                                                                |
+| [Redisson](https://github.com/redisson/redisson)                                            | Redis 客户端            | 3.17.7           | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao)           |
+| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架               | 5.3.20           | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao)               |
+| [Spring Security](https://github.com/spring-projects/spring-security)                       | Spring 安全框架         | 5.6.5            | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
+| [Hibernate Validator](https://github.com/hibernate/hibernate-validator)                     | 参数校验组件             | 6.2.3            | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao)      |
+| [Flowable](https://github.com/flowable/flowable-engine)                                     | 工作流引擎               | 6.7.2            | [文档](https://doc.iocoder.cn/bpm/)                                                     |
+| [Quartz](https://github.com/quartz-scheduler)                                               | 任务调度组件             | 2.3.2            | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao)             |
+| [Knife4j](https://gitee.com/xiaoym/knife4j)                                                 | Swagger 增强 UI 实现    | 3.0.3            | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao)         |
+| [Resilience4j](https://github.com/resilience4j/resilience4j)                                | 服务保障组件             | 1.7.1            | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao)    |
+| [SkyWalking](https://skywalking.apache.org/)                                                | 分布式应用追踪系统        | 8.5.0            | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao)      |
+| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin)                       | Spring Boot 监控平台    | 2.6.9            | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao)           |
+| [Jackson](https://github.com/FasterXML/jackson)                                             | JSON 工具库             | 2.13.3           |                                                                |
+| [MapStruct](https://mapstruct.org/)                                                         | Java Bean 转换         | 1.5.2.Final      | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao)       |
+| [Lombok](https://projectlombok.org/)                                                        | 消除冗长的 Java 代码     | 1.18.24          | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao)          |
+| [JUnit](https://junit.org/junit5/)                                                          | Java 单元测试框架        | 5.8.2            | -                                                              |
+| [Mockito](https://github.com/mockito/mockito)                                               | Java Mock 框架         | 4.8.0            | -                                                              |
 
 ### [管理后台 Vue2 前端](./yudao-ui-admin)
 
@@ -209,14 +209,14 @@ ps:核心功能已经实现,正在对接微信小程序中...
 
 | 框架                                                                  | 说明              | 版本     |
 |----------------------------------------------------------------------|-----------------|--------|
-| [Vue](https://staging-cn.vuejs.org/)                                 | Vue 框架          | 3.2.37 |
-| [Vite](https://cn.vitejs.dev//)                                      | 开发与构建工具         | 3.0.4  |
-| [Element Plus](https://element-plus.org/zh-CN/)                      | Element Plus    | 2.2.12 |
-| [TypeScript](https://www.typescriptlang.org/docs/)                   | TypeScript      | 4.7.4  |
-| [pinia](https://pinia.vuejs.org/)                                    | vuex5           | 2.0.17 |
+| [Vue](https://staging-cn.vuejs.org/)                                 | Vue 框架          | 3.2.41 |
+| [Vite](https://cn.vitejs.dev//)                                      | 开发与构建工具         | 3.1.8  |
+| [Element Plus](https://element-plus.org/zh-CN/)                      | Element Plus    | 2.2.18 |
+| [TypeScript](https://www.typescriptlang.org/docs/)                   | TypeScript      | 4.8.4  |
+| [pinia](https://pinia.vuejs.org/)                                    | vuex5           | 2.0.23 |
 | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化             | 9.2.2  |
 | [windicss](https://cn.windicss.org/)                                 | 下一代工具优先的 CSS 框架 | 3.5.6  |
-| [iconify](https://icon-sets.iconify.design/)                         | 在线图标库           | 2.2.1  |
+| [iconify](https://icon-sets.iconify.design/)                         | 在线图标库           | 3.0.0  |
 
 ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)
 

+ 2 - 2
pom.xml

@@ -37,8 +37,8 @@
         <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
         <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
         <!-- 看看咋放到 bom 里 -->
-        <lombok.version>1.18.20</lombok.version>
-        <mapstruct.version>1.4.1.Final</mapstruct.version>
+        <lombok.version>1.18.24</lombok.version>
+        <mapstruct.version>1.5.2.Final</mapstruct.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 

+ 23 - 23
yudao-dependencies/pom.xml

@@ -16,58 +16,58 @@
     <properties>
         <revision>1.6.4-snapshot</revision>
         <!-- 统一依赖管理 -->
-        <spring.boot.version>2.6.10</spring.boot.version>
+        <spring.boot.version>2.6.12</spring.boot.version>
         <!-- Web 相关 -->
         <knife4j.version>3.0.3</knife4j.version>
-        <swagger-annotations.version>1.6.6</swagger-annotations.version>
+        <swagger-annotations.version>1.6.7</swagger-annotations.version>
         <servlet.versoin>2.5</servlet.versoin>
         <!-- DB 相关 -->
-        <druid.version>1.2.11</druid.version>
+        <druid.version>1.2.13-SNSAPSHOT</druid.version>
         <mybatis-plus.version>3.5.2</mybatis-plus.version>
         <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
-        <dynamic-datasource.version>3.5.0</dynamic-datasource.version>
-        <redisson.version>3.17.4</redisson.version>
+        <dynamic-datasource.version>3.5.2</dynamic-datasource.version>
+        <redisson.version>3.17.7</redisson.version>
         <!-- Config 配置中心相关 -->
-        <apollo.version>1.9.2</apollo.version>
+        <apollo.version>2.0.1</apollo.version>
         <!-- 服务保障相关 -->
-        <lock4j.version>2.2.0</lock4j.version>
+        <lock4j.version>2.2.2</lock4j.version>
         <resilience4j.version>1.7.1</resilience4j.version>
         <!-- 监控相关 -->
-        <skywalking.version>8.7.0</skywalking.version>
-        <spring-boot-admin.version>2.6.7</spring-boot-admin.version>
-        <opentracing.version>0.31.0</opentracing.version>
+        <skywalking.version>8.12.0</skywalking.version>
+        <spring-boot-admin.version>2.6.9</spring-boot-admin.version>
+        <opentracing.version>0.33.0</opentracing.version>
         <!-- Test 测试相关 -->
-        <podam.version>7.2.6.RELEASE</podam.version>
-        <jedis-mock.version>0.1.16</jedis-mock.version>
-        <mockito-inline.version>4.0.0</mockito-inline.version>
+        <podam.version>7.2.9.RELEASE</podam.version>
+        <jedis-mock.version>1.0.4</jedis-mock.version>
+        <mockito-inline.version>4.8.0</mockito-inline.version>
         <!-- Bpm 工作流相关 -->
         <flowable.version>6.7.2</flowable.version>
         <!-- 工具类相关 -->
         <jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
-        <lombok.version>1.18.20</lombok.version>
-        <mapstruct.version>1.4.1.Final</mapstruct.version>
-        <hutool.version>5.8.5</hutool.version>
+        <lombok.version>1.18.24</lombok.version>
+        <mapstruct.version>1.5.2.Final</mapstruct.version>
+        <hutool.version>5.8.8</hutool.version>
         <easyexcel.verion>3.1.1</easyexcel.verion>
         <velocity.version>2.3</velocity.version>
         <screw.version>1.0.5</screw.version>
-		<fastjson.version>1.2.83</fastjson.version>
-        <guava.version>30.1.1-jre</guava.version>
+        <fastjson.version>1.2.83</fastjson.version>
+        <guava.version>31.1-jre</guava.version>
         <guice.version>5.1.0</guice.version>
-        <transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
+        <transmittable-thread-local.version>2.14.0</transmittable-thread-local.version>
         <commons-net.version>3.8.0</commons-net.version>
         <jsch.version>0.1.55</jsch.version>
-        <tika-core.version>2.4.1</tika-core.version>
+        <tika-core.version>2.5.0</tika-core.version>
         <aj-captcha.version>1.3.0</aj-captcha.version>
         <netty-all.version>4.1.82.Final</netty-all.version>
         <!-- 三方云服务相关 -->
         <minio.version>8.2.2</minio.version>
-        <aliyun-java-sdk-core.version>4.6.0</aliyun-java-sdk-core.version>
+        <aliyun-java-sdk-core.version>4.6.2</aliyun-java-sdk-core.version>
         <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
         <tencentcloud-sdk-java.version>3.1.561</tencentcloud-sdk-java.version>
         <yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
         <justauth.version>1.4.0</justauth.version>
-        <jimureport.version>1.5.2</jimureport.version>
-        <xercesImpl.version>2.12.0</xercesImpl.version>
+        <jimureport.version>1.5.3</jimureport.version>
+        <xercesImpl.version>2.12.2</xercesImpl.version>
     </properties>
 
     <dependencyManagement>

+ 1 - 1
yudao-example/yudao-sso-demo-by-code/pom.xml

@@ -52,7 +52,7 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.8.5</version>
+            <version>5.8.8</version>
         </dependency>
 
         <dependency>

+ 1 - 1
yudao-example/yudao-sso-demo-by-password/pom.xml

@@ -52,7 +52,7 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.8.5</version>
+            <version>5.8.8</version>
         </dependency>
 
         <dependency>

+ 2 - 2
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml

@@ -52,7 +52,7 @@
         <dependency>
             <groupId>com.alipay.sdk</groupId>
             <artifactId>alipay-sdk-java</artifactId>
-            <version>4.31.72.ALL</version>
+            <version>4.33.44.ALL</version>
             <exclusions>
                 <exclusion>
                     <groupId>org.bouncycastle</groupId>
@@ -63,7 +63,7 @@
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-pay</artifactId>
-            <version>4.3.8.B</version>
+            <version>4.4.0</version>
         </dependency>
         <!-- TODO 芋艿:清理 -->
 

+ 2 - 2
yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml

@@ -35,12 +35,12 @@
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>wx-java-mp-spring-boot-starter</artifactId>
-            <version>4.3.8.B</version>
+            <version>4.4.0</version>
         </dependency>
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
-            <version>4.3.8.B</version>
+            <version>4.4.0</version>
         </dependency>
         <!-- TODO 芋艿:清理 -->
     </dependencies>

+ 4 - 3
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java

@@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant
 import com.baomidou.lock.LockFailureStrategy;
 import lombok.extern.slf4j.Slf4j;
 
+import java.lang.reflect.Method;
+
 /**
  * 自定义获取锁失败策略,抛出 {@link ServiceException} 异常
  */
@@ -12,9 +14,8 @@ import lombok.extern.slf4j.Slf4j;
 public class DefaultLockFailureStrategy implements LockFailureStrategy {
 
     @Override
-    public void onLockFailure(String key, long acquireTimeout, int acquireCount) {
-        log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout);
+    public void onLockFailure(String key, Method method, Object[] arguments) {
+        log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取失败:{} ]", Thread.currentThread().getName(), key, arguments);
         throw new ServiceException(GlobalErrorCodeConstants.LOCKED);
     }
-
 }

+ 5 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.convert.message;
 
 import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
 import org.mapstruct.factory.Mappers;
 
 import java.util.Map;
@@ -11,6 +12,10 @@ public interface BpmMessageConvert {
 
     BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class);
 
+    @Mapping(target = "mobile", ignore = true)
+    @Mapping(source = "userId", target = "userId")
+    @Mapping(source = "templateCode", target = "templateCode")
+    @Mapping(source = "templateParams", target = "templateParams")
     SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map<String, Object> templateParams);
 
 }

+ 22 - 16
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm

@@ -50,23 +50,29 @@
 
   // 提交按钮
   const submitForm = async () => {
-    actionLoading.value = true
-    // 提交请求
-    try {
-      const data = unref(formRef)?.formModel as ${simpleClassName}VO
-      if (actionType.value === 'create') {
-        await ${simpleClassName}Api.create${simpleClassName}Api(data)
-        ElMessage.success(t('common.createSuccess'))
-      } else {
-        await ${simpleClassName}Api.update${simpleClassName}Api(data)
-        ElMessage.success(t('common.updateSuccess'))
+    const elForm = unref(formRef)?.getElFormRef()
+    if (!elForm) return
+    elForm.validate(async (valid) => {
+      if (valid) {
+        actionLoading.value = true
+        // 提交请求
+        try {
+          const data = unref(formRef)?.formModel as ${simpleClassName}VO
+          if (actionType.value === 'create') {
+            await ${simpleClassName}Api.create${simpleClassName}Api(data)
+            ElMessage.success(t('common.createSuccess'))
+          } else {
+            await ${simpleClassName}Api.update${simpleClassName}Api(data)
+            ElMessage.success(t('common.updateSuccess'))
+          }
+          // 操作成功,重新加载列表
+          dialogVisible.value = false
+          await getList()
+        } finally {
+          actionLoading.value = false
+        }
       }
-      // 操作成功,重新加载列表
-      dialogVisible.value = false
-      await getList()
-    } finally {
-      actionLoading.value = false
-    }
+    })
   }
 
   // ========== 详情相关 ==========

+ 2 - 3
yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/app/banner/AppBannerController.java

@@ -7,13 +7,13 @@ import cn.iocoder.yudao.module.market.dal.dataobject.banner.BannerDO;
 import cn.iocoder.yudao.module.market.service.banner.BannerService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -27,8 +27,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 @Validated
 public class AppBannerController {
 
-    // TODO @xia:使用 @Resource 哈
-    @Autowired
+    @Resource
     private BannerService bannerService;
 
     // TODO @xia:新建一个 AppBannerRespVO,只返回必要的字段。status 要过滤下。然后 sort 下结果

+ 0 - 1
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java

@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.validation.Mobile;
 import lombok.Data;
 
 import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
 import java.util.Map;
 
 /**

+ 10 - 10
yudao-ui-admin-vue3/README.md

@@ -27,17 +27,17 @@
 
 | 框架 | 说明 | 版本     |
 | --- | --- |--------|
-| [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.37 |
-| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.4 |
-| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.12 |
-| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.7.4 |
-| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 |
-| [vueuse](https://vueuse.org//) | 常用工具集 | 9.0.2 |
-| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.0 |
-| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.3 |
+| [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.41 |
+| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.1.8 |
+| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.18 |
+| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.8.4 |
+| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.23 |
+| [vueuse](https://vueuse.org//) | 常用工具集 | 9.3.1 |
+| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
+| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.5 |
 | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
-| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
-| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.14 |
+| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.0.0 |
+| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.21 |
 
 ### 推荐 VScode 开发,插件如下
 

+ 41 - 41
yudao-ui-admin-vue3/package.json

@@ -1,6 +1,6 @@
 {
   "name": "ruoyi-vue-pro-vue3",
-  "version": "1.6.3.1611",
+  "version": "1.6.4.1811",
   "description": "基于vue3、element-plus、typesScript、vite3",
   "author": "xingyu",
   "private": false,
@@ -10,7 +10,7 @@
     "ts:check": "vue-tsc --noEmit",
     "build:pro": "vite build --mode pro",
     "build:dev": "vite build --mode dev",
-    "build:test": "pnpm run ts:check && vite build --mode test",
+    "build:test": "npm run ts:check && vite build --mode test",
     "serve:pro": "vite preview --mode pro",
     "serve:dev": "vite preview --mode dev",
     "serve:test": "vite preview --mode test",
@@ -25,84 +25,84 @@
     "p": "plop"
   },
   "dependencies": {
-    "@iconify/iconify": "^2.2.1",
-    "@vueuse/core": "^9.1.0",
-    "@wangeditor/editor": "^5.1.14",
+    "@iconify/iconify": "^3.0.0",
+    "@vueuse/core": "^9.3.1",
+    "@wangeditor/editor": "^5.1.21",
     "@wangeditor/editor-for-vue": "^5.1.10",
-    "@zxcvbn-ts/core": "^2.0.4",
+    "@zxcvbn-ts/core": "^2.0.5",
     "animate.css": "^4.1.1",
     "axios": "^0.27.2",
     "crypto-js": "^4.1.1",
-    "dayjs": "^1.11.4",
-    "echarts": "^5.3.3",
+    "dayjs": "^1.11.5",
+    "echarts": "^5.4.0",
     "echarts-wordcloud": "^2.0.0",
-    "element-plus": "2.2.12",
+    "element-plus": "2.2.18",
     "intro.js": "^6.0.0",
     "jsencrypt": "^3.2.1",
     "lodash-es": "^4.17.21",
     "mitt": "^3.0.0",
     "nprogress": "^0.2.0",
-    "pinia": "^2.0.17",
-    "pinia-plugin-persist": "^1.0.0",
+    "pinia": "^2.0.23",
     "qrcode": "^1.5.1",
     "qs": "^6.11.0",
     "url": "^0.11.0",
-    "vue": "3.2.37",
+    "vue": "3.2.41",
     "vue-cropper": "^1.0.3",
     "vue-i18n": "9.2.2",
-    "vue-router": "^4.1.3",
+    "vue-router": "^4.1.5",
     "vue-types": "^4.2.1",
     "web-storage-cache": "^1.1.1"
   },
   "devDependencies": {
-    "@commitlint/cli": "^17.0.3",
-    "@commitlint/config-conventional": "^17.0.3",
-    "@iconify/json": "^2.1.89",
-    "@intlify/vite-plugin-vue-i18n": "^6.0.0",
+    "@commitlint/cli": "^17.1.2",
+    "@commitlint/config-conventional": "^17.1.0",
+    "@iconify/json": "^2.1.122",
+    "@intlify/vite-plugin-vue-i18n": "^6.0.3",
     "@purge-icons/generated": "^0.9.0",
     "@types/intro.js": "^5.1.0",
     "@types/lodash-es": "^4.17.6",
-    "@types/node": "^18.6.5",
+    "@types/node": "^18.11.0",
     "@types/nprogress": "^0.2.0",
-    "@types/qrcode": "^1.4.2",
+    "@types/qrcode": "^1.5.0",
     "@types/qs": "^6.9.7",
-    "@typescript-eslint/eslint-plugin": "^5.33.0",
-    "@typescript-eslint/parser": "^5.33.0",
-    "@vitejs/plugin-vue": "^3.0.1",
-    "@vitejs/plugin-vue-jsx": "^2.0.0",
-    "autoprefixer": "^10.4.8",
-    "eslint": "^8.21.0",
+    "@typescript-eslint/eslint-plugin": "^5.40.0",
+    "@typescript-eslint/parser": "^5.40.0",
+    "@vitejs/plugin-vue": "^3.1.2",
+    "@vitejs/plugin-vue-jsx": "^2.0.1",
+    "autoprefixer": "^10.4.12",
+    "eslint": "^8.25.0",
     "eslint-config-prettier": "^8.5.0",
-    "eslint-define-config": "^1.6.0",
+    "eslint-define-config": "^1.7.0",
     "eslint-plugin-prettier": "^4.2.1",
-    "eslint-plugin-vue": "^9.3.0",
+    "eslint-plugin-vue": "^9.6.0",
     "less": "^4.1.3",
     "lint-staged": "^13.0.3",
     "plop": "^3.1.1",
-    "postcss": "^8.4.16",
+    "postcss": "^8.4.18",
     "postcss-html": "^1.5.0",
     "postcss-less": "^6.0.0",
     "prettier": "^2.7.1",
     "rimraf": "^3.0.2",
-    "rollup": "^2.77.2",
-    "stylelint": "^14.9.1",
+    "rollup": "^2.79.1",
+    "stylelint": "^14.14.0",
     "stylelint-config-html": "^1.1.0",
     "stylelint-config-prettier": "^9.0.3",
-    "stylelint-config-recommended": "^8.0.0",
-    "stylelint-config-standard": "^26.0.0",
+    "stylelint-config-recommended": "^9.0.0",
+    "stylelint-config-standard": "^29.0.0",
     "stylelint-order": "^5.0.0",
-    "typescript": "4.7.4",
-    "unplugin-vue-define-options": "^0.7.3",
-    "vite": "3.0.5",
+    "typescript": "4.8.4",
+    "unplugin-vue-macros": "^0.13.2",
+    "vite": "3.1.8",
     "vite-plugin-compression": "^0.5.1",
-    "vite-plugin-eslint": "^1.7.0",
+    "vite-plugin-eslint": "^1.8.1",
     "vite-plugin-html": "^3.2.0",
-    "vite-plugin-purge-icons": "^0.9.0",
-    "vite-plugin-style-import": "^2.0.0",
+    "vite-plugin-purge-icons": "^0.9.1",
+    "vite-plugin-style-import": "2.0.0",
     "vite-plugin-svg-icons": "^2.0.1",
-    "vite-plugin-windicss": "^1.8.7",
-    "vue-tsc": "^0.39.5",
-    "windicss": "^3.5.6"
+    "vite-plugin-windicss": "^1.8.8",
+    "vue-tsc": "^1.0.8",
+    "windicss": "^3.5.6",
+    "windicss-analysis": "^0.3.5"
   },
   "engines": {
     "node": ">= 14.18.0"

+ 2 - 0
yudao-ui-admin-vue3/src/api/system/tenant/types.ts

@@ -4,6 +4,8 @@ export type TenantVO = {
   packageId: number
   contactName: string
   contactMobile: string
+  username: string
+  password: string
   accountCount: number
   expireTime: string
   domain: string

+ 2 - 1
yudao-ui-admin-vue3/src/components/ConfigGlobal/src/ConfigGlobal.vue

@@ -7,13 +7,14 @@ import { useWindowSize } from '@vueuse/core'
 import { useAppStore } from '@/store/modules/app'
 import { setCssVar } from '@/utils'
 import { useDesign } from '@/hooks/web/useDesign'
+import { ElementPlusSize } from '@/types/elementPlus'
 
 const { variables } = useDesign()
 
 const appStore = useAppStore()
 
 const props = defineProps({
-  size: propTypes.oneOf<ElememtPlusSize[]>(['default', 'small', 'large']).def('default')
+  size: propTypes.oneOf<ElementPlusSize[]>(['default', 'small', 'large']).def('default')
 })
 
 provide('configGlobal', props)

+ 2 - 1
yudao-ui-admin-vue3/src/components/ContextMenu/src/ContextMenu.vue

@@ -1,9 +1,10 @@
 <script setup lang="ts">
 import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
-import { PropType, ref } from 'vue'
+import { PropType, ref, defineEmits } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useDesign } from '@/hooks/web/useDesign'
 import type { RouteLocationNormalizedLoaded } from 'vue-router'
+import { contextMenuSchema } from '../../../types/contextMenu'
 
 const { getPrefixCls } = useDesign()
 

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

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { reactive, computed, watch, onMounted, unref, toRef, PropType } from 'vue'
+import { reactive, computed, watch, onMounted, unref, toRef, PropType, defineEmits } from 'vue'
 import { isNumber } from '@/utils/is'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'

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

@@ -24,7 +24,7 @@ import {
   ElRadioButton,
   ElMessage
 } from 'element-plus'
-import { ref, computed, onMounted, reactive, watch, PropType } from 'vue'
+import { ref, computed, onMounted, reactive, watch, PropType, defineEmits } from 'vue'
 interface shortcutsType {
   text: string
   value: string

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

@@ -4,6 +4,7 @@ import { useDesign } from '@/hooks/web/useDesign'
 import { propTypes } from '@/utils/propTypes'
 import { ref, unref, PropType, computed, useAttrs } from 'vue'
 import { useAppStore } from '@/store/modules/app'
+import { DescriptionsSchema } from '@/types/descriptions'
 
 const appStore = useAppStore()
 

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

@@ -74,7 +74,7 @@ const dialogStyle = computed(() => {
         </slot>
         <Icon
           v-if="fullscreen"
-          class="mr-22px cursor-pointer is-hover mt-2px"
+          class="mr-22px cursor-pointer is-hover mt-2px z-10"
           :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
           color="var(--el-color-info)"
           @click="toggleFull"

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

@@ -177,7 +177,7 @@ defineExpose({
 </script>
 
 <template>
-  <div class="border-1 border-solid border-[var(--tags-view-border-color)]">
+  <div class="border-1 border-solid border-[var(--tags-view-border-color)] z-3000">
     <!-- 工具栏 -->
     <Toolbar
       :editor="editorRef"

+ 1 - 0
yudao-ui-admin-vue3/src/components/Error/src/Error.vue

@@ -4,6 +4,7 @@ import networkError from '@/assets/svgs/500.svg'
 import noPermission from '@/assets/svgs/403.svg'
 import { propTypes } from '@/utils/propTypes'
 import { useI18n } from '@/hooks/web/useI18n'
+import { defineEmits } from 'vue'
 
 interface ErrorMap {
   url: string

+ 1 - 0
yudao-ui-admin-vue3/src/components/Form/index.ts

@@ -1,5 +1,6 @@
 import Form from './src/Form.vue'
 import { ElForm } from 'element-plus'
+import { FormSchema, FormSetPropsType } from '@/types/form'
 
 export interface FormExpose {
   setValues: (data: Recordable) => void

+ 1 - 0
yudao-ui-admin-vue3/src/components/Form/src/Form.vue

@@ -20,6 +20,7 @@ import { findIndex } from '@/utils'
 import { set } from 'lodash-es'
 import { FormProps } from './types'
 import { Icon } from '@/components/Icon'
+import { FormSchema, FormSetPropsType } from '@/types/form'
 
 const { getPrefixCls } = useDesign()
 

+ 1 - 0
yudao-ui-admin-vue3/src/components/Form/src/componentMap.ts

@@ -20,6 +20,7 @@ import {
 } from 'element-plus'
 import { InputPassword } from '@/components/InputPassword'
 import { Editor } from '@/components/Editor'
+import { ComponentName } from '@/types/components'
 
 const componentMap: Recordable<Component, ComponentName> = {
   Radio: ElRadioGroup,

+ 1 - 0
yudao-ui-admin-vue3/src/components/Form/src/components/useRenderCheckbox.tsx

@@ -1,3 +1,4 @@
+import { FormSchema } from '@/types/form'
 import { ElCheckbox, ElCheckboxButton } from 'element-plus'
 import { defineComponent } from 'vue'
 

+ 1 - 0
yudao-ui-admin-vue3/src/components/Form/src/components/useRenderRadio.tsx

@@ -1,3 +1,4 @@
+import { FormSchema } from '@/types/form'
 import { ElRadio, ElRadioButton } from 'element-plus'
 import { defineComponent } from 'vue'
 

+ 10 - 1
yudao-ui-admin-vue3/src/components/Form/src/components/useRenderSelect.tsx

@@ -1,3 +1,5 @@
+import { FormSchema } from '@/types/form'
+import { ComponentOptions } from '@/types/components'
 import { ElOption, ElOptionGroup } from 'element-plus'
 import { getSlot } from '@/utils/tsxHelper'
 import { Slots } from 'vue'
@@ -29,8 +31,15 @@ export const useRenderSelect = (slots: Slots) => {
     // 如果有别名,就取别名
     const labelAlias = item?.componentProps?.optionsAlias?.labelField
     const valueAlias = item?.componentProps?.optionsAlias?.valueField
+
+    const { label, value, ...other } = option
+
     return (
-      <ElOption label={option[labelAlias || 'label']} value={option[valueAlias || 'value']}>
+      <ElOption
+        label={labelAlias ? option[labelAlias] : label}
+        value={valueAlias ? option[valueAlias] : value}
+        {...other}
+      >
         {{
           default: () =>
             // option 插槽名规则,{field}-option

+ 2 - 0
yudao-ui-admin-vue3/src/components/Form/src/helper.ts

@@ -2,6 +2,8 @@ import { useI18n } from '@/hooks/web/useI18n'
 import type { Slots } from 'vue'
 import { getSlot } from '@/utils/tsxHelper'
 import { PlaceholderMoel } from './types'
+import { FormSchema } from '@/types/form'
+import { ColProps } from '@/types/components'
 
 /**
  *

+ 2 - 0
yudao-ui-admin-vue3/src/components/Form/src/types.ts

@@ -1,3 +1,5 @@
+import { FormSchema } from '@/types/form'
+
 export interface PlaceholderMoel {
   placeholder?: string
   startPlaceholder?: string

+ 1 - 1
yudao-ui-admin-vue3/src/components/Icon/src/IconSelect.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import { cloneDeep } from 'lodash-es'
-import { ref, computed, CSSProperties, toRef, watch } from 'vue'
+import { ref, computed, CSSProperties, toRef, watch, defineEmits } from 'vue'
 import {
   ElInput,
   ElPopover,

+ 3 - 2
yudao-ui-admin-vue3/src/components/Infotip/src/Infotip.vue

@@ -1,8 +1,9 @@
 <script setup lang="ts">
-import { PropType } from 'vue'
-import { Highlight } from '@//components/Highlight'
+import { PropType, defineEmits } from 'vue'
+import { Highlight } from '@/components/Highlight'
 import { useDesign } from '@/hooks/web/useDesign'
 import { propTypes } from '@/utils/propTypes'
+import { TipSchema } from '@/types/infoTip'
 
 const { getPrefixCls } = useDesign()
 

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

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { ref, unref, computed, watch } from 'vue'
+import { ref, unref, computed, watch, defineEmits } from 'vue'
 import { ElInput } from 'element-plus'
 import { propTypes } from '@/utils/propTypes'
 import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'

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

@@ -3,11 +3,11 @@ import { computed, defineComponent, unref, PropType } from 'vue'
 import { ElMenu, ElScrollbar } from 'element-plus'
 import { useAppStore } from '@/store/modules/app'
 import { usePermissionStore } from '@/store/modules/permission'
-import type { LayoutType } from '@/config/app'
 import { useRenderMenuItem } from './components/useRenderMenuItem'
 import { useRouter } from 'vue-router'
 import { isUrl } from '@/utils/is'
 import { useDesign } from '@/hooks/web/useDesign'
+import { LayoutType } from '@/types/layout'
 
 const { getPrefixCls } = useDesign()
 

+ 2 - 1
yudao-ui-admin-vue3/src/components/Qrcode/src/Qrcode.vue

@@ -1,11 +1,12 @@
 <script setup lang="ts">
-import { PropType, nextTick, ref, watch, computed, unref } from 'vue'
+import { PropType, nextTick, ref, watch, computed, unref, defineEmits } from 'vue'
 import QRCode from 'qrcode'
 import { QRCodeRenderersOptions } from 'qrcode'
 import { cloneDeep } from 'lodash-es'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
 import { isString } from '@/utils/is'
+import { QrcodeLogo } from '@/types/qrcode'
 
 const props = defineProps({
   // img 或者 canvas,img不支持logo嵌套

+ 2 - 1
yudao-ui-admin-vue3/src/components/Search/src/Search.vue

@@ -1,12 +1,13 @@
 <script setup lang="ts">
 import { Form } from '@/components/Form'
-import { PropType, computed, unref, ref } from 'vue'
+import { PropType, computed, unref, ref, defineEmits } from 'vue'
 import { propTypes } from '@/utils/propTypes'
 import { ElButton } from 'element-plus'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useForm } from '@/hooks/web/useForm'
 import { findIndex } from '@/utils'
 import { cloneDeep } from 'lodash-es'
+import { FormSchema } from '@/types/form'
 
 const { t } = useI18n()
 

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

@@ -208,7 +208,7 @@ const clear = () => {
     <Icon icon="ep:setting" color="#fff" />
   </div>
 
-  <ElDrawer v-model="drawer" direction="rtl" size="350px">
+  <ElDrawer v-model="drawer" direction="rtl" size="350px" :z-index="4000">
     <template #header>
       <span class="text-16px font-700">{{ t('setting.projectSetting') }}</span>
     </template>

+ 1 - 1
yudao-ui-admin-vue3/src/components/Setting/src/components/ColorRadioPicker.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { PropType, watch, unref, ref } from 'vue'
+import { PropType, watch, unref, ref, defineEmits } from 'vue'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
 

+ 26 - 1
yudao-ui-admin-vue3/src/components/Setting/src/components/InterfaceDisplay.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { ElSwitch } from 'element-plus'
+import { ElSwitch, ElMessage } from 'element-plus'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useAppStore } from '@/store/modules/app'
 import { computed, ref, watch } from 'vue'
@@ -107,6 +107,21 @@ const greyModeChange = (show: boolean) => {
   appStore.setGreyMode(show)
 }
 
+// 动态路由
+const dynamicRouter = ref(appStore.getDynamicRouter)
+
+const dynamicRouterChange = (show: boolean) => {
+  ElMessage.info(t('setting.reExperienced'))
+  appStore.setDynamicRouter(show)
+}
+
+// 固定菜单
+const fixedMenu = ref(appStore.getFixedMenu)
+
+const fixedMenuChange = (show: boolean) => {
+  appStore.setFixedMenu(show)
+}
+
 const layout = computed(() => appStore.getLayout)
 
 watch(
@@ -185,5 +200,15 @@ watch(
       <span class="text-14px">{{ t('setting.greyMode') }}</span>
       <ElSwitch v-model="greyMode" @change="greyModeChange" />
     </div>
+
+    <div class="flex justify-between items-center">
+      <span class="text-14px">{{ t('setting.dynamicRouter') }}</span>
+      <ElSwitch v-model="dynamicRouter" @change="dynamicRouterChange" />
+    </div>
+
+    <div class="flex justify-between items-center">
+      <span class="text-14px">{{ t('setting.fixedMenu') }}</span>
+      <ElSwitch v-model="fixedMenu" @change="fixedMenuChange" />
+    </div>
   </div>
 </template>

+ 2 - 1
yudao-ui-admin-vue3/src/components/SizeDropdown/src/SizeDropdown.vue

@@ -5,6 +5,7 @@ import { useAppStore } from '@/store/modules/app'
 import { useI18n } from '@/hooks/web/useI18n'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
+import { ElementPlusSize } from '@/types/elementPlus'
 
 const { getPrefixCls } = useDesign()
 
@@ -20,7 +21,7 @@ const appStore = useAppStore()
 
 const sizeMap = computed(() => appStore.sizeMap)
 
-const setCurrentSize = (size: ElememtPlusSize) => {
+const setCurrentSize = (size: ElementPlusSize) => {
   appStore.setCurrentSize(size)
 }
 </script>

+ 36 - 9
yudao-ui-admin-vue3/src/components/TabMenu/src/TabMenu.vue

@@ -1,7 +1,7 @@
 <script lang="tsx">
 import { usePermissionStore } from '@/store/modules/permission'
 import { useAppStore } from '@/store/modules/app'
-import { computed, unref, defineComponent, watch, ref } from 'vue'
+import { computed, unref, defineComponent, watch, ref, onMounted } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { ElScrollbar } from 'element-plus'
 import { Icon } from '@/components/Icon'
@@ -28,6 +28,8 @@ export default defineComponent({
 
     const collapse = computed(() => appStore.getCollapse)
 
+    const fixedMenu = computed(() => appStore.getFixedMenu)
+
     const permissionStore = usePermissionStore()
 
     const routers = computed(() => permissionStore.getRouters)
@@ -38,6 +40,27 @@ export default defineComponent({
       appStore.setCollapse(!unref(collapse))
     }
 
+    onMounted(() => {
+      if (unref(fixedMenu)) {
+        const path = `/${unref(currentRoute).path.split('/')[1]}`
+        const children = unref(tabRouters).find(
+          (v) =>
+            (v.meta?.alwaysShow || (v?.children?.length && v?.children?.length > 1)) &&
+            v.path === path
+        )?.children
+
+        tabActive.value = path
+        if (children) {
+          permissionStore.setMenuTabRouters(
+            cloneDeep(children).map((v) => {
+              v.path = pathResolve(unref(tabActive), v.path)
+              return v
+            })
+          )
+        }
+      }
+    })
+
     watch(
       () => routers.value,
       (routers: AppRouteRecordRaw[]) => {
@@ -66,7 +89,7 @@ export default defineComponent({
     )
 
     // 是否显示菜单
-    const showMenu = ref(false)
+    const showMenu = ref(unref(fixedMenu) ? true : false)
 
     // tab高亮
     const tabActive = ref('')
@@ -77,9 +100,13 @@ export default defineComponent({
         window.open(item.path)
         return
       }
+      const newPath = item.children ? item.path : item.path.split('/')[0]
+      const oldPath = unref(tabActive)
       tabActive.value = item.children ? item.path : item.path.split('/')[0]
       if (item.children) {
-        showMenu.value = !unref(showMenu)
+        if (newPath === oldPath || !unref(showMenu)) {
+          showMenu.value = unref(fixedMenu) ? true : !unref(showMenu)
+        }
         if (unref(showMenu)) {
           permissionStore.setMenuTabRouters(
             cloneDeep(item.children).map((v) => {
@@ -96,7 +123,7 @@ export default defineComponent({
     }
 
     // 设置高亮
-    const isActice = (currentPath: string) => {
+    const isActive = (currentPath: string) => {
       const { path } = unref(currentRoute)
       if (tabPathMap[currentPath].includes(path)) {
         return true
@@ -105,7 +132,7 @@ export default defineComponent({
     }
 
     const mouseleave = () => {
-      if (!unref(showMenu)) return
+      if (!unref(showMenu) || unref(fixedMenu)) return
       showMenu.value = false
     }
 
@@ -114,7 +141,7 @@ export default defineComponent({
         id={`${variables.namespace}-menu`}
         class={[
           prefixCls,
-          'relative bg-[var(--left-menu-bg-color)] top-1px z-999',
+          'relative bg-[var(--left-menu-bg-color)] top-1px z-3000',
           {
             'w-[var(--tab-menu-max-width)]': !unref(collapse),
             'w-[var(--tab-menu-min-width)]': unref(collapse)
@@ -140,7 +167,7 @@ export default defineComponent({
                       `${prefixCls}__item`,
                       'text-center text-12px relative py-12px cursor-pointer',
                       {
-                        'is-active': isActice(v.path)
+                        'is-active': isActive(v.path)
                       }
                     ]}
                     onClick={() => {
@@ -174,8 +201,8 @@ export default defineComponent({
             {
               '!left-[var(--tab-menu-min-width)]': unref(collapse),
               '!left-[var(--tab-menu-max-width)]': !unref(collapse),
-              '!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu),
-              '!w-0': !unref(showMenu)
+              '!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu) || unref(fixedMenu),
+              '!w-0': !unref(showMenu) && !unref(fixedMenu)
             }
           ]}
           style="transition: width var(--transition-time-02), left var(--transition-time-02);"

+ 4 - 4
yudao-ui-admin-vue3/src/components/TabMenu/src/helper.ts

@@ -28,9 +28,9 @@ export const filterMenusPath = (
     let data: Nullable<AppRouteRecordRaw> = null
     const meta = (v.meta ?? {}) as RouteMeta
     if (!meta.hidden || meta.canTo) {
-      const allParentPaht = getAllParentPath<AppRouteRecordRaw>(allRoutes, v.path)
+      const allParentPath = getAllParentPath<AppRouteRecordRaw>(allRoutes, v.path)
 
-      const fullPath = isUrl(v.path) ? v.path : allParentPaht.join('/')
+      const fullPath = isUrl(v.path) ? v.path : allParentPath.join('/')
 
       data = cloneDeep(v)
       data.path = fullPath
@@ -42,8 +42,8 @@ export const filterMenusPath = (
         res.push(data)
       }
 
-      if (allParentPaht.length && Reflect.has(tabPathMap, allParentPaht[0])) {
-        tabPathMap[allParentPaht[0]].push(fullPath)
+      if (allParentPath.length && Reflect.has(tabPathMap, allParentPath[0])) {
+        tabPathMap[allParentPath[0]].push(fullPath)
       }
     }
   }

+ 3 - 0
yudao-ui-admin-vue3/src/components/Table/index.ts

@@ -1,9 +1,12 @@
 import Table from './src/Table.vue'
+import { ElTable } from 'element-plus'
+import { TableSetPropsType } from '@/types/table'
 
 export interface TableExpose {
   setProps: (props: Recordable) => void
   setColumn: (columnProps: TableSetPropsType[]) => void
   selections: Recordable[]
+  elTableRef: ComponentRef<typeof ElTable>
 }
 
 export { Table }

+ 1 - 0
yudao-ui-admin-vue3/src/components/Table/src/Table.vue

@@ -6,6 +6,7 @@ import { setIndex } from './helper'
 import { getSlot } from '@/utils/tsxHelper'
 import type { TableProps } from './types'
 import { set } from 'lodash-es'
+import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table'
 
 export default defineComponent({
   name: 'Table',

+ 2 - 0
yudao-ui-admin-vue3/src/components/Table/src/types.ts

@@ -1,3 +1,5 @@
+import { Pagination, TableColumn } from '@/types/table'
+
 export type TableProps = {
   pageSize?: number
   currentPage?: number

+ 2 - 2
yudao-ui-admin-vue3/src/components/UserInfo/src/UserInfo.vue

@@ -36,8 +36,8 @@ const loginOut = () => {
   })
     .then(async () => {
       userStore.loginOut()
-      tagsViewStore.delAllViews
-      replace('/login')
+      tagsViewStore.delAllViews()
+      replace('/login?redirect=/index')
     })
     .catch(() => {})
 }

+ 0 - 104
yudao-ui-admin-vue3/src/config/app.ts

@@ -1,104 +0,0 @@
-import { useCache } from '@/hooks/web/useCache'
-
-const { wsCache } = useCache()
-
-export type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'
-
-export type ThemeTypes = {
-  elColorPrimary?: string
-  leftMenuBorderColor?: string
-  leftMenuBgColor?: string
-  leftMenuBgLightColor?: string
-  leftMenuBgActiveColor?: string
-  leftMenuCollapseBgActiveColor?: string
-  leftMenuTextColor?: string
-  leftMenuTextActiveColor?: string
-  logoTitleTextColor?: string
-  logoBorderColor?: string
-  topHeaderBgColor?: string
-  topHeaderTextColor?: string
-  topHeaderHoverColor?: string
-  topToolBorderColor?: string
-}
-export interface AppState {
-  breadcrumb: boolean
-  breadcrumbIcon: boolean
-  collapse: boolean
-  uniqueOpened: boolean
-  hamburger: boolean
-  screenfull: boolean
-  size: boolean
-  locale: boolean
-  tagsView: boolean
-  tagsViewIcon: boolean
-  logo: boolean
-  fixedHeader: boolean
-  greyMode: boolean
-  pageLoading: boolean
-  layout: LayoutType
-  title: string
-  userInfo: string
-  isDark: boolean
-  currentSize: ElememtPlusSize
-  sizeMap: ElememtPlusSize[]
-  mobile: boolean
-  footer: boolean
-  theme: ThemeTypes
-}
-
-export const appModules: AppState = {
-  userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
-  sizeMap: ['default', 'large', 'small'],
-  mobile: false, // 是否是移动端
-  title: import.meta.env.VITE_APP_TITLE, // 标题
-  pageLoading: false, // 路由跳转loading
-
-  breadcrumb: true, // 面包屑
-  breadcrumbIcon: false, // 面包屑图标
-  collapse: false, // 折叠菜单
-  uniqueOpened: true, // 是否只保持一个子菜单的展开
-  hamburger: true, // 折叠图标
-  screenfull: true, // 全屏图标
-  size: true, // 尺寸图标
-  locale: true, // 多语言图标
-  tagsView: true, // 标签页
-  tagsViewIcon: false, // 是否显示标签图标
-  logo: true, // logo
-  fixedHeader: true, // 固定toolheader
-  footer: true, // 显示页脚
-  greyMode: false, // 是否开始灰色模式,用于特殊悼念日
-
-  layout: wsCache.get('layout') || 'topLeft', // layout布局
-  isDark: wsCache.get('isDark') || false, // 是否是暗黑模式
-  currentSize: wsCache.get('default') || 'default', // 组件尺寸
-  theme: wsCache.get('theme') || {
-    // 主题色
-    elColorPrimary: '#409eff',
-    // 左侧菜单边框颜色
-    leftMenuBorderColor: 'inherit',
-    // 左侧菜单背景颜色
-    leftMenuBgColor: '#001529',
-    // 左侧菜单浅色背景颜色
-    leftMenuBgLightColor: '#0f2438',
-    // 左侧菜单选中背景颜色
-    leftMenuBgActiveColor: 'var(--el-color-primary)',
-    // 左侧菜单收起选中背景颜色
-    leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
-    // 左侧菜单字体颜色
-    leftMenuTextColor: '#bfcbd9',
-    // 左侧菜单选中字体颜色
-    leftMenuTextActiveColor: '#fff',
-    // logo字体颜色
-    logoTitleTextColor: '#fff',
-    // logo边框颜色
-    logoBorderColor: 'inherit',
-    // 头部背景颜色
-    topHeaderBgColor: '#fff',
-    // 头部字体颜色
-    topHeaderTextColor: 'inherit',
-    // 头部悬停颜色
-    topHeaderHoverColor: '#f6f6f6',
-    // 头部边框颜色
-    topToolBorderColor: '#eee'
-  }
-}

+ 18 - 8
yudao-ui-admin-vue3/src/config/axios/index.ts

@@ -1,4 +1,10 @@
-import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
+import axios, {
+  AxiosInstance,
+  AxiosRequestConfig,
+  AxiosRequestHeaders,
+  AxiosResponse,
+  AxiosError
+} from 'axios'
 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
 import qs from 'qs'
 import { config } from '@/config/axios/config'
@@ -48,7 +54,8 @@ service.interceptors.request.use(
     const data = config.data || false
     if (
       config.method?.toUpperCase() === 'POST' &&
-      config!.headers!['Content-Type'] === 'application/x-www-form-urlencoded'
+      (config.headers as AxiosRequestHeaders)['Content-Type'] ===
+        'application/x-www-form-urlencoded'
     ) {
       config.data = qs.stringify(data)
     }
@@ -121,12 +128,18 @@ service.interceptors.response.use(
           const refreshTokenRes = await refreshToken()
           // 2.1 刷新成功,则回放队列的请求 + 当前请求
           setToken(refreshTokenRes.data)
-          requestList.forEach((cb: any) => cb())
+          ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken()
+          requestList.forEach((cb: any) => {
+            cb()
+          })
+          requestList = []
           return service(response.config)
         } catch (e) {
           // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
           // 2.2 刷新失败,只回放队列的请求
-          requestList.forEach((cb: any) => cb())
+          requestList.forEach((cb: any) => {
+            cb()
+          })
           // 提示是否要登出。即不回放当前请求!不然会形成递归
           return handleAuthorized()
         } finally {
@@ -187,10 +200,7 @@ service.interceptors.response.use(
 )
 
 const refreshToken = async () => {
-  return await service({
-    url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken(),
-    method: 'post'
-  })
+  return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
 }
 const handleAuthorized = () => {
   const { t } = useI18n()

+ 0 - 32
yudao-ui-admin-vue3/src/config/locale.ts

@@ -1,32 +0,0 @@
-import { useCache } from '@/hooks/web/useCache'
-import zhCn from 'element-plus/es/locale/lang/zh-cn'
-import en from 'element-plus/es/locale/lang/en'
-
-const { wsCache } = useCache()
-
-export const elLocaleMap = {
-  'zh-CN': zhCn,
-  en: en
-}
-export interface LocaleState {
-  currentLocale: LocaleDropdownType
-  localeMap: LocaleDropdownType[]
-}
-
-export const localeModules: LocaleState = {
-  currentLocale: {
-    lang: wsCache.get('lang') || 'zh-CN',
-    elLocale: elLocaleMap[wsCache.get('lang') || 'zh-CN']
-  },
-  // 多语言
-  localeMap: [
-    {
-      lang: 'zh-CN',
-      name: '简体中文'
-    },
-    {
-      lang: 'en',
-      name: 'English'
-    }
-  ]
-}

+ 1 - 0
yudao-ui-admin-vue3/src/hooks/web/useConfigGlobal.ts

@@ -1,3 +1,4 @@
+import { ConfigGlobalTypes } from '@/types/configGlobal'
 import { inject } from 'vue'
 
 export const useConfigGlobal = () => {

+ 4 - 0
yudao-ui-admin-vue3/src/hooks/web/useCrudSchemas.ts

@@ -1,6 +1,10 @@
 import { reactive } from 'vue'
 import { eachTree, treeMap, filter } from '@/utils/tree'
 import { getIntDictOptions } from '@/utils/dict'
+import { FormSchema } from '@/types/form'
+import { TableColumn } from '@/types/table'
+import { DescriptionsSchema } from '@/types/descriptions'
+import { ComponentOptions } from '@/types/components'
 
 export type CrudSchema = Omit<TableColumn, 'children'> & {
   search?: CrudSearchParams

+ 1 - 0
yudao-ui-admin-vue3/src/hooks/web/useForm.ts

@@ -2,6 +2,7 @@ import type { Form, FormExpose } from '@/components/Form'
 import type { ElForm } from 'element-plus'
 import { ref, unref, nextTick } from 'vue'
 import type { FormProps } from '@/components/Form/src/types'
+import { FormSchema, FormSetPropsType } from '@/types/form'
 
 export const useForm = (props?: FormProps) => {
   // From实例

+ 1 - 0
yudao-ui-admin-vue3/src/hooks/web/useIcon.ts

@@ -1,6 +1,7 @@
 import { h } from 'vue'
 import type { VNode } from 'vue'
 import { Icon } from '@/components/Icon'
+import { IconTypes } from '@/types/icon'
 
 export const useIcon = (props: IconTypes): VNode => {
   return h(Icon, props)

+ 8 - 3
yudao-ui-admin-vue3/src/hooks/web/useTable.ts

@@ -4,6 +4,7 @@ import { ElMessage, ElMessageBox, ElTable } from 'element-plus'
 import { computed, nextTick, reactive, ref, unref, watch } from 'vue'
 import type { TableProps } from '@/components/Table/src/types'
 import { useI18n } from '@/hooks/web/useI18n'
+import { TableSetPropsType } from '@/types/table'
 
 const { t } = useI18n()
 interface ResponseType<T = any> {
@@ -150,13 +151,17 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
     },
     // 与Search组件结合
     setSearchParams: (data: Recordable) => {
-      tableObject.currentPage = 1
       tableObject.params = Object.assign(tableObject.params, {
         pageSize: tableObject.pageSize,
-        pageNo: tableObject.currentPage,
+        pageNo: 1,
         ...data
       })
-      methods.getList()
+      // 页码不等于1时更新页码重新获取数据,页码等于1时重新获取数据
+      if (tableObject.currentPage !== 1) {
+        tableObject.currentPage = 1
+      } else {
+        methods.getList()
+      }
     },
     // 删除数据
     delList: async (

+ 16 - 3
yudao-ui-admin-vue3/src/layout/components/useRenderLayout.tsx

@@ -32,6 +32,9 @@ const fixedHeader = computed(() => appStore.getFixedHeader)
 // 是否是移动端
 const mobile = computed(() => appStore.getMobile)
 
+// 固定菜单
+const fixedMenu = computed(() => appStore.getFixedMenu)
+
 export const useRenderLayout = () => {
   const renderClassic = () => {
     return (
@@ -213,9 +216,13 @@ export const useRenderLayout = () => {
               'h-[100%]',
               {
                 'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)]':
-                  collapse.value,
+                  collapse.value && !fixedMenu.value,
                 'w-[calc(100%-var(--tab-menu-max-width))] left-[var(--tab-menu-max-width)]':
-                  !collapse.value
+                  !collapse.value && !fixedMenu.value,
+                'w-[calc(100%-var(--tab-menu-min-width)-var(--left-menu-max-width))] ml-[var(--left-menu-max-width)]':
+                  collapse.value && fixedMenu.value,
+                'w-[calc(100%-var(--tab-menu-max-width)-var(--left-menu-max-width))] ml-[var(--left-menu-max-width)]':
+                  !collapse.value && fixedMenu.value
               }
             ]}
             style="transition: all var(--transition-time-02);"
@@ -239,7 +246,13 @@ export const useRenderLayout = () => {
                       'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)] mt-[var(--logo-height)]':
                         collapse.value && fixedHeader.value,
                       'w-[calc(100%-var(--tab-menu-max-width))] left-[var(--tab-menu-max-width)] mt-[var(--logo-height)]':
-                        !collapse.value && fixedHeader.value
+                        !collapse.value && fixedHeader.value,
+                      '!fixed top-0 left-[var(--tab-menu-min-width)+var(--left-menu-max-width)] z-10':
+                        fixedHeader.value && fixedMenu.value,
+                      'w-[calc(100%-var(--tab-menu-min-width)-var(--left-menu-max-width))] left-[var(--tab-menu-min-width)+var(--left-menu-max-width)] mt-[var(--logo-height)]':
+                        collapse.value && fixedHeader.value && fixedMenu.value,
+                      'w-[calc(100%-var(--tab-menu-max-width)-var(--left-menu-max-width))] left-[var(--tab-menu-max-width)+var(--left-menu-max-width)] mt-[var(--logo-height)]':
+                        !collapse.value && fixedHeader.value && fixedMenu.value
                     }
                   ]}
                   style="transition: width var(--transition-time-02), left var(--transition-time-02);"

+ 4 - 1
yudao-ui-admin-vue3/src/locales/en.ts

@@ -91,7 +91,10 @@ export default {
     copyFailed: 'Copy failed',
     footer: 'Footer',
     uniqueOpened: 'Unique opened',
-    tagsViewIcon: 'Tags view icon'
+    tagsViewIcon: 'Tags view icon',
+    dynamicRouter: 'Dynamic router',
+    reExperienced: 'Please exit the login experience again',
+    fixedMenu: 'Fixed menu'
   },
   size: {
     default: 'Default',

+ 4 - 1
yudao-ui-admin-vue3/src/locales/zh-CN.ts

@@ -91,7 +91,10 @@ export default {
     copyFailed: '拷贝失败',
     footer: '页脚',
     uniqueOpened: '菜单手风琴',
-    tagsViewIcon: '标签页图标'
+    tagsViewIcon: '标签页图标',
+    dynamicRouter: '动态路由',
+    reExperienced: '请重新退出登录体验',
+    fixedMenu: '固定菜单'
   },
   size: {
     default: '默认',

+ 0 - 3
yudao-ui-admin-vue3/src/store/index.ts

@@ -1,11 +1,8 @@
 import type { App } from 'vue'
 import { createPinia } from 'pinia'
-import piniaPluginPersist from 'pinia-plugin-persist'
 
 const store = createPinia()
 
-store.use(piniaPluginPersist)
-
 export const setupStore = (app: App<Element>) => {
   app.use(store)
 }

+ 100 - 11
yudao-ui-admin-vue3/src/store/modules/app.ts

@@ -1,18 +1,100 @@
 import { defineStore } from 'pinia'
 import { store } from '../index'
-import { useCache } from '@/hooks/web/useCache'
-import { appModules } from '@/config/app'
-import type { AppState, LayoutType, ThemeTypes } from '@/config/app'
 import { setCssVar, humpToUnderline } from '@/utils'
 import { ElMessage } from 'element-plus'
+import { useCache } from '@/hooks/web/useCache'
+import { ElementPlusSize } from '@/types/elementPlus'
+import { LayoutType } from '@/types/layout'
+import { ThemeTypes } from '@/types/theme'
 
 const { wsCache } = useCache()
 
-export const useAppStore = defineStore({
-  id: 'app',
-  state: (): AppState => appModules,
-  persist: {
-    enabled: true
+interface AppState {
+  breadcrumb: boolean
+  breadcrumbIcon: boolean
+  collapse: boolean
+  uniqueOpened: boolean
+  hamburger: boolean
+  screenfull: boolean
+  size: boolean
+  locale: boolean
+  tagsView: boolean
+  tagsViewIcon: boolean
+  logo: boolean
+  fixedHeader: boolean
+  greyMode: boolean
+  pageLoading: boolean
+  layout: LayoutType
+  title: string
+  userInfo: string
+  isDark: boolean
+  currentSize: ElementPlusSize
+  sizeMap: ElementPlusSize[]
+  mobile: boolean
+  footer: boolean
+  theme: ThemeTypes
+  fixedMenu: boolean
+}
+
+export const useAppStore = defineStore('app', {
+  state: (): AppState => {
+    return {
+      userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
+      sizeMap: ['default', 'large', 'small'],
+      mobile: false, // 是否是移动端
+      title: import.meta.env.VITE_APP_TITLE, // 标题
+      pageLoading: false, // 路由跳转loading
+
+      breadcrumb: true, // 面包屑
+      breadcrumbIcon: true, // 面包屑图标
+      collapse: false, // 折叠菜单
+      uniqueOpened: true, // 是否只保持一个子菜单的展开
+      hamburger: true, // 折叠图标
+      screenfull: true, // 全屏图标
+      size: true, // 尺寸图标
+      locale: true, // 多语言图标
+      tagsView: true, // 标签页
+      tagsViewIcon: true, // 是否显示标签图标
+      logo: true, // logo
+      fixedHeader: true, // 固定toolheader
+      footer: true, // 显示页脚
+      greyMode: false, // 是否开始灰色模式,用于特殊悼念日
+      fixedMenu: wsCache.get('fixedMenu') || false, // 是否固定菜单
+
+      layout: wsCache.get('layout') || 'classic', // layout布局
+      isDark: wsCache.get('isDark') || false, // 是否是暗黑模式
+      currentSize: wsCache.get('default') || 'default', // 组件尺寸
+      theme: wsCache.get('theme') || {
+        // 主题色
+        elColorPrimary: '#409eff',
+        // 左侧菜单边框颜色
+        leftMenuBorderColor: 'inherit',
+        // 左侧菜单背景颜色
+        leftMenuBgColor: '#001529',
+        // 左侧菜单浅色背景颜色
+        leftMenuBgLightColor: '#0f2438',
+        // 左侧菜单选中背景颜色
+        leftMenuBgActiveColor: 'var(--el-color-primary)',
+        // 左侧菜单收起选中背景颜色
+        leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
+        // 左侧菜单字体颜色
+        leftMenuTextColor: '#bfcbd9',
+        // 左侧菜单选中字体颜色
+        leftMenuTextActiveColor: '#fff',
+        // logo字体颜色
+        logoTitleTextColor: '#fff',
+        // logo边框颜色
+        logoBorderColor: 'inherit',
+        // 头部背景颜色
+        topHeaderBgColor: '#fff',
+        // 头部字体颜色
+        topHeaderTextColor: 'inherit',
+        // 头部悬停颜色
+        topHeaderHoverColor: '#f6f6f6',
+        // 头部边框颜色
+        topToolBorderColor: '#eee'
+      }
+    }
   },
   getters: {
     getBreadcrumb(): boolean {
@@ -54,6 +136,9 @@ export const useAppStore = defineStore({
     getGreyMode(): boolean {
       return this.greyMode
     },
+    getFixedMenu(): boolean {
+      return this.fixedMenu
+    },
     getPageLoading(): boolean {
       return this.pageLoading
     },
@@ -69,10 +154,10 @@ export const useAppStore = defineStore({
     getIsDark(): boolean {
       return this.isDark
     },
-    getCurrentSize(): ElememtPlusSize {
+    getCurrentSize(): ElementPlusSize {
       return this.currentSize
     },
-    getSizeMap(): ElememtPlusSize[] {
+    getSizeMap(): ElementPlusSize[] {
       return this.sizeMap
     },
     getMobile(): boolean {
@@ -125,6 +210,10 @@ export const useAppStore = defineStore({
     setGreyMode(greyMode: boolean) {
       this.greyMode = greyMode
     },
+    setFixedMenu(fixedMenu: boolean) {
+      wsCache.set('fixedMenu', fixedMenu)
+      this.fixedMenu = fixedMenu
+    },
     setPageLoading(pageLoading: boolean) {
       this.pageLoading = pageLoading
     },
@@ -150,7 +239,7 @@ export const useAppStore = defineStore({
       }
       wsCache.set('isDark', this.isDark)
     },
-    setCurrentSize(currentSize: ElememtPlusSize) {
+    setCurrentSize(currentSize: ElementPlusSize) {
       this.currentSize = currentSize
       wsCache.set('currentSize', this.currentSize)
     },

+ 1 - 5
yudao-ui-admin-vue3/src/store/modules/dict.ts

@@ -16,14 +16,10 @@ export interface DictState {
   dictMap: Recordable
 }
 
-export const useDictStore = defineStore({
-  id: 'dict',
+export const useDictStore = defineStore('dict', {
   state: (): DictState => ({
     dictMap: {}
   }),
-  persist: {
-    enabled: true
-  },
   getters: {
     getDictMap(): Recordable {
       return this.dictMap

+ 31 - 7
yudao-ui-admin-vue3/src/store/modules/locale.ts

@@ -1,16 +1,40 @@
 import { defineStore } from 'pinia'
 import { store } from '../index'
+import zhCn from 'element-plus/es/locale/lang/zh-cn'
+import en from 'element-plus/es/locale/lang/en'
 import { useCache } from '@/hooks/web/useCache'
-import { localeModules, elLocaleMap } from '@/config/locale'
-import type { LocaleState } from '@/config/locale'
+import { LocaleDropdownType } from '@/types/localeDropdown'
 
 const { wsCache } = useCache()
 
-export const useLocaleStore = defineStore({
-  id: 'locales',
-  state: (): LocaleState => localeModules,
-  persist: {
-    enabled: true
+const elLocaleMap = {
+  'zh-CN': zhCn,
+  en: en
+}
+interface LocaleState {
+  currentLocale: LocaleDropdownType
+  localeMap: LocaleDropdownType[]
+}
+
+export const useLocaleStore = defineStore('locales', {
+  state: (): LocaleState => {
+    return {
+      currentLocale: {
+        lang: wsCache.get('lang') || 'zh-CN',
+        elLocale: elLocaleMap[wsCache.get('lang') || 'zh-CN']
+      },
+      // 多语言
+      localeMap: [
+        {
+          lang: 'zh-CN',
+          name: '简体中文'
+        },
+        {
+          lang: 'en',
+          name: 'English'
+        }
+      ]
+    }
   },
   getters: {
     getCurrentLocale(): LocaleDropdownType {

+ 1 - 5
yudao-ui-admin-vue3/src/store/modules/permission.ts

@@ -14,16 +14,12 @@ export interface PermissionState {
   menuTabRouters: AppRouteRecordRaw[]
 }
 
-export const usePermissionStore = defineStore({
-  id: 'permission',
+export const usePermissionStore = defineStore('permission', {
   state: (): PermissionState => ({
     routers: [],
     addRouters: [],
     menuTabRouters: []
   }),
-  persist: {
-    enabled: true
-  },
   getters: {
     getRouters(): AppRouteRecordRaw[] {
       return this.routers

+ 1 - 2
yudao-ui-admin-vue3/src/store/modules/tagsView.ts

@@ -10,8 +10,7 @@ export interface TagsViewState {
   cachedViews: Set<string>
 }
 
-export const useTagsViewStore = defineStore({
-  id: 'tagsView',
+export const useTagsViewStore = defineStore('tagsView', {
   state: (): TagsViewState => ({
     visitedViews: [],
     cachedViews: new Set()

+ 1 - 2
yudao-ui-admin-vue3/src/store/modules/user.ts

@@ -16,8 +16,7 @@ interface UserInfoVO {
   user: UserVO
 }
 
-export const useUserStore = defineStore({
-  id: 'admin-user',
+export const useUserStore = defineStore('admin-user', {
   state: (): UserInfoVO => ({
     permissions: [],
     roles: [],

+ 52 - 0
yudao-ui-admin-vue3/src/types/components.d.ts

@@ -0,0 +1,52 @@
+export type ComponentName =
+  | 'Radio'
+  | 'RadioButton'
+  | 'Checkbox'
+  | 'CheckboxButton'
+  | 'Input'
+  | 'Autocomplete'
+  | 'InputNumber'
+  | 'Select'
+  | 'Cascader'
+  | 'Switch'
+  | 'Slider'
+  | 'TimePicker'
+  | 'DatePicker'
+  | 'Rate'
+  | 'ColorPicker'
+  | 'Transfer'
+  | 'Divider'
+  | 'TimeSelect'
+  | 'SelectV2'
+  | 'InputPassword'
+  | 'Editor'
+
+export type ColProps = {
+  span?: number
+  xs?: number
+  sm?: number
+  md?: number
+  lg?: number
+  xl?: number
+  tag?: string
+}
+
+export type ComponentOptions = {
+  label?: string
+  value?: FormValueType
+  disabled?: boolean
+  key?: string | number
+  children?: ComponentOptions[]
+  options?: ComponentOptions[]
+} & Recordable
+
+export type ComponentOptionsAlias = {
+  labelField?: string
+  valueField?: string
+}
+
+export type ComponentProps = {
+  optionsAlias?: ComponentOptionsAlias
+  options?: ComponentOptions[]
+  optionsSlot?: boolean
+} & Recordable

+ 4 - 0
yudao-ui-admin-vue3/src/types/configGlobal.d.ts

@@ -0,0 +1,4 @@
+import { ElementPlusSize } from './elementPlus'
+export interface ConfigGlobalTypes {
+  size?: ElementPlusSize
+}

+ 7 - 0
yudao-ui-admin-vue3/src/types/contextMenu.d.ts

@@ -0,0 +1,7 @@
+export type contextMenuSchema = {
+  disabled?: boolean
+  divided?: boolean
+  icon?: string
+  label: string
+  command?: (item: contextMenuSchema) => void
+}

+ 1 - 1
yudao-ui-admin-vue3/types/componentType/descriptions.d.ts → yudao-ui-admin-vue3/src/types/descriptions.d.ts

@@ -1,4 +1,4 @@
-declare interface DescriptionsSchema {
+export interface DescriptionsSchema {
   span?: number // 占多少分
   field: string // 字段名
   label?: string // label名

+ 3 - 0
yudao-ui-admin-vue3/src/types/elementPlus.d.ts

@@ -0,0 +1,3 @@
+export type ElementPlusSize = 'default' | 'small' | 'large'
+
+export type ElementPlusInfoType = 'success' | 'info' | 'warning' | 'danger'

+ 45 - 0
yudao-ui-admin-vue3/src/types/form.d.ts

@@ -0,0 +1,45 @@
+import type { CSSProperties } from 'vue'
+import { ColProps, ComponentProps, ComponentName } from '@/types/components'
+import { FormValueType, FormValueType } from '@/types/form'
+import type { AxiosPromise } from 'axios'
+
+export type FormSetPropsType = {
+  field: string
+  path: string
+  value: any
+}
+
+export type FormValueType = string | number | string[] | number[] | boolean | undefined | null
+
+export type FormItemProps = {
+  labelWidth?: string | number
+  required?: boolean
+  rules?: Recordable
+  error?: string
+  showMessage?: boolean
+  inlineMessage?: boolean
+  style?: CSSProperties
+}
+
+export type FormSchema = {
+  // 唯一值
+  field: string
+  // 标题
+  label?: string
+  // 提示
+  labelMessage?: string
+  // col组件属性
+  colProps?: ColProps
+  // 表单组件属性,slots对应的是表单组件的插槽,规则:${field}-xxx,具体可以查看element-plus文档
+  componentProps?: { slots?: Recordable } & ComponentProps
+  // formItem组件属性
+  formItemProps?: FormItemProps
+  // 渲染的组件
+  component?: ComponentName
+  // 初始值
+  value?: FormValueType
+  // 是否隐藏
+  hidden?: boolean
+  // 远程加载下拉项
+  api?: <T = any>() => AxiosPromise<T>
+}

+ 1 - 1
yudao-ui-admin-vue3/types/componentType/icon.d.ts → yudao-ui-admin-vue3/src/types/icon.d.ts

@@ -1,4 +1,4 @@
-declare interface IconTypes {
+export interface IconTypes {
   size?: number
   color?: string
   icon: string

+ 1 - 1
yudao-ui-admin-vue3/types/componentType/infotip.d.ts → yudao-ui-admin-vue3/src/types/infoTip.d.ts

@@ -1,4 +1,4 @@
-declare interface TipSchema {
+export interface TipSchema {
   label: string
   keys?: string[]
 }

+ 1 - 0
yudao-ui-admin-vue3/src/types/layout.d.ts

@@ -0,0 +1 @@
+export type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'

+ 2 - 2
yudao-ui-admin-vue3/types/componentType/localeDropdown.d.ts → yudao-ui-admin-vue3/src/types/localeDropdown.d.ts

@@ -1,9 +1,9 @@
-declare interface Language {
+export interface Language {
   el: Recordable
   name: string
 }
 
-declare interface LocaleDropdownType {
+export interface LocaleDropdownType {
   lang: LocaleType
   name?: string
   elLocale?: Language

+ 1 - 1
yudao-ui-admin-vue3/types/componentType/qrcode.d.ts → yudao-ui-admin-vue3/src/types/qrcode.d.ts

@@ -1,4 +1,4 @@
-declare interface QrcodeLogo {
+export interface QrcodeLogo {
   src?: string
   logoSize?: number
   bgColor?: string

+ 4 - 4
yudao-ui-admin-vue3/types/componentType/table.d.ts → yudao-ui-admin-vue3/src/types/table.d.ts

@@ -1,16 +1,16 @@
-declare type TableColumn = {
+export type TableColumn = {
   field: string
   label?: string
   children?: TableColumn[]
 } & Recordable
 
-declare type TableSlotDefault = {
+export type TableSlotDefault = {
   row: Recordable
   column: TableColumn
   $index: number
 } & Recordable
 
-declare interface Pagination {
+export interface Pagination {
   small?: boolean
   background?: boolean
   pageSize?: number
@@ -29,7 +29,7 @@ declare interface Pagination {
   hideOnSinglePage?: boolean
 }
 
-declare interface TableSetPropsType {
+export interface TableSetPropsType {
   field: string
   path: string
   value: any

+ 16 - 0
yudao-ui-admin-vue3/src/types/theme.d.ts

@@ -0,0 +1,16 @@
+export type ThemeTypes = {
+  elColorPrimary?: string
+  leftMenuBorderColor?: string
+  leftMenuBgColor?: string
+  leftMenuBgLightColor?: string
+  leftMenuBgActiveColor?: string
+  leftMenuCollapseBgActiveColor?: string
+  leftMenuTextColor?: string
+  leftMenuTextActiveColor?: string
+  logoTitleTextColor?: string
+  logoBorderColor?: string
+  topHeaderBgColor?: string
+  topHeaderTextColor?: string
+  topHeaderHoverColor?: string
+  topToolBorderColor?: string
+}

+ 1 - 0
yudao-ui-admin-vue3/src/utils/dict.ts

@@ -2,6 +2,7 @@
  * 数据字典工具类
  */
 import { useDictStoreWithOut } from '@/store/modules/dict'
+import { ElementPlusInfoType } from '@/types/elementPlus'
 
 const dictStore = useDictStoreWithOut()
 

+ 17 - 12
yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue

@@ -103,20 +103,25 @@ const getCookie = () => {
 // 登录
 const handleLogin = async (params) => {
   loginLoading.value = true
-  await getTenantId()
-  const data = await validForm()
-  if (!data) {
+  try {
+    await getTenantId()
+    const data = await validForm()
+    if (!data) {
+      return
+    }
+    loginData.loginForm.captchaVerification = params.captchaVerification
+    const res = await LoginApi.loginApi(loginData.loginForm)
+    if (!res) {
+      return
+    }
+    setToken(res)
+    if (!redirect.value) {
+      redirect.value = '/'
+    }
+    push({ path: redirect.value || permissionStore.addRouters[0].path })
+  } finally {
     loginLoading.value = false
-    return
-  }
-  loginData.loginForm.captchaVerification = params.captchaVerification
-  const res = await LoginApi.loginApi(loginData.loginForm)
-  setToken(res)
-  if (!redirect.value) {
-    redirect.value = '/'
   }
-  push({ path: redirect.value || permissionStore.addRouters[0].path })
-  loginLoading.value = false
 }
 
 // 社交登录

+ 1 - 0
yudao-ui-admin-vue3/src/views/Login/components/RegisterForm.vue

@@ -7,6 +7,7 @@ import { ElInput, FormRules } from 'element-plus'
 import { useValidator } from '@/hooks/web/useValidator'
 import { useLoginState, LoginStateEnum } from './useLogin'
 import LoginFormTitle from './LoginFormTitle.vue'
+import { FormSchema } from '@/types/form'
 
 const { register, elFormRef } = useForm()
 const { handleBackLogin, getLoginState } = useLoginState()

+ 22 - 16
yudao-ui-admin-vue3/src/views/bpm/form/index.vue

@@ -49,23 +49,29 @@ const handleUpdate = async (row: FormVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as FormVO
-    if (actionType.value === 'create') {
-      await FormApi.createFormApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await FormApi.updateFormApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as FormVO
+        if (actionType.value === 'create') {
+          await FormApi.createFormApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await FormApi.updateFormApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 23 - 17
yudao-ui-admin-vue3/src/views/bpm/group/index.vue

@@ -62,24 +62,30 @@ const handleUpdate = async (row: UserGroupVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as UserGroupVO
-    data.memberUserIds = userIds.value
-    if (actionType.value === 'create') {
-      await UserGroupApi.createUserGroupApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await UserGroupApi.updateUserGroupApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as UserGroupVO
+        data.memberUserIds = userIds.value
+        if (actionType.value === 'create') {
+          await UserGroupApi.createUserGroupApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await UserGroupApi.updateUserGroupApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // 根据用户名获取用户真实名

+ 22 - 16
yudao-ui-admin-vue3/src/views/bpm/model/index.vue

@@ -51,23 +51,29 @@ const handleUpdate = async (row: ModelVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as ModelVO
-    if (actionType.value === 'create') {
-      await ModelApi.createModelApi(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await ModelApi.updateModelApi(data)
-      message.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as ModelVO
+        if (actionType.value === 'create') {
+          await ModelApi.createModelApi(data)
+          message.success(t('common.createSuccess'))
+        } else {
+          await ModelApi.updateModelApi(data)
+          message.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 /** 流程表单的详情按钮操作 */

+ 10 - 1
yudao-ui-admin-vue3/src/views/infra/codegen/EditTable.vue

@@ -26,6 +26,10 @@ const activeName = ref('cloum')
 const basicInfoRef = ref<ComponentRef<typeof BasicInfoForm>>()
 const genInfoRef = ref<ComponentRef<typeof GenInfoForm>>()
 const cloumInfoRef = ref(null)
+const parentMenuId = ref<number>()
+const menu = (id: number) => {
+  parentMenuId.value = id
+}
 const submitForm = async () => {
   const basicInfo = unref(basicInfoRef)
   const genInfo = unref(genInfoRef)
@@ -38,6 +42,11 @@ const submitForm = async () => {
       table: Object.assign({}, basicInfoData, genInfoData),
       columns: cloumCurrentRow.value
     }
+    if (parentMenuId.value) {
+      genInfoData.parentMenuId = parentMenuId.value
+    } else {
+      genInfoData.parentMenuId = 0
+    }
     await updateCodegenTableApi(genTable)
     ElMessage.success(t('common.updateSuccess'))
     push('/infra/codegen')
@@ -57,7 +66,7 @@ onMounted(() => {
         <CloumInfoForm ref="cloumInfoRef" :info="cloumCurrentRow" />
       </el-tab-pane>
       <el-tab-pane label="生成信息" name="genInfo">
-        <GenInfoForm ref="genInfoRef" :genInfo="tableCurrentRow" />
+        <GenInfoForm ref="genInfoRef" :genInfo="tableCurrentRow" @menu="menu" />
       </el-tab-pane>
     </el-tabs>
     <template #right>

+ 2 - 0
yudao-ui-admin-vue3/src/views/infra/codegen/components/BasicInfoForm.vue

@@ -4,6 +4,8 @@ import { required } from '@/utils/formRules'
 import { CodegenTableVO } from '@/api/infra/codegen/types'
 import { Form } from '@/components/Form'
 import { useForm } from '@/hooks/web/useForm'
+import { FormSchema } from '@/types/form'
+
 const props = defineProps({
   basicInfo: {
     type: Object as PropType<Nullable<CodegenTableVO>>,

+ 45 - 5
yudao-ui-admin-vue3/src/views/infra/codegen/components/GenInfoForm.vue

@@ -1,16 +1,26 @@
 <script setup lang="ts">
-import { PropType, reactive, watch } from 'vue'
+import { onMounted, PropType, reactive, ref, watch } from 'vue'
 import { required } from '@/utils/formRules'
-import { CodegenTableVO } from '@/api/infra/codegen/types'
 import { Form } from '@/components/Form'
+import { handleTree } from '@/utils/tree'
+import { ElTreeSelect } from 'element-plus'
 import { useForm } from '@/hooks/web/useForm'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { listSimpleMenusApi } from '@/api/system/menu'
+import { CodegenTableVO } from '@/api/infra/codegen/types'
+import { FormSchema } from '@/types/form'
 const props = defineProps({
   genInfo: {
     type: Object as PropType<Nullable<CodegenTableVO>>,
     default: () => null
   }
 })
+const menuProps = {
+  checkStrictly: true,
+  children: 'children',
+  label: 'name',
+  value: 'id'
+}
 const rules = reactive({
   templateType: [required],
   scene: [required],
@@ -22,6 +32,12 @@ const rules = reactive({
 })
 const templateTypeOptions = getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE)
 const sceneOptions = getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE)
+const treeRef = ref<InstanceType<typeof ElTreeSelect>>()
+const menuOptions = ref<any>([]) // 树形结构
+const getTree = async () => {
+  const res = await listSimpleMenusApi()
+  menuOptions.value = handleTree(res)
+}
 const schema = reactive<FormSchema[]>([
   {
     label: '生成模板',
@@ -84,7 +100,9 @@ const schema = reactive<FormSchema[]>([
   {
     label: '上级菜单',
     field: 'parentMenuId',
-    component: 'Input',
+    componentProps: {
+      optionsSlot: true
+    },
     labelMessage: '分配到指定菜单下,例如 系统管理',
     colProps: {
       span: 12
@@ -94,6 +112,17 @@ const schema = reactive<FormSchema[]>([
 const { register, methods, elFormRef } = useForm({
   schema
 })
+const parentMenuId = ref<number>()
+//子组件像父组件传值
+const emit = defineEmits(['menu'])
+const handleNodeClick = () => {
+  emit('menu', parentMenuId.value)
+}
+
+// ========== 初始化 ==========
+onMounted(async () => {
+  await getTree()
+})
 watch(
   () => props.genInfo,
   (genInfo) => {
@@ -106,12 +135,23 @@ watch(
     immediate: true
   }
 )
-
 defineExpose({
   elFormRef,
   getFormData: methods.getFormData
 })
 </script>
 <template>
-  <Form :rules="rules" @register="register" />
+  <Form :rules="rules" @register="register">
+    <template #parentMenuId>
+      <el-tree-select
+        v-model="parentMenuId"
+        ref="treeRef"
+        node-key="id"
+        :props="menuProps"
+        :data="menuOptions"
+        check-strictly
+        @node-click="handleNodeClick"
+      />
+    </template>
+  </Form>
 </template>

+ 1 - 1
yudao-ui-admin-vue3/src/views/infra/codegen/components/ImportTable.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { reactive, ref } from 'vue'
+import { reactive, ref, defineEmits } from 'vue'
 import { getSchemaTableListApi, createCodegenListApi } from '@/api/infra/codegen'
 import {
   ElMessage,

+ 22 - 16
yudao-ui-admin-vue3/src/views/infra/config/index.vue

@@ -50,23 +50,29 @@ const handleUpdate = async (row: ConfigVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as ConfigVO
-    if (actionType.value === 'create') {
-      await ConfigApi.createConfigApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await ConfigApi.updateConfigApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as ConfigVO
+        if (actionType.value === 'create') {
+          await ConfigApi.createConfigApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await ConfigApi.updateConfigApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 22 - 16
yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/index.vue

@@ -44,23 +44,29 @@ const handleUpdate = async (row: DataSourceConfigVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  loading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as DataSourceConfigVO
-    if (actionType.value === 'create') {
-      await DataSourceConfiggApi.createDataSourceConfigApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await DataSourceConfiggApi.updateDataSourceConfigApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      loading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as DataSourceConfigVO
+        if (actionType.value === 'create') {
+          await DataSourceConfiggApi.createDataSourceConfigApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await DataSourceConfiggApi.updateDataSourceConfigApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        loading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    loading.value = false
-  }
+  })
 }
 
 // 删除操作

+ 22 - 16
yudao-ui-admin-vue3/src/views/infra/fileConfig/index.vue

@@ -60,23 +60,29 @@ const handleMaster = (row: FileConfigVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as FileConfigVO
-    if (actionType.value === 'create') {
-      await FileConfigApi.createFileConfigApi(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await FileConfigApi.updateFileConfigApi(data)
-      message.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as FileConfigVO
+        if (actionType.value === 'create') {
+          await FileConfigApi.createFileConfigApi(data)
+          message.success(t('common.createSuccess'))
+        } else {
+          await FileConfigApi.updateFileConfigApi(data)
+          message.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 23 - 17
yudao-ui-admin-vue3/src/views/infra/job/index.vue

@@ -98,24 +98,30 @@ const handleRun = (row: JobVO) => {
 }
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as JobVO
-    data.cronExpression = cronExpression.value
-    if (actionType.value === 'create') {
-      await JobApi.createJobApi(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await JobApi.updateJobApi(data)
-      message.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as JobVO
+        data.cronExpression = cronExpression.value
+        if (actionType.value === 'create') {
+          await JobApi.createJobApi(data)
+          message.success(t('common.createSuccess'))
+        } else {
+          await JobApi.updateJobApi(data)
+          message.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 22 - 16
yudao-ui-admin-vue3/src/views/pay/app/index.vue

@@ -50,23 +50,29 @@ const handleUpdate = async (row: AppVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as AppVO
-    if (actionType.value === 'create') {
-      await AppApi.createAppApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await AppApi.updateAppApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as AppVO
+        if (actionType.value === 'create') {
+          await AppApi.createAppApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await AppApi.updateAppApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 22 - 16
yudao-ui-admin-vue3/src/views/pay/merchant/index.vue

@@ -50,23 +50,29 @@ const handleUpdate = async (row: MerchantVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as MerchantVO
-    if (actionType.value === 'create') {
-      await MerchantApi.createMerchantApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await MerchantApi.updateMerchantApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as MerchantVO
+        if (actionType.value === 'create') {
+          await MerchantApi.createMerchantApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await MerchantApi.updateMerchantApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 22 - 16
yudao-ui-admin-vue3/src/views/pay/order/index.vue

@@ -48,23 +48,29 @@ const handleUpdate = async (row: OrderVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as OrderVO
-    if (actionType.value === 'create') {
-      await OrderApi.createOrderApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await OrderApi.updateOrderApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as OrderVO
+        if (actionType.value === 'create') {
+          await OrderApi.createOrderApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await OrderApi.updateOrderApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 2 - 0
yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts

@@ -1,5 +1,7 @@
 import { required } from '@/utils/formRules'
 import { reactive } from 'vue'
+import { FormSchema } from '@/types/form'
+
 // 表单校验
 export const rules = reactive({
   name: [required],

+ 21 - 15
yudao-ui-admin-vue3/src/views/system/dept/index.vue

@@ -82,22 +82,28 @@ const handleDelete = async (data: { id: number }) => {
 }
 // 提交按钮
 const submitForm = async () => {
-  loading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as DeptVO
-    data.parentId = deptParentId.value
-    data.leaderUserId = leaderUserId.value
-    if (formTitle.value.startsWith('新增')) {
-      await DeptApi.createDeptApi(data)
-    } else if (formTitle.value.startsWith('修改')) {
-      await DeptApi.updateDeptApi(data)
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      loading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as DeptVO
+        data.parentId = deptParentId.value
+        data.leaderUserId = leaderUserId.value
+        if (formTitle.value.startsWith('新增')) {
+          await DeptApi.createDeptApi(data)
+        } else if (formTitle.value.startsWith('修改')) {
+          await DeptApi.updateDeptApi(data)
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+      } finally {
+        loading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-  } finally {
-    loading.value = false
-  }
+  })
 }
 onMounted(async () => {
   await getTree()

+ 45 - 33
yudao-ui-admin-vue3/src/views/system/dict/index.vue

@@ -92,43 +92,55 @@ const setDialogTile = (type: string) => {
 }
 // 提交按钮
 const submitTypeForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(typeFormRef)?.formModel as DictTypeVO
-    if (actionType.value === 'typeCreate') {
-      await DictTypeApi.createDictTypeApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else if (actionType.value === 'typeUpdate') {
-      await DictTypeApi.updateDictTypeApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(typeFormRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(typeFormRef)?.formModel as DictTypeVO
+        if (actionType.value === 'typeCreate') {
+          await DictTypeApi.createDictTypeApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else if (actionType.value === 'typeUpdate') {
+          await DictTypeApi.updateDictTypeApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        await getTypeList()
+        dialogVisible.value = false
+      } finally {
+        actionLoading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    await getTypeList()
-    dialogVisible.value = false
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 const submitDataForm = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = unref(dataFormRef)?.formModel as DictDataVO
-    if (actionType.value === 'dataCreate') {
-      data.dictType = parentType.value
-      await DictDataApi.createDictDataApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else if (actionType.value === 'dataUpdate') {
-      await DictDataApi.updateDictDataApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(dataFormRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(dataFormRef)?.formModel as DictDataVO
+        if (actionType.value === 'dataCreate') {
+          data.dictType = parentType.value
+          await DictDataApi.createDictDataApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else if (actionType.value === 'dataUpdate') {
+          await DictDataApi.updateDictDataApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        await getDataList()
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+      } finally {
+        actionLoading.value = false
+      }
     }
-    await getDataList()
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-  } finally {
-    actionLoading.value = false
-  }
+  })
 }
 // 初始化查询
 onMounted(async () => {

+ 22 - 16
yudao-ui-admin-vue3/src/views/system/errorCode/index.vue

@@ -49,23 +49,29 @@ const handleUpdate = async (row: ErrorCodeVO) => {
 
 // 提交按钮
 const submitForm = async () => {
-  loading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as ErrorCodeVO
-    if (actionType.value === 'create') {
-      await ErrorCodeApi.createErrorCodeApi(data)
-      ElMessage.success(t('common.createSuccess'))
-    } else {
-      await ErrorCodeApi.updateErrorCodeApi(data)
-      ElMessage.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      loading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as ErrorCodeVO
+        if (actionType.value === 'create') {
+          await ErrorCodeApi.createErrorCodeApi(data)
+          ElMessage.success(t('common.createSuccess'))
+        } else {
+          await ErrorCodeApi.updateErrorCodeApi(data)
+          ElMessage.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+        await getList()
+      } finally {
+        loading.value = false
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    loading.value = false
-  }
+  })
 }
 
 // ========== 详情相关 ==========

+ 11 - 5
yudao-ui-admin-vue3/src/views/system/menu/index.vue

@@ -42,12 +42,18 @@ const menuProps = {
   label: 'name',
   value: 'id'
 }
-const menuOptions = ref() // 树形结构
+interface Tree {
+  id: number
+  name: string
+  children?: Tree[] | any[]
+}
+const menuOptions = ref<any[]>([]) // 树形结构
 const getTree = async () => {
+  menuOptions.value = []
   const res = await MenuApi.listSimpleMenusApi()
-  const menu = { id: 0, name: '主类目', children: [] as any[] }
+  let menu: Tree = { id: 0, name: '主类目', children: [] }
   menu.children = handleTree(res)
-  menuOptions.value = menu
+  menuOptions.value.push(menu)
 }
 // ========== 查询 ==========
 const queryParams = reactive({
@@ -121,7 +127,7 @@ const handleDelete = async (row: MenuVO) => {
   await getList()
 }
 // 保存操作
-function isExternal(path: string) {
+const isExternal = (path: string) => {
   return /^(https?:|mailto:|tel:)/.test(path)
 }
 const submitForm = async () => {
@@ -268,7 +274,7 @@ onMounted(async () => {
               node-key="id"
               v-model="menuForm.parentId"
               :props="menuProps"
-              :data="menuData"
+              :data="menuOptions"
               check-strictly
             />
           </el-form-item>

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików