Compare commits

...

39 Commits

Author SHA1 Message Date
64b29f47e0 其他数据库脚本,转库说明文档 2024-12-06 16:33:22 +08:00
6198a3702f 其他数据库脚本,转库说明文档 2024-12-06 16:32:33 +08:00
453acb9b4e 升级积木报表到最新版1.9.1,支持大屏 2024-12-04 09:58:40 +08:00
565753e370 运行时间好长,效率慢 #7491 2024-12-04 09:52:29 +08:00
e2aaf0f978 【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去 2024-11-27 18:41:24 +08:00
32c8370ef2 【issues/7500】vue-router4.5.0版本路由name:PageNotFound同名导致登录进不去 2024-11-27 10:51:44 +08:00
a79004b924 【issues/7488】手机号码登录,在请求头中无法获取租户id 2024-11-27 09:46:34 +08:00
eb1612f8dd 开源协议说明 2024-11-22 10:44:47 +08:00
a35555619c Merge pull request #7370 from EightMonth/master
使seata直接与springboot datasource挂钩
2024-11-20 10:30:39 +08:00
b3e3951064 【issues/7433】vue3 数据字典优化建议 2024-11-14 19:35:59 +08:00
44ec26574e 【issues/7402】CollapseContainer组件增加默认不展开属性 2024-11-12 09:37:49 +08:00
55a25caafd 【issues/7413】合计行有点对不齐 2024-11-12 09:36:53 +08:00
62f7b0d489 【issues/7442】basicTable从默认切换到宽松紧凑时多选框显示异常 2024-11-12 09:35:00 +08:00
b16fdef8dc 【issues/7422】BasicTable列表canResize属性为true时合计行不能横向滚动 2024-11-12 09:34:18 +08:00
b5b667058b 【issues/7405】部门选择用户同时全部选择两页用户,回显到父页面。第二页用户显示的不是真是姓名 2024-11-12 09:33:25 +08:00
6c0c259742 QQ群满,提交新群号 ⑩716488839 2024-10-29 11:45:00 +08:00
ca56c54aa0 升级seata server1.7.0版本sql 2024-10-24 10:52:23 +08:00
74297af987 使seata直接与springboot datasource挂钩 2024-10-22 14:09:02 +08:00
fedb6b84b9 Merge remote-tracking branch 'origin/master' 2024-10-21 11:30:20 +08:00
fdc713339e 引入AI能力,支持自动建表等功能; 2024-10-21 11:26:23 +08:00
f28a2dbbeb Merge pull request #7364 from 94464562/patch-1
remove dbsource from cache
2024-10-19 17:04:24 +08:00
b81435aaca remove dbsource from cache
remove dbsource from cache
2024-10-19 11:49:27 +08:00
48805484d4 MK编辑器,无法上传多个图片 2024-09-24 22:47:44 +08:00
7fecdf94e5 修改柱体颜色 2024-09-24 22:47:04 +08:00
a3997dfd16 【issues/7200】basicTable选中后没有选中样式 --- 2024-09-24 22:43:44 +08:00
c868d90c2f 【issues/7209】顶部左侧组合菜单关闭之后左侧导航没还原 --- 2024-09-24 22:43:06 +08:00
77aebf5dd2 租户套餐的菜单名称没国际化 2024-09-24 22:42:21 +08:00
e770524f3a 【issues/7203】自动生成一对多表单代码中,省市区回显问题-- 2024-09-24 22:41:34 +08:00
c5fee07cba 【issues/7136】单元格上的tooltip提示,如果表格有滚动条,会不跟着单元格滚动 2024-09-24 22:40:47 +08:00
9fd20fde9e 【issues/7250】自动锁屏无法解锁 2024-09-24 22:39:52 +08:00
2af9451b7f 【issues/7217】BasicTable树形表格设置checkStrictly无效 ---
【issues/7200】basicTable选中后没有选中样式 ---
2024-09-24 22:38:24 +08:00
575baa8d49 JeecgBoot3.7XSS漏洞处理 2024-09-14 14:15:31 +08:00
48bc76cce7 在线演示地址 2024-09-14 11:46:03 +08:00
58c0882329 更新README.md 2024-09-13 09:52:02 +08:00
c400ec8482 前端环境,要求Node 20+ 版本以上 2024-09-13 09:31:37 +08:00
2068bdc112 前端环境要求Node.js 版本建议v20.15.0 2024-09-13 09:29:01 +08:00
ffe806352e 前端环境要求Node.js 版本建议v20.15.0 2024-09-13 09:20:28 +08:00
167a6c458c 前端环境要求Node.js 版本建议v20.15.0 2024-09-13 09:18:36 +08:00
872e6ed024 开源协议中文释意 2024-09-13 09:10:45 +08:00
41 changed files with 1151 additions and 436 deletions

12
LICENSE
View File

@ -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

View File

@ -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

View File

@ -18,7 +18,7 @@ JeecgBoot 低代码开发平台
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.xSpringCloudAnt Design Vue3Mybatis-plusShiroJWT支持微服务。强大的代码生成器让前后端代码一键生成实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE) 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.xSpringCloudAnt Design Vue3Mybatis-plusShiroJWT支持微服务。强大的代码生成器让前后端代码一键生成实现低代码开发! 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.0Jwt 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在线表单无需编码通过在线配置表单实现表单的增删改查支持单表、树、一对多、一对一等模型实现人人皆可编码

View File

@ -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

View File

@ -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.0Jwt 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

View File

@ -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.兼容问题
每次发版,会针对不兼容地方重点说明。

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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/)
## 浏览器支持

View File

@ -169,6 +169,6 @@
},
"homepage": "https://www.jeecg.com",
"engines": {
"node": "^12 || >=14"
"node": "^18 || >=20"
}
}

View File

@ -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');

View File

@ -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;
}

View File

@ -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;

View File

@ -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(`![${res.message}](${getFileAccessHttpUrl(res.message)})`);
}
};
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) => {

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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 };

View File

@ -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(' ');
}

View File

@ -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;

View File

@ -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)) {

View File

@ -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'));

View File

@ -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();
}
);

View File

@ -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">

View File

@ -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');

View File

@ -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同名导致登录进不去
});
}

View File

@ -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',

View File

@ -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

View File

@ -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);

View File

@ -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 fortoken过期退出重新登录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 fortoken过期退出重新登录online菜单还是提示token过期----------
return localMemory.get(key)?.value as Nullable<T>;
}

View File

@ -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 };
})();

View File

@ -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' },
};