Commit d1736af6daf9ce446b07cc448f5aef3dc57b1def

Authored by 芋道源码
Committed by Gitee
2 parents 587360a5 922b39c0

!271 升级后端及 vue3部分依赖

Merge pull request !271 from xingyu/dev
Showing 115 changed files with 1247 additions and 900 deletions

Too many changes.

To preserve performance only 100 of 115 files are displayed.

README.md
... ... @@ -174,29 +174,29 @@ ps:核心功能已经实现,正在对接微信小程序中...
174 174  
175 175 ### 后端
176 176  
177   -| 框架 | 说明 | 版本 | 学习指南 |
178   -|---------------------------------------------------------------------------------------------|-----------------------|---------|----------------------------------------------------------------|
179   -| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.6.10 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
180   -| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | |
181   -| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.11 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
182   -| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
183   -| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
184   -| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
185   -| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.17.4 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
186   -| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.20 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
187   -| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.6.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
188   -| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.3 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
189   -| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) |
190   -| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
191   -| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
192   -| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
193   -| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
194   -| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.6.7 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
195   -| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
196   -| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
197   -| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
198   -| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
199   -| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.0.0 | - |
  177 +| 框架 | 说明 | 版本 | 学习指南 |
  178 +|---------------------------------------------------------------------------------------------|-----------------------|------------------|----------------------------------------------------------------|
  179 +| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.6.12 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
  180 +| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |
  181 +| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.13-SNSAPSHOT | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
  182 +| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
  183 +| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
  184 +| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
  185 +| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.17.7 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
  186 +| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.20 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
  187 +| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.6.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
  188 +| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.3 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
  189 +| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) |
  190 +| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
  191 +| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
  192 +| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
  193 +| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
  194 +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.6.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
  195 +| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
  196 +| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.2.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
  197 +| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
  198 +| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
  199 +| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - |
200 200  
201 201 ### [管理后台 Vue2 前端](./yudao-ui-admin)
202 202  
... ... @@ -209,14 +209,14 @@ ps:核心功能已经实现,正在对接微信小程序中...
209 209  
210 210 | 框架 | 说明 | 版本 |
211 211 |----------------------------------------------------------------------|-----------------|--------|
212   -| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.37 |
213   -| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.4 |
214   -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.12 |
215   -| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.7.4 |
216   -| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.17 |
  212 +| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.41 |
  213 +| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.1.8 |
  214 +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.18 |
  215 +| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.8.4 |
  216 +| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.23 |
217 217 | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
218 218 | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
219   -| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
  219 +| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.0.0 |
220 220  
221 221 ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)
222 222  
... ...
... ... @@ -37,8 +37,8 @@
37 37 <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
38 38 <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
39 39 <!-- 看看咋放到 bom 里 -->
40   - <lombok.version>1.18.20</lombok.version>
41   - <mapstruct.version>1.4.1.Final</mapstruct.version>
  40 + <lombok.version>1.18.24</lombok.version>
  41 + <mapstruct.version>1.5.2.Final</mapstruct.version>
42 42 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
43 43 </properties>
44 44  
... ...
yudao-dependencies/pom.xml
... ... @@ -16,58 +16,58 @@
16 16 <properties>
17 17 <revision>1.6.4-snapshot</revision>
18 18 <!-- 统一依赖管理 -->
19   - <spring.boot.version>2.6.10</spring.boot.version>
  19 + <spring.boot.version>2.6.12</spring.boot.version>
20 20 <!-- Web 相关 -->
21 21 <knife4j.version>3.0.3</knife4j.version>
22   - <swagger-annotations.version>1.6.6</swagger-annotations.version>
  22 + <swagger-annotations.version>1.6.7</swagger-annotations.version>
23 23 <servlet.versoin>2.5</servlet.versoin>
24 24 <!-- DB 相关 -->
25   - <druid.version>1.2.11</druid.version>
  25 + <druid.version>1.2.13-SNSAPSHOT</druid.version>
26 26 <mybatis-plus.version>3.5.2</mybatis-plus.version>
27 27 <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
28   - <dynamic-datasource.version>3.5.0</dynamic-datasource.version>
29   - <redisson.version>3.17.4</redisson.version>
  28 + <dynamic-datasource.version>3.5.2</dynamic-datasource.version>
  29 + <redisson.version>3.17.7</redisson.version>
30 30 <!-- Config 配置中心相关 -->
31   - <apollo.version>1.9.2</apollo.version>
  31 + <apollo.version>2.0.1</apollo.version>
32 32 <!-- 服务保障相关 -->
33   - <lock4j.version>2.2.0</lock4j.version>
  33 + <lock4j.version>2.2.2</lock4j.version>
34 34 <resilience4j.version>1.7.1</resilience4j.version>
35 35 <!-- 监控相关 -->
36   - <skywalking.version>8.7.0</skywalking.version>
37   - <spring-boot-admin.version>2.6.7</spring-boot-admin.version>
38   - <opentracing.version>0.31.0</opentracing.version>
  36 + <skywalking.version>8.12.0</skywalking.version>
  37 + <spring-boot-admin.version>2.6.9</spring-boot-admin.version>
  38 + <opentracing.version>0.33.0</opentracing.version>
39 39 <!-- Test 测试相关 -->
40   - <podam.version>7.2.6.RELEASE</podam.version>
41   - <jedis-mock.version>0.1.16</jedis-mock.version>
42   - <mockito-inline.version>4.0.0</mockito-inline.version>
  40 + <podam.version>7.2.9.RELEASE</podam.version>
  41 + <jedis-mock.version>1.0.4</jedis-mock.version>
  42 + <mockito-inline.version>4.8.0</mockito-inline.version>
43 43 <!-- Bpm 工作流相关 -->
44 44 <flowable.version>6.7.2</flowable.version>
45 45 <!-- 工具类相关 -->
46 46 <jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
47   - <lombok.version>1.18.20</lombok.version>
48   - <mapstruct.version>1.4.1.Final</mapstruct.version>
49   - <hutool.version>5.8.5</hutool.version>
  47 + <lombok.version>1.18.24</lombok.version>
  48 + <mapstruct.version>1.5.2.Final</mapstruct.version>
  49 + <hutool.version>5.8.8</hutool.version>
50 50 <easyexcel.verion>3.1.1</easyexcel.verion>
51 51 <velocity.version>2.3</velocity.version>
52 52 <screw.version>1.0.5</screw.version>
53   - <fastjson.version>1.2.83</fastjson.version>
54   - <guava.version>30.1.1-jre</guava.version>
  53 + <fastjson.version>1.2.83</fastjson.version>
  54 + <guava.version>31.1-jre</guava.version>
55 55 <guice.version>5.1.0</guice.version>
56   - <transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
  56 + <transmittable-thread-local.version>2.14.0</transmittable-thread-local.version>
57 57 <commons-net.version>3.8.0</commons-net.version>
58 58 <jsch.version>0.1.55</jsch.version>
59   - <tika-core.version>2.4.1</tika-core.version>
  59 + <tika-core.version>2.5.0</tika-core.version>
60 60 <aj-captcha.version>1.3.0</aj-captcha.version>
61 61 <netty-all.version>4.1.82.Final</netty-all.version>
62 62 <!-- 三方云服务相关 -->
63 63 <minio.version>8.2.2</minio.version>
64   - <aliyun-java-sdk-core.version>4.6.0</aliyun-java-sdk-core.version>
  64 + <aliyun-java-sdk-core.version>4.6.2</aliyun-java-sdk-core.version>
65 65 <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
66 66 <tencentcloud-sdk-java.version>3.1.561</tencentcloud-sdk-java.version>
67 67 <yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
68 68 <justauth.version>1.4.0</justauth.version>
69   - <jimureport.version>1.5.2</jimureport.version>
70   - <xercesImpl.version>2.12.0</xercesImpl.version>
  69 + <jimureport.version>1.5.3</jimureport.version>
  70 + <xercesImpl.version>2.12.2</xercesImpl.version>
71 71 </properties>
72 72  
73 73 <dependencyManagement>
... ...
yudao-example/yudao-sso-demo-by-code/pom.xml
... ... @@ -52,7 +52,7 @@
52 52 <dependency>
53 53 <groupId>cn.hutool</groupId>
54 54 <artifactId>hutool-all</artifactId>
55   - <version>5.8.5</version>
  55 + <version>5.8.8</version>
56 56 </dependency>
57 57  
58 58 <dependency>
... ...
yudao-example/yudao-sso-demo-by-password/pom.xml
... ... @@ -52,7 +52,7 @@
52 52 <dependency>
53 53 <groupId>cn.hutool</groupId>
54 54 <artifactId>hutool-all</artifactId>
55   - <version>5.8.5</version>
  55 + <version>5.8.8</version>
56 56 </dependency>
57 57  
58 58 <dependency>
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
... ... @@ -52,7 +52,7 @@
52 52 <dependency>
53 53 <groupId>com.alipay.sdk</groupId>
54 54 <artifactId>alipay-sdk-java</artifactId>
55   - <version>4.31.72.ALL</version>
  55 + <version>4.33.44.ALL</version>
56 56 <exclusions>
57 57 <exclusion>
58 58 <groupId>org.bouncycastle</groupId>
... ... @@ -63,7 +63,7 @@
63 63 <dependency>
64 64 <groupId>com.github.binarywang</groupId>
65 65 <artifactId>weixin-java-pay</artifactId>
66   - <version>4.3.8.B</version>
  66 + <version>4.4.0</version>
67 67 </dependency>
68 68 <!-- TODO 芋艿:清理 -->
69 69  
... ...
yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml
... ... @@ -35,12 +35,12 @@
35 35 <dependency>
36 36 <groupId>com.github.binarywang</groupId>
37 37 <artifactId>wx-java-mp-spring-boot-starter</artifactId>
38   - <version>4.3.8.B</version>
  38 + <version>4.4.0</version>
39 39 </dependency>
40 40 <dependency>
41 41 <groupId>com.github.binarywang</groupId>
42 42 <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
43   - <version>4.3.8.B</version>
  43 + <version>4.4.0</version>
44 44 </dependency>
45 45 <!-- TODO 芋艿:清理 -->
46 46 </dependencies>
... ...
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
5 5 import com.baomidou.lock.LockFailureStrategy;
6 6 import lombok.extern.slf4j.Slf4j;
7 7  
  8 +import java.lang.reflect.Method;
  9 +
8 10 /**
9 11 * 自定义获取锁失败策略,抛出 {@link ServiceException} 异常
10 12 */
... ... @@ -12,9 +14,8 @@ import lombok.extern.slf4j.Slf4j;
12 14 public class DefaultLockFailureStrategy implements LockFailureStrategy {
13 15  
14 16 @Override
15   - public void onLockFailure(String key, long acquireTimeout, int acquireCount) {
16   - log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout);
  17 + public void onLockFailure(String key, Method method, Object[] arguments) {
  18 + log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取失败:{} ]", Thread.currentThread().getName(), key, arguments);
17 19 throw new ServiceException(GlobalErrorCodeConstants.LOCKED);
18 20 }
19   -
20 21 }
... ...
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;
2 2  
3 3 import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
4 4 import org.mapstruct.Mapper;
  5 +import org.mapstruct.Mapping;
5 6 import org.mapstruct.factory.Mappers;
6 7  
7 8 import java.util.Map;
... ... @@ -11,6 +12,10 @@ public interface BpmMessageConvert {
11 12  
12 13 BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class);
13 14  
  15 + @Mapping(target = "mobile", ignore = true)
  16 + @Mapping(source = "userId", target = "userId")
  17 + @Mapping(source = "templateCode", target = "templateCode")
  18 + @Mapping(source = "templateParams", target = "templateParams")
14 19 SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map<String, Object> templateParams);
15 20  
16 21 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
... ... @@ -50,23 +50,29 @@
50 50  
51 51 // 提交按钮
52 52 const submitForm = async () => {
53   - actionLoading.value = true
54   - // 提交请求
55   - try {
56   - const data = unref(formRef)?.formModel as ${simpleClassName}VO
57   - if (actionType.value === 'create') {
58   - await ${simpleClassName}Api.create${simpleClassName}Api(data)
59   - ElMessage.success(t('common.createSuccess'))
60   - } else {
61   - await ${simpleClassName}Api.update${simpleClassName}Api(data)
62   - ElMessage.success(t('common.updateSuccess'))
  53 + const elForm = unref(formRef)?.getElFormRef()
  54 + if (!elForm) return
  55 + elForm.validate(async (valid) => {
  56 + if (valid) {
  57 + actionLoading.value = true
  58 + // 提交请求
  59 + try {
  60 + const data = unref(formRef)?.formModel as ${simpleClassName}VO
  61 + if (actionType.value === 'create') {
  62 + await ${simpleClassName}Api.create${simpleClassName}Api(data)
  63 + ElMessage.success(t('common.createSuccess'))
  64 + } else {
  65 + await ${simpleClassName}Api.update${simpleClassName}Api(data)
  66 + ElMessage.success(t('common.updateSuccess'))
  67 + }
  68 + // 操作成功,重新加载列表
  69 + dialogVisible.value = false
  70 + await getList()
  71 + } finally {
  72 + actionLoading.value = false
  73 + }
63 74 }
64   - // 操作成功,重新加载列表
65   - dialogVisible.value = false
66   - await getList()
67   - } finally {
68   - actionLoading.value = false
69   - }
  75 + })
70 76 }
71 77  
72 78 // ========== 详情相关 ==========
... ...
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;
7 7 import cn.iocoder.yudao.module.market.service.banner.BannerService;
8 8 import io.swagger.annotations.Api;
9 9 import io.swagger.annotations.ApiOperation;
10   -import org.springframework.beans.factory.annotation.Autowired;
11 10 import org.springframework.security.access.prepost.PreAuthorize;
12 11 import org.springframework.validation.annotation.Validated;
13 12 import org.springframework.web.bind.annotation.GetMapping;
14 13 import org.springframework.web.bind.annotation.RequestMapping;
15 14 import org.springframework.web.bind.annotation.RestController;
16 15  
  16 +import javax.annotation.Resource;
17 17 import java.util.List;
18 18  
19 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -27,8 +27,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 27 @Validated
28 28 public class AppBannerController {
29 29  
30   - // TODO @xia:使用 @Resource 哈
31   - @Autowired
  30 + @Resource
32 31 private BannerService bannerService;
33 32  
34 33 // TODO @xia:新建一个 AppBannerRespVO,只返回必要的字段。status 要过滤下。然后 sort 下结果
... ...
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;
4 4 import lombok.Data;
5 5  
6 6 import javax.validation.constraints.NotEmpty;
7   -import javax.validation.constraints.NotNull;
8 7 import java.util.Map;
9 8  
10 9 /**
... ...
yudao-ui-admin-vue3/README.md
... ... @@ -27,17 +27,17 @@
27 27  
28 28 | 框架 | 说明 | 版本 |
29 29 | --- | --- |--------|
30   -| [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.37 |
31   -| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.4 |
32   -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.12 |
33   -| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.7.4 |
34   -| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 |
35   -| [vueuse](https://vueuse.org//) | 常用工具集 | 9.0.2 |
36   -| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.0 |
37   -| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.3 |
  30 +| [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.41 |
  31 +| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.1.8 |
  32 +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.18 |
  33 +| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.8.4 |
  34 +| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.23 |
  35 +| [vueuse](https://vueuse.org//) | 常用工具集 | 9.3.1 |
  36 +| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
  37 +| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.5 |
38 38 | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
39   -| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
40   -| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.14 |
  39 +| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.0.0 |
  40 +| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.21 |
41 41  
42 42 ### 推荐 VScode 开发,插件如下
43 43  
... ...
yudao-ui-admin-vue3/package.json
1 1 {
2 2 "name": "ruoyi-vue-pro-vue3",
3   - "version": "1.6.3.1611",
  3 + "version": "1.6.4.1811",
4 4 "description": "基于vue3、element-plus、typesScript、vite3",
5 5 "author": "xingyu",
6 6 "private": false,
... ... @@ -10,7 +10,7 @@
10 10 "ts:check": "vue-tsc --noEmit",
11 11 "build:pro": "vite build --mode pro",
12 12 "build:dev": "vite build --mode dev",
13   - "build:test": "pnpm run ts:check && vite build --mode test",
  13 + "build:test": "npm run ts:check && vite build --mode test",
14 14 "serve:pro": "vite preview --mode pro",
15 15 "serve:dev": "vite preview --mode dev",
16 16 "serve:test": "vite preview --mode test",
... ... @@ -25,84 +25,84 @@
25 25 "p": "plop"
26 26 },
27 27 "dependencies": {
28   - "@iconify/iconify": "^2.2.1",
29   - "@vueuse/core": "^9.1.0",
30   - "@wangeditor/editor": "^5.1.14",
  28 + "@iconify/iconify": "^3.0.0",
  29 + "@vueuse/core": "^9.3.1",
  30 + "@wangeditor/editor": "^5.1.21",
31 31 "@wangeditor/editor-for-vue": "^5.1.10",
32   - "@zxcvbn-ts/core": "^2.0.4",
  32 + "@zxcvbn-ts/core": "^2.0.5",
33 33 "animate.css": "^4.1.1",
34 34 "axios": "^0.27.2",
35 35 "crypto-js": "^4.1.1",
36   - "dayjs": "^1.11.4",
37   - "echarts": "^5.3.3",
  36 + "dayjs": "^1.11.5",
  37 + "echarts": "^5.4.0",
38 38 "echarts-wordcloud": "^2.0.0",
39   - "element-plus": "2.2.12",
  39 + "element-plus": "2.2.18",
40 40 "intro.js": "^6.0.0",
41 41 "jsencrypt": "^3.2.1",
42 42 "lodash-es": "^4.17.21",
43 43 "mitt": "^3.0.0",
44 44 "nprogress": "^0.2.0",
45   - "pinia": "^2.0.17",
46   - "pinia-plugin-persist": "^1.0.0",
  45 + "pinia": "^2.0.23",
47 46 "qrcode": "^1.5.1",
48 47 "qs": "^6.11.0",
49 48 "url": "^0.11.0",
50   - "vue": "3.2.37",
  49 + "vue": "3.2.41",
51 50 "vue-cropper": "^1.0.3",
52 51 "vue-i18n": "9.2.2",
53   - "vue-router": "^4.1.3",
  52 + "vue-router": "^4.1.5",
54 53 "vue-types": "^4.2.1",
55 54 "web-storage-cache": "^1.1.1"
56 55 },
57 56 "devDependencies": {
58   - "@commitlint/cli": "^17.0.3",
59   - "@commitlint/config-conventional": "^17.0.3",
60   - "@iconify/json": "^2.1.89",
61   - "@intlify/vite-plugin-vue-i18n": "^6.0.0",
  57 + "@commitlint/cli": "^17.1.2",
  58 + "@commitlint/config-conventional": "^17.1.0",
  59 + "@iconify/json": "^2.1.122",
  60 + "@intlify/vite-plugin-vue-i18n": "^6.0.3",
62 61 "@purge-icons/generated": "^0.9.0",
63 62 "@types/intro.js": "^5.1.0",
64 63 "@types/lodash-es": "^4.17.6",
65   - "@types/node": "^18.6.5",
  64 + "@types/node": "^18.11.0",
66 65 "@types/nprogress": "^0.2.0",
67   - "@types/qrcode": "^1.4.2",
  66 + "@types/qrcode": "^1.5.0",
68 67 "@types/qs": "^6.9.7",
69   - "@typescript-eslint/eslint-plugin": "^5.33.0",
70   - "@typescript-eslint/parser": "^5.33.0",
71   - "@vitejs/plugin-vue": "^3.0.1",
72   - "@vitejs/plugin-vue-jsx": "^2.0.0",
73   - "autoprefixer": "^10.4.8",
74   - "eslint": "^8.21.0",
  68 + "@typescript-eslint/eslint-plugin": "^5.40.0",
  69 + "@typescript-eslint/parser": "^5.40.0",
  70 + "@vitejs/plugin-vue": "^3.1.2",
  71 + "@vitejs/plugin-vue-jsx": "^2.0.1",
  72 + "autoprefixer": "^10.4.12",
  73 + "eslint": "^8.25.0",
75 74 "eslint-config-prettier": "^8.5.0",
76   - "eslint-define-config": "^1.6.0",
  75 + "eslint-define-config": "^1.7.0",
77 76 "eslint-plugin-prettier": "^4.2.1",
78   - "eslint-plugin-vue": "^9.3.0",
  77 + "eslint-plugin-vue": "^9.6.0",
79 78 "less": "^4.1.3",
80 79 "lint-staged": "^13.0.3",
81 80 "plop": "^3.1.1",
82   - "postcss": "^8.4.16",
  81 + "postcss": "^8.4.18",
83 82 "postcss-html": "^1.5.0",
84 83 "postcss-less": "^6.0.0",
85 84 "prettier": "^2.7.1",
86 85 "rimraf": "^3.0.2",
87   - "rollup": "^2.77.2",
88   - "stylelint": "^14.9.1",
  86 + "rollup": "^2.79.1",
  87 + "stylelint": "^14.14.0",
89 88 "stylelint-config-html": "^1.1.0",
90 89 "stylelint-config-prettier": "^9.0.3",
91   - "stylelint-config-recommended": "^8.0.0",
92   - "stylelint-config-standard": "^26.0.0",
  90 + "stylelint-config-recommended": "^9.0.0",
  91 + "stylelint-config-standard": "^29.0.0",
93 92 "stylelint-order": "^5.0.0",
94   - "typescript": "4.7.4",
95   - "unplugin-vue-define-options": "^0.7.3",
96   - "vite": "3.0.5",
  93 + "typescript": "4.8.4",
  94 + "unplugin-vue-macros": "^0.13.2",
  95 + "vite": "3.1.8",
97 96 "vite-plugin-compression": "^0.5.1",
98   - "vite-plugin-eslint": "^1.7.0",
  97 + "vite-plugin-eslint": "^1.8.1",
99 98 "vite-plugin-html": "^3.2.0",
100   - "vite-plugin-purge-icons": "^0.9.0",
101   - "vite-plugin-style-import": "^2.0.0",
  99 + "vite-plugin-purge-icons": "^0.9.1",
  100 + "vite-plugin-style-import": "2.0.0",
102 101 "vite-plugin-svg-icons": "^2.0.1",
103   - "vite-plugin-windicss": "^1.8.7",
104   - "vue-tsc": "^0.39.5",
105   - "windicss": "^3.5.6"
  102 + "vite-plugin-windicss": "^1.8.8",
  103 + "vue-tsc": "^1.0.8",
  104 + "windicss": "^3.5.6",
  105 + "windicss-analysis": "^0.3.5"
106 106 },
107 107 "engines": {
108 108 "node": ">= 14.18.0"
... ...
yudao-ui-admin-vue3/src/api/system/tenant/types.ts
... ... @@ -4,6 +4,8 @@ export type TenantVO = {
4 4 packageId: number
5 5 contactName: string
6 6 contactMobile: string
  7 + username: string
  8 + password: string
7 9 accountCount: number
8 10 expireTime: string
9 11 domain: string
... ...
yudao-ui-admin-vue3/src/components/ConfigGlobal/src/ConfigGlobal.vue
... ... @@ -7,13 +7,14 @@ import { useWindowSize } from &#39;@vueuse/core&#39;
7 7 import { useAppStore } from '@/store/modules/app'
8 8 import { setCssVar } from '@/utils'
9 9 import { useDesign } from '@/hooks/web/useDesign'
  10 +import { ElementPlusSize } from '@/types/elementPlus'
10 11  
11 12 const { variables } = useDesign()
12 13  
13 14 const appStore = useAppStore()
14 15  
15 16 const props = defineProps({
16   - size: propTypes.oneOf<ElememtPlusSize[]>(['default', 'small', 'large']).def('default')
  17 + size: propTypes.oneOf<ElementPlusSize[]>(['default', 'small', 'large']).def('default')
17 18 })
18 19  
19 20 provide('configGlobal', props)
... ...
yudao-ui-admin-vue3/src/components/ContextMenu/src/ContextMenu.vue
1 1 <script setup lang="ts">
2 2 import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
3   -import { PropType, ref } from 'vue'
  3 +import { PropType, ref, defineEmits } from 'vue'
4 4 import { useI18n } from '@/hooks/web/useI18n'
5 5 import { useDesign } from '@/hooks/web/useDesign'
6 6 import type { RouteLocationNormalizedLoaded } from 'vue-router'
  7 +import { contextMenuSchema } from '../../../types/contextMenu'
7 8  
8 9 const { getPrefixCls } = useDesign()
9 10  
... ...
yudao-ui-admin-vue3/src/components/CountTo/src/CountTo.vue
1 1 <script setup lang="ts">
2   -import { reactive, computed, watch, onMounted, unref, toRef, PropType } from 'vue'
  2 +import { reactive, computed, watch, onMounted, unref, toRef, PropType, defineEmits } from 'vue'
3 3 import { isNumber } from '@/utils/is'
4 4 import { propTypes } from '@/utils/propTypes'
5 5 import { useDesign } from '@/hooks/web/useDesign'
... ...
yudao-ui-admin-vue3/src/components/Crontab/src/Crontab.vue
... ... @@ -24,7 +24,7 @@ import {
24 24 ElRadioButton,
25 25 ElMessage
26 26 } from 'element-plus'
27   -import { ref, computed, onMounted, reactive, watch, PropType } from 'vue'
  27 +import { ref, computed, onMounted, reactive, watch, PropType, defineEmits } from 'vue'
28 28 interface shortcutsType {
29 29 text: string
30 30 value: string
... ...
yudao-ui-admin-vue3/src/components/Descriptions/src/Descriptions.vue
... ... @@ -4,6 +4,7 @@ import { useDesign } from &#39;@/hooks/web/useDesign&#39;
4 4 import { propTypes } from '@/utils/propTypes'
5 5 import { ref, unref, PropType, computed, useAttrs } from 'vue'
6 6 import { useAppStore } from '@/store/modules/app'
  7 +import { DescriptionsSchema } from '@/types/descriptions'
7 8  
8 9 const appStore = useAppStore()
9 10  
... ...
yudao-ui-admin-vue3/src/components/Dialog/src/Dialog.vue
... ... @@ -74,7 +74,7 @@ const dialogStyle = computed(() =&gt; {
74 74 </slot>
75 75 <Icon
76 76 v-if="fullscreen"
77   - class="mr-22px cursor-pointer is-hover mt-2px"
  77 + class="mr-22px cursor-pointer is-hover mt-2px z-10"
78 78 :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
79 79 color="var(--el-color-info)"
80 80 @click="toggleFull"
... ...
yudao-ui-admin-vue3/src/components/Editor/src/Editor.vue
... ... @@ -177,7 +177,7 @@ defineExpose({
177 177 </script>
178 178  
179 179 <template>
180   - <div class="border-1 border-solid border-[var(--tags-view-border-color)]">
  180 + <div class="border-1 border-solid border-[var(--tags-view-border-color)] z-3000">
181 181 <!-- 工具栏 -->
182 182 <Toolbar
183 183 :editor="editorRef"
... ...
yudao-ui-admin-vue3/src/components/Error/src/Error.vue
... ... @@ -4,6 +4,7 @@ import networkError from &#39;@/assets/svgs/500.svg&#39;
4 4 import noPermission from '@/assets/svgs/403.svg'
5 5 import { propTypes } from '@/utils/propTypes'
6 6 import { useI18n } from '@/hooks/web/useI18n'
  7 +import { defineEmits } from 'vue'
7 8  
8 9 interface ErrorMap {
9 10 url: string
... ...
yudao-ui-admin-vue3/src/components/Form/index.ts
1 1 import Form from './src/Form.vue'
2 2 import { ElForm } from 'element-plus'
  3 +import { FormSchema, FormSetPropsType } from '@/types/form'
3 4  
4 5 export interface FormExpose {
5 6 setValues: (data: Recordable) => void
... ...
yudao-ui-admin-vue3/src/components/Form/src/Form.vue
... ... @@ -20,6 +20,7 @@ import { findIndex } from &#39;@/utils&#39;
20 20 import { set } from 'lodash-es'
21 21 import { FormProps } from './types'
22 22 import { Icon } from '@/components/Icon'
  23 +import { FormSchema, FormSetPropsType } from '@/types/form'
23 24  
24 25 const { getPrefixCls } = useDesign()
25 26  
... ...
yudao-ui-admin-vue3/src/components/Form/src/componentMap.ts
... ... @@ -20,6 +20,7 @@ import {
20 20 } from 'element-plus'
21 21 import { InputPassword } from '@/components/InputPassword'
22 22 import { Editor } from '@/components/Editor'
  23 +import { ComponentName } from '@/types/components'
23 24  
24 25 const componentMap: Recordable<Component, ComponentName> = {
25 26 Radio: ElRadioGroup,
... ...
yudao-ui-admin-vue3/src/components/Form/src/components/useRenderCheckbox.tsx
  1 +import { FormSchema } from '@/types/form'
1 2 import { ElCheckbox, ElCheckboxButton } from 'element-plus'
2 3 import { defineComponent } from 'vue'
3 4  
... ...
yudao-ui-admin-vue3/src/components/Form/src/components/useRenderRadio.tsx
  1 +import { FormSchema } from '@/types/form'
1 2 import { ElRadio, ElRadioButton } from 'element-plus'
2 3 import { defineComponent } from 'vue'
3 4  
... ...
yudao-ui-admin-vue3/src/components/Form/src/components/useRenderSelect.tsx
  1 +import { FormSchema } from '@/types/form'
  2 +import { ComponentOptions } from '@/types/components'
1 3 import { ElOption, ElOptionGroup } from 'element-plus'
2 4 import { getSlot } from '@/utils/tsxHelper'
3 5 import { Slots } from 'vue'
... ... @@ -29,8 +31,15 @@ export const useRenderSelect = (slots: Slots) =&gt; {
29 31 // 如果有别名,就取别名
30 32 const labelAlias = item?.componentProps?.optionsAlias?.labelField
31 33 const valueAlias = item?.componentProps?.optionsAlias?.valueField
  34 +
  35 + const { label, value, ...other } = option
  36 +
32 37 return (
33   - <ElOption label={option[labelAlias || 'label']} value={option[valueAlias || 'value']}>
  38 + <ElOption
  39 + label={labelAlias ? option[labelAlias] : label}
  40 + value={valueAlias ? option[valueAlias] : value}
  41 + {...other}
  42 + >
34 43 {{
35 44 default: () =>
36 45 // option 插槽名规则,{field}-option
... ...
yudao-ui-admin-vue3/src/components/Form/src/helper.ts
... ... @@ -2,6 +2,8 @@ import { useI18n } from &#39;@/hooks/web/useI18n&#39;
2 2 import type { Slots } from 'vue'
3 3 import { getSlot } from '@/utils/tsxHelper'
4 4 import { PlaceholderMoel } from './types'
  5 +import { FormSchema } from '@/types/form'
  6 +import { ColProps } from '@/types/components'
5 7  
6 8 /**
7 9 *
... ...
yudao-ui-admin-vue3/src/components/Form/src/types.ts
  1 +import { FormSchema } from '@/types/form'
  2 +
1 3 export interface PlaceholderMoel {
2 4 placeholder?: string
3 5 startPlaceholder?: string
... ...
yudao-ui-admin-vue3/src/components/Icon/src/IconSelect.vue
1 1 <script setup lang="ts">
2 2 import { cloneDeep } from 'lodash-es'
3   -import { ref, computed, CSSProperties, toRef, watch } from 'vue'
  3 +import { ref, computed, CSSProperties, toRef, watch, defineEmits } from 'vue'
4 4 import {
5 5 ElInput,
6 6 ElPopover,
... ...
yudao-ui-admin-vue3/src/components/Infotip/src/Infotip.vue
1 1 <script setup lang="ts">
2   -import { PropType } from 'vue'
3   -import { Highlight } from '@//components/Highlight'
  2 +import { PropType, defineEmits } from 'vue'
  3 +import { Highlight } from '@/components/Highlight'
4 4 import { useDesign } from '@/hooks/web/useDesign'
5 5 import { propTypes } from '@/utils/propTypes'
  6 +import { TipSchema } from '@/types/infoTip'
6 7  
7 8 const { getPrefixCls } = useDesign()
8 9  
... ...
yudao-ui-admin-vue3/src/components/InputPassword/src/InputPassword.vue
1 1 <script setup lang="ts">
2   -import { ref, unref, computed, watch } from 'vue'
  2 +import { ref, unref, computed, watch, defineEmits } from 'vue'
3 3 import { ElInput } from 'element-plus'
4 4 import { propTypes } from '@/utils/propTypes'
5 5 import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
... ...
yudao-ui-admin-vue3/src/components/Menu/src/Menu.vue
... ... @@ -3,11 +3,11 @@ import { computed, defineComponent, unref, PropType } from &#39;vue&#39;
3 3 import { ElMenu, ElScrollbar } from 'element-plus'
4 4 import { useAppStore } from '@/store/modules/app'
5 5 import { usePermissionStore } from '@/store/modules/permission'
6   -import type { LayoutType } from '@/config/app'
7 6 import { useRenderMenuItem } from './components/useRenderMenuItem'
8 7 import { useRouter } from 'vue-router'
9 8 import { isUrl } from '@/utils/is'
10 9 import { useDesign } from '@/hooks/web/useDesign'
  10 +import { LayoutType } from '@/types/layout'
11 11  
12 12 const { getPrefixCls } = useDesign()
13 13  
... ...
yudao-ui-admin-vue3/src/components/Qrcode/src/Qrcode.vue
1 1 <script setup lang="ts">
2   -import { PropType, nextTick, ref, watch, computed, unref } from 'vue'
  2 +import { PropType, nextTick, ref, watch, computed, unref, defineEmits } from 'vue'
3 3 import QRCode from 'qrcode'
4 4 import { QRCodeRenderersOptions } from 'qrcode'
5 5 import { cloneDeep } from 'lodash-es'
6 6 import { propTypes } from '@/utils/propTypes'
7 7 import { useDesign } from '@/hooks/web/useDesign'
8 8 import { isString } from '@/utils/is'
  9 +import { QrcodeLogo } from '@/types/qrcode'
9 10  
10 11 const props = defineProps({
11 12 // img 或者 canvas,img不支持logo嵌套
... ...
yudao-ui-admin-vue3/src/components/Search/src/Search.vue
1 1 <script setup lang="ts">
2 2 import { Form } from '@/components/Form'
3   -import { PropType, computed, unref, ref } from 'vue'
  3 +import { PropType, computed, unref, ref, defineEmits } from 'vue'
4 4 import { propTypes } from '@/utils/propTypes'
5 5 import { ElButton } from 'element-plus'
6 6 import { useI18n } from '@/hooks/web/useI18n'
7 7 import { useForm } from '@/hooks/web/useForm'
8 8 import { findIndex } from '@/utils'
9 9 import { cloneDeep } from 'lodash-es'
  10 +import { FormSchema } from '@/types/form'
10 11  
11 12 const { t } = useI18n()
12 13  
... ...
yudao-ui-admin-vue3/src/components/Setting/src/Setting.vue
... ... @@ -208,7 +208,7 @@ const clear = () =&gt; {
208 208 <Icon icon="ep:setting" color="#fff" />
209 209 </div>
210 210  
211   - <ElDrawer v-model="drawer" direction="rtl" size="350px">
  211 + <ElDrawer v-model="drawer" direction="rtl" size="350px" :z-index="4000">
212 212 <template #header>
213 213 <span class="text-16px font-700">{{ t('setting.projectSetting') }}</span>
214 214 </template>
... ...
yudao-ui-admin-vue3/src/components/Setting/src/components/ColorRadioPicker.vue
1 1 <script setup lang="ts">
2   -import { PropType, watch, unref, ref } from 'vue'
  2 +import { PropType, watch, unref, ref, defineEmits } from 'vue'
3 3 import { propTypes } from '@/utils/propTypes'
4 4 import { useDesign } from '@/hooks/web/useDesign'
5 5  
... ...
yudao-ui-admin-vue3/src/components/Setting/src/components/InterfaceDisplay.vue
1 1 <script setup lang="ts">
2   -import { ElSwitch } from 'element-plus'
  2 +import { ElSwitch, ElMessage } from 'element-plus'
3 3 import { useI18n } from '@/hooks/web/useI18n'
4 4 import { useAppStore } from '@/store/modules/app'
5 5 import { computed, ref, watch } from 'vue'
... ... @@ -107,6 +107,21 @@ const greyModeChange = (show: boolean) =&gt; {
107 107 appStore.setGreyMode(show)
108 108 }
109 109  
  110 +// 动态路由
  111 +const dynamicRouter = ref(appStore.getDynamicRouter)
  112 +
  113 +const dynamicRouterChange = (show: boolean) => {
  114 + ElMessage.info(t('setting.reExperienced'))
  115 + appStore.setDynamicRouter(show)
  116 +}
  117 +
  118 +// 固定菜单
  119 +const fixedMenu = ref(appStore.getFixedMenu)
  120 +
  121 +const fixedMenuChange = (show: boolean) => {
  122 + appStore.setFixedMenu(show)
  123 +}
  124 +
110 125 const layout = computed(() => appStore.getLayout)
111 126  
112 127 watch(
... ... @@ -185,5 +200,15 @@ watch(
185 200 <span class="text-14px">{{ t('setting.greyMode') }}</span>
186 201 <ElSwitch v-model="greyMode" @change="greyModeChange" />
187 202 </div>
  203 +
  204 + <div class="flex justify-between items-center">
  205 + <span class="text-14px">{{ t('setting.dynamicRouter') }}</span>
  206 + <ElSwitch v-model="dynamicRouter" @change="dynamicRouterChange" />
  207 + </div>
  208 +
  209 + <div class="flex justify-between items-center">
  210 + <span class="text-14px">{{ t('setting.fixedMenu') }}</span>
  211 + <ElSwitch v-model="fixedMenu" @change="fixedMenuChange" />
  212 + </div>
188 213 </div>
189 214 </template>
... ...
yudao-ui-admin-vue3/src/components/SizeDropdown/src/SizeDropdown.vue
... ... @@ -5,6 +5,7 @@ import { useAppStore } from &#39;@/store/modules/app&#39;
5 5 import { useI18n } from '@/hooks/web/useI18n'
6 6 import { propTypes } from '@/utils/propTypes'
7 7 import { useDesign } from '@/hooks/web/useDesign'
  8 +import { ElementPlusSize } from '@/types/elementPlus'
8 9  
9 10 const { getPrefixCls } = useDesign()
10 11  
... ... @@ -20,7 +21,7 @@ const appStore = useAppStore()
20 21  
21 22 const sizeMap = computed(() => appStore.sizeMap)
22 23  
23   -const setCurrentSize = (size: ElememtPlusSize) => {
  24 +const setCurrentSize = (size: ElementPlusSize) => {
24 25 appStore.setCurrentSize(size)
25 26 }
26 27 </script>
... ...
yudao-ui-admin-vue3/src/components/TabMenu/src/TabMenu.vue
1 1 <script lang="tsx">
2 2 import { usePermissionStore } from '@/store/modules/permission'
3 3 import { useAppStore } from '@/store/modules/app'
4   -import { computed, unref, defineComponent, watch, ref } from 'vue'
  4 +import { computed, unref, defineComponent, watch, ref, onMounted } from 'vue'
5 5 import { useI18n } from '@/hooks/web/useI18n'
6 6 import { ElScrollbar } from 'element-plus'
7 7 import { Icon } from '@/components/Icon'
... ... @@ -28,6 +28,8 @@ export default defineComponent({
28 28  
29 29 const collapse = computed(() => appStore.getCollapse)
30 30  
  31 + const fixedMenu = computed(() => appStore.getFixedMenu)
  32 +
31 33 const permissionStore = usePermissionStore()
32 34  
33 35 const routers = computed(() => permissionStore.getRouters)
... ... @@ -38,6 +40,27 @@ export default defineComponent({
38 40 appStore.setCollapse(!unref(collapse))
39 41 }
40 42  
  43 + onMounted(() => {
  44 + if (unref(fixedMenu)) {
  45 + const path = `/${unref(currentRoute).path.split('/')[1]}`
  46 + const children = unref(tabRouters).find(
  47 + (v) =>
  48 + (v.meta?.alwaysShow || (v?.children?.length && v?.children?.length > 1)) &&
  49 + v.path === path
  50 + )?.children
  51 +
  52 + tabActive.value = path
  53 + if (children) {
  54 + permissionStore.setMenuTabRouters(
  55 + cloneDeep(children).map((v) => {
  56 + v.path = pathResolve(unref(tabActive), v.path)
  57 + return v
  58 + })
  59 + )
  60 + }
  61 + }
  62 + })
  63 +
41 64 watch(
42 65 () => routers.value,
43 66 (routers: AppRouteRecordRaw[]) => {
... ... @@ -66,7 +89,7 @@ export default defineComponent({
66 89 )
67 90  
68 91 // 是否显示菜单
69   - const showMenu = ref(false)
  92 + const showMenu = ref(unref(fixedMenu) ? true : false)
70 93  
71 94 // tab高亮
72 95 const tabActive = ref('')
... ... @@ -77,9 +100,13 @@ export default defineComponent({
77 100 window.open(item.path)
78 101 return
79 102 }
  103 + const newPath = item.children ? item.path : item.path.split('/')[0]
  104 + const oldPath = unref(tabActive)
80 105 tabActive.value = item.children ? item.path : item.path.split('/')[0]
81 106 if (item.children) {
82   - showMenu.value = !unref(showMenu)
  107 + if (newPath === oldPath || !unref(showMenu)) {
  108 + showMenu.value = unref(fixedMenu) ? true : !unref(showMenu)
  109 + }
83 110 if (unref(showMenu)) {
84 111 permissionStore.setMenuTabRouters(
85 112 cloneDeep(item.children).map((v) => {
... ... @@ -96,7 +123,7 @@ export default defineComponent({
96 123 }
97 124  
98 125 // 设置高亮
99   - const isActice = (currentPath: string) => {
  126 + const isActive = (currentPath: string) => {
100 127 const { path } = unref(currentRoute)
101 128 if (tabPathMap[currentPath].includes(path)) {
102 129 return true
... ... @@ -105,7 +132,7 @@ export default defineComponent({
105 132 }
106 133  
107 134 const mouseleave = () => {
108   - if (!unref(showMenu)) return
  135 + if (!unref(showMenu) || unref(fixedMenu)) return
109 136 showMenu.value = false
110 137 }
111 138  
... ... @@ -114,7 +141,7 @@ export default defineComponent({
114 141 id={`${variables.namespace}-menu`}
115 142 class={[
116 143 prefixCls,
117   - 'relative bg-[var(--left-menu-bg-color)] top-1px z-999',
  144 + 'relative bg-[var(--left-menu-bg-color)] top-1px z-3000',
118 145 {
119 146 'w-[var(--tab-menu-max-width)]': !unref(collapse),
120 147 'w-[var(--tab-menu-min-width)]': unref(collapse)
... ... @@ -140,7 +167,7 @@ export default defineComponent({
140 167 `${prefixCls}__item`,
141 168 'text-center text-12px relative py-12px cursor-pointer',
142 169 {
143   - 'is-active': isActice(v.path)
  170 + 'is-active': isActive(v.path)
144 171 }
145 172 ]}
146 173 onClick={() => {
... ... @@ -174,8 +201,8 @@ export default defineComponent({
174 201 {
175 202 '!left-[var(--tab-menu-min-width)]': unref(collapse),
176 203 '!left-[var(--tab-menu-max-width)]': !unref(collapse),
177   - '!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu),
178   - '!w-0': !unref(showMenu)
  204 + '!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu) || unref(fixedMenu),
  205 + '!w-0': !unref(showMenu) && !unref(fixedMenu)
179 206 }
180 207 ]}
181 208 style="transition: width var(--transition-time-02), left var(--transition-time-02);"
... ...
yudao-ui-admin-vue3/src/components/TabMenu/src/helper.ts
... ... @@ -28,9 +28,9 @@ export const filterMenusPath = (
28 28 let data: Nullable<AppRouteRecordRaw> = null
29 29 const meta = (v.meta ?? {}) as RouteMeta
30 30 if (!meta.hidden || meta.canTo) {
31   - const allParentPaht = getAllParentPath<AppRouteRecordRaw>(allRoutes, v.path)
  31 + const allParentPath = getAllParentPath<AppRouteRecordRaw>(allRoutes, v.path)
32 32  
33   - const fullPath = isUrl(v.path) ? v.path : allParentPaht.join('/')
  33 + const fullPath = isUrl(v.path) ? v.path : allParentPath.join('/')
34 34  
35 35 data = cloneDeep(v)
36 36 data.path = fullPath
... ... @@ -42,8 +42,8 @@ export const filterMenusPath = (
42 42 res.push(data)
43 43 }
44 44  
45   - if (allParentPaht.length && Reflect.has(tabPathMap, allParentPaht[0])) {
46   - tabPathMap[allParentPaht[0]].push(fullPath)
  45 + if (allParentPath.length && Reflect.has(tabPathMap, allParentPath[0])) {
  46 + tabPathMap[allParentPath[0]].push(fullPath)
47 47 }
48 48 }
49 49 }
... ...
yudao-ui-admin-vue3/src/components/Table/index.ts
1 1 import Table from './src/Table.vue'
  2 +import { ElTable } from 'element-plus'
  3 +import { TableSetPropsType } from '@/types/table'
2 4  
3 5 export interface TableExpose {
4 6 setProps: (props: Recordable) => void
5 7 setColumn: (columnProps: TableSetPropsType[]) => void
6 8 selections: Recordable[]
  9 + elTableRef: ComponentRef<typeof ElTable>
7 10 }
8 11  
9 12 export { Table }
... ...
yudao-ui-admin-vue3/src/components/Table/src/Table.vue
... ... @@ -6,6 +6,7 @@ import { setIndex } from &#39;./helper&#39;
6 6 import { getSlot } from '@/utils/tsxHelper'
7 7 import type { TableProps } from './types'
8 8 import { set } from 'lodash-es'
  9 +import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table'
9 10  
10 11 export default defineComponent({
11 12 name: 'Table',
... ...
yudao-ui-admin-vue3/src/components/Table/src/types.ts
  1 +import { Pagination, TableColumn } from '@/types/table'
  2 +
1 3 export type TableProps = {
2 4 pageSize?: number
3 5 currentPage?: number
... ...
yudao-ui-admin-vue3/src/components/UserInfo/src/UserInfo.vue
... ... @@ -36,8 +36,8 @@ const loginOut = () =&gt; {
36 36 })
37 37 .then(async () => {
38 38 userStore.loginOut()
39   - tagsViewStore.delAllViews
40   - replace('/login')
  39 + tagsViewStore.delAllViews()
  40 + replace('/login?redirect=/index')
41 41 })
42 42 .catch(() => {})
43 43 }
... ...
yudao-ui-admin-vue3/src/config/app.ts deleted
1   -import { useCache } from '@/hooks/web/useCache'
2   -
3   -const { wsCache } = useCache()
4   -
5   -export type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'
6   -
7   -export type ThemeTypes = {
8   - elColorPrimary?: string
9   - leftMenuBorderColor?: string
10   - leftMenuBgColor?: string
11   - leftMenuBgLightColor?: string
12   - leftMenuBgActiveColor?: string
13   - leftMenuCollapseBgActiveColor?: string
14   - leftMenuTextColor?: string
15   - leftMenuTextActiveColor?: string
16   - logoTitleTextColor?: string
17   - logoBorderColor?: string
18   - topHeaderBgColor?: string
19   - topHeaderTextColor?: string
20   - topHeaderHoverColor?: string
21   - topToolBorderColor?: string
22   -}
23   -export interface AppState {
24   - breadcrumb: boolean
25   - breadcrumbIcon: boolean
26   - collapse: boolean
27   - uniqueOpened: boolean
28   - hamburger: boolean
29   - screenfull: boolean
30   - size: boolean
31   - locale: boolean
32   - tagsView: boolean
33   - tagsViewIcon: boolean
34   - logo: boolean
35   - fixedHeader: boolean
36   - greyMode: boolean
37   - pageLoading: boolean
38   - layout: LayoutType
39   - title: string
40   - userInfo: string
41   - isDark: boolean
42   - currentSize: ElememtPlusSize
43   - sizeMap: ElememtPlusSize[]
44   - mobile: boolean
45   - footer: boolean
46   - theme: ThemeTypes
47   -}
48   -
49   -export const appModules: AppState = {
50   - userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
51   - sizeMap: ['default', 'large', 'small'],
52   - mobile: false, // 是否是移动端
53   - title: import.meta.env.VITE_APP_TITLE, // 标题
54   - pageLoading: false, // 路由跳转loading
55   -
56   - breadcrumb: true, // 面包屑
57   - breadcrumbIcon: false, // 面包屑图标
58   - collapse: false, // 折叠菜单
59   - uniqueOpened: true, // 是否只保持一个子菜单的展开
60   - hamburger: true, // 折叠图标
61   - screenfull: true, // 全屏图标
62   - size: true, // 尺寸图标
63   - locale: true, // 多语言图标
64   - tagsView: true, // 标签页
65   - tagsViewIcon: false, // 是否显示标签图标
66   - logo: true, // logo
67   - fixedHeader: true, // 固定toolheader
68   - footer: true, // 显示页脚
69   - greyMode: false, // 是否开始灰色模式,用于特殊悼念日
70   -
71   - layout: wsCache.get('layout') || 'topLeft', // layout布局
72   - isDark: wsCache.get('isDark') || false, // 是否是暗黑模式
73   - currentSize: wsCache.get('default') || 'default', // 组件尺寸
74   - theme: wsCache.get('theme') || {
75   - // 主题色
76   - elColorPrimary: '#409eff',
77   - // 左侧菜单边框颜色
78   - leftMenuBorderColor: 'inherit',
79   - // 左侧菜单背景颜色
80   - leftMenuBgColor: '#001529',
81   - // 左侧菜单浅色背景颜色
82   - leftMenuBgLightColor: '#0f2438',
83   - // 左侧菜单选中背景颜色
84   - leftMenuBgActiveColor: 'var(--el-color-primary)',
85   - // 左侧菜单收起选中背景颜色
86   - leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
87   - // 左侧菜单字体颜色
88   - leftMenuTextColor: '#bfcbd9',
89   - // 左侧菜单选中字体颜色
90   - leftMenuTextActiveColor: '#fff',
91   - // logo字体颜色
92   - logoTitleTextColor: '#fff',
93   - // logo边框颜色
94   - logoBorderColor: 'inherit',
95   - // 头部背景颜色
96   - topHeaderBgColor: '#fff',
97   - // 头部字体颜色
98   - topHeaderTextColor: 'inherit',
99   - // 头部悬停颜色
100   - topHeaderHoverColor: '#f6f6f6',
101   - // 头部边框颜色
102   - topToolBorderColor: '#eee'
103   - }
104   -}
yudao-ui-admin-vue3/src/config/axios/index.ts
1   -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
  1 +import axios, {
  2 + AxiosInstance,
  3 + AxiosRequestConfig,
  4 + AxiosRequestHeaders,
  5 + AxiosResponse,
  6 + AxiosError
  7 +} from 'axios'
2 8 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
3 9 import qs from 'qs'
4 10 import { config } from '@/config/axios/config'
... ... @@ -48,7 +54,8 @@ service.interceptors.request.use(
48 54 const data = config.data || false
49 55 if (
50 56 config.method?.toUpperCase() === 'POST' &&
51   - config!.headers!['Content-Type'] === 'application/x-www-form-urlencoded'
  57 + (config.headers as AxiosRequestHeaders)['Content-Type'] ===
  58 + 'application/x-www-form-urlencoded'
52 59 ) {
53 60 config.data = qs.stringify(data)
54 61 }
... ... @@ -121,12 +128,18 @@ service.interceptors.response.use(
121 128 const refreshTokenRes = await refreshToken()
122 129 // 2.1 刷新成功,则回放队列的请求 + 当前请求
123 130 setToken(refreshTokenRes.data)
124   - requestList.forEach((cb: any) => cb())
  131 + ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken()
  132 + requestList.forEach((cb: any) => {
  133 + cb()
  134 + })
  135 + requestList = []
125 136 return service(response.config)
126 137 } catch (e) {
127 138 // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
128 139 // 2.2 刷新失败,只回放队列的请求
129   - requestList.forEach((cb: any) => cb())
  140 + requestList.forEach((cb: any) => {
  141 + cb()
  142 + })
130 143 // 提示是否要登出。即不回放当前请求!不然会形成递归
131 144 return handleAuthorized()
132 145 } finally {
... ... @@ -187,10 +200,7 @@ service.interceptors.response.use(
187 200 )
188 201  
189 202 const refreshToken = async () => {
190   - return await service({
191   - url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken(),
192   - method: 'post'
193   - })
  203 + return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
194 204 }
195 205 const handleAuthorized = () => {
196 206 const { t } = useI18n()
... ...
yudao-ui-admin-vue3/src/config/locale.ts deleted
1   -import { useCache } from '@/hooks/web/useCache'
2   -import zhCn from 'element-plus/es/locale/lang/zh-cn'
3   -import en from 'element-plus/es/locale/lang/en'
4   -
5   -const { wsCache } = useCache()
6   -
7   -export const elLocaleMap = {
8   - 'zh-CN': zhCn,
9   - en: en
10   -}
11   -export interface LocaleState {
12   - currentLocale: LocaleDropdownType
13   - localeMap: LocaleDropdownType[]
14   -}
15   -
16   -export const localeModules: LocaleState = {
17   - currentLocale: {
18   - lang: wsCache.get('lang') || 'zh-CN',
19   - elLocale: elLocaleMap[wsCache.get('lang') || 'zh-CN']
20   - },
21   - // 多语言
22   - localeMap: [
23   - {
24   - lang: 'zh-CN',
25   - name: '简体中文'
26   - },
27   - {
28   - lang: 'en',
29   - name: 'English'
30   - }
31   - ]
32   -}
yudao-ui-admin-vue3/src/hooks/web/useConfigGlobal.ts
  1 +import { ConfigGlobalTypes } from '@/types/configGlobal'
1 2 import { inject } from 'vue'
2 3  
3 4 export const useConfigGlobal = () => {
... ...
yudao-ui-admin-vue3/src/hooks/web/useCrudSchemas.ts
1 1 import { reactive } from 'vue'
2 2 import { eachTree, treeMap, filter } from '@/utils/tree'
3 3 import { getIntDictOptions } from '@/utils/dict'
  4 +import { FormSchema } from '@/types/form'
  5 +import { TableColumn } from '@/types/table'
  6 +import { DescriptionsSchema } from '@/types/descriptions'
  7 +import { ComponentOptions } from '@/types/components'
4 8  
5 9 export type CrudSchema = Omit<TableColumn, 'children'> & {
6 10 search?: CrudSearchParams
... ...
yudao-ui-admin-vue3/src/hooks/web/useForm.ts
... ... @@ -2,6 +2,7 @@ import type { Form, FormExpose } from &#39;@/components/Form&#39;
2 2 import type { ElForm } from 'element-plus'
3 3 import { ref, unref, nextTick } from 'vue'
4 4 import type { FormProps } from '@/components/Form/src/types'
  5 +import { FormSchema, FormSetPropsType } from '@/types/form'
5 6  
6 7 export const useForm = (props?: FormProps) => {
7 8 // From实例
... ...
yudao-ui-admin-vue3/src/hooks/web/useIcon.ts
1 1 import { h } from 'vue'
2 2 import type { VNode } from 'vue'
3 3 import { Icon } from '@/components/Icon'
  4 +import { IconTypes } from '@/types/icon'
4 5  
5 6 export const useIcon = (props: IconTypes): VNode => {
6 7 return h(Icon, props)
... ...
yudao-ui-admin-vue3/src/hooks/web/useTable.ts
... ... @@ -4,6 +4,7 @@ import { ElMessage, ElMessageBox, ElTable } from &#39;element-plus&#39;
4 4 import { computed, nextTick, reactive, ref, unref, watch } from 'vue'
5 5 import type { TableProps } from '@/components/Table/src/types'
6 6 import { useI18n } from '@/hooks/web/useI18n'
  7 +import { TableSetPropsType } from '@/types/table'
7 8  
8 9 const { t } = useI18n()
9 10 interface ResponseType<T = any> {
... ... @@ -150,13 +151,17 @@ export const useTable = &lt;T = any&gt;(config?: UseTableConfig&lt;T&gt;) =&gt; {
150 151 },
151 152 // 与Search组件结合
152 153 setSearchParams: (data: Recordable) => {
153   - tableObject.currentPage = 1
154 154 tableObject.params = Object.assign(tableObject.params, {
155 155 pageSize: tableObject.pageSize,
156   - pageNo: tableObject.currentPage,
  156 + pageNo: 1,
157 157 ...data
158 158 })
159   - methods.getList()
  159 + // 页码不等于1时更新页码重新获取数据,页码等于1时重新获取数据
  160 + if (tableObject.currentPage !== 1) {
  161 + tableObject.currentPage = 1
  162 + } else {
  163 + methods.getList()
  164 + }
160 165 },
161 166 // 删除数据
162 167 delList: async (
... ...
yudao-ui-admin-vue3/src/layout/components/useRenderLayout.tsx
... ... @@ -32,6 +32,9 @@ const fixedHeader = computed(() =&gt; appStore.getFixedHeader)
32 32 // 是否是移动端
33 33 const mobile = computed(() => appStore.getMobile)
34 34  
  35 +// 固定菜单
  36 +const fixedMenu = computed(() => appStore.getFixedMenu)
  37 +
35 38 export const useRenderLayout = () => {
36 39 const renderClassic = () => {
37 40 return (
... ... @@ -213,9 +216,13 @@ export const useRenderLayout = () =&gt; {
213 216 'h-[100%]',
214 217 {
215 218 'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)]':
216   - collapse.value,
  219 + collapse.value && !fixedMenu.value,
217 220 'w-[calc(100%-var(--tab-menu-max-width))] left-[var(--tab-menu-max-width)]':
218   - !collapse.value
  221 + !collapse.value && !fixedMenu.value,
  222 + 'w-[calc(100%-var(--tab-menu-min-width)-var(--left-menu-max-width))] ml-[var(--left-menu-max-width)]':
  223 + collapse.value && fixedMenu.value,
  224 + 'w-[calc(100%-var(--tab-menu-max-width)-var(--left-menu-max-width))] ml-[var(--left-menu-max-width)]':
  225 + !collapse.value && fixedMenu.value
219 226 }
220 227 ]}
221 228 style="transition: all var(--transition-time-02);"
... ... @@ -239,7 +246,13 @@ export const useRenderLayout = () =&gt; {
239 246 'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)] mt-[var(--logo-height)]':
240 247 collapse.value && fixedHeader.value,
241 248 'w-[calc(100%-var(--tab-menu-max-width))] left-[var(--tab-menu-max-width)] mt-[var(--logo-height)]':
242   - !collapse.value && fixedHeader.value
  249 + !collapse.value && fixedHeader.value,
  250 + '!fixed top-0 left-[var(--tab-menu-min-width)+var(--left-menu-max-width)] z-10':
  251 + fixedHeader.value && fixedMenu.value,
  252 + '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)]':
  253 + collapse.value && fixedHeader.value && fixedMenu.value,
  254 + '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)]':
  255 + !collapse.value && fixedHeader.value && fixedMenu.value
243 256 }
244 257 ]}
245 258 style="transition: width var(--transition-time-02), left var(--transition-time-02);"
... ...
yudao-ui-admin-vue3/src/locales/en.ts
... ... @@ -91,7 +91,10 @@ export default {
91 91 copyFailed: 'Copy failed',
92 92 footer: 'Footer',
93 93 uniqueOpened: 'Unique opened',
94   - tagsViewIcon: 'Tags view icon'
  94 + tagsViewIcon: 'Tags view icon',
  95 + dynamicRouter: 'Dynamic router',
  96 + reExperienced: 'Please exit the login experience again',
  97 + fixedMenu: 'Fixed menu'
95 98 },
96 99 size: {
97 100 default: 'Default',
... ...
yudao-ui-admin-vue3/src/locales/zh-CN.ts
... ... @@ -91,7 +91,10 @@ export default {
91 91 copyFailed: '拷贝失败',
92 92 footer: '页脚',
93 93 uniqueOpened: '菜单手风琴',
94   - tagsViewIcon: '标签页图标'
  94 + tagsViewIcon: '标签页图标',
  95 + dynamicRouter: '动态路由',
  96 + reExperienced: '请重新退出登录体验',
  97 + fixedMenu: '固定菜单'
95 98 },
96 99 size: {
97 100 default: '默认',
... ...
yudao-ui-admin-vue3/src/store/index.ts
1 1 import type { App } from 'vue'
2 2 import { createPinia } from 'pinia'
3   -import piniaPluginPersist from 'pinia-plugin-persist'
4 3  
5 4 const store = createPinia()
6 5  
7   -store.use(piniaPluginPersist)
8   -
9 6 export const setupStore = (app: App<Element>) => {
10 7 app.use(store)
11 8 }
... ...
yudao-ui-admin-vue3/src/store/modules/app.ts
1 1 import { defineStore } from 'pinia'
2 2 import { store } from '../index'
3   -import { useCache } from '@/hooks/web/useCache'
4   -import { appModules } from '@/config/app'
5   -import type { AppState, LayoutType, ThemeTypes } from '@/config/app'
6 3 import { setCssVar, humpToUnderline } from '@/utils'
7 4 import { ElMessage } from 'element-plus'
  5 +import { useCache } from '@/hooks/web/useCache'
  6 +import { ElementPlusSize } from '@/types/elementPlus'
  7 +import { LayoutType } from '@/types/layout'
  8 +import { ThemeTypes } from '@/types/theme'
8 9  
9 10 const { wsCache } = useCache()
10 11  
11   -export const useAppStore = defineStore({
12   - id: 'app',
13   - state: (): AppState => appModules,
14   - persist: {
15   - enabled: true
  12 +interface AppState {
  13 + breadcrumb: boolean
  14 + breadcrumbIcon: boolean
  15 + collapse: boolean
  16 + uniqueOpened: boolean
  17 + hamburger: boolean
  18 + screenfull: boolean
  19 + size: boolean
  20 + locale: boolean
  21 + tagsView: boolean
  22 + tagsViewIcon: boolean
  23 + logo: boolean
  24 + fixedHeader: boolean
  25 + greyMode: boolean
  26 + pageLoading: boolean
  27 + layout: LayoutType
  28 + title: string
  29 + userInfo: string
  30 + isDark: boolean
  31 + currentSize: ElementPlusSize
  32 + sizeMap: ElementPlusSize[]
  33 + mobile: boolean
  34 + footer: boolean
  35 + theme: ThemeTypes
  36 + fixedMenu: boolean
  37 +}
  38 +
  39 +export const useAppStore = defineStore('app', {
  40 + state: (): AppState => {
  41 + return {
  42 + userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
  43 + sizeMap: ['default', 'large', 'small'],
  44 + mobile: false, // 是否是移动端
  45 + title: import.meta.env.VITE_APP_TITLE, // 标题
  46 + pageLoading: false, // 路由跳转loading
  47 +
  48 + breadcrumb: true, // 面包屑
  49 + breadcrumbIcon: true, // 面包屑图标
  50 + collapse: false, // 折叠菜单
  51 + uniqueOpened: true, // 是否只保持一个子菜单的展开
  52 + hamburger: true, // 折叠图标
  53 + screenfull: true, // 全屏图标
  54 + size: true, // 尺寸图标
  55 + locale: true, // 多语言图标
  56 + tagsView: true, // 标签页
  57 + tagsViewIcon: true, // 是否显示标签图标
  58 + logo: true, // logo
  59 + fixedHeader: true, // 固定toolheader
  60 + footer: true, // 显示页脚
  61 + greyMode: false, // 是否开始灰色模式,用于特殊悼念日
  62 + fixedMenu: wsCache.get('fixedMenu') || false, // 是否固定菜单
  63 +
  64 + layout: wsCache.get('layout') || 'classic', // layout布局
  65 + isDark: wsCache.get('isDark') || false, // 是否是暗黑模式
  66 + currentSize: wsCache.get('default') || 'default', // 组件尺寸
  67 + theme: wsCache.get('theme') || {
  68 + // 主题色
  69 + elColorPrimary: '#409eff',
  70 + // 左侧菜单边框颜色
  71 + leftMenuBorderColor: 'inherit',
  72 + // 左侧菜单背景颜色
  73 + leftMenuBgColor: '#001529',
  74 + // 左侧菜单浅色背景颜色
  75 + leftMenuBgLightColor: '#0f2438',
  76 + // 左侧菜单选中背景颜色
  77 + leftMenuBgActiveColor: 'var(--el-color-primary)',
  78 + // 左侧菜单收起选中背景颜色
  79 + leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
  80 + // 左侧菜单字体颜色
  81 + leftMenuTextColor: '#bfcbd9',
  82 + // 左侧菜单选中字体颜色
  83 + leftMenuTextActiveColor: '#fff',
  84 + // logo字体颜色
  85 + logoTitleTextColor: '#fff',
  86 + // logo边框颜色
  87 + logoBorderColor: 'inherit',
  88 + // 头部背景颜色
  89 + topHeaderBgColor: '#fff',
  90 + // 头部字体颜色
  91 + topHeaderTextColor: 'inherit',
  92 + // 头部悬停颜色
  93 + topHeaderHoverColor: '#f6f6f6',
  94 + // 头部边框颜色
  95 + topToolBorderColor: '#eee'
  96 + }
  97 + }
16 98 },
17 99 getters: {
18 100 getBreadcrumb(): boolean {
... ... @@ -54,6 +136,9 @@ export const useAppStore = defineStore({
54 136 getGreyMode(): boolean {
55 137 return this.greyMode
56 138 },
  139 + getFixedMenu(): boolean {
  140 + return this.fixedMenu
  141 + },
57 142 getPageLoading(): boolean {
58 143 return this.pageLoading
59 144 },
... ... @@ -69,10 +154,10 @@ export const useAppStore = defineStore({
69 154 getIsDark(): boolean {
70 155 return this.isDark
71 156 },
72   - getCurrentSize(): ElememtPlusSize {
  157 + getCurrentSize(): ElementPlusSize {
73 158 return this.currentSize
74 159 },
75   - getSizeMap(): ElememtPlusSize[] {
  160 + getSizeMap(): ElementPlusSize[] {
76 161 return this.sizeMap
77 162 },
78 163 getMobile(): boolean {
... ... @@ -125,6 +210,10 @@ export const useAppStore = defineStore({
125 210 setGreyMode(greyMode: boolean) {
126 211 this.greyMode = greyMode
127 212 },
  213 + setFixedMenu(fixedMenu: boolean) {
  214 + wsCache.set('fixedMenu', fixedMenu)
  215 + this.fixedMenu = fixedMenu
  216 + },
128 217 setPageLoading(pageLoading: boolean) {
129 218 this.pageLoading = pageLoading
130 219 },
... ... @@ -150,7 +239,7 @@ export const useAppStore = defineStore({
150 239 }
151 240 wsCache.set('isDark', this.isDark)
152 241 },
153   - setCurrentSize(currentSize: ElememtPlusSize) {
  242 + setCurrentSize(currentSize: ElementPlusSize) {
154 243 this.currentSize = currentSize
155 244 wsCache.set('currentSize', this.currentSize)
156 245 },
... ...
yudao-ui-admin-vue3/src/store/modules/dict.ts
... ... @@ -16,14 +16,10 @@ export interface DictState {
16 16 dictMap: Recordable
17 17 }
18 18  
19   -export const useDictStore = defineStore({
20   - id: 'dict',
  19 +export const useDictStore = defineStore('dict', {
21 20 state: (): DictState => ({
22 21 dictMap: {}
23 22 }),
24   - persist: {
25   - enabled: true
26   - },
27 23 getters: {
28 24 getDictMap(): Recordable {
29 25 return this.dictMap
... ...
yudao-ui-admin-vue3/src/store/modules/locale.ts
1 1 import { defineStore } from 'pinia'
2 2 import { store } from '../index'
  3 +import zhCn from 'element-plus/es/locale/lang/zh-cn'
  4 +import en from 'element-plus/es/locale/lang/en'
3 5 import { useCache } from '@/hooks/web/useCache'
4   -import { localeModules, elLocaleMap } from '@/config/locale'
5   -import type { LocaleState } from '@/config/locale'
  6 +import { LocaleDropdownType } from '@/types/localeDropdown'
6 7  
7 8 const { wsCache } = useCache()
8 9  
9   -export const useLocaleStore = defineStore({
10   - id: 'locales',
11   - state: (): LocaleState => localeModules,
12   - persist: {
13   - enabled: true
  10 +const elLocaleMap = {
  11 + 'zh-CN': zhCn,
  12 + en: en
  13 +}
  14 +interface LocaleState {
  15 + currentLocale: LocaleDropdownType
  16 + localeMap: LocaleDropdownType[]
  17 +}
  18 +
  19 +export const useLocaleStore = defineStore('locales', {
  20 + state: (): LocaleState => {
  21 + return {
  22 + currentLocale: {
  23 + lang: wsCache.get('lang') || 'zh-CN',
  24 + elLocale: elLocaleMap[wsCache.get('lang') || 'zh-CN']
  25 + },
  26 + // 多语言
  27 + localeMap: [
  28 + {
  29 + lang: 'zh-CN',
  30 + name: '简体中文'
  31 + },
  32 + {
  33 + lang: 'en',
  34 + name: 'English'
  35 + }
  36 + ]
  37 + }
14 38 },
15 39 getters: {
16 40 getCurrentLocale(): LocaleDropdownType {
... ...
yudao-ui-admin-vue3/src/store/modules/permission.ts
... ... @@ -14,16 +14,12 @@ export interface PermissionState {
14 14 menuTabRouters: AppRouteRecordRaw[]
15 15 }
16 16  
17   -export const usePermissionStore = defineStore({
18   - id: 'permission',
  17 +export const usePermissionStore = defineStore('permission', {
19 18 state: (): PermissionState => ({
20 19 routers: [],
21 20 addRouters: [],
22 21 menuTabRouters: []
23 22 }),
24   - persist: {
25   - enabled: true
26   - },
27 23 getters: {
28 24 getRouters(): AppRouteRecordRaw[] {
29 25 return this.routers
... ...
yudao-ui-admin-vue3/src/store/modules/tagsView.ts
... ... @@ -10,8 +10,7 @@ export interface TagsViewState {
10 10 cachedViews: Set<string>
11 11 }
12 12  
13   -export const useTagsViewStore = defineStore({
14   - id: 'tagsView',
  13 +export const useTagsViewStore = defineStore('tagsView', {
15 14 state: (): TagsViewState => ({
16 15 visitedViews: [],
17 16 cachedViews: new Set()
... ...
yudao-ui-admin-vue3/src/store/modules/user.ts
... ... @@ -16,8 +16,7 @@ interface UserInfoVO {
16 16 user: UserVO
17 17 }
18 18  
19   -export const useUserStore = defineStore({
20   - id: 'admin-user',
  19 +export const useUserStore = defineStore('admin-user', {
21 20 state: (): UserInfoVO => ({
22 21 permissions: [],
23 22 roles: [],
... ...
yudao-ui-admin-vue3/types/componentType/form.d.ts renamed to yudao-ui-admin-vue3/src/types/components.d.ts
1   -import type { CSSProperties } from 'vue'
2   -
3   -declare global {
4   - declare type ComponentName =
5   - | 'Radio'
6   - | 'RadioButton'
7   - | 'Checkbox'
8   - | 'CheckboxButton'
9   - | 'Input'
10   - | 'Autocomplete'
11   - | 'InputNumber'
12   - | 'Select'
13   - | 'Cascader'
14   - | 'Switch'
15   - | 'Slider'
16   - | 'TimePicker'
17   - | 'DatePicker'
18   - | 'Rate'
19   - | 'ColorPicker'
20   - | 'Transfer'
21   - | 'Divider'
22   - | 'TimeSelect'
23   - | 'SelectV2'
24   - | 'InputPassword'
25   - | 'Editor'
26   -
27   - declare type ColProps = {
28   - span?: number
29   - xs?: number
30   - sm?: number
31   - md?: number
32   - lg?: number
33   - xl?: number
34   - tag?: string
35   - }
36   -
37   - declare type FormValueType = string | number | string[] | number[] | boolean | undefined | null
38   -
39   - declare type FormItemProps = {
40   - labelWidth?: string | number
41   - required?: boolean
42   - rules?: Recordable
43   - error?: string
44   - showMessage?: boolean
45   - inlineMessage?: boolean
46   - style?: CSSProperties
47   - }
48   -
49   - declare type ComponentOptions = {
50   - label?: string
51   - value?: FormValueType
52   - disabled?: boolean
53   - key?: string | number
54   - children?: ComponentOptions[]
55   - options?: ComponentOptions[]
56   - } & Recordable
57   -
58   - declare type ComponentOptionsAlias = {
59   - labelField?: string
60   - valueField?: string
61   - }
62   -
63   - declare type ComponentProps = {
64   - optionsAlias?: ComponentOptionsAlias
65   - options?: ComponentOptions[]
66   - optionsSlot?: boolean
67   - } & Recordable
68   -
69   - declare type FormSchema = {
70   - // 唯一值
71   - field: string
72   - // 标题
73   - label?: string
74   - // 提示
75   - labelMessage?: string
76   - // col组件属性
77   - colProps?: ColProps
78   - // 表单组件属性,slots对应的是表单组件的插槽,规则:${field}-xxx,具体可以查看element-plus文档
79   - componentProps?: { slots?: Recordable } & ComponentProps
80   - // formItem组件属性
81   - formItemProps?: FormItemProps
82   - // 渲染的组件
83   - component?: ComponentName
84   - // 初始值
85   - value?: FormValueType
86   - // 是否隐藏
87   - hidden?: boolean
88   - // 远程加载下拉项
89   - api?: <T = any>() => Promise<T>
90   - }
  1 +export type ComponentName =
  2 + | 'Radio'
  3 + | 'RadioButton'
  4 + | 'Checkbox'
  5 + | 'CheckboxButton'
  6 + | 'Input'
  7 + | 'Autocomplete'
  8 + | 'InputNumber'
  9 + | 'Select'
  10 + | 'Cascader'
  11 + | 'Switch'
  12 + | 'Slider'
  13 + | 'TimePicker'
  14 + | 'DatePicker'
  15 + | 'Rate'
  16 + | 'ColorPicker'
  17 + | 'Transfer'
  18 + | 'Divider'
  19 + | 'TimeSelect'
  20 + | 'SelectV2'
  21 + | 'InputPassword'
  22 + | 'Editor'
  23 +
  24 +export type ColProps = {
  25 + span?: number
  26 + xs?: number
  27 + sm?: number
  28 + md?: number
  29 + lg?: number
  30 + xl?: number
  31 + tag?: string
  32 +}
91 33  
92   - declare type FormSetPropsType = {
93   - field: string
94   - path: string
95   - value: any
96   - }
  34 +export type ComponentOptions = {
  35 + label?: string
  36 + value?: FormValueType
  37 + disabled?: boolean
  38 + key?: string | number
  39 + children?: ComponentOptions[]
  40 + options?: ComponentOptions[]
  41 +} & Recordable
  42 +
  43 +export type ComponentOptionsAlias = {
  44 + labelField?: string
  45 + valueField?: string
97 46 }
  47 +
  48 +export type ComponentProps = {
  49 + optionsAlias?: ComponentOptionsAlias
  50 + options?: ComponentOptions[]
  51 + optionsSlot?: boolean
  52 +} & Recordable
... ...
yudao-ui-admin-vue3/src/types/configGlobal.d.ts 0 → 100644
  1 +import { ElementPlusSize } from './elementPlus'
  2 +export interface ConfigGlobalTypes {
  3 + size?: ElementPlusSize
  4 +}
... ...
yudao-ui-admin-vue3/types/componentType/contextMenu.d.ts renamed to yudao-ui-admin-vue3/src/types/contextMenu.d.ts
1   -declare type contextMenuSchema = {
  1 +export type contextMenuSchema = {
2 2 disabled?: boolean
3 3 divided?: boolean
4 4 icon?: string
5 5 label: string
6   - command?: (item: contextMenuSchema) => viod
  6 + command?: (item: contextMenuSchema) => void
7 7 }
... ...
yudao-ui-admin-vue3/types/componentType/descriptions.d.ts renamed to yudao-ui-admin-vue3/src/types/descriptions.d.ts
1   -declare interface DescriptionsSchema {
  1 +export interface DescriptionsSchema {
2 2 span?: number // 占多少分
3 3 field: string // 字段名
4 4 label?: string // label名
... ...
yudao-ui-admin-vue3/src/types/elementPlus.d.ts 0 → 100644
  1 +export type ElementPlusSize = 'default' | 'small' | 'large'
  2 +
  3 +export type ElementPlusInfoType = 'success' | 'info' | 'warning' | 'danger'
... ...
yudao-ui-admin-vue3/src/types/form.d.ts 0 → 100644
  1 +import type { CSSProperties } from 'vue'
  2 +import { ColProps, ComponentProps, ComponentName } from '@/types/components'
  3 +import { FormValueType, FormValueType } from '@/types/form'
  4 +import type { AxiosPromise } from 'axios'
  5 +
  6 +export type FormSetPropsType = {
  7 + field: string
  8 + path: string
  9 + value: any
  10 +}
  11 +
  12 +export type FormValueType = string | number | string[] | number[] | boolean | undefined | null
  13 +
  14 +export type FormItemProps = {
  15 + labelWidth?: string | number
  16 + required?: boolean
  17 + rules?: Recordable
  18 + error?: string
  19 + showMessage?: boolean
  20 + inlineMessage?: boolean
  21 + style?: CSSProperties
  22 +}
  23 +
  24 +export type FormSchema = {
  25 + // 唯一值
  26 + field: string
  27 + // 标题
  28 + label?: string
  29 + // 提示
  30 + labelMessage?: string
  31 + // col组件属性
  32 + colProps?: ColProps
  33 + // 表单组件属性,slots对应的是表单组件的插槽,规则:${field}-xxx,具体可以查看element-plus文档
  34 + componentProps?: { slots?: Recordable } & ComponentProps
  35 + // formItem组件属性
  36 + formItemProps?: FormItemProps
  37 + // 渲染的组件
  38 + component?: ComponentName
  39 + // 初始值
  40 + value?: FormValueType
  41 + // 是否隐藏
  42 + hidden?: boolean
  43 + // 远程加载下拉项
  44 + api?: <T = any>() => AxiosPromise<T>
  45 +}
... ...
yudao-ui-admin-vue3/types/componentType/icon.d.ts renamed to yudao-ui-admin-vue3/src/types/icon.d.ts
1   -declare interface IconTypes {
  1 +export interface IconTypes {
2 2 size?: number
3 3 color?: string
4 4 icon: string
... ...
yudao-ui-admin-vue3/types/componentType/infotip.d.ts renamed to yudao-ui-admin-vue3/src/types/infoTip.d.ts
1   -declare interface TipSchema {
  1 +export interface TipSchema {
2 2 label: string
3 3 keys?: string[]
4 4 }
... ...
yudao-ui-admin-vue3/src/types/layout.d.ts 0 → 100644
  1 +export type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'
... ...
yudao-ui-admin-vue3/types/componentType/localeDropdown.d.ts renamed to yudao-ui-admin-vue3/src/types/localeDropdown.d.ts
1   -declare interface Language {
  1 +export interface Language {
2 2 el: Recordable
3 3 name: string
4 4 }
5 5  
6   -declare interface LocaleDropdownType {
  6 +export interface LocaleDropdownType {
7 7 lang: LocaleType
8 8 name?: string
9 9 elLocale?: Language
... ...
yudao-ui-admin-vue3/types/componentType/qrcode.d.ts renamed to yudao-ui-admin-vue3/src/types/qrcode.d.ts
1   -declare interface QrcodeLogo {
  1 +export interface QrcodeLogo {
2 2 src?: string
3 3 logoSize?: number
4 4 bgColor?: string
... ...
yudao-ui-admin-vue3/types/componentType/table.d.ts renamed to yudao-ui-admin-vue3/src/types/table.d.ts
1   -declare type TableColumn = {
  1 +export type TableColumn = {
2 2 field: string
3 3 label?: string
4 4 children?: TableColumn[]
5 5 } & Recordable
6 6  
7   -declare type TableSlotDefault = {
  7 +export type TableSlotDefault = {
8 8 row: Recordable
9 9 column: TableColumn
10 10 $index: number
11 11 } & Recordable
12 12  
13   -declare interface Pagination {
  13 +export interface Pagination {
14 14 small?: boolean
15 15 background?: boolean
16 16 pageSize?: number
... ... @@ -29,7 +29,7 @@ declare interface Pagination {
29 29 hideOnSinglePage?: boolean
30 30 }
31 31  
32   -declare interface TableSetPropsType {
  32 +export interface TableSetPropsType {
33 33 field: string
34 34 path: string
35 35 value: any
... ...
yudao-ui-admin-vue3/src/types/theme.d.ts 0 → 100644
  1 +export type ThemeTypes = {
  2 + elColorPrimary?: string
  3 + leftMenuBorderColor?: string
  4 + leftMenuBgColor?: string
  5 + leftMenuBgLightColor?: string
  6 + leftMenuBgActiveColor?: string
  7 + leftMenuCollapseBgActiveColor?: string
  8 + leftMenuTextColor?: string
  9 + leftMenuTextActiveColor?: string
  10 + logoTitleTextColor?: string
  11 + logoBorderColor?: string
  12 + topHeaderBgColor?: string
  13 + topHeaderTextColor?: string
  14 + topHeaderHoverColor?: string
  15 + topToolBorderColor?: string
  16 +}
... ...
yudao-ui-admin-vue3/src/utils/dict.ts
... ... @@ -2,6 +2,7 @@
2 2 * 数据字典工具类
3 3 */
4 4 import { useDictStoreWithOut } from '@/store/modules/dict'
  5 +import { ElementPlusInfoType } from '@/types/elementPlus'
5 6  
6 7 const dictStore = useDictStoreWithOut()
7 8  
... ...
yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue
... ... @@ -103,20 +103,25 @@ const getCookie = () =&gt; {
103 103 // 登录
104 104 const handleLogin = async (params) => {
105 105 loginLoading.value = true
106   - await getTenantId()
107   - const data = await validForm()
108   - if (!data) {
  106 + try {
  107 + await getTenantId()
  108 + const data = await validForm()
  109 + if (!data) {
  110 + return
  111 + }
  112 + loginData.loginForm.captchaVerification = params.captchaVerification
  113 + const res = await LoginApi.loginApi(loginData.loginForm)
  114 + if (!res) {
  115 + return
  116 + }
  117 + setToken(res)
  118 + if (!redirect.value) {
  119 + redirect.value = '/'
  120 + }
  121 + push({ path: redirect.value || permissionStore.addRouters[0].path })
  122 + } finally {
109 123 loginLoading.value = false
110   - return
111   - }
112   - loginData.loginForm.captchaVerification = params.captchaVerification
113   - const res = await LoginApi.loginApi(loginData.loginForm)
114   - setToken(res)
115   - if (!redirect.value) {
116   - redirect.value = '/'
117 124 }
118   - push({ path: redirect.value || permissionStore.addRouters[0].path })
119   - loginLoading.value = false
120 125 }
121 126  
122 127 // 社交登录
... ...
yudao-ui-admin-vue3/src/views/Login/components/RegisterForm.vue
... ... @@ -7,6 +7,7 @@ import { ElInput, FormRules } from &#39;element-plus&#39;
7 7 import { useValidator } from '@/hooks/web/useValidator'
8 8 import { useLoginState, LoginStateEnum } from './useLogin'
9 9 import LoginFormTitle from './LoginFormTitle.vue'
  10 +import { FormSchema } from '@/types/form'
10 11  
11 12 const { register, elFormRef } = useForm()
12 13 const { handleBackLogin, getLoginState } = useLoginState()
... ...
yudao-ui-admin-vue3/src/views/bpm/form/index.vue
... ... @@ -49,23 +49,29 @@ const handleUpdate = async (row: FormVO) =&gt; {
49 49  
50 50 // 提交按钮
51 51 const submitForm = async () => {
52   - actionLoading.value = true
53   - // 提交请求
54   - try {
55   - const data = unref(formRef)?.formModel as FormVO
56   - if (actionType.value === 'create') {
57   - await FormApi.createFormApi(data)
58   - ElMessage.success(t('common.createSuccess'))
59   - } else {
60   - await FormApi.updateFormApi(data)
61   - ElMessage.success(t('common.updateSuccess'))
  52 + const elForm = unref(formRef)?.getElFormRef()
  53 + if (!elForm) return
  54 + elForm.validate(async (valid) => {
  55 + if (valid) {
  56 + actionLoading.value = true
  57 + // 提交请求
  58 + try {
  59 + const data = unref(formRef)?.formModel as FormVO
  60 + if (actionType.value === 'create') {
  61 + await FormApi.createFormApi(data)
  62 + ElMessage.success(t('common.createSuccess'))
  63 + } else {
  64 + await FormApi.updateFormApi(data)
  65 + ElMessage.success(t('common.updateSuccess'))
  66 + }
  67 + // 操作成功,重新加载列表
  68 + dialogVisible.value = false
  69 + await getList()
  70 + } finally {
  71 + actionLoading.value = false
  72 + }
62 73 }
63   - // 操作成功,重新加载列表
64   - dialogVisible.value = false
65   - await getList()
66   - } finally {
67   - actionLoading.value = false
68   - }
  74 + })
69 75 }
70 76  
71 77 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/bpm/group/index.vue
... ... @@ -62,24 +62,30 @@ const handleUpdate = async (row: UserGroupVO) =&gt; {
62 62  
63 63 // 提交按钮
64 64 const submitForm = async () => {
65   - actionLoading.value = true
66   - // 提交请求
67   - try {
68   - const data = unref(formRef)?.formModel as UserGroupVO
69   - data.memberUserIds = userIds.value
70   - if (actionType.value === 'create') {
71   - await UserGroupApi.createUserGroupApi(data)
72   - ElMessage.success(t('common.createSuccess'))
73   - } else {
74   - await UserGroupApi.updateUserGroupApi(data)
75   - ElMessage.success(t('common.updateSuccess'))
  65 + const elForm = unref(formRef)?.getElFormRef()
  66 + if (!elForm) return
  67 + elForm.validate(async (valid) => {
  68 + if (valid) {
  69 + actionLoading.value = true
  70 + // 提交请求
  71 + try {
  72 + const data = unref(formRef)?.formModel as UserGroupVO
  73 + data.memberUserIds = userIds.value
  74 + if (actionType.value === 'create') {
  75 + await UserGroupApi.createUserGroupApi(data)
  76 + ElMessage.success(t('common.createSuccess'))
  77 + } else {
  78 + await UserGroupApi.updateUserGroupApi(data)
  79 + ElMessage.success(t('common.updateSuccess'))
  80 + }
  81 + // 操作成功,重新加载列表
  82 + dialogVisible.value = false
  83 + await getList()
  84 + } finally {
  85 + actionLoading.value = false
  86 + }
76 87 }
77   - // 操作成功,重新加载列表
78   - dialogVisible.value = false
79   - await getList()
80   - } finally {
81   - actionLoading.value = false
82   - }
  88 + })
83 89 }
84 90  
85 91 // 根据用户名获取用户真实名
... ...
yudao-ui-admin-vue3/src/views/bpm/model/index.vue
... ... @@ -51,23 +51,29 @@ const handleUpdate = async (row: ModelVO) =&gt; {
51 51  
52 52 // 提交按钮
53 53 const submitForm = async () => {
54   - actionLoading.value = true
55   - // 提交请求
56   - try {
57   - const data = unref(formRef)?.formModel as ModelVO
58   - if (actionType.value === 'create') {
59   - await ModelApi.createModelApi(data)
60   - message.success(t('common.createSuccess'))
61   - } else {
62   - await ModelApi.updateModelApi(data)
63   - message.success(t('common.updateSuccess'))
  54 + const elForm = unref(formRef)?.getElFormRef()
  55 + if (!elForm) return
  56 + elForm.validate(async (valid) => {
  57 + if (valid) {
  58 + actionLoading.value = true
  59 + // 提交请求
  60 + try {
  61 + const data = unref(formRef)?.formModel as ModelVO
  62 + if (actionType.value === 'create') {
  63 + await ModelApi.createModelApi(data)
  64 + message.success(t('common.createSuccess'))
  65 + } else {
  66 + await ModelApi.updateModelApi(data)
  67 + message.success(t('common.updateSuccess'))
  68 + }
  69 + // 操作成功,重新加载列表
  70 + dialogVisible.value = false
  71 + await getList()
  72 + } finally {
  73 + actionLoading.value = false
  74 + }
64 75 }
65   - // 操作成功,重新加载列表
66   - dialogVisible.value = false
67   - await getList()
68   - } finally {
69   - actionLoading.value = false
70   - }
  76 + })
71 77 }
72 78  
73 79 /** 流程表单的详情按钮操作 */
... ...
yudao-ui-admin-vue3/src/views/infra/codegen/EditTable.vue
... ... @@ -26,6 +26,10 @@ const activeName = ref(&#39;cloum&#39;)
26 26 const basicInfoRef = ref<ComponentRef<typeof BasicInfoForm>>()
27 27 const genInfoRef = ref<ComponentRef<typeof GenInfoForm>>()
28 28 const cloumInfoRef = ref(null)
  29 +const parentMenuId = ref<number>()
  30 +const menu = (id: number) => {
  31 + parentMenuId.value = id
  32 +}
29 33 const submitForm = async () => {
30 34 const basicInfo = unref(basicInfoRef)
31 35 const genInfo = unref(genInfoRef)
... ... @@ -38,6 +42,11 @@ const submitForm = async () =&gt; {
38 42 table: Object.assign({}, basicInfoData, genInfoData),
39 43 columns: cloumCurrentRow.value
40 44 }
  45 + if (parentMenuId.value) {
  46 + genInfoData.parentMenuId = parentMenuId.value
  47 + } else {
  48 + genInfoData.parentMenuId = 0
  49 + }
41 50 await updateCodegenTableApi(genTable)
42 51 ElMessage.success(t('common.updateSuccess'))
43 52 push('/infra/codegen')
... ... @@ -57,7 +66,7 @@ onMounted(() =&gt; {
57 66 <CloumInfoForm ref="cloumInfoRef" :info="cloumCurrentRow" />
58 67 </el-tab-pane>
59 68 <el-tab-pane label="生成信息" name="genInfo">
60   - <GenInfoForm ref="genInfoRef" :genInfo="tableCurrentRow" />
  69 + <GenInfoForm ref="genInfoRef" :genInfo="tableCurrentRow" @menu="menu" />
61 70 </el-tab-pane>
62 71 </el-tabs>
63 72 <template #right>
... ...
yudao-ui-admin-vue3/src/views/infra/codegen/components/BasicInfoForm.vue
... ... @@ -4,6 +4,8 @@ import { required } from &#39;@/utils/formRules&#39;
4 4 import { CodegenTableVO } from '@/api/infra/codegen/types'
5 5 import { Form } from '@/components/Form'
6 6 import { useForm } from '@/hooks/web/useForm'
  7 +import { FormSchema } from '@/types/form'
  8 +
7 9 const props = defineProps({
8 10 basicInfo: {
9 11 type: Object as PropType<Nullable<CodegenTableVO>>,
... ...
yudao-ui-admin-vue3/src/views/infra/codegen/components/GenInfoForm.vue
1 1 <script setup lang="ts">
2   -import { PropType, reactive, watch } from 'vue'
  2 +import { onMounted, PropType, reactive, ref, watch } from 'vue'
3 3 import { required } from '@/utils/formRules'
4   -import { CodegenTableVO } from '@/api/infra/codegen/types'
5 4 import { Form } from '@/components/Form'
  5 +import { handleTree } from '@/utils/tree'
  6 +import { ElTreeSelect } from 'element-plus'
6 7 import { useForm } from '@/hooks/web/useForm'
7 8 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  9 +import { listSimpleMenusApi } from '@/api/system/menu'
  10 +import { CodegenTableVO } from '@/api/infra/codegen/types'
  11 +import { FormSchema } from '@/types/form'
8 12 const props = defineProps({
9 13 genInfo: {
10 14 type: Object as PropType<Nullable<CodegenTableVO>>,
11 15 default: () => null
12 16 }
13 17 })
  18 +const menuProps = {
  19 + checkStrictly: true,
  20 + children: 'children',
  21 + label: 'name',
  22 + value: 'id'
  23 +}
14 24 const rules = reactive({
15 25 templateType: [required],
16 26 scene: [required],
... ... @@ -22,6 +32,12 @@ const rules = reactive({
22 32 })
23 33 const templateTypeOptions = getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE)
24 34 const sceneOptions = getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE)
  35 +const treeRef = ref<InstanceType<typeof ElTreeSelect>>()
  36 +const menuOptions = ref<any>([]) // 树形结构
  37 +const getTree = async () => {
  38 + const res = await listSimpleMenusApi()
  39 + menuOptions.value = handleTree(res)
  40 +}
25 41 const schema = reactive<FormSchema[]>([
26 42 {
27 43 label: '生成模板',
... ... @@ -84,7 +100,9 @@ const schema = reactive&lt;FormSchema[]&gt;([
84 100 {
85 101 label: '上级菜单',
86 102 field: 'parentMenuId',
87   - component: 'Input',
  103 + componentProps: {
  104 + optionsSlot: true
  105 + },
88 106 labelMessage: '分配到指定菜单下,例如 系统管理',
89 107 colProps: {
90 108 span: 12
... ... @@ -94,6 +112,17 @@ const schema = reactive&lt;FormSchema[]&gt;([
94 112 const { register, methods, elFormRef } = useForm({
95 113 schema
96 114 })
  115 +const parentMenuId = ref<number>()
  116 +//子组件像父组件传值
  117 +const emit = defineEmits(['menu'])
  118 +const handleNodeClick = () => {
  119 + emit('menu', parentMenuId.value)
  120 +}
  121 +
  122 +// ========== 初始化 ==========
  123 +onMounted(async () => {
  124 + await getTree()
  125 +})
97 126 watch(
98 127 () => props.genInfo,
99 128 (genInfo) => {
... ... @@ -106,12 +135,23 @@ watch(
106 135 immediate: true
107 136 }
108 137 )
109   -
110 138 defineExpose({
111 139 elFormRef,
112 140 getFormData: methods.getFormData
113 141 })
114 142 </script>
115 143 <template>
116   - <Form :rules="rules" @register="register" />
  144 + <Form :rules="rules" @register="register">
  145 + <template #parentMenuId>
  146 + <el-tree-select
  147 + v-model="parentMenuId"
  148 + ref="treeRef"
  149 + node-key="id"
  150 + :props="menuProps"
  151 + :data="menuOptions"
  152 + check-strictly
  153 + @node-click="handleNodeClick"
  154 + />
  155 + </template>
  156 + </Form>
117 157 </template>
... ...
yudao-ui-admin-vue3/src/views/infra/codegen/components/ImportTable.vue
1 1 <script setup lang="ts">
2   -import { reactive, ref } from 'vue'
  2 +import { reactive, ref, defineEmits } from 'vue'
3 3 import { getSchemaTableListApi, createCodegenListApi } from '@/api/infra/codegen'
4 4 import {
5 5 ElMessage,
... ...
yudao-ui-admin-vue3/src/views/infra/config/index.vue
... ... @@ -50,23 +50,29 @@ const handleUpdate = async (row: ConfigVO) =&gt; {
50 50  
51 51 // 提交按钮
52 52 const submitForm = async () => {
53   - actionLoading.value = true
54   - // 提交请求
55   - try {
56   - const data = unref(formRef)?.formModel as ConfigVO
57   - if (actionType.value === 'create') {
58   - await ConfigApi.createConfigApi(data)
59   - ElMessage.success(t('common.createSuccess'))
60   - } else {
61   - await ConfigApi.updateConfigApi(data)
62   - ElMessage.success(t('common.updateSuccess'))
  53 + const elForm = unref(formRef)?.getElFormRef()
  54 + if (!elForm) return
  55 + elForm.validate(async (valid) => {
  56 + if (valid) {
  57 + actionLoading.value = true
  58 + // 提交请求
  59 + try {
  60 + const data = unref(formRef)?.formModel as ConfigVO
  61 + if (actionType.value === 'create') {
  62 + await ConfigApi.createConfigApi(data)
  63 + ElMessage.success(t('common.createSuccess'))
  64 + } else {
  65 + await ConfigApi.updateConfigApi(data)
  66 + ElMessage.success(t('common.updateSuccess'))
  67 + }
  68 + // 操作成功,重新加载列表
  69 + dialogVisible.value = false
  70 + await getList()
  71 + } finally {
  72 + actionLoading.value = false
  73 + }
63 74 }
64   - // 操作成功,重新加载列表
65   - dialogVisible.value = false
66   - await getList()
67   - } finally {
68   - actionLoading.value = false
69   - }
  75 + })
70 76 }
71 77  
72 78 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/index.vue
... ... @@ -44,23 +44,29 @@ const handleUpdate = async (row: DataSourceConfigVO) =&gt; {
44 44  
45 45 // 提交按钮
46 46 const submitForm = async () => {
47   - loading.value = true
48   - // 提交请求
49   - try {
50   - const data = unref(formRef)?.formModel as DataSourceConfigVO
51   - if (actionType.value === 'create') {
52   - await DataSourceConfiggApi.createDataSourceConfigApi(data)
53   - ElMessage.success(t('common.createSuccess'))
54   - } else {
55   - await DataSourceConfiggApi.updateDataSourceConfigApi(data)
56   - ElMessage.success(t('common.updateSuccess'))
  47 + const elForm = unref(formRef)?.getElFormRef()
  48 + if (!elForm) return
  49 + elForm.validate(async (valid) => {
  50 + if (valid) {
  51 + loading.value = true
  52 + // 提交请求
  53 + try {
  54 + const data = unref(formRef)?.formModel as DataSourceConfigVO
  55 + if (actionType.value === 'create') {
  56 + await DataSourceConfiggApi.createDataSourceConfigApi(data)
  57 + ElMessage.success(t('common.createSuccess'))
  58 + } else {
  59 + await DataSourceConfiggApi.updateDataSourceConfigApi(data)
  60 + ElMessage.success(t('common.updateSuccess'))
  61 + }
  62 + // 操作成功,重新加载列表
  63 + dialogVisible.value = false
  64 + await getList()
  65 + } finally {
  66 + loading.value = false
  67 + }
57 68 }
58   - // 操作成功,重新加载列表
59   - dialogVisible.value = false
60   - await getList()
61   - } finally {
62   - loading.value = false
63   - }
  69 + })
64 70 }
65 71  
66 72 // 删除操作
... ...
yudao-ui-admin-vue3/src/views/infra/fileConfig/index.vue
... ... @@ -60,23 +60,29 @@ const handleMaster = (row: FileConfigVO) =&gt; {
60 60  
61 61 // 提交按钮
62 62 const submitForm = async () => {
63   - actionLoading.value = true
64   - // 提交请求
65   - try {
66   - const data = unref(formRef)?.formModel as FileConfigVO
67   - if (actionType.value === 'create') {
68   - await FileConfigApi.createFileConfigApi(data)
69   - message.success(t('common.createSuccess'))
70   - } else {
71   - await FileConfigApi.updateFileConfigApi(data)
72   - message.success(t('common.updateSuccess'))
  63 + const elForm = unref(formRef)?.getElFormRef()
  64 + if (!elForm) return
  65 + elForm.validate(async (valid) => {
  66 + if (valid) {
  67 + actionLoading.value = true
  68 + // 提交请求
  69 + try {
  70 + const data = unref(formRef)?.formModel as FileConfigVO
  71 + if (actionType.value === 'create') {
  72 + await FileConfigApi.createFileConfigApi(data)
  73 + message.success(t('common.createSuccess'))
  74 + } else {
  75 + await FileConfigApi.updateFileConfigApi(data)
  76 + message.success(t('common.updateSuccess'))
  77 + }
  78 + // 操作成功,重新加载列表
  79 + dialogVisible.value = false
  80 + await getList()
  81 + } finally {
  82 + actionLoading.value = false
  83 + }
73 84 }
74   - // 操作成功,重新加载列表
75   - dialogVisible.value = false
76   - await getList()
77   - } finally {
78   - actionLoading.value = false
79   - }
  85 + })
80 86 }
81 87  
82 88 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/infra/job/index.vue
... ... @@ -98,24 +98,30 @@ const handleRun = (row: JobVO) =&gt; {
98 98 }
99 99 // 提交按钮
100 100 const submitForm = async () => {
101   - actionLoading.value = true
102   - // 提交请求
103   - try {
104   - const data = unref(formRef)?.formModel as JobVO
105   - data.cronExpression = cronExpression.value
106   - if (actionType.value === 'create') {
107   - await JobApi.createJobApi(data)
108   - message.success(t('common.createSuccess'))
109   - } else {
110   - await JobApi.updateJobApi(data)
111   - message.success(t('common.updateSuccess'))
  101 + const elForm = unref(formRef)?.getElFormRef()
  102 + if (!elForm) return
  103 + elForm.validate(async (valid) => {
  104 + if (valid) {
  105 + actionLoading.value = true
  106 + // 提交请求
  107 + try {
  108 + const data = unref(formRef)?.formModel as JobVO
  109 + data.cronExpression = cronExpression.value
  110 + if (actionType.value === 'create') {
  111 + await JobApi.createJobApi(data)
  112 + message.success(t('common.createSuccess'))
  113 + } else {
  114 + await JobApi.updateJobApi(data)
  115 + message.success(t('common.updateSuccess'))
  116 + }
  117 + // 操作成功,重新加载列表
  118 + dialogVisible.value = false
  119 + await getList()
  120 + } finally {
  121 + actionLoading.value = false
  122 + }
112 123 }
113   - // 操作成功,重新加载列表
114   - dialogVisible.value = false
115   - await getList()
116   - } finally {
117   - actionLoading.value = false
118   - }
  124 + })
119 125 }
120 126  
121 127 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/pay/app/index.vue
... ... @@ -50,23 +50,29 @@ const handleUpdate = async (row: AppVO) =&gt; {
50 50  
51 51 // 提交按钮
52 52 const submitForm = async () => {
53   - actionLoading.value = true
54   - // 提交请求
55   - try {
56   - const data = unref(formRef)?.formModel as AppVO
57   - if (actionType.value === 'create') {
58   - await AppApi.createAppApi(data)
59   - ElMessage.success(t('common.createSuccess'))
60   - } else {
61   - await AppApi.updateAppApi(data)
62   - ElMessage.success(t('common.updateSuccess'))
  53 + const elForm = unref(formRef)?.getElFormRef()
  54 + if (!elForm) return
  55 + elForm.validate(async (valid) => {
  56 + if (valid) {
  57 + actionLoading.value = true
  58 + // 提交请求
  59 + try {
  60 + const data = unref(formRef)?.formModel as AppVO
  61 + if (actionType.value === 'create') {
  62 + await AppApi.createAppApi(data)
  63 + ElMessage.success(t('common.createSuccess'))
  64 + } else {
  65 + await AppApi.updateAppApi(data)
  66 + ElMessage.success(t('common.updateSuccess'))
  67 + }
  68 + // 操作成功,重新加载列表
  69 + dialogVisible.value = false
  70 + await getList()
  71 + } finally {
  72 + actionLoading.value = false
  73 + }
63 74 }
64   - // 操作成功,重新加载列表
65   - dialogVisible.value = false
66   - await getList()
67   - } finally {
68   - actionLoading.value = false
69   - }
  75 + })
70 76 }
71 77  
72 78 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/pay/merchant/index.vue
... ... @@ -50,23 +50,29 @@ const handleUpdate = async (row: MerchantVO) =&gt; {
50 50  
51 51 // 提交按钮
52 52 const submitForm = async () => {
53   - actionLoading.value = true
54   - // 提交请求
55   - try {
56   - const data = unref(formRef)?.formModel as MerchantVO
57   - if (actionType.value === 'create') {
58   - await MerchantApi.createMerchantApi(data)
59   - ElMessage.success(t('common.createSuccess'))
60   - } else {
61   - await MerchantApi.updateMerchantApi(data)
62   - ElMessage.success(t('common.updateSuccess'))
  53 + const elForm = unref(formRef)?.getElFormRef()
  54 + if (!elForm) return
  55 + elForm.validate(async (valid) => {
  56 + if (valid) {
  57 + actionLoading.value = true
  58 + // 提交请求
  59 + try {
  60 + const data = unref(formRef)?.formModel as MerchantVO
  61 + if (actionType.value === 'create') {
  62 + await MerchantApi.createMerchantApi(data)
  63 + ElMessage.success(t('common.createSuccess'))
  64 + } else {
  65 + await MerchantApi.updateMerchantApi(data)
  66 + ElMessage.success(t('common.updateSuccess'))
  67 + }
  68 + // 操作成功,重新加载列表
  69 + dialogVisible.value = false
  70 + await getList()
  71 + } finally {
  72 + actionLoading.value = false
  73 + }
63 74 }
64   - // 操作成功,重新加载列表
65   - dialogVisible.value = false
66   - await getList()
67   - } finally {
68   - actionLoading.value = false
69   - }
  75 + })
70 76 }
71 77  
72 78 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/pay/order/index.vue
... ... @@ -48,23 +48,29 @@ const handleUpdate = async (row: OrderVO) =&gt; {
48 48  
49 49 // 提交按钮
50 50 const submitForm = async () => {
51   - actionLoading.value = true
52   - // 提交请求
53   - try {
54   - const data = unref(formRef)?.formModel as OrderVO
55   - if (actionType.value === 'create') {
56   - await OrderApi.createOrderApi(data)
57   - ElMessage.success(t('common.createSuccess'))
58   - } else {
59   - await OrderApi.updateOrderApi(data)
60   - ElMessage.success(t('common.updateSuccess'))
  51 + const elForm = unref(formRef)?.getElFormRef()
  52 + if (!elForm) return
  53 + elForm.validate(async (valid) => {
  54 + if (valid) {
  55 + actionLoading.value = true
  56 + // 提交请求
  57 + try {
  58 + const data = unref(formRef)?.formModel as OrderVO
  59 + if (actionType.value === 'create') {
  60 + await OrderApi.createOrderApi(data)
  61 + ElMessage.success(t('common.createSuccess'))
  62 + } else {
  63 + await OrderApi.updateOrderApi(data)
  64 + ElMessage.success(t('common.updateSuccess'))
  65 + }
  66 + // 操作成功,重新加载列表
  67 + dialogVisible.value = false
  68 + await getList()
  69 + } finally {
  70 + actionLoading.value = false
  71 + }
61 72 }
62   - // 操作成功,重新加载列表
63   - dialogVisible.value = false
64   - await getList()
65   - } finally {
66   - actionLoading.value = false
67   - }
  73 + })
68 74 }
69 75  
70 76 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts
1 1 import { required } from '@/utils/formRules'
2 2 import { reactive } from 'vue'
  3 +import { FormSchema } from '@/types/form'
  4 +
3 5 // 表单校验
4 6 export const rules = reactive({
5 7 name: [required],
... ...
yudao-ui-admin-vue3/src/views/system/dept/index.vue
... ... @@ -82,22 +82,28 @@ const handleDelete = async (data: { id: number }) =&gt; {
82 82 }
83 83 // 提交按钮
84 84 const submitForm = async () => {
85   - loading.value = true
86   - // 提交请求
87   - try {
88   - const data = unref(formRef)?.formModel as DeptVO
89   - data.parentId = deptParentId.value
90   - data.leaderUserId = leaderUserId.value
91   - if (formTitle.value.startsWith('新增')) {
92   - await DeptApi.createDeptApi(data)
93   - } else if (formTitle.value.startsWith('修改')) {
94   - await DeptApi.updateDeptApi(data)
  85 + const elForm = unref(formRef)?.getElFormRef()
  86 + if (!elForm) return
  87 + elForm.validate(async (valid) => {
  88 + if (valid) {
  89 + loading.value = true
  90 + // 提交请求
  91 + try {
  92 + const data = unref(formRef)?.formModel as DeptVO
  93 + data.parentId = deptParentId.value
  94 + data.leaderUserId = leaderUserId.value
  95 + if (formTitle.value.startsWith('新增')) {
  96 + await DeptApi.createDeptApi(data)
  97 + } else if (formTitle.value.startsWith('修改')) {
  98 + await DeptApi.updateDeptApi(data)
  99 + }
  100 + // 操作成功,重新加载列表
  101 + dialogVisible.value = false
  102 + } finally {
  103 + loading.value = false
  104 + }
95 105 }
96   - // 操作成功,重新加载列表
97   - dialogVisible.value = false
98   - } finally {
99   - loading.value = false
100   - }
  106 + })
101 107 }
102 108 onMounted(async () => {
103 109 await getTree()
... ...
yudao-ui-admin-vue3/src/views/system/dict/index.vue
... ... @@ -92,43 +92,55 @@ const setDialogTile = (type: string) =&gt; {
92 92 }
93 93 // 提交按钮
94 94 const submitTypeForm = async () => {
95   - actionLoading.value = true
96   - // 提交请求
97   - try {
98   - const data = unref(typeFormRef)?.formModel as DictTypeVO
99   - if (actionType.value === 'typeCreate') {
100   - await DictTypeApi.createDictTypeApi(data)
101   - ElMessage.success(t('common.createSuccess'))
102   - } else if (actionType.value === 'typeUpdate') {
103   - await DictTypeApi.updateDictTypeApi(data)
104   - ElMessage.success(t('common.updateSuccess'))
  95 + const elForm = unref(typeFormRef)?.getElFormRef()
  96 + if (!elForm) return
  97 + elForm.validate(async (valid) => {
  98 + if (valid) {
  99 + actionLoading.value = true
  100 + // 提交请求
  101 + try {
  102 + const data = unref(typeFormRef)?.formModel as DictTypeVO
  103 + if (actionType.value === 'typeCreate') {
  104 + await DictTypeApi.createDictTypeApi(data)
  105 + ElMessage.success(t('common.createSuccess'))
  106 + } else if (actionType.value === 'typeUpdate') {
  107 + await DictTypeApi.updateDictTypeApi(data)
  108 + ElMessage.success(t('common.updateSuccess'))
  109 + }
  110 + // 操作成功,重新加载列表
  111 + await getTypeList()
  112 + dialogVisible.value = false
  113 + } finally {
  114 + actionLoading.value = false
  115 + }
105 116 }
106   - // 操作成功,重新加载列表
107   - await getTypeList()
108   - dialogVisible.value = false
109   - } finally {
110   - actionLoading.value = false
111   - }
  117 + })
112 118 }
113 119 const submitDataForm = async () => {
114   - actionLoading.value = true
115   - // 提交请求
116   - try {
117   - const data = unref(dataFormRef)?.formModel as DictDataVO
118   - if (actionType.value === 'dataCreate') {
119   - data.dictType = parentType.value
120   - await DictDataApi.createDictDataApi(data)
121   - ElMessage.success(t('common.createSuccess'))
122   - } else if (actionType.value === 'dataUpdate') {
123   - await DictDataApi.updateDictDataApi(data)
124   - ElMessage.success(t('common.updateSuccess'))
  120 + const elForm = unref(dataFormRef)?.getElFormRef()
  121 + if (!elForm) return
  122 + elForm.validate(async (valid) => {
  123 + if (valid) {
  124 + actionLoading.value = true
  125 + // 提交请求
  126 + try {
  127 + const data = unref(dataFormRef)?.formModel as DictDataVO
  128 + if (actionType.value === 'dataCreate') {
  129 + data.dictType = parentType.value
  130 + await DictDataApi.createDictDataApi(data)
  131 + ElMessage.success(t('common.createSuccess'))
  132 + } else if (actionType.value === 'dataUpdate') {
  133 + await DictDataApi.updateDictDataApi(data)
  134 + ElMessage.success(t('common.updateSuccess'))
  135 + }
  136 + await getDataList()
  137 + // 操作成功,重新加载列表
  138 + dialogVisible.value = false
  139 + } finally {
  140 + actionLoading.value = false
  141 + }
125 142 }
126   - await getDataList()
127   - // 操作成功,重新加载列表
128   - dialogVisible.value = false
129   - } finally {
130   - actionLoading.value = false
131   - }
  143 + })
132 144 }
133 145 // 初始化查询
134 146 onMounted(async () => {
... ...
yudao-ui-admin-vue3/src/views/system/errorCode/index.vue
... ... @@ -49,23 +49,29 @@ const handleUpdate = async (row: ErrorCodeVO) =&gt; {
49 49  
50 50 // 提交按钮
51 51 const submitForm = async () => {
52   - loading.value = true
53   - // 提交请求
54   - try {
55   - const data = unref(formRef)?.formModel as ErrorCodeVO
56   - if (actionType.value === 'create') {
57   - await ErrorCodeApi.createErrorCodeApi(data)
58   - ElMessage.success(t('common.createSuccess'))
59   - } else {
60   - await ErrorCodeApi.updateErrorCodeApi(data)
61   - ElMessage.success(t('common.updateSuccess'))
  52 + const elForm = unref(formRef)?.getElFormRef()
  53 + if (!elForm) return
  54 + elForm.validate(async (valid) => {
  55 + if (valid) {
  56 + loading.value = true
  57 + // 提交请求
  58 + try {
  59 + const data = unref(formRef)?.formModel as ErrorCodeVO
  60 + if (actionType.value === 'create') {
  61 + await ErrorCodeApi.createErrorCodeApi(data)
  62 + ElMessage.success(t('common.createSuccess'))
  63 + } else {
  64 + await ErrorCodeApi.updateErrorCodeApi(data)
  65 + ElMessage.success(t('common.updateSuccess'))
  66 + }
  67 + // 操作成功,重新加载列表
  68 + dialogVisible.value = false
  69 + await getList()
  70 + } finally {
  71 + loading.value = false
  72 + }
62 73 }
63   - // 操作成功,重新加载列表
64   - dialogVisible.value = false
65   - await getList()
66   - } finally {
67   - loading.value = false
68   - }
  74 + })
69 75 }
70 76  
71 77 // ========== 详情相关 ==========
... ...
yudao-ui-admin-vue3/src/views/system/menu/index.vue
... ... @@ -42,12 +42,18 @@ const menuProps = {
42 42 label: 'name',
43 43 value: 'id'
44 44 }
45   -const menuOptions = ref() // 树形结构
  45 +interface Tree {
  46 + id: number
  47 + name: string
  48 + children?: Tree[] | any[]
  49 +}
  50 +const menuOptions = ref<any[]>([]) // 树形结构
46 51 const getTree = async () => {
  52 + menuOptions.value = []
47 53 const res = await MenuApi.listSimpleMenusApi()
48   - const menu = { id: 0, name: '主类目', children: [] as any[] }
  54 + let menu: Tree = { id: 0, name: '主类目', children: [] }
49 55 menu.children = handleTree(res)
50   - menuOptions.value = menu
  56 + menuOptions.value.push(menu)
51 57 }
52 58 // ========== 查询 ==========
53 59 const queryParams = reactive({
... ... @@ -121,7 +127,7 @@ const handleDelete = async (row: MenuVO) =&gt; {
121 127 await getList()
122 128 }
123 129 // 保存操作
124   -function isExternal(path: string) {
  130 +const isExternal = (path: string) => {
125 131 return /^(https?:|mailto:|tel:)/.test(path)
126 132 }
127 133 const submitForm = async () => {
... ... @@ -268,7 +274,7 @@ onMounted(async () =&gt; {
268 274 node-key="id"
269 275 v-model="menuForm.parentId"
270 276 :props="menuProps"
271   - :data="menuData"
  277 + :data="menuOptions"
272 278 check-strictly
273 279 />
274 280 </el-form-item>
... ...