mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 08:52:28 +08:00
Compare commits
39 Commits
v3.7.1
...
v3.7.1last
| Author | SHA1 | Date | |
|---|---|---|---|
| 64b29f47e0 | |||
| 6198a3702f | |||
| 453acb9b4e | |||
| 565753e370 | |||
| e2aaf0f978 | |||
| 32c8370ef2 | |||
| a79004b924 | |||
| eb1612f8dd | |||
| a35555619c | |||
| b3e3951064 | |||
| 44ec26574e | |||
| 55a25caafd | |||
| 62f7b0d489 | |||
| b16fdef8dc | |||
| b5b667058b | |||
| 6c0c259742 | |||
| ca56c54aa0 | |||
| 74297af987 | |||
| fedb6b84b9 | |||
| fdc713339e | |||
| f28a2dbbeb | |||
| b81435aaca | |||
| 48805484d4 | |||
| 7fecdf94e5 | |||
| a3997dfd16 | |||
| c868d90c2f | |||
| 77aebf5dd2 | |||
| e770524f3a | |||
| c5fee07cba | |||
| 9fd20fde9e | |||
| 2af9451b7f | |||
| 575baa8d49 | |||
| 48bc76cce7 | |||
| 58c0882329 | |||
| c400ec8482 | |||
| 2068bdc112 | |||
| ffe806352e | |||
| 167a6c458c | |||
| 872e6ed024 |
12
LICENSE
12
LICENSE
@ -200,4 +200,14 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||
|
||||
开源协议中文释意如下:
|
||||
1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
2.允许基于本平台软件开展业务系统开发。
|
||||
3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
|
||||
最终解释权归:http://www.jeecg.com
|
||||
14
README-EN.md
14
README-EN.md
@ -72,10 +72,11 @@ Technical documentation
|
||||
-----------------------------------
|
||||
|
||||
- Website: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- Demo : [OnlineDemo](http://boot3.jeecg.com) | [APP](http://jeecg.com/appIndex)
|
||||
- Doc: [http://help.jeecg.com](http://help.jeecg.com)
|
||||
- Newbie guide: [Quick start](http://www.jeecg.com/doc/quickstart) | [Q&A ](http://www.jeecg.com/doc/qa) | [1 minute experience](https://my.oschina.net/jeecg/blog/3083313)
|
||||
- QQ group : ⑨808791225、⑧825232878、⑦791696430、⑥730954414(full)、683903138(full)、⑤860162132(full)、④774126647(full)、③816531124(full)、②769925425(full)、①284271917(full)
|
||||
- Demo : [OnlineDemo](http://boot3.jeecg.com) | [APP](http://jeecg.com/appIndex)
|
||||
- QQ group : ⑩716488839、⑨808791225、⑧825232878、⑦791696430、⑥730954414(full)、683903138(full)、⑤860162132(full)、④774126647(full)、③816531124(full)、②769925425(full)、①284271917(full)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -195,7 +196,7 @@ Technical Architecture:
|
||||
|
||||
- Persistence layer framework: MybatisPlus 3.5.3.2
|
||||
|
||||
- Report tool: JimuReport 1.7.6
|
||||
- Report tool: JimuReport 1.8.1
|
||||
|
||||
- Security framework: Apache Shiro 1.12.0, Jwt 3.11.0
|
||||
|
||||
@ -212,6 +213,12 @@ Technical Architecture:
|
||||
|
||||
- TechnologyStack:`Vue3.0+TypeScript+Vite+AntDesignVue+pinia+echarts`
|
||||
|
||||
#### Front-end environment requirements
|
||||
|
||||
* `Node.js 、npm 、pnpm`
|
||||
* Node.js Version suggestion: `v20.15.0`
|
||||
` ( Since Vite5 no longer supports EOL Node.js 14/16/17/19, Node.js 18/20 + is now required )`
|
||||
|
||||
#### Support library
|
||||
|
||||
| database | support |
|
||||
@ -223,6 +230,7 @@ Technical Architecture:
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
| TiDB | √ |
|
||||
|
||||
|
||||
## Microservice solutions
|
||||
|
||||
35
README.md
35
README.md
@ -18,7 +18,7 @@ JeecgBoot 低代码开发平台
|
||||
|
||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||
|
||||
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.x,SpringCloud,Ant Design Vue3,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.x,SpringCloud,Ant Design Vue3,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot集成AI模型能力,引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||
|
||||
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、仪表盘设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||
|
||||
@ -33,7 +33,6 @@ JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零
|
||||
Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,支持信创国产化(默认适配达梦和人大金仓)。尤其适合SAAS项目、企业信息管理系统(MIS)、内部办公系统(OA)、企业资源计划系统(ERP)、客户关系管理系统(CRM)等,其半智能手工Merge的开发方式,可以显著提高开发效率70%以上,极大降低开发成本。
|
||||
|
||||
|
||||
|
||||
#### 项目说明
|
||||
|
||||
| 项目名 | 说明 |
|
||||
@ -43,15 +42,27 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
| `jeecg-uniapp` | [配套APP框架](https://github.com/jeecgboot/jeecg-uniapp) 适配多个终端,支持APP、小程序、H5 |
|
||||
|
||||
|
||||
开源协议说明
|
||||
-----------------------------------
|
||||
JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0协议,详细见 https://github.com/jeecgboot/JeecgBoot#Apache-2.0-1-ov-file
|
||||
|
||||
开源协议中文释意如下:
|
||||
- 1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
- 2.允许基于本平台软件开展业务系统开发。
|
||||
- 3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
- 4.针对企业用户我们也提供“企业级版本”,详细见 https://jeecg.com/vip
|
||||
|
||||
|
||||
技术文档
|
||||
-----------------------------------
|
||||
|
||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
- 开发文档: [https://help.jeecg.com](https://help.jeecg.com)
|
||||
- 反馈问题: [在Github上提Issues](https://github.com/jeecgboot/JeecgBoot/issues/new)
|
||||
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart) | [入门视频](http://jeecg.com/doc/video)
|
||||
- QQ交流群 : ⑨808791225、其他(满)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
- QQ交流群 : ⑩716488839、⑨808791225(满)、其他(满)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -73,7 +84,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
- 基础框架:Spring Boot 2.7.18
|
||||
- 微服务框架: Spring Cloud Alibaba 2021.0.1.0
|
||||
- 持久层框架:MybatisPlus 3.5.3.2
|
||||
- 报表工具: JimuReport 1.7.6
|
||||
- 报表工具: JimuReport 1.8.1
|
||||
- 安全框架:Apache Shiro 1.12.0,Jwt 3.11.0
|
||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||
@ -87,11 +98,18 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
#### 前端
|
||||
|
||||
- 前端IDE建议:WebStorm、Vscode
|
||||
- 采用 Vue3.0+TypeScript+Vite+Ant-Design-Vue等新技术方案,包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
|
||||
- 采用 Vue3.0+TypeScript+Vite5+Ant-Design-Vue等新技术方案,包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
|
||||
- 最新技术栈:Vue3.0 + TypeScript + Vite5 + ant-design-vue4 + pinia + echarts + unocss + vxe-table + qiankun + es6
|
||||
- 依赖管理:node、npm、pnpm
|
||||
|
||||
|
||||
#### 前端环境要求
|
||||
|
||||
* 本地环境安装 `Node.js 、npm 、pnpm`
|
||||
* Node.js 版本建议`v20.15.0`,要求`Node 20+` 版本以上
|
||||
|
||||
` ( 因为Vite5 不再支持已 EOL 的 Node.js 14 / 16 / 17 / 19,现在需要 Node.js 18 / 20+ )`
|
||||
|
||||
|
||||
#### 支持库
|
||||
|
||||
@ -102,9 +120,10 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
| Sqlserver2017 | √ |
|
||||
| PostgreSQL | √ |
|
||||
| MariaDB | √ |
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
|
||||
| TiDB | √ |
|
||||
|
||||
|
||||
## 微服务解决方案
|
||||
@ -143,7 +162,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
-----------------------------------
|
||||
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd+vue3),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供切换机制支持单体和微服务自由切换
|
||||
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
||||
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;引入AI能力,支持自动建表等功能;
|
||||
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
||||
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
||||
* 6.低代码能力:Online在线表单(无需编码,通过在线配置表单,实现表单的增删改查,支持单表、树、一对多、一对一等模型,实现人人皆可编码)
|
||||
|
||||
@ -200,4 +200,14 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||
|
||||
开源协议中文释意如下:
|
||||
1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
2.允许基于本平台软件开展业务系统开发。
|
||||
3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
|
||||
最终解释权归:http://www.jeecg.com
|
||||
@ -35,7 +35,7 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
|
||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart)
|
||||
- QQ交流群 : ⑨808791225、其他(满)
|
||||
- QQ交流群 : ⑩716488839、⑨808791225、其他(满)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
> 演示系统的登录账号密码,请点击 [获取账号密码](http://jeecg.com/doc/demo) 获取
|
||||
|
||||
@ -66,7 +66,7 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
- 基础框架:Spring Boot 2.7.18
|
||||
- 微服务框架: Spring Cloud Alibaba 2021.0.1.0
|
||||
- 持久层框架:MybatisPlus 3.5.3.2
|
||||
- 报表工具: JimuReport 1.7.6
|
||||
- 报表工具: JimuReport 1.8.1
|
||||
- 安全框架:Apache Shiro 1.12.0,Jwt 3.11.0
|
||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||
@ -97,6 +97,7 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
| TiDB | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -3,6 +3,7 @@
|
||||
> JeecgBoot属于平台级产品,每次升级改动较大,目前做不到平滑升级。
|
||||
|
||||
### 增量升级方案
|
||||
|
||||
#### 1.代码合并
|
||||
本地通过svn或git做好主干,在分支上做业务开发,jeecg每次版本发布,可以手工覆盖主干的代码,对比合并代码;
|
||||
|
||||
@ -11,5 +12,12 @@
|
||||
- 其他库请手工执行SQL, 目录: `jeecg-module-system\jeecg-system-start\src\main\resources\flyway\sql\mysql`
|
||||
> 注意: 升级sql只提供mysql版本;如果有权限升级, 还需要手工角色授权,退出重新登录才好使。
|
||||
|
||||
#### 3.兼容问题
|
||||
#### 3.其他数据库脚本说明
|
||||
原先官方默认提供oracle和SqlServer的脚本,但是维护成本太高,未提供脚本的数据库,可以参考下面的文档自己转
|
||||
https://my.oschina.net/jeecg/blog/4905722
|
||||
(注意:定时任务的表qrtz_*,需要删掉用原始的脚本重新执行一下)
|
||||
quartz-2.2.3-distribution.tar.gz放到百度网盘中,大家自己下载,执行所需数据库脚本
|
||||
https://pan.baidu.com/s/1WrmZdUuAPg3iBwJ-LoHWyg?pwd=8mdz
|
||||
|
||||
#### 4.兼容问题
|
||||
每次发版,会针对不兼容地方重点说明。
|
||||
@ -106,9 +106,10 @@ public class DynamicDBUtil {
|
||||
dataSource.getConnection().commit();
|
||||
dataSource.getConnection().close();
|
||||
dataSource.close();
|
||||
DataSourceCachePool.removeCache(dbKey);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
log.info(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package org.jeecg.config.shiro;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
||||
@ -18,17 +17,15 @@ import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
|
||||
import org.jeecg.config.shiro.filters.JwtFilter;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
@ -36,7 +33,6 @@ import redis.clients.jedis.JedisCluster;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -127,6 +123,9 @@ public class ShiroConfig {
|
||||
filterChainDefinitionMap.put("/**/*.ttf", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.woff", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.woff2", "anon");
|
||||
|
||||
filterChainDefinitionMap.put("/**/*.glb", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.wasm", "anon");
|
||||
//update-end--Author:scott Date:20221116 for:排除静态资源后缀
|
||||
|
||||
filterChainDefinitionMap.put("/druid/**", "anon");
|
||||
@ -190,12 +189,24 @@ public class ShiroConfig {
|
||||
}
|
||||
|
||||
//update-begin---author:chenrui ---date:20240126 for:【QQYUN-7932】AI助手------------
|
||||
|
||||
/**
|
||||
* spring过滤装饰器 <br/>
|
||||
* 因为shiro的filter不支持异步请求,导致所有的异步请求都会报错. <br/>
|
||||
* 所以需要用spring的FilterRegistrationBean再代理一下shiro的filter.为他扩展异步支持. <br/>
|
||||
* 后续所有异步的接口都需要再这里增加registration.addUrlPatterns("/xxx/xxx");
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2024/12/3 19:49
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean shiroFilterRegistration() {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setFilter(new DelegatingFilterProxy("shiroFilterFactoryBean"));
|
||||
registration.setEnabled(true);
|
||||
registration.addUrlPatterns("/*");
|
||||
//update-begin---author:chenrui ---date:20241202 for:[issues/7491]运行时间好长,效率慢 ------------
|
||||
registration.addUrlPatterns("/test/ai/chat/send");
|
||||
//update-end---author:chenrui ---date:20241202 for:[issues/7491]运行时间好长,效率慢 ------------
|
||||
//支持异步
|
||||
registration.setAsyncSupported(true);
|
||||
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
|
||||
|
||||
@ -34,10 +34,10 @@
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 积木仪表盘 -->
|
||||
<!-- 积木BI -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-dashboard-spring-boot-starter</artifactId>
|
||||
<artifactId>jimubi-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 积木报表 mongo redis 支持包
|
||||
<dependency>
|
||||
|
||||
@ -3,6 +3,8 @@ package org.jeecg.modules.system.controller;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.system.util.XssUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -23,8 +25,13 @@ public class WechatVerifyController {
|
||||
*/
|
||||
@RequestMapping(value = "/WW_verify_{code}.txt")
|
||||
public void mpVerify(@PathVariable("code") String code, HttpServletResponse response) {
|
||||
if(StringUtils.isEmpty(code)){
|
||||
log.error("企业微信证书验证失败!(code为空)");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
PrintWriter writer = response.getWriter();
|
||||
code = XssUtils.scriptXss(code);
|
||||
writer.write(code);
|
||||
writer.close();
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -1,79 +1,77 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : localhost
|
||||
Source Server Type : MariaDB
|
||||
Source Server Version : 100316
|
||||
Source Host : localhost:3300
|
||||
Source Schema : seata
|
||||
|
||||
Target Server Type : MariaDB
|
||||
Target Server Version : 100316
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 05/01/2022 20:25:07
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for branch_table
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `branch_table`;
|
||||
CREATE TABLE `branch_table` (
|
||||
`branch_id` bigint(20) NOT NULL,
|
||||
`xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
|
||||
`transaction_id` bigint(20) NULL DEFAULT NULL,
|
||||
`resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`status` tinyint(4) NULL DEFAULT NULL,
|
||||
`client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`gmt_create` datetime(6) NULL DEFAULT NULL,
|
||||
`gmt_modified` datetime(6) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`branch_id`) USING BTREE,
|
||||
INDEX `idx_xid`(`xid`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for global_table
|
||||
-- ----------------------------
|
||||
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
|
||||
-- the table to store GlobalSession data
|
||||
DROP TABLE IF EXISTS `global_table`;
|
||||
CREATE TABLE `global_table` (
|
||||
`xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
|
||||
`transaction_id` bigint(20) NULL DEFAULT NULL,
|
||||
`status` tinyint(4) NOT NULL,
|
||||
`application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`timeout` int(11) NULL DEFAULT NULL,
|
||||
`begin_time` bigint(20) NULL DEFAULT NULL,
|
||||
`application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`gmt_create` datetime(0) NULL DEFAULT NULL,
|
||||
`gmt_modified` datetime(0) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`xid`) USING BTREE,
|
||||
INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,
|
||||
INDEX `idx_transaction_id`(`transaction_id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
|
||||
CREATE TABLE IF NOT EXISTS `global_table`
|
||||
(
|
||||
`xid` VARCHAR(128) NOT NULL,
|
||||
`transaction_id` BIGINT,
|
||||
`status` TINYINT NOT NULL,
|
||||
`application_id` VARCHAR(32),
|
||||
`transaction_service_group` VARCHAR(32),
|
||||
`transaction_name` VARCHAR(128),
|
||||
`timeout` INT,
|
||||
`begin_time` BIGINT,
|
||||
`application_data` VARCHAR(2000),
|
||||
`gmt_create` DATETIME,
|
||||
`gmt_modified` DATETIME,
|
||||
PRIMARY KEY (`xid`),
|
||||
KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
|
||||
KEY `idx_transaction_id` (`transaction_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for lock_table
|
||||
-- ----------------------------
|
||||
-- the table to store BranchSession data
|
||||
DROP TABLE IF EXISTS `branch_table`;
|
||||
CREATE TABLE IF NOT EXISTS `branch_table`
|
||||
(
|
||||
`branch_id` BIGINT NOT NULL,
|
||||
`xid` VARCHAR(128) NOT NULL,
|
||||
`transaction_id` BIGINT,
|
||||
`resource_group_id` VARCHAR(32),
|
||||
`resource_id` VARCHAR(256),
|
||||
`branch_type` VARCHAR(8),
|
||||
`status` TINYINT,
|
||||
`client_id` VARCHAR(64),
|
||||
`application_data` VARCHAR(2000),
|
||||
`gmt_create` DATETIME(6),
|
||||
`gmt_modified` DATETIME(6),
|
||||
PRIMARY KEY (`branch_id`),
|
||||
KEY `idx_xid` (`xid`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4;
|
||||
|
||||
-- the table to store lock data
|
||||
DROP TABLE IF EXISTS `lock_table`;
|
||||
CREATE TABLE `lock_table` (
|
||||
`row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
|
||||
`xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`transaction_id` bigint(20) NULL DEFAULT NULL,
|
||||
`branch_id` bigint(20) NOT NULL,
|
||||
`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`gmt_create` datetime(0) NULL DEFAULT NULL,
|
||||
`gmt_modified` datetime(0) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`row_key`) USING BTREE,
|
||||
INDEX `idx_branch_id`(`branch_id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
|
||||
CREATE TABLE IF NOT EXISTS `lock_table`
|
||||
(
|
||||
`row_key` VARCHAR(128) NOT NULL,
|
||||
`xid` VARCHAR(128),
|
||||
`transaction_id` BIGINT,
|
||||
`branch_id` BIGINT NOT NULL,
|
||||
`resource_id` VARCHAR(256),
|
||||
`table_name` VARCHAR(32),
|
||||
`pk` VARCHAR(36),
|
||||
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
|
||||
`gmt_create` DATETIME,
|
||||
`gmt_modified` DATETIME,
|
||||
PRIMARY KEY (`row_key`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_branch_id` (`branch_id`),
|
||||
KEY `idx_xid` (`xid`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
DROP TABLE IF EXISTS `distributed_lock`;
|
||||
CREATE TABLE IF NOT EXISTS `distributed_lock`
|
||||
(
|
||||
`lock_key` CHAR(20) NOT NULL,
|
||||
`lock_value` VARCHAR(20) NOT NULL,
|
||||
`expire` BIGINT,
|
||||
primary key (`lock_key`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4;
|
||||
|
||||
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
|
||||
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
|
||||
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
|
||||
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
|
||||
@ -6,20 +6,15 @@ spring:
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
autoconfigure:
|
||||
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
|
||||
exclude: com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
|
||||
datasource:
|
||||
dynamic:
|
||||
seata: true # 开启对 seata的支持
|
||||
primary: account
|
||||
datasource:
|
||||
account:
|
||||
url: jdbc:mysql://127.0.0.1:3306/jeecg_account?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
schema: classpath:sql/schema-account.sql
|
||||
url: jdbc:mysql://127.0.0.1:3306/jeecg_account?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
schema: classpath:sql/schema-account.sql
|
||||
seata:
|
||||
enable-auto-data-source-proxy: false
|
||||
# enable-auto-data-source-proxy: false
|
||||
service:
|
||||
grouplist:
|
||||
default: 127.0.0.1:8091
|
||||
|
||||
@ -6,21 +6,15 @@ spring:
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
autoconfigure:
|
||||
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
|
||||
exclude: com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
|
||||
datasource:
|
||||
dynamic:
|
||||
primary: order
|
||||
seata: true # 开启对 seata的支持
|
||||
datasource:
|
||||
# 设置 账号数据源配置
|
||||
order:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/jeecg_order?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
schema: classpath:sql/schema-order.sql
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/jeecg_order?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
schema: classpath:sql/schema-order.sql
|
||||
seata:
|
||||
enable-auto-data-source-proxy: false
|
||||
# enable-auto-data-source-proxy: false
|
||||
service:
|
||||
grouplist:
|
||||
default: 127.0.0.1:8091
|
||||
|
||||
@ -5,21 +5,16 @@ spring:
|
||||
name: seata-product
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
autoconfigure:
|
||||
exclude: com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
|
||||
datasource:
|
||||
dynamic:
|
||||
primary: product
|
||||
seata: true # 开启对 seata的支持
|
||||
seata-mode: AT #支持XA及AT模式,默认AT
|
||||
datasource:
|
||||
# 设置 账号数据源配置
|
||||
product:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/jeecg_product?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
schema: classpath:sql/schema-product.sql
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/jeecg_product?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
schema: classpath:sql/schema-product.sql
|
||||
seata:
|
||||
enable-auto-data-source-proxy: false
|
||||
# enable-auto-data-source-proxy: false
|
||||
service:
|
||||
grouplist:
|
||||
default: 127.0.0.1:8091
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
<druid.version>1.2.22</druid.version>
|
||||
|
||||
<!-- 积木报表-->
|
||||
<jimureport-spring-boot-starter.version>1.8.1</jimureport-spring-boot-starter.version>
|
||||
<jimureport-spring-boot-starter.version>1.9.1</jimureport-spring-boot-starter.version>
|
||||
<commons-io.version>2.11.0</commons-io.version>
|
||||
<commons.version>2.6</commons.version>
|
||||
<aliyun-java-sdk-dysmsapi.version>2.1.0</aliyun-java-sdk-dysmsapi.version>
|
||||
@ -403,27 +403,17 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- 积木BI-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimubi-spring-boot-starter</artifactId>
|
||||
<version>${jimureport-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-nosql-starter</artifactId>
|
||||
<version>1.6.0</version>
|
||||
</dependency>
|
||||
<!-- 积木仪表盘-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-dashboard-spring-boot-starter</artifactId>
|
||||
<version>1.8.1-beta</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>autopoi-web</artifactId>
|
||||
<groupId>org.jeecgframework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-spring-boot-starter</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- chatgpt -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
|
||||
@ -21,3 +21,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||
|
||||
开源协议中文释意如下:
|
||||
1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
2.允许基于本平台软件开展业务系统开发。
|
||||
3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
|
||||
最终解释权归:http://www.jeecg.com
|
||||
|
||||
@ -27,16 +27,18 @@ JeecgBoot-Vue3采用 Vue3.0、Vite、 Ant-Design-Vue4、TypeScript 等新技术
|
||||
|
||||
- 官方文档:[https://help.jeecg.com](https://help.jeecg.com)
|
||||
- 快速入门:[快速入门](http://jeecg.com/doc/quickstart) | [常见问题](http://help.jeecg.com/qa.html)
|
||||
- QQ交流群:⑨808791225、其他满
|
||||
- QQ交流群:⑩716488839、⑨808791225、其他满
|
||||
- 在线演示 : [系统演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
> 演示系统的登录账号密码,请点击 [获取账号密码](http://jeecg.com/doc/demo) 获取
|
||||
|
||||
|
||||
## 安装与使用
|
||||
|
||||
* 本地环境安装 `Node.js 、npm 、pnpm`
|
||||
* Node.js 版本建议`v20.15.0`,要求`Node 20+` 版本以上
|
||||
|
||||
` ( 因为Vite5 不再支持已 EOL 的 Node.js 14 / 16 / 17 / 19,现在需要 Node.js 18 / 20+ )`
|
||||
|
||||
> 环境要求: 版本要求Node 14.18+ / 16+ 版本以上,不再支持 Node 12 / 13 / 15。
|
||||
> 建议使用pnpm,如果使用yarn,请用Yarn1.x版本,否则依赖可能安装不上。
|
||||
|
||||
|
||||
- Get the project code
|
||||
@ -76,80 +78,6 @@ pnpm dev
|
||||
pnpm build
|
||||
```
|
||||
|
||||
|
||||
## Docker镜像启动前端(单体模式)
|
||||
|
||||
- host设置
|
||||
|
||||
>注意: 需要把`127.0.0.1`替换成真实IP 比如`192.`开头,不然后端不通。
|
||||
|
||||
```bash
|
||||
127.0.0.1 jeecg-boot-system
|
||||
127.0.0.1 jeecg-boot-gateway
|
||||
```
|
||||
|
||||
|
||||
- 下载项目
|
||||
|
||||
```bash
|
||||
git clone https://github.com/jeecgboot/JeecgBoot.git
|
||||
|
||||
cd JeecgBoot/jeecgboot-vue3
|
||||
```
|
||||
|
||||
- 配置接口域名 `.env.production`
|
||||
|
||||
```bash
|
||||
VITE_GLOB_API_URL=/jeecgboot
|
||||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot
|
||||
```
|
||||
后台单体启动 [见此文档](https://help.jeecg.com/java/setup/docker/up.html)
|
||||
|
||||
- 编译项目
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
|
||||
pnpm build
|
||||
```
|
||||
|
||||
- 启动容器
|
||||
```bash
|
||||
docker build -t jeecgboot-vue3 .
|
||||
docker run --name jeecgboot-vue3-nginx -p 80:80 -d jeecgboot-vue3
|
||||
```
|
||||
|
||||
- 访问前台
|
||||
|
||||
http://localhost
|
||||
|
||||
## Docker镜像启动前端(微服务模式)
|
||||
> 这里只写与单体的区别步骤
|
||||
|
||||
- 区别1. 修改后台域名
|
||||
.env.production
|
||||
|
||||
```bash
|
||||
VITE_GLOB_API_URL=/jeecgboot
|
||||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-gateway:9999
|
||||
```
|
||||
|
||||
后台微服务启动 [见此文档](https://help.jeecg.com/java/springcloud/docker.html)
|
||||
|
||||
- 区别2. 修改Dockerfile文件
|
||||
|
||||
```bash
|
||||
- 把`http://jeecg-boot-system:8080/jeecg-boot`替换成 `http://jeecg-boot-gateway:9999`
|
||||
- 把`jeecg-boot-system`替换成 `jeecg-boot-gateway`
|
||||
```
|
||||
|
||||
- 其他与单体模式一样
|
||||
|
||||
```bash
|
||||
镜像需要重现构建,最好把单体的镜像删掉,重新构建docker镜像。
|
||||
```
|
||||
|
||||
|
||||
## 入门必备
|
||||
|
||||
本项目需要一定前端基础知识,请确保掌握 Vue 的基础知识,以便能处理一些常见的问题。 建议在开发前先学一下以下内容,提前了解和学习这些知识,会对项目理解非常有帮助:
|
||||
@ -164,9 +92,7 @@ VITE_GLOB_DOMAIN_URL=http://jeecg-boot-gateway:9999
|
||||
* [Vitejs](https://cn.vitejs.dev/guide/)
|
||||
* [Pinia(vuex替代方案)](https://pinia.esm.dev/introduction.html)
|
||||
* [Vue-RFCS](https://github.com/vuejs/rfcs)
|
||||
* [Vue2 迁移到 3](https://v3.vuejs.org/guide/migration/introduction.html)
|
||||
* [vxetable文档](https://vxetable.cn)
|
||||
* [~~WindiCss~~](https://windicss.netlify.app/)
|
||||
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
@ -169,6 +169,6 @@
|
||||
},
|
||||
"homepage": "https://www.jeecg.com",
|
||||
"engines": {
|
||||
"node": "^12 || >=14"
|
||||
"node": "^18 || >=20"
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
|
||||
const props = defineProps({
|
||||
title: { type: String, default: '' },
|
||||
defaultExpan: { type: Boolean, default: true },
|
||||
loading: { type: Boolean },
|
||||
/**
|
||||
* Can it be expanded
|
||||
@ -58,8 +59,9 @@
|
||||
*/
|
||||
lazyTime: { type: Number, default: 0 },
|
||||
});
|
||||
|
||||
const show = ref(true);
|
||||
// update-begin-author:liaozhiyang---date:2024-11-11--for:【issues/7402】CollapseContainer组件增加默认不展开属性
|
||||
const show = ref(props.defaultExpan);
|
||||
// update-begin-author:liaozhiyang---date:2024-11-11--for:【issues/7402】CollapseContainer组件增加默认不展开属性
|
||||
|
||||
const { prefixCls } = useDesign('collapse-container');
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
import { TreeSelect } from 'ant-design-vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { isObject } from '/@/utils/is';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
enum Api {
|
||||
url = '/sys/dict/loadTreeData',
|
||||
view = '/sys/dict/loadDictItem/',
|
||||
@ -65,6 +65,7 @@
|
||||
hiddenNodeKey: propTypes.string.def(''),
|
||||
});
|
||||
const attrs = useAttrs();
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(['change', 'update:value']);
|
||||
const slots = defineSlots();
|
||||
const { createMessage } = useMessage();
|
||||
@ -151,10 +152,10 @@
|
||||
treeValue.value = result.result.map((item, index) => ({
|
||||
key: values[index],
|
||||
value: values[index],
|
||||
label: item,
|
||||
label: translateTitle(item),
|
||||
}));
|
||||
}else{
|
||||
treeValue.value = { key: props.value, value: props.value, label: result.result[0] };
|
||||
treeValue.value = { key: props.value, value: props.value, label: translateTitle(result.result[0]) };
|
||||
}
|
||||
//update-end-author:liaozhiyang date:2023-7-17 for:【issues/5141】使用JtreeSelect 组件 控制台报错
|
||||
onLoadTriggleChange(result.result[0]);
|
||||
@ -198,6 +199,7 @@
|
||||
let res = await defHttp.get({ url: Api.url, params }, { isTransformResponse: false });
|
||||
if (res.success && res.result) {
|
||||
for (let i of res.result) {
|
||||
i.title = translateTitle(i.title);
|
||||
i.value = i.key;
|
||||
i.isLeaf = !!i.leaf;
|
||||
}
|
||||
@ -210,6 +212,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译
|
||||
* @param text
|
||||
*/
|
||||
function translateTitle(text) {
|
||||
if (text.includes("t('") && t) {
|
||||
return new Function('t', `return ${text}`)(t);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
/**
|
||||
* 异步加载数据
|
||||
*/
|
||||
@ -217,7 +229,7 @@
|
||||
if (treeNode.dataRef.children) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if(props.url){
|
||||
if (props.url) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
let pid = treeNode.dataRef.key;
|
||||
@ -234,6 +246,7 @@
|
||||
let res = await defHttp.get({ url: Api.url, params }, { isTransformResponse: false });
|
||||
if (res.success) {
|
||||
for (let i of res.result) {
|
||||
i.title = translateTitle(i.title);
|
||||
i.value = i.key;
|
||||
i.isLeaf = !!i.leaf;
|
||||
}
|
||||
@ -334,6 +347,7 @@
|
||||
let res = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||
if (res.success && res.result) {
|
||||
for (let i of res.result) {
|
||||
i.title = translateTitle(i.title);
|
||||
i.key = i.value;
|
||||
i.isLeaf = !!i.leaf;
|
||||
}
|
||||
|
||||
@ -31,7 +31,9 @@ export function useSelectBiz(getList, props, emit?) {
|
||||
if (selectValues['change'] == false && !isEmpty(selectValues['value'])) {
|
||||
//update-end-author:liusq---date:2023-10-19--for: [issues/788]判断有设置数值才去加载
|
||||
//update-begin---author:wangshuai ---date:20220412 for:[VUEN-672]发文草稿箱编辑时拟稿人显示用户名------------
|
||||
let params = { isMultiTranslate: 'true' };
|
||||
// update-begin-author:liaozhiyang---date:2024-11-11--for:【issues/7405】部门选择用户同时全部选择两页用户,回显到父页面。第二页用户显示的不是真是姓名
|
||||
let params = { isMultiTranslate: 'true', pageSize: selectValues.value?.length };
|
||||
// update-end-author:liaozhiyang---date:2024-10-11--for:【issues/7405】部门选择用户同时全部选择两页用户,回显到父页面。第二页用户显示的不是真是姓名
|
||||
params[props.rowKey] = selectValues['value'].join(',');
|
||||
//update-end---author:wangshuai ---date:20220412 for:[VUEN-672]发文草稿箱编辑时拟稿人显示用户名--------------
|
||||
loadingEcho.value = isFirstLoadEcho;
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||
import { getTenantId, getToken } from '/@/utils/auth';
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { uploadFile } from '@/api/common/api';
|
||||
|
||||
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
|
||||
|
||||
@ -161,7 +162,7 @@
|
||||
//update-begin-author:taoyan date:2022-5-24 for: VUEN-1090 markdown 无法上传
|
||||
upload: {
|
||||
accept: 'image/*',
|
||||
url: uploadUrl,
|
||||
//url: uploadUrl,
|
||||
fieldName: 'file',
|
||||
extraData: { biz: 'markdown' },
|
||||
setHeaders() {
|
||||
@ -173,6 +174,23 @@
|
||||
format(files, response) {
|
||||
return formatResult(files, response);
|
||||
},
|
||||
// 遍历文件上传并展示
|
||||
async handler(files) {
|
||||
const uploadSuccess = (res) => {
|
||||
// {"success":true,"message":"markdown/aa_1653391146501.png","code":0,"result":null,"timestamp":1653391146501}'
|
||||
if (res.success) {
|
||||
vditorRef.value?.insertValue(`})`);
|
||||
}
|
||||
};
|
||||
for (const file of files) {
|
||||
let params = {
|
||||
file: file,
|
||||
filename: file.name,
|
||||
data: { biz: 'markdown' },
|
||||
};
|
||||
await uploadFile(params, uploadSuccess);
|
||||
}
|
||||
},
|
||||
},
|
||||
//update-end-author:taoyan date:2022-5-24 for: VUEN-1090 markdown 无法上传
|
||||
input: (v) => {
|
||||
|
||||
@ -222,7 +222,7 @@
|
||||
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
);
|
||||
|
||||
const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef, getColumnsRef, getRowSelectionRef, getDataSourceRef);
|
||||
const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef, getColumnsRef, getRowSelectionRef, getDataSourceRef, slots);
|
||||
|
||||
const { customRow } = useCustomRow(getProps, {
|
||||
setSelectedRowKeys,
|
||||
@ -605,7 +605,12 @@
|
||||
.ant-table > .ant-table-footer {
|
||||
padding: 12px 0 0;
|
||||
}
|
||||
|
||||
.ant-table > .ant-table-footer {
|
||||
// update-begin--author:liaozhiyang---date:20241111---for:【issues/7413】合计行有点对不齐
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
// update-end--author:liaozhiyang---date:20241111---for:【issues/7413】合计行有点对不齐
|
||||
}
|
||||
.ant-table.ant-table-bordered > .ant-table-footer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@ -113,10 +113,17 @@
|
||||
const val = unref(currentValueRef);
|
||||
|
||||
const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
|
||||
|
||||
//update-begin---author:wangshuai---date:2024-09-19---for:【issues/7136】单元格上的tooltip提示,如果表格有滚动条,会不跟着单元格滚动---
|
||||
let tooltipPosition:any = unref(table?.wrapRef.value)?.parentElement?.querySelector('.ant-table-body');
|
||||
if(tooltipPosition){
|
||||
tooltipPosition.style.position = 'relative';
|
||||
}
|
||||
//update-end---author:wangshuai---date:2024-09-19---for:【issues/7136】单元格上的tooltip提示,如果表格有滚动条,会不跟着单元格滚动---
|
||||
return {
|
||||
size: 'small',
|
||||
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
||||
//update-begin---author:wangshuai---date:2024-09-19---for:【issues/7136】单元格上的tooltip提示,如果表格有滚动条,会不跟着单元格滚动---
|
||||
getPopupContainer: () => tooltipPosition ?? document.body,
|
||||
//update-end---author:wangshuai---date:2024-09-19---for:【issues/7136】单元格上的tooltip提示,如果表格有滚动条,会不跟着单元格滚动---
|
||||
getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
||||
placeholder: createPlaceholderMessage(unref(getComponent)),
|
||||
...apiSelectProps,
|
||||
|
||||
@ -43,6 +43,8 @@ export function useCustomSelection(
|
||||
let changeRows: Recordable[] = [];
|
||||
let allSelected: boolean = false;
|
||||
|
||||
let timer;
|
||||
|
||||
// 扁平化数据,children数据也会放到一起
|
||||
const flattedData = computed(() => {
|
||||
// update-begin--author:liaozhiyang---date:20231016---for:【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
@ -122,7 +124,7 @@ export function useCustomSelection(
|
||||
selectedLength: flattedData.value.filter((data) => selectedKeys.value.includes(getRecordKey(data))).length,
|
||||
// update-begin--author:liaozhiyang---date:20240511---for:【QQYUN-9289】解决表格条数不足pageSize数量时行数全部勾选但是全选框不勾选
|
||||
// 【TV360X-53】为空时会报错,加强判断
|
||||
pageSize: tableData.value?.length ?? 0,
|
||||
pageSize: flattedData.value?.length ?? 0,
|
||||
// update-end--author:liaozhiyang---date:20240511---for:【QQYUN-9289】解决表格条数不足pageSize数量时行数全部勾选但是全选框不勾选
|
||||
// 【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
disabled: flattedData.value.length == 0,
|
||||
@ -183,6 +185,10 @@ export function useCustomSelection(
|
||||
let bodyResizeObserver: Nullable<ResizeObserver> = null;
|
||||
// 获取首行行高
|
||||
watchEffect(() => {
|
||||
// update-begin--author:liaozhiyang---date:20241111---for:【issues/7442】basicTable从默认切换到宽松紧凑时多选框显示异常
|
||||
// 这种写法是为了监听到 size 的变化
|
||||
propsRef.value.size && void 0;
|
||||
// update-end--author:liaozhiyang---date:20241111---for:【issues/7442】basicTable从默认切换到宽松紧凑时多选框显示异常
|
||||
if (bodyEl.value) {
|
||||
// 监听div高度变化
|
||||
bodyResizeObserver = new ResizeObserver((entries) => {
|
||||
@ -196,13 +202,15 @@ export function useCustomSelection(
|
||||
bodyResizeObserver.observe(bodyEl.value);
|
||||
const el = bodyEl.value?.querySelector('tbody.ant-table-tbody tr.ant-table-row') as HTMLDivElement;
|
||||
if (el) {
|
||||
rowHeight.value = el.offsetHeight;
|
||||
// update-begin--author:liaozhiyang---date:20241111---for:【issues/7442】basicTable从默认切换到宽松紧凑时多选框显示异常
|
||||
nextTick(() => {
|
||||
rowHeight.value = el.offsetHeight;
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20241111---for:【issues/7442】basicTable从默认切换到宽松紧凑时多选框显示异常
|
||||
return;
|
||||
}
|
||||
}
|
||||
rowHeight.value = 50;
|
||||
// 这种写法是为了监听到 size 的变化
|
||||
propsRef.value.size && void 0;
|
||||
});
|
||||
|
||||
onMountedOrActivated(async () => {
|
||||
@ -317,6 +325,7 @@ export function useCustomSelection(
|
||||
function onSelect(record, checked) {
|
||||
onSelectChild(record, checked);
|
||||
updateSelected(record, checked);
|
||||
onSelectParent(record, checked);
|
||||
emitChange();
|
||||
}
|
||||
|
||||
@ -339,6 +348,12 @@ export function useCustomSelection(
|
||||
selectedRows.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20240919---for:【issues/7200】basicTable选中后没有选中样式
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
selectedKeys.value = [...selectedKeys.value];
|
||||
}, 0);
|
||||
// update-end--author:liaozhiyang---date:20240919---for:【issues/7200】basicTable选中后没有选中样式
|
||||
}
|
||||
|
||||
// 调用用户自定义的onChange事件
|
||||
@ -372,7 +387,7 @@ export function useCustomSelection(
|
||||
* @param checked
|
||||
*/
|
||||
function onSelectChild(record, checked) {
|
||||
if (unref(propsRef)?.isTreeTable && unref(propsRef)?.rowSelection?.checkStrictly && !isRadio.value) {
|
||||
if (unref(propsRef)?.isTreeTable && unref(propsRef)?.rowSelection?.checkStrictly === false && !isRadio.value) {
|
||||
if (record[childrenColumnName.value] && record[childrenColumnName.value].length > 0) {
|
||||
record[childrenColumnName.value].forEach((children) => {
|
||||
updateSelected(children, checked);
|
||||
@ -384,6 +399,59 @@ export function useCustomSelection(
|
||||
}
|
||||
}
|
||||
// update-end--author:liusq---date:20240819---for:树形表格设置层级关联不生效
|
||||
/**
|
||||
* 2024-09-24
|
||||
* liaozhiyang
|
||||
* 层级关联时,选中上级数据
|
||||
* 【issues/7217】BasicTable树形表格设置checkStrictly无效
|
||||
* */
|
||||
function onSelectParent(record, checked) {
|
||||
if (unref(propsRef)?.isTreeTable && unref(propsRef)?.rowSelection?.checkStrictly === false && !isRadio.value) {
|
||||
let condition = true,
|
||||
currentRecord = record;
|
||||
while (condition) {
|
||||
const parentRecord: any = findParent(tableData.value, currentRecord, childrenColumnName.value);
|
||||
if (parentRecord) {
|
||||
const childrenRecordKeys: any = [];
|
||||
parentRecord[childrenColumnName.value].forEach((item) => {
|
||||
childrenRecordKeys.push(getRecordKey(item));
|
||||
});
|
||||
if (checked === true) {
|
||||
const isSubSet = childrenRecordKeys.every((item) => selectedKeys.value.includes(item));
|
||||
isSubSet && updateSelected(parentRecord, checked);
|
||||
} else if (checked === false) {
|
||||
updateSelected(parentRecord, checked);
|
||||
}
|
||||
if (tableData.value.find((item) => getRecordKey(item) === getRecordKey(parentRecord))) {
|
||||
// 循环终止
|
||||
condition = false;
|
||||
} else {
|
||||
currentRecord = parentRecord;
|
||||
}
|
||||
} else {
|
||||
// 循环终止
|
||||
condition = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
function findParent(tree, record, children = 'children') {
|
||||
let parent = null;
|
||||
function search(nodes) {
|
||||
for (let node of nodes) {
|
||||
if (node[children]?.some((child) => getRecordKey(child) === getRecordKey(record))) {
|
||||
parent = node;
|
||||
return true;
|
||||
}
|
||||
if (node[children] && search(node[children])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
search(tree);
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
// 用于判断是否是自定义选择列
|
||||
function isCustomSelection(column: BasicColumn) {
|
||||
return column.key === CUS_SEL_COLUMN_KEY;
|
||||
|
||||
@ -38,24 +38,34 @@ export function useTableFooter(
|
||||
});
|
||||
|
||||
function handleSummary() {
|
||||
const { showSummary } = unref(propsRef);
|
||||
const { showSummary, canResize } = unref(propsRef);
|
||||
if (!showSummary || unref(getIsEmptyData)) return;
|
||||
|
||||
nextTick(() => {
|
||||
const tableEl = unref(tableElRef);
|
||||
if (!tableEl) return;
|
||||
const bodyDom = tableEl.$el.querySelector('.ant-table-content');
|
||||
useEventListener({
|
||||
el: bodyDom,
|
||||
name: 'scroll',
|
||||
listener: () => {
|
||||
const footerBodyDom = tableEl.$el.querySelector('.ant-table-footer .ant-table-content') as HTMLDivElement;
|
||||
if (!footerBodyDom || !bodyDom) return;
|
||||
footerBodyDom.scrollLeft = bodyDom.scrollLeft;
|
||||
},
|
||||
wait: 0,
|
||||
options: true,
|
||||
});
|
||||
let bodyDom;
|
||||
// update-begin--author:liaozhiyang---date:20241111---for:【issues/7422】BasicTable列表canResize属性为true时合计行不能横向滚动
|
||||
if (canResize) {
|
||||
setTimeout(() => {
|
||||
bodyDom = tableEl.$el.querySelector('.ant-table-body');
|
||||
}, 0);
|
||||
} else {
|
||||
bodyDom = tableEl.$el.querySelector('.ant-table-content');
|
||||
}
|
||||
setTimeout(() => {
|
||||
useEventListener({
|
||||
el: bodyDom,
|
||||
name: 'scroll',
|
||||
listener: () => {
|
||||
const footerBodyDom = tableEl.$el.querySelector('.ant-table-footer .ant-table-content') as HTMLDivElement;
|
||||
if (!footerBodyDom || !bodyDom) return;
|
||||
footerBodyDom.scrollLeft = bodyDom.scrollLeft;
|
||||
},
|
||||
wait: 0,
|
||||
options: true,
|
||||
});
|
||||
}, 0);
|
||||
// update-end--author:liaozhiyang---date:20241111---for:【issues/7422】BasicTable列表canResize属性为true时合计行不能横向滚动
|
||||
});
|
||||
}
|
||||
return { getFooterProps };
|
||||
|
||||
@ -2,8 +2,40 @@ import type { ComputedRef } from 'vue';
|
||||
import type { BasicTableProps, TableCustomRecord } from '../types/table';
|
||||
import { unref } from 'vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { ROW_KEY } from '/@/components/Table/src/const';
|
||||
|
||||
export function useTableStyle(propsRef: ComputedRef<BasicTableProps>, prefixCls: string) {
|
||||
/**
|
||||
* 2024-09-19
|
||||
* liaozhiyang
|
||||
* 【issues/7200】basicTable选中后没有选中样式
|
||||
* */
|
||||
const isChecked = (propsRef, record) => {
|
||||
const getAutoCreateKey = () => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
};
|
||||
const getRowKey = () => {
|
||||
const { rowKey } = unref(propsRef);
|
||||
return getAutoCreateKey() ? ROW_KEY : rowKey;
|
||||
};
|
||||
// 获取行的key字段数据
|
||||
const getRecordKey = (record) => {
|
||||
const key = getRowKey();
|
||||
if (!key) {
|
||||
return record[ROW_KEY];
|
||||
} else if (isFunction(key)) {
|
||||
return key(record);
|
||||
} else {
|
||||
return record[key];
|
||||
}
|
||||
};
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (rowSelection?.selectedRowKeys?.length) {
|
||||
return rowSelection.selectedRowKeys.includes(getRecordKey(record));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function getRowClassName(record: TableCustomRecord, index: number) {
|
||||
const { striped, rowClassName } = unref(propsRef);
|
||||
const classNames: string[] = [];
|
||||
@ -13,6 +45,11 @@ export function useTableStyle(propsRef: ComputedRef<BasicTableProps>, prefixCls:
|
||||
if (rowClassName && isFunction(rowClassName)) {
|
||||
classNames.push(rowClassName(record, index));
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20240919---for:【issues/7200】basicTable选中后没有选中样式
|
||||
if (isChecked(propsRef, record)) {
|
||||
classNames.push('ant-table-row-selected');
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240919---for:【issues/7200】basicTable选中后没有选中样式
|
||||
return classNames.filter((cls) => !!cls).join(' ');
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,10 @@
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
customColor: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
@ -68,12 +72,15 @@
|
||||
//轴数据
|
||||
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
|
||||
let seriesData = [];
|
||||
typeArr.forEach((type) => {
|
||||
typeArr.forEach((type,index) => {
|
||||
let obj = { name: type };
|
||||
let chartArr = props.chartData.filter((item) => type === item.type);
|
||||
//data数据
|
||||
obj['data'] = chartArr.map((item) => item.value);
|
||||
obj['type'] = chartArr[0].seriesType;
|
||||
if(props?.customColor && props?.customColor[index]){
|
||||
obj['color'] = props.customColor[index];
|
||||
}
|
||||
seriesData.push(obj);
|
||||
});
|
||||
option.series = seriesData;
|
||||
|
||||
@ -7,6 +7,7 @@ import { JVxeRenderType } from '../types/JVxeTypes';
|
||||
import { isBoolean, isFunction, isObject, isPromise } from '/@/utils/is';
|
||||
import { JVxeComponent } from '../types/JVxeComponent';
|
||||
import { filterDictText } from '/@/utils/dict/JDictSelectUtil';
|
||||
import { getAreaTextByCode } from "@/components/Form/src/utils/Area";
|
||||
|
||||
export function useJVxeCompProps() {
|
||||
return {
|
||||
@ -160,6 +161,14 @@ export function useJVxeComponent(props: JVxeComponent.Props) {
|
||||
return;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240509---for:【QQYUN-9205】一对多(jVxetable组件date)支持年,年月,年度度,年周
|
||||
|
||||
//update-begin---author:wangshuai---date:2024-09-18---for:【issues/7203】自动生成一对多表单代码中,省市区回显问题---
|
||||
if (props.type === 'pca' && props.renderType === JVxeRenderType.spaner) {
|
||||
innerValue.value = getAreaTextByCode(newValue);
|
||||
return;
|
||||
}
|
||||
//update-end---author:wangshuai---date:2024-09-18---for:【issues/7203】自动生成一对多表单代码中,省市区回显问题---
|
||||
|
||||
// 判断是否启用翻译
|
||||
if (props.renderType === JVxeRenderType.spaner && enhanced.translate.enabled === true) {
|
||||
if (isFunction(enhanced.translate.handler)) {
|
||||
|
||||
@ -129,6 +129,9 @@
|
||||
// update-begin--author:liaozhiyang---date:20240124---for:【QQYUN-7970】国际化
|
||||
createMessage.success(t('layout.header.refreshCacheComplete'));
|
||||
// update-end--author:liaozhiyang---date:20240124---for:【QQYUN-7970】国际化
|
||||
// update-begin--author:wangshuai---date:20241112---for:【issues/7433】vue3 数据字典优化建议
|
||||
userStore.setAllDictItems(res.result);
|
||||
// update-end--author:wangshuai---date:20241112---for:【issues/7433】vue3 数据字典优化建议
|
||||
} else {
|
||||
// update-begin--author:liaozhiyang---date:20240124---for:【QQYUN-7970】国际化
|
||||
createMessage.error(t('layout.header.refreshCacheFailure'));
|
||||
|
||||
@ -62,7 +62,9 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
||||
watch(
|
||||
() => getSplit.value,
|
||||
() => {
|
||||
if (unref(splitNotLeft)) return;
|
||||
// update-begin--author:liaozhiyang---date:20240919---for:【issues/7209】顶部左侧组合菜单关闭之后左侧导航没还原
|
||||
// if (unref(splitNotLeft)) return;
|
||||
// update-end--author:liaozhiyang---date:20240919---for:【issues/7209】顶部左侧组合菜单关闭之后左侧导航没还原
|
||||
genMenus();
|
||||
}
|
||||
);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<InputNumber v-bind="$attrs" size="small" :class="`${prefixCls}-input-number`" @change="handleChange" />
|
||||
<InputNumber :max="7200" v-bind="$attrs" size="small" :class="`${prefixCls}-input-number`" @change="handleChange" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
||||
@ -3,6 +3,9 @@ export const REDIRECT_NAME = 'Redirect';
|
||||
export const PARENT_LAYOUT_NAME = 'ParentLayout';
|
||||
|
||||
export const PAGE_NOT_FOUND_NAME = 'PageNotFound';
|
||||
// update-begin--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
export const PAGE_NOT_FOUND_NAME_404 = 'PageNotFound404';
|
||||
// update-end--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
|
||||
export const EXCEPTION_COMPONENT = () => import('/@/views/sys/exception/Exception.vue');
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import { RootRoute } from '/@/router/routes';
|
||||
import { isOAuth2AppEnv } from '/@/views/sys/login/useLogin';
|
||||
import { OAUTH2_THIRD_LOGIN_TENANT_ID } from "/@/enums/cacheEnum";
|
||||
import { setAuthCache } from "/@/utils/auth";
|
||||
import { PAGE_NOT_FOUND_NAME_404 } from '/@/router/constant';
|
||||
|
||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||
//auth2登录路由
|
||||
@ -162,12 +163,13 @@ export function createPermissionGuard(router: Router) {
|
||||
return;
|
||||
}
|
||||
//==============================【首次登录并且是企业微信或者钉钉的情况下才会调用】==================
|
||||
|
||||
// update-begin--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
// Jump to the 404 page after processing the login
|
||||
if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name && to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)) {
|
||||
if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_NAME_404 && to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)) {
|
||||
next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
|
||||
return;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
|
||||
//update-begin---author:scott ---date:2024-02-21 for:【QQYUN-8326】刷新首页,不需要重新获取用户信息---
|
||||
// // get userinfo while last fetch time is empty
|
||||
@ -199,8 +201,8 @@ export function createPermissionGuard(router: Router) {
|
||||
|
||||
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
|
||||
permissionStore.setDynamicAddedRoute(true);
|
||||
|
||||
if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
|
||||
// update-begin--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
if (to.name === PAGE_NOT_FOUND_NAME_404) {
|
||||
// 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容
|
||||
next({ path: to.fullPath, replace: true, query: to.query });
|
||||
} else {
|
||||
@ -209,5 +211,6 @@ export function createPermissionGuard(router: Router) {
|
||||
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
||||
next(nextData);
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
||||
import { t } from '/@/hooks/web/useI18n';
|
||||
import { REDIRECT_NAME, LAYOUT, EXCEPTION_COMPONENT, PAGE_NOT_FOUND_NAME } from '/@/router/constant';
|
||||
import { REDIRECT_NAME, LAYOUT, EXCEPTION_COMPONENT, PAGE_NOT_FOUND_NAME, PAGE_NOT_FOUND_NAME_404 } from '/@/router/constant';
|
||||
|
||||
// 404 on a page
|
||||
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
||||
path: '/:path(.*)*',
|
||||
|
||||
name: PAGE_NOT_FOUND_NAME,
|
||||
component: LAYOUT,
|
||||
meta: {
|
||||
@ -15,7 +16,9 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
||||
children: [
|
||||
{
|
||||
path: '/:path(.*)*',
|
||||
name: PAGE_NOT_FOUND_NAME,
|
||||
// update-begin--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
name: PAGE_NOT_FOUND_NAME_404,
|
||||
// update-end--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
component: EXCEPTION_COMPONENT,
|
||||
meta: {
|
||||
title: 'ErrorPage',
|
||||
|
||||
@ -3,6 +3,7 @@ import type { RouteLocationNormalized, RouteLocationRaw, Router } from 'vue-rout
|
||||
import { toRaw, unref } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { store } from '/@/store';
|
||||
import { PAGE_NOT_FOUND_NAME_404 } from '/@/router/constant';
|
||||
|
||||
import { useGo, useRedo } from '/@/hooks/web/usePage';
|
||||
import { Persistent } from '/@/utils/cache/persistent';
|
||||
@ -152,15 +153,17 @@ export const useMultipleTabStore = defineStore({
|
||||
|
||||
async addTab(route: RouteLocationNormalized) {
|
||||
const { path, name, fullPath, params, query, meta } = getRawRoute(route);
|
||||
// update-begin--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
// 404 The page does not need to add a tab
|
||||
if (
|
||||
path === PageEnum.ERROR_PAGE ||
|
||||
path === PageEnum.BASE_LOGIN ||
|
||||
!name ||
|
||||
[REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
|
||||
[REDIRECT_ROUTE.name, PAGE_NOT_FOUND_NAME_404].includes(name as string)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:202401127---for:【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去
|
||||
|
||||
let updateIndex = -1;
|
||||
// Existing pages, do not add tabs repeatedly
|
||||
|
||||
@ -249,7 +249,10 @@ export const useUserStore = defineStore({
|
||||
try {
|
||||
const { goHome = true, mode, ...loginParams } = params;
|
||||
const data = await phoneLoginApi(loginParams, mode);
|
||||
const { token } = data;
|
||||
//update-begin---author:wangshuai---date:2024-11-25---for:【issues/7488】手机号码登录,在请求头中无法获取租户id---
|
||||
const { token , userInfo } = data;
|
||||
this.setTenant(userInfo!.loginTenantId);
|
||||
//update-end---author:wangshuai---date:2024-11-25---for:【issues/7488】手机号码登录,在请求头中无法获取租户id---
|
||||
// save token
|
||||
this.setToken(token);
|
||||
return this.afterLoginAction(goHome, data);
|
||||
|
||||
6
jeecgboot-vue3/src/utils/cache/persistent.ts
vendored
6
jeecgboot-vue3/src/utils/cache/persistent.ts
vendored
@ -21,6 +21,8 @@ import {
|
||||
import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
|
||||
import { toRaw } from 'vue';
|
||||
import { pick, omit } from 'lodash-es';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import { router } from '/@/router';
|
||||
|
||||
interface BasicStore {
|
||||
[TOKEN_KEY]: string | number | null | undefined;
|
||||
@ -60,9 +62,11 @@ export class Persistent {
|
||||
static getLocal<T>(key: LocalKeys) {
|
||||
//update-begin---author:scott ---date:2022-10-27 for:token过期退出重新登录,online菜单还是提示token过期----------
|
||||
const globalCache = ls.get(APP_LOCAL_CACHE_KEY);
|
||||
if(globalCache){
|
||||
// update-begin--author:liaozhiyang---date:20240920---for:【issues/7250】自动锁屏无法解锁
|
||||
if (globalCache && router?.currentRoute?.value.path !== PageEnum.BASE_LOGIN) {
|
||||
localMemory.setCache(globalCache);
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240920---for:【issues/7250】自动锁屏无法解锁
|
||||
//update-end---author:scott ---date::2022-10-27 for:token过期退出重新登录,online菜单还是提示token过期----------
|
||||
return localMemory.get(key)?.value as Nullable<T>;
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
const colors = ['#4db6ac', '#ffb74d', '#64b5f6', '#e57373', '#9575cd', '#a1887f', '#90a4ae', '#4dd0e1', '#81c784', '#ff8a65'];
|
||||
export const getData = (() => {
|
||||
let dottedBase = +new Date();
|
||||
const barDataSource: any[] = [];
|
||||
const barMultiData: any[] = [];
|
||||
const barLineData: any[] = [];
|
||||
const barLineColors: any[] = [];
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
let obj = { name: '', value: 0 };
|
||||
@ -44,6 +46,7 @@ export const getData = (() => {
|
||||
obj.value = Math.random() * 200;
|
||||
barLineData.push(obj);
|
||||
}
|
||||
barLineColors.push(colors[j]);
|
||||
}
|
||||
return { barDataSource, barMultiData, pieData, barLineData, radarData };
|
||||
return { barDataSource, barMultiData, pieData, barLineData, barLineColors,radarData };
|
||||
})();
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
<Gauge :chartData="{ name: '出勤率', value: 70 }" height="50vh"></Gauge>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="10" tab="折柱图">
|
||||
<BarAndLine :chartData="barLineData" height="50vh"></BarAndLine>
|
||||
<BarAndLine :chartData="barLineData" :customColor="barLineColors" height="50vh"></BarAndLine>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="11" tab="排名列表">
|
||||
<RankList title="门店销售排行榜" :list="rankList" style="width: 600px; margin: 0 auto"></RankList>
|
||||
@ -71,7 +71,7 @@
|
||||
import BarAndLine from '/@/components/chart/BarAndLine.vue';
|
||||
|
||||
const activeKey = ref('1');
|
||||
const { barDataSource, barMultiData, pieData, barLineData, radarData } = getData;
|
||||
const { barDataSource, barMultiData, pieData, barLineData, radarData,barLineColors } = getData;
|
||||
const multiBarOption = {
|
||||
title: { text: '多列柱状图', left: 'center' },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user