mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
17 Commits
v3.7.1
...
v3.7.0last
| Author | SHA1 | Date | |
|---|---|---|---|
| 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
|
||||
12
README-EN.md
12
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)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
17
README.md
17
README.md
@ -47,11 +47,12 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
-----------------------------------
|
||||
|
||||
- 官方网站: [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)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -73,7 +74,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 +88,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 +110,10 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
| Sqlserver2017 | √ |
|
||||
| PostgreSQL | √ |
|
||||
| MariaDB | √ |
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
|
||||
| TiDB | √ |
|
||||
|
||||
|
||||
## 微服务解决方案
|
||||
|
||||
@ -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
|
||||
@ -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 | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -34,9 +34,11 @@ JeecgBoot-Vue3采用 Vue3.0、Vite、 Ant-Design-Vue4、TypeScript 等新技术
|
||||
|
||||
## 安装与使用
|
||||
|
||||
* 本地环境安装 `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"
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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,
|
||||
@ -317,6 +319,7 @@ export function useCustomSelection(
|
||||
function onSelect(record, checked) {
|
||||
onSelectChild(record, checked);
|
||||
updateSelected(record, checked);
|
||||
onSelectParent(record, checked);
|
||||
emitChange();
|
||||
}
|
||||
|
||||
@ -339,6 +342,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 +381,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 +393,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;
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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">
|
||||
|
||||
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