Merge pull request !15 from Foming/dev
V0.9.4
Foming 3 years ago committed by Gitee
commit 3334ce7672

@ -143,3 +143,29 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------
This product has a bundle Luckysheet
The source code of Luckysheet can be found at https://gitee.com/mengshukeji/Luckysheet.
The MIT License (MIT)
Copyright (c) 2020-present, Mengshukeji
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,7 +1,7 @@
## 简介
&emsp; &emsp; AJ-Report由 [安吉加加](http://www.anji-plus.com) 开源的一个BI平台酷炫大屏展示能随时随地掌控业务动态让每个决策都有数据支撑。<br>
&emsp; &emsp; 多数据源支持内置mysql、elasticsearch、kudu驱动支持自定义数据集省去数据接口开发支持17种大屏组件不会开发照着设计稿也可以制作大屏。<br>
&emsp; &emsp; 多数据源支持内置mysql、elasticsearch、kudu驱动支持自定义数据集省去数据接口开发支持17+种大屏组件,不会开发,照着设计稿也可以制作大屏。<br>
&emsp; &emsp; 三步轻松完成大屏设计:配置数据源---->写SQL配置数据集---->拖拽配置大屏---->保存发布。欢迎体验。
## 在线体验
@ -85,6 +85,7 @@
- [vue-echarts](https://www.npmjs.com/package/vue-echarts/): vue-echarts是封装后的vue插件,基于 ECharts v4.0.1+ 开发
- [vue-superslide](https://www.npmjs.com/package/vue-super-slider/): Vue-SuperSlide(Github) 是 SuperSlide 的 Vue 封装版本
- [vuedraggable](https://github.com/SortableJS/Vue.Draggable/): 是一款基于Sortable.js实现的vue拖拽插件。
- [luckysheet](https://gitee.com/mengshukeji/Luckysheet): Luckysheet 一款纯前端类似excel的在线表格功能强大、配置简单、完全开源。
## 编译打包
@ -142,11 +143,11 @@ sql文件的目录在report-core --> src --> main --> resources -- > db.migra
已知以下版本存在兼容性问题
- Node.js V16
- Jdk 11
- Mysql 8.08.0.26版本没有问题8.0.21版本存在问题)
- Mysql 8.08.0.23/26版本没有问题8.0.21版本存在问题)
- Windows 11
AJ-Report 使用Druid版本为1.2.6如果你觉得你配置都是正常但是数据源测试不过请尝试修改pom文件降低Druid版本。
例如MSSQLSERVER 2014请将Druid版本降低为1.2.1以下
AJ-Report 使用Druid版本为1.2.6如果你觉得你配置都是正常但是数据源测试不过请尝试修改pom文件降低Druid版本。 <br>
例如MSSQLSERVER 2014请将Druid版本降低为1.2.1以下<br>
## 商业授权
AJ-Report使用[Apache2.0开源协议](http://www.apache.org/licenses/LICENSE-2.0.html) <br>

@ -50,7 +50,9 @@ module.exports = {
children: [
{title: '数据源', path: '/guide/datasource'},
{title: '数据集', path: '/guide/dataset'},
{title: '大屏设计', path: '/guide/dashboard'},
{title: '报表管理', path: '/guide/reportmanager'},
{title: '大屏报表', path: '/guide/dashboard'},
{title: '表格报表', path: '/guide/execl'},
{title: '导入导出', path: '/guide/importexport'},
]
},
@ -65,7 +67,8 @@ module.exports = {
title: '社区提供',
collapsable: false,
children: [
{title: '搭建AJ-Report开发环境', path: '/community/AC1688/'}
{title: '说明', path: '/guide/community/report'},
{title: '搭建AJ-Report开发环境', path: '/guide/community/AC1688/搭建aj-report开发环境'}
]
}
],

@ -1,5 +1,5 @@
&emsp; &emsp; AJ-Report是一个完全开源的BI平台酷炫大屏展示能随时随地掌控业务动态让每个决策都有数据支撑。<br>
&emsp; &emsp; 多数据源支持内置mysql、elasticsearch、kudu等多种驱动支持自定义数据集省去数据接口开发支持17+大屏组件,不会开发,照着设计稿也可以制作大屏。<br>
&emsp; &emsp; 多数据源支持内置mysql、elasticsearch、kudu等多种驱动支持自定义数据集省去数据接口开发支持17+大屏组件,不会开发,照着设计稿也可以制作大屏。<br>
&emsp; &emsp; 三步轻松完成大屏设计:配置数据源---->写SQL配置数据集---->拖拽配置大屏---->保存发布。欢迎体验。
## 系统特性

@ -0,0 +1,29 @@
## 新增用户
![img](../picture/authmanager/img.png) <br>
![img](../picture/authmanager/img_1.png) <br>
新增用户的默认密码是在bootstrap.yml文件中配置的 <br>
![img](../picture/authmanager/img_2.png) <br>
## 用户授权
**注意**:新建用户完成后需要给用户授权,否则新用户登陆是啥也看不到。<br>
![img](../picture/authmanager/img_3.png) <br>
![img](../picture/authmanager/img_4.png) <br>
**注**:这里没有给新用户赋予默认角色的原因是,在角色管理中角色是可以被删除和修改的,因此在新建用户时需要手动的去授权角色 <br>
## 角色管理
![img](../picture/authmanager/img_5.png) <br>
## 权限分配
为角色分配权限,可看已有角色示例 <br>
![img](../picture/authmanager/img_6.png) <br>
## 导入导出权限
**注**现在guest用户的权限是底层写死只有访问权限无实质操作权限。<br>
导入导出的权限是在 角色 --> 分配权限中控制。 <br>
![img](../picture/authmanager/img_7.png) <br>
用户绑定了角色,角色则绑定了权限,是这样一层关系。 <br>

@ -0,0 +1,14 @@
# 社区用户提交文档PR的简易说明
## 提交位置
doc -- > docs --> guide -- > community 目录 <br>
![img](../../guide/community/report/img.png) <br>
## 具体操作
- 请在community目录下新建属于你自己的文件目录命名方式可以使用自己在gitee的名字作为命名注意中文命令可能会存在的一些问题。<br>
- 在你的个人目录下你可以新建MD文件需要用到图片可以直接放一个目录如果md多图片也多建议再建下级目录存放。<br>
最后别忘了在config.js中添加配置如图示。<br>
![img](../../guide/community/report/img_1.png) <br>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@ -1,16 +1,21 @@
## 介绍
## 新增大屏
![img.png](../picture/dashboard/img.png)
## 设计大屏
进入大屏设计方法1 <br>
从报表管理模块选择需要设计的大屏,按图示进入大屏设计界面 <br>
![img](../picture/dashboard/img22.png) <br>
进入大屏设计方法2 <br>
从大屏报表模块选择需要设计的大屏,按图示进入大屏设计界面 <br>
![img](../picture/dashboard/img23.png) <br>
## 大屏简介
![img_2.png](../picture/dashboard/img_2.png)
![img_2.png](../picture/dashboard/img_2.png) <br>
## 工具栏
### 文本框
![img_3.png](../picture/dashboard/img_3.png)
![img_4.png](../picture/dashboard/img_4.png)
![img_5.png](../picture/dashboard/img_5.png)
![img_6.png](../picture/dashboard/img_6.png)
![img_3.png](../picture/dashboard/img_3.png) <br>
![img_4.png](../picture/dashboard/img_4.png) <br>
![img_5.png](../picture/dashboard/img_5.png) <br>
![img_6.png](../picture/dashboard/img_6.png) <br>
### 滚动文本
已支持动态数据,请参考文本框的操作 <br>
@ -73,7 +78,7 @@
### 仪表盘
数据集只能有一个字段,且字典选择“文本数字” <br>
![img14](../picture/dashboard/img_14.png) <br>
![img21](../picture/dashboard/img_21.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 中国地图
@ -81,16 +86,20 @@
气泡地图动态数据集和饼图一样对应字典值需要选择一个“Name”、“Value”且name的字段值要和echarts图表里面的值能对应上可参考静态数据 <br>
![img15](../picture/dashboard/img_15.png) <br>
### 百分百图
数据集只能有一个字段,且字典选择“文本数字” <br>
![img16](../picture/dashboard/img_16.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 散点图
**规划中** <br>
### 对比图
柱状对比图数据集需要3个字段其中一个作为对比的字段只能为2种值只有2种值作为对比的字段要选择“y轴字段”字典。因为底层的解析用的是堆叠图的解析这里的y轴字段并不是指的图表上面的y轴还请注意有强迫症可以自行修改源码的解析剩下的2个字段对应字典看图<br>
![img18](../picture/dashboard/img_18.png)
柱状对比图: <br>
数据集需要3个字段其中一个作为对比的字段只能为2种值只有2种值作为对比的字段要选择“y轴字段”字典。因为底层的解析用的是堆叠图的解析这里的y轴字段并不是指的图表上面的y轴还请注意有强迫症可以自行修改源码的解析剩下的2个字段对应字典看图<br>
![img18](../picture/dashboard/img_18.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
折线对比图: <br>
数据集需要3个字段其中一个作为对比的字段只能为2种值只有2种值作为对比的字段要选择“y轴字段”字典剩下的字典对应看图<br>
![img19](../picture/dashboard/img_19.png) <br>
**注**:如果提示语设置选择“十字形”,请注意需要选择 “X轴颜色、上Y轴颜色、下Y轴颜色”不然预览图表鼠标选择是全白色还请注意。<br>
![img20](../picture/dashboard/img_20.png)
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**

@ -4,10 +4,12 @@
![source.png](../picture/datasource/img_1.png)
## 数据源类型
- 没有找到新增数据源类型?<br>
查看已有的数据源类型 <br>
![img2](../picture/datasource/img_2.png) <br>
![img3](../picture/datasource/img_3.png) <br>
```text
字典管理目前暂未有页面维护,可自行去数据库中增加你需要的数据源类型。
表aj_report.gaea_dict字段dict_typeSOURCE_TYPE
可以在此页面进行新增数据源配置,也可以去数据库中增加你需要的数据源类型。
表aj_report.gaea_dict_item字段dict_codeSOURCE_TYPE
表aj_report.gaea_dict_item, item_extend字段是下拉选择后动态表单渲染的json数据
```

@ -0,0 +1,27 @@
# 介绍
execl报表基于Luckysheet开发[Luckysheet](https://gitee.com/mengshukeji/Luckysheet) 一款纯前端类似excel的在线表格功能强大、配置简单、完全开源。
**注意:** execl报表目前只是简单集成如果你遇到了一些问题请在此[Issue](https://gitee.com/anji-plus/report/issues/I4CEWV) 下面进行回复。<br>
## 表格报表设计
进入表格设计方法1 <br>
从报表管理模块选择需要设计的大屏,按图示进入大屏设计界面 <br>
![img](../picture/execl/img.png) <br>
进入大屏设计方法2 <br>
从大屏报表模块选择需要设计的大屏,按图示进入大屏设计界面 <br>
![img2](../picture/execl/img_1.png) <br>
## 简介
![img3](../picture/execl/img_2.png) <br>
## 使用
**注**:不建议一列中同时存在俩个字段数据,同时一列值也建议不要存到超大数据量,肯定无法显示的<br>
![img4](../picture/execl/img_3.png) <br>
## 预览/保存
点击保存,则会将数据写入到库中。<br>
点击预览,则进入预览界面。<br>
![img](../picture/execl/img_4.png) <br>
## 预览界面
可以进行导出操作。<br>
![img](../picture/execl/img_5.png) <br>

@ -15,3 +15,7 @@
![img1](../picture/imexport/img_1.png) <br>
选择一个导出的zip文件导入即可。注意导入会覆盖当前大屏请新建一张空白的大屏进行导入。<br>
**注:如果你导入的大屏中含有你当前系统不存在的图表,整个大屏是不会显示的。** <br>
## 导入导出权限
请查看权限控制模块中关于导入导出权限的说明。 <br>

@ -0,0 +1,3 @@
## 新增报表
![img](../picture/reportmanager/img.png) <br>
状态默认为已启用。

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

@ -105,6 +105,33 @@
<version>1.18.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
</dependencies>
<developers>

@ -3,6 +3,7 @@ package com.anjiplus.template.gaea.business.config;
import com.zaxxer.hikari.HikariDataSource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.flyway.FlywayProperties;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.stereotype.Component;
@ -18,6 +19,7 @@ import java.sql.Statement;
@Slf4j
@Component
@AllArgsConstructor
@ConditionalOnProperty(value = {"spring.flyway.enabled"})
public class DatabaseInitializer {
private final FlywayProperties flywayProperties;

@ -0,0 +1,73 @@
package com.anjiplus.template.gaea.business.enums;
/**
* @author zhouhang
* @description EXCEL
* @date 2021/4/26
*/
public enum ExcelCenterStyleEnum {
/**
*
*/
LEFT((short) 1, 1, "左对齐"),
/**
*
*/
RIGHT((short) 3, 2, "右对齐"),
/**
*
*/
CENTER((short) 2, 0, "居中"),
;
/**
* excelcode
*/
private final short excelCode;
/**
* 线code
*/
private final Integer onlineExcelCode;
/**
*
*/
private final String name;
public Integer getOnlineExcelCode() {
return onlineExcelCode;
}
public String getName() {
return name;
}
public short getExcelCode() {
return excelCode;
}
ExcelCenterStyleEnum(short excelCode, Integer onlineExcelCode, String name) {
this.excelCode = excelCode;
this.onlineExcelCode = onlineExcelCode;
this.name = name;
}
/**
* @param code excelcode
* @return Enum_ExcelCenterStyle
* @description excel线
* @author zhouhang
* @date 2021/4/26
*/
public static ExcelCenterStyleEnum getExcelCenterStyleByExcelCenterCode(short code) {
for (ExcelCenterStyleEnum value : ExcelCenterStyleEnum.values()) {
if (code == value.getExcelCode()) {
return value;
}
}
return CENTER;
}
}

@ -0,0 +1,30 @@
package com.anjiplus.template.gaea.business.enums;
/**
* Created by raodeming on 2021/9/3.
*/
public enum ExportTypeEnum {
/**gaea_excel*/
GAEA_TEMPLATE_EXCEL("gaea_template_excel", "gaea_template_excel"),
/**gaea_pdf*/
GAEA_TEMPLATE_PDF("gaea_template_pdf", "gaea_template_pdf"),
;
private String codeValue;
private String codeDesc;
private ExportTypeEnum(String codeValue, String codeDesc) {
this.codeValue = codeValue;
this.codeDesc = codeDesc;
}
public String getCodeValue() {
return this.codeValue;
}
public String getCodeDesc() {
return this.codeDesc;
}
}

@ -8,6 +8,7 @@ import com.anji.plus.gaea.utils.JwtBean;
import com.anjiplus.template.gaea.business.constant.BusinessConstant;
import com.anjiplus.template.gaea.business.util.JwtUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
@ -57,6 +58,12 @@ public class TokenFilter implements Filter {
HttpServletResponse response = (HttpServletResponse) servletResponse;
String uri = request.getRequestURI();
//OPTIONS直接放行
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
filterChain.doFilter(request, response);
return;
}
if (SLASH.equals(uri)) {
response.sendRedirect("/index.html");
return;
@ -123,9 +130,11 @@ public class TokenFilter implements Filter {
if (HttpMethod.POST.name().equalsIgnoreCase(method)
|| HttpMethod.PUT.name().equalsIgnoreCase(method)
|| HttpMethod.DELETE.name().equalsIgnoreCase(method)
|| uri.contains("/reportDashboard/export")
) {
ResponseBean responseBean = ResponseBean.builder().code("50001")
.message("在线体验版本,不允许此操作。请自行下载本地运行").build();
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().print(JSONObject.toJSONString(responseBean));
return;
}
@ -167,6 +176,7 @@ public class TokenFilter implements Filter {
private void error(HttpServletResponse response) throws IOException {
ResponseBean responseBean = ResponseBean.builder().code("50014").message("The Token has expired").build();
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().print(JSONObject.toJSONString(responseBean));
}
}

@ -12,7 +12,7 @@ import java.util.Date;
* @author ·De <lide1202@hotmail.com>
* @date 2019-02-17 08:50:10.009
**/
@TableName(value="access_authority")
@TableName(keepGlobalPrefix=true, value="access_authority")
@Data
public class AccessAuthority extends GaeaBaseEntity {
/** 父菜单代码 */
@ -40,4 +40,4 @@ public class AccessAuthority extends GaeaBaseEntity {
}
}

@ -11,7 +11,7 @@ import java.util.Date;
* @author ·De <lide1202@hotmail.com>
* @date 2019-02-17 08:50:14.136
**/
@TableName(value="access_role")
@TableName(keepGlobalPrefix=true, value="access_role")
@Data
public class AccessRole extends GaeaBaseEntity {
@ -27,4 +27,4 @@ public class AccessRole extends GaeaBaseEntity {
/** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */
private Integer enableFlag;
}
}

@ -14,7 +14,7 @@ import java.util.Date;
* @author ·De <lide1202@hotmail.com>
* @date 2019-02-17 08:50:14.136
**/
@TableName(value="access_role_authority")
@TableName(keepGlobalPrefix=true, value="access_role_authority")
@Data
public class AccessRoleAuthority extends GaeaBaseEntity {

@ -21,6 +21,7 @@ import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @desc AccessRole
@ -52,7 +53,14 @@ public class AccessRoleServiceImpl implements AccessRoleService {
List<TreeNode> treeData = accessAuthorityService.getAuthorityTree(operator, true);
// 该角色已选中的菜单及按钮
List<String> checkedKeys = accessRoleMapper.checkedAuthoritys(roleCode);
// List<String> checkedKeys = accessRoleMapper.checkedAuthoritys(roleCode);
LambdaQueryWrapper<AccessRoleAuthority> accessRoleAuthorityWrapper = Wrappers.lambdaQuery();
accessRoleAuthorityWrapper.select(AccessRoleAuthority::getTarget, AccessRoleAuthority::getAction);
accessRoleAuthorityWrapper.eq(AccessRoleAuthority::getRoleCode, roleCode);
List<AccessRoleAuthority> accessRoleAuthorities = accessRoleAuthorityMapper.selectList(accessRoleAuthorityWrapper);
List<String> checkedKeys = accessRoleAuthorities.stream()
.map(accessRoleAuthority -> accessRoleAuthority.getTarget().concat("_").concat(accessRoleAuthority.getAction())).distinct().collect(Collectors.toList());
result.put("treeData", treeData);
result.put("checkedKeys", checkedKeys);
@ -90,4 +98,4 @@ public class AccessRoleServiceImpl implements AccessRoleService {
});
return true;
}
}
}

@ -11,7 +11,7 @@ import java.util.Date;
* @author ·De <lide1202@hotmail.com>
* @date 2019-02-17 08:50:11.902
**/
@TableName(value="access_user")
@TableName(keepGlobalPrefix=true, value="access_user")
@Data
public class AccessUser extends GaeaBaseEntity {
@ -45,4 +45,4 @@ public class AccessUser extends GaeaBaseEntity {
/** 最后一次登陆时间 */
private Date lastLoginTime;
}
}

@ -13,7 +13,7 @@ import java.util.Date;
* @author ·De <lide1202@hotmail.com>
* @date 2019-02-17 08:50:11.902
**/
@TableName(value="access_user_role")
@TableName(keepGlobalPrefix=true, value="access_user_role")
@Data
public class AccessUserRole extends GaeaBaseEntity {
@ -37,4 +37,4 @@ public class AccessUserRole extends GaeaBaseEntity {
@TableField(exist = false)
private Integer version;
}
}

@ -13,8 +13,10 @@ import com.anji.plus.gaea.utils.GaeaUtils;
import com.anji.plus.gaea.utils.JwtBean;
import com.anjiplus.template.gaea.business.code.ResponseCode;
import com.anjiplus.template.gaea.business.constant.BusinessConstant;
import com.anjiplus.template.gaea.business.modules.accessrole.dao.AccessRoleAuthorityMapper;
import com.anjiplus.template.gaea.business.modules.accessrole.dao.AccessRoleMapper;
import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRole;
import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRoleAuthority;
import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.AccessUserDto;
import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.GaeaUserDto;
import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.UpdatePasswordDto;
@ -31,10 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -54,6 +53,9 @@ public class AccessUserServiceImpl implements AccessUserService {
@Autowired
private AccessUserRoleMapper accessUserRoleMapper;
@Autowired
private AccessRoleAuthorityMapper accessRoleAuthorityMapper;
@Value("${customer.user.default.password:'123456'}")
private String defaultPassword;
@ -168,11 +170,31 @@ public class AccessUserServiceImpl implements AccessUserService {
// 4.读取用户最新人权限主信息
String userKey = String.format(BusinessConstant.GAEA_SECURITY_LOGIN_USER, loginName);
List<String> authorities = accessUserMapper.queryAuthoritiesByLoginName(loginName);
//为了兼容底层其他数据库不再写自定义sql
// List<String> authorities = accessUserMapper.queryAuthoritiesByLoginName(loginName);
//当前用户的roleCode集合
LambdaQueryWrapper<AccessUserRole> accessUserWrapper = Wrappers.lambdaQuery();
accessUserWrapper.select(AccessUserRole::getRoleCode);
accessUserWrapper.eq(AccessUserRole::getLoginName, loginName);
List<AccessUserRole> accessUserRoles = accessUserRoleMapper.selectList(accessUserWrapper);
Set<String> roleCodeSet = accessUserRoles.stream().map(AccessUserRole::getRoleCode).collect(Collectors.toSet());
if (roleCodeSet.size() < 1) {
gaeaUser.setAuthorities(new ArrayList<>());
}else {
LambdaQueryWrapper<AccessRoleAuthority> accessRoleAuthorityWrapper = Wrappers.lambdaQuery();
accessRoleAuthorityWrapper.select(AccessRoleAuthority::getTarget, AccessRoleAuthority::getAction);
accessRoleAuthorityWrapper.in(AccessRoleAuthority::getRoleCode, roleCodeSet);
List<AccessRoleAuthority> accessRoleAuthorities = accessRoleAuthorityMapper.selectList(accessRoleAuthorityWrapper);
List<String> authorities = accessRoleAuthorities.stream()
.map(accessRoleAuthority -> accessRoleAuthority.getTarget().concat(":").concat(accessRoleAuthority.getAction())).distinct().collect(Collectors.toList());
gaeaUser.setAuthorities(authorities);
}
gaeaUser.setLoginName(loginName);
gaeaUser.setRealName(accessUser.getRealName());
gaeaUser.setToken(token);
gaeaUser.setAuthorities(authorities);
String gaeaUserStr = JSONObject.toJSONString(gaeaUser);
cacheHelper.stringSetExpire(userKey, gaeaUserStr, 3600);

@ -74,7 +74,7 @@ public class ReportDashboardController {
* @return
*/
@GetMapping("/export")
@Permission(code = "view", name = "导出大屏")
@Permission(code = "export", name = "导出大屏")
public ResponseEntity<byte[]> exportDashboard(HttpServletRequest request, HttpServletResponse response,
@RequestParam("reportCode") String reportCode, @RequestParam(value = "showDataSet",required = false, defaultValue = "1") Integer showDataSet) {
return reportDashboardService.exportDashboard(request, response, reportCode, showDataSet);
@ -87,7 +87,7 @@ public class ReportDashboardController {
* @return
*/
@PostMapping("/import/{reportCode}")
@Permission(code = "design", name = "导入大屏")
@Permission(code = "import", name = "导入大屏")
public ResponseBean importDashboard(@RequestParam("file") MultipartFile file, @PathVariable("reportCode") String reportCode) {
reportDashboardService.importDashboard(file, reportCode);
return ResponseBean.builder().build();

@ -13,7 +13,7 @@ import lombok.Data;
* @author Raod
* @date 2021-04-12 14:52:21.761
**/
@TableName(value="gaea_report_dashboard")
@TableName(keepGlobalPrefix=true, value="gaea_report_dashboard")
@Data
public class ReportDashboard extends GaeaBaseEntity {
@ApiModelProperty(value = "报表编码")

@ -159,7 +159,7 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
.lambda().eq(ReportDashboardWidget::getReportCode, reportCode));
List<ReportDashboardWidgetDto> widgets = dto.getWidgets();
List<ReportDashboardWidget> reportDashboardWidgetList = new ArrayList<>();
// List<ReportDashboardWidget> reportDashboardWidgetList = new ArrayList<>();
for (int i = 0; i < widgets.size(); i++) {
ReportDashboardWidget reportDashboardWidget = new ReportDashboardWidget();
ReportDashboardWidgetDto reportDashboardWidgetDto = widgets.get(i);
@ -175,9 +175,13 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
reportDashboardWidget.setEnableFlag(1);
reportDashboardWidget.setDeleteFlag(0);
reportDashboardWidget.setSort((long) (i + 1));
reportDashboardWidgetList.add(reportDashboardWidget);
//兼容底层,不采用批量插入
reportDashboardWidgetService.insert(reportDashboardWidget);
// reportDashboardWidgetList.add(reportDashboardWidget);
}
reportDashboardWidgetService.insertBatch(reportDashboardWidgetList);
// reportDashboardWidgetService.insertBatch(reportDashboardWidgetList);
}
@ -348,6 +352,9 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
private String replaceUrl(String imageAddress, Map<String, String> fileMap) {
if (StringUtils.isBlank(imageAddress)) {
return "";
}
String fileId = imageAddress.substring(imageAddress.trim().length() - 36);
String orDefault = fileMap.getOrDefault(fileId, null);
if (StringUtils.isBlank(orDefault)) {
@ -443,14 +450,19 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
return data;
}
//获取时间轴字段和解析时间颗粒度
chartProperties.forEach((key, value) -> {
for (Map.Entry<String, String> entry : chartProperties.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
dto.setParticles(value);
setTimeLineFormat(dto);
if (StringUtils.isNotBlank(dto.getDataTimeFormat())) {
dto.setTimeLineFiled(key);
return;
break;
}
});
}
if (StringUtils.isBlank(dto.getDataTimeFormat())) {
return data;

@ -11,7 +11,7 @@ import lombok.Data;
* @author Raod
* @date 2021-04-12 15:12:43.724
**/
@TableName(value="gaea_report_dashboard_widget")
@TableName(keepGlobalPrefix=true, value="gaea_report_dashboard_widget")
@Data
public class ReportDashboardWidget extends GaeaBaseEntity {
@ApiModelProperty(value = "报表编码")

@ -55,4 +55,7 @@ public class DataSetDto extends GaeaBaseDTO implements Serializable {
private Set<String> setParamList;
/**指定字段*/
private String fieldLabel;
}

@ -13,7 +13,7 @@ import lombok.Data;
* @author Raod
* @date 2021-03-18 12:11:31.150755900
**/
@TableName(value="gaea_report_data_set")
@TableName(keepGlobalPrefix=true, value="gaea_report_data_set")
@Data
public class DataSet extends GaeaBaseEntity {
@ApiModelProperty(value = "数据集编码")

@ -226,11 +226,13 @@ public class DataSetServiceImpl implements DataSetService {
DataSource dataSource = dataSourceService.selectOne("source_code", dataSetDto.getSourceCode());
//3.参数替换
//3.1参数校验
log.debug("参数校验替换前:{}", dto.getContextData());
boolean verification = dataSetParamService.verification(dataSetDto.getDataSetParamDtoList(), dto.getContextData());
if (!verification) {
throw BusinessExceptionBuilder.build(ResponseCode.RULE_FIELDS_CHECK_ERROR);
}
String dynSentence = dataSetParamService.transform(dto.getContextData(), dataSetDto.getDynSentence());
log.debug("参数校验替换后:{}", dto.getContextData());
//4.获取数据
DataSourceDto dataSourceDto = new DataSourceDto();
BeanUtils.copyProperties(dataSource, dataSourceDto);
@ -300,6 +302,7 @@ public class DataSetServiceImpl implements DataSetService {
LambdaQueryWrapper<DataSet> wrapper = Wrappers.lambdaQuery();
wrapper.select(DataSet::getSetCode, DataSet::getSetName, DataSet::getSetDesc, DataSet::getId)
.eq(DataSet::getEnableFlag, Enabled.YES.getValue());
wrapper.orderByDesc(DataSet::getUpdateTime);
return dataSetMapper.selectList(wrapper);
}
@ -312,14 +315,16 @@ public class DataSetServiceImpl implements DataSetService {
if (null == dataSetParamDtoList || dataSetParamDtoList.size() <= 0) {
return;
}
List<DataSetParam> dataSetParamList = new ArrayList<>();
// List<DataSetParam> dataSetParamList = new ArrayList<>();
dataSetParamDtoList.forEach(dataSetParamDto -> {
DataSetParam dataSetParam = new DataSetParam();
BeanUtils.copyProperties(dataSetParamDto, dataSetParam);
dataSetParam.setSetCode(setCode);
dataSetParamList.add(dataSetParam);
//不采用批量
dataSetParamService.insert(dataSetParam);
// dataSetParamList.add(dataSetParam);
});
dataSetParamService.insertBatch(dataSetParamList);
// dataSetParamService.insertBatch(dataSetParamList);
}
@ -332,15 +337,17 @@ public class DataSetServiceImpl implements DataSetService {
if (null == dataSetTransformDtoList || dataSetTransformDtoList.size() <= 0) {
return;
}
List<DataSetTransform> dataSetTransformList = new ArrayList<>();
// List<DataSetTransform> dataSetTransformList = new ArrayList<>();
for (int i = 0; i < dataSetTransformDtoList.size(); i++) {
DataSetTransform dataSetTransform = new DataSetTransform();
BeanUtils.copyProperties(dataSetTransformDtoList.get(i), dataSetTransform);
dataSetTransform.setOrderNum(i + 1);
dataSetTransform.setSetCode(setCode);
dataSetTransformList.add(dataSetTransform);
//不采用批量
dataSetTransformService.insert(dataSetTransform);
// dataSetTransformList.add(dataSetTransform);
}
dataSetTransformService.insertBatch(dataSetTransformList);
// dataSetTransformService.insertBatch(dataSetTransformList);
}
}

@ -11,7 +11,7 @@ import lombok.Data;
* @author Raod
* @date 2021-03-18 12:12:33.108033200
**/
@TableName(value="gaea_report_data_set_param")
@TableName(keepGlobalPrefix=true, value="gaea_report_data_set_param")
@Data
public class DataSetParam extends GaeaBaseEntity {
@ApiModelProperty(value = "数据集编码")

@ -39,7 +39,7 @@ public interface DataSetParamService extends GaeaBaseService<DataSetParamParam,
* @param dataSetParamDto
* @return
*/
boolean verification(DataSetParamDto dataSetParamDto);
Object verification(DataSetParamDto dataSetParamDto);
/**
* js

@ -93,7 +93,7 @@ public class DataSetParamServiceImpl implements DataSetParamService {
* @return
*/
@Override
public boolean verification(DataSetParamDto dataSetParamDto) {
public Object verification(DataSetParamDto dataSetParamDto) {
String validationRules = dataSetParamDto.getValidationRules();
if (StringUtils.isNotBlank(validationRules)) {
@ -103,7 +103,12 @@ public class DataSetParamServiceImpl implements DataSetParamService {
Invocable invocable = (Invocable) engine;
Object exec = invocable.invokeFunction("verification", dataSetParamDto);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.convertValue(exec, Boolean.class);
if (exec instanceof Boolean) {
return objectMapper.convertValue(exec, Boolean.class);
}else {
return objectMapper.convertValue(exec, String.class);
}
}
} catch (Exception ex) {
@ -131,9 +136,20 @@ public class DataSetParamServiceImpl implements DataSetParamService {
String value = contextData.getOrDefault(dataSetParamDto.getParamName(), "").toString();
dataSetParamDto.setSampleItem(value);
}
if (!verification(dataSetParamDto)) {
return false;
Object verification = verification(dataSetParamDto);
if (verification instanceof Boolean) {
if (!(Boolean) verification) {
return false;
}
}else {
//将得到的值重新赋值给contextData
if (null != contextData) {
contextData.put(dataSetParamDto.getParamName(), verification);
}
dataSetParamDto.setSampleItem(verification.toString());
}
}
return true;
}

@ -11,7 +11,7 @@ import lombok.Data;
* @author Raod
* @date 2021-03-18 12:13:15.591309400
**/
@TableName(value="gaea_report_data_set_transform")
@TableName(keepGlobalPrefix=true, value="gaea_report_data_set_transform")
@Data
public class DataSetTransform extends GaeaBaseEntity {
@ApiModelProperty(value = "数据集编码")

@ -13,7 +13,7 @@ import lombok.Data;
* @author Raod
* @date 2021-03-18 12:09:57.728203200
**/
@TableName(value="gaea_report_data_source")
@TableName(keepGlobalPrefix=true, value="gaea_report_data_source")
@Data
public class DataSource extends GaeaBaseEntity {
@ApiModelProperty(value = "数据源编码")

@ -33,11 +33,9 @@ import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -77,6 +75,7 @@ public class DataSourceServiceImpl implements DataSourceService {
LambdaQueryWrapper<DataSource> wrapper = Wrappers.lambdaQuery();
wrapper.select(DataSource::getSourceCode, DataSource::getSourceName)
.eq(DataSource::getEnableFlag, Enabled.YES.getValue());
wrapper.orderByDesc(DataSource::getUpdateTime);
return dataSourceMapper.selectList(wrapper);
}
@ -243,7 +242,9 @@ public class DataSourceServiceImpl implements DataSourceService {
columns.forEach(t -> {
try {
Object value = rs.getObject(t);
jo.put(t, value);
//数据类型转换
Object result = dealResult(value);
jo.put(t, result);
} catch (SQLException throwable) {
log.error("error",throwable);
throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_SQL_ERROR, throwable.getMessage());
@ -267,6 +268,26 @@ public class DataSourceServiceImpl implements DataSourceService {
}
}
/**
* sql
* (through reference chain: java.util.HashMap["pageData"]->java.util.ArrayList[0]->java.util.HashMap["UPDATE_TIME"]->oracle.sql.TIMESTAMP["stream"])
* @param result
* @return
* @throws SQLException
*/
private Object dealResult(Object result) throws SQLException {
if (null == result) {
return result;
}
String type = result.getClass().getName();
if ("oracle.sql.TIMESTAMP".equals(type)) {
//oracle.sql.TIMESTAMP处理逻辑
return new Date((Long) JSONObject.toJSON(result));
}
return result;
}
/**
* http
*

@ -13,7 +13,7 @@ import java.io.Serializable;
* @author lr
* @since 2021-02-23 10:01:02
*/
@TableName("gaea_dict")
@TableName(keepGlobalPrefix=true, value = "gaea_dict")
public class GaeaDict extends GaeaBaseEntity implements Serializable {
/**
*

@ -15,7 +15,7 @@ import java.io.Serializable;
* @author lirui
* @since 2021-03-09 15:52:41
*/
@TableName("gaea_dict_item")
@TableName(keepGlobalPrefix=true,value = "gaea_dict_item")
@UnionUniqueCode(group = BusinessConstant.DICT_ITEM_EXIST_GROUP, code = ResponseCode.DICT_ITEM_REPEAT)
public class GaeaDictItem extends GaeaBaseEntity implements Serializable {

@ -13,7 +13,7 @@ import java.io.Serializable;
* @author peiyanni
* @since 2021-02-18 14:48:20
*/
@TableName("gaea_file")
@TableName(keepGlobalPrefix=true, value = "gaea_file")
@Data
public class GaeaFile extends GaeaBaseEntity implements Serializable {

@ -99,7 +99,7 @@ public class GaeaFileServiceImpl implements GaeaFileService {
String newFileName = fileId + suffixName;
// 本地文件保存路径
String filePath = dictPath + newFileName;
String urlPath = fileDownloadPath + java.io.File.separator + fileId;
String urlPath = fileDownloadPath + "/" + fileId;
GaeaFile gaeaFile = new GaeaFile();
gaeaFile.setFilePath(filePath);

@ -13,7 +13,7 @@ import lombok.Data;
* @author chenkening
* @date 2021/3/26 10:20
*/
@TableName(value="gaea_report")
@TableName(keepGlobalPrefix=true, value="gaea_report")
@Data
public class Report extends GaeaBaseEntity {

@ -11,7 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* TODO
*
* @author chenkening
* @date 2021/3/26 10:35
@ -31,11 +30,12 @@ public class ReportServiceImpl implements ReportService {
@Override
public void delReport(ReportDto reportDto) {
deleteById(reportDto.getId());
//删除gaea_report_excel、gaea_report_dashboard、gaea_report_dashboard_widget
//...
}
@Override
public void processBeforeOperation(Report entity, BaseOperationEnum operationEnum) throws BusinessException {
//目前只有大屏一种类型
entity.setReportType("report_screen");
}
}

@ -0,0 +1,78 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.controller;
import com.anji.plus.gaea.annotation.Permission;
import com.anji.plus.gaea.annotation.log.GaeaAuditLog;
import com.anji.plus.gaea.bean.ResponseBean;
import com.anji.plus.gaea.code.ResponseCode;
import com.anji.plus.gaea.curd.controller.GaeaBaseController;
import com.anji.plus.gaea.curd.service.GaeaBaseService;
import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto;
import com.anjiplus.template.gaea.business.modules.reportexcel.controller.param.ReportExcelParam;
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel;
import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author chenkening
* @date 2021/4/13 15:12
*/
@RestController
@Api(tags = "报表表格管理")
@Permission(code = "excelManage", name = "报表管理")
@RequestMapping("/reportExcel")
public class ReportExcelController extends GaeaBaseController<ReportExcelParam, ReportExcel, ReportExcelDto> {
@Autowired
private ReportExcelService reportExcelService;
@Override
public GaeaBaseService<ReportExcelParam, ReportExcel> getService() {
return reportExcelService;
}
@Override
public ReportExcel getEntity() {
return new ReportExcel();
}
@Override
public ReportExcelDto getDTO() {
return new ReportExcelDto();
}
@GetMapping("/detailByReportCode/{reportCode}")
@Permission(code = "query", name = "详情")
@GaeaAuditLog(pageTitle = "详情")
public ResponseBean detailByReportCode(@PathVariable String reportCode) {
ReportExcelDto reportExcelDto = reportExcelService.detailByReportCode(reportCode);
return ResponseBean.builder().data(reportExcelDto).build();
}
@PostMapping("/preview")
@Permission(code = "view", name = "预览")
@GaeaAuditLog(pageTitle = "预览")
public ResponseBean preview(@RequestBody ReportExcelDto reportExcelDto) {
ReportExcelDto result = reportExcelService.preview(reportExcelDto);
return ResponseBean.builder().data(result).build();
}
@PostMapping("/exportExcel")
@Permission(code = "export", name = "导出")
@GaeaAuditLog(pageTitle = "报表导出")
public ResponseBean exportExcel(@RequestBody ReportExcelDto reportExcelDto) {
return ResponseBean.builder().code(ResponseCode.SUCCESS_CODE)
.data(reportExcelService.exportExcel(reportExcelDto))
.message("导出成功,请稍后在文件管理中查看").build();
}
// @PostMapping("/exportPdf")
// public ResponseBean exportPdf(@RequestBody ReportExcelDto reportExcelDto) {
// reportExcelService.exportPdf(reportExcelDto);
// return ResponseBean.builder().code(ResponseCode.SUCCESS_CODE)
// .build();
// }
}

@ -0,0 +1,58 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import java.util.List;
/**
*
*
* @author Administrator
*/
@Data
public class GridRecordDataModel {
/**
*
*/
Long id;
/**
* ID
*/
String list_id;
/**
* _
*/
String row_col;
/**
* sheet
*/
String index;
/**
* sheet
*/
Integer status;
/**
* fblock
*/
String block_id;
/**
* json
*/
JSONObject json_data;
/**
*
*/
Integer order;
/**
*
*/
Integer is_delete;
/**
* sheet
*/
List<JSONObject> dataList;
}

@ -0,0 +1,61 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto;
import com.anji.plus.gaea.curd.dto.GaeaBaseDTO;
import lombok.Data;
import java.io.Serializable;
/**
* @author chenkening
* @date 2021/4/13 15:12
*/
@Data
public class ReportExcelDto extends GaeaBaseDTO implements Serializable {
/**
*
*/
private String reportName;
/**
*
*/
private String reportCode;
/**
* |
*/
private String setCodes;
/**
*
*/
private String reportGroup;
/**
*
*/
private String setParam;
/**
* json
*/
private String jsonStr;
/**
*
*/
private String reportType;
/**
*
*/
private long total;
/**
*
*/
private String exportType;
}

@ -0,0 +1,18 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.controller.param;
import com.anji.plus.gaea.curd.params.PageParam;
import lombok.Data;
import java.io.Serializable;
/**
* @author chenkening
* @date 2021/4/13 15:12
*/
@Data
public class ReportExcelParam extends PageParam implements Serializable {
}

@ -0,0 +1,11 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.dao;
import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel;
/**
* @author chenkening
* @date 2021/4/13 15:11
*/
public interface ReportExcelMapper extends GaeaBaseMapper<ReportExcel> {
}

@ -0,0 +1,33 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity;
import com.anji.plus.gaea.curd.entity.GaeaBaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author chenkening
* @date 2021/4/13 15:11
*/
@TableName(value = "gaea_report_excel")
@Data
public class ReportExcel extends GaeaBaseEntity {
@ApiModelProperty(value = "报表编码")
private String reportCode;
@ApiModelProperty(value = "数据集编码,以|分割")
private String setCodes;
@ApiModelProperty(value = "数据集查询参数")
private String setParam;
@ApiModelProperty(value = "报表json字符串")
private String jsonStr;
@ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG")
private Integer enableFlag;
@ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG")
private Integer deleteFlag;
}

@ -0,0 +1,43 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.service;
import com.anji.plus.gaea.curd.service.GaeaBaseService;
import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto;
import com.anjiplus.template.gaea.business.modules.reportexcel.controller.param.ReportExcelParam;
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel;
/**
* TODO
*
* @author chenkening
* @date 2021/4/13 15:14
*/
public interface ReportExcelService extends GaeaBaseService<ReportExcelParam, ReportExcel> {
/**
*
*
* @param reportCode
* @return
*/
ReportExcelDto detailByReportCode(String reportCode);
/**
*
*
* @param reportExcelDto
* @return
*/
ReportExcelDto preview(ReportExcelDto reportExcelDto);
/**
* excel
*
* @param reportExcelDto
* @return
*/
Boolean exportExcel(ReportExcelDto reportExcelDto);
// Boolean exportPdf(ReportExcelDto reportExcelDto);
}

@ -0,0 +1,362 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.anji.plus.gaea.constant.BaseOperationEnum;
import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
import com.anji.plus.gaea.exception.BusinessException;
import com.anji.plus.gaea.utils.GaeaAssert;
import com.anji.plus.gaea.utils.GaeaBeanUtils;
import com.anjiplus.template.gaea.business.code.ResponseCode;
import com.anjiplus.template.gaea.business.enums.ExportTypeEnum;
import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto;
import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto;
import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService;
import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper;
import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
import com.anjiplus.template.gaea.business.modules.report.dao.ReportMapper;
import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto;
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.ReportExcelMapper;
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel;
import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService;
import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsSheetUtil;
import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.*;
/**
* TODO
*
* @author chenkening
* @date 2021/4/13 15:14
*/
@Service
public class ReportExcelServiceImpl implements ReportExcelService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private ReportExcelMapper reportExcelMapper;
@Autowired
private DataSetService dataSetService;
@Autowired
private ReportMapper reportMapper;
@Value("${customer.file.dist-path:''}")
private String dictPath;
@Value("${customer.file.downloadPath:''}")
private String fileDownloadPath;
@Autowired
private GaeaFileMapper gaeaFileMapper;
@Override
public GaeaBaseMapper<ReportExcel> getMapper() {
return reportExcelMapper;
}
@Override
public ReportExcelDto detailByReportCode(String reportCode) {
QueryWrapper<ReportExcel> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("report_code", reportCode);
ReportExcel reportExcel = reportExcelMapper.selectOne(queryWrapper);
if (reportExcel != null) {
ReportExcelDto dto = new ReportExcelDto();
BeanUtils.copyProperties(reportExcel, dto);
return dto;
}
return null;
}
/**
*
*
* @param entity
* @param operationEnum
* @throws BusinessException
*/
@Override
public void processBeforeOperation(ReportExcel entity, BaseOperationEnum operationEnum) throws BusinessException {
if (operationEnum.equals(BaseOperationEnum.INSERT)) {
String reportCode = entity.getReportCode();
ReportExcel report = this.selectOne("report_code", reportCode);
if (null != report) {
this.deleteById(report.getId());
}
}
}
/**
*
*/
@Override
public ReportExcelDto preview(ReportExcelDto reportExcelDto) {
// 根据id查询 报表详情
ReportExcel reportExcel = selectOne("report_code", reportExcelDto.getReportCode());
QueryWrapper<Report> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("report_code", reportExcelDto.getReportCode());
Report report = reportMapper.selectOne(queryWrapper);
GaeaAssert.notNull(reportExcel, ResponseCode.RULE_CONTENT_NOT_EXIST, "reportExcel");
String setParam = reportExcelDto.getSetParam();
GaeaBeanUtils.copyAndFormatter(reportExcel, reportExcelDto);
if (StringUtils.isNotBlank(setParam)) {
reportExcelDto.setSetParam(setParam);
}
reportExcelDto.setReportName(report.getReportName());
// 数据集解析
String jsonStr = analysisReportData(reportExcelDto);
reportExcelDto.setJsonStr(jsonStr);
// reportExcelDto.setTotal(jsonObject.getJSONObject("rows").size());
return reportExcelDto;
}
@Override
public Boolean exportExcel(ReportExcelDto reportExcelDto) {
String reportCode = reportExcelDto.getReportCode();
String exportType = reportExcelDto.getExportType();
logger.error("导出...");
if (exportType.equals(ExportTypeEnum.GAEA_TEMPLATE_EXCEL.getCodeValue())) {
ReportExcelDto report = detailByReportCode(reportCode);
reportExcelDto.setJsonStr(report.getJsonStr());
String jsonStr = analysisReportData(reportExcelDto);
List<JSONObject> lists=(List<JSONObject> ) JSON.parse(jsonStr);
OutputStream out;
try {
String fileId = UUID.randomUUID().toString();
String filePath = dictPath + File.separator + fileId + ".xlsx";
String urlPath = fileDownloadPath + java.io.File.separator + fileId;
GaeaFile gaeaFile = new GaeaFile();
gaeaFile.setFilePath(filePath);
gaeaFile.setFileId(fileId);
gaeaFile.setUrlPath(urlPath);
gaeaFile.setFileType("xlsx");
gaeaFile.setFileInstruction(reportCode + ".xlsx");
out = new FileOutputStream(filePath);
XlsUtil.exportXlsFile(out, true, lists);
gaeaFileMapper.insert(gaeaFile);
logger.info("导出成功:{}", gaeaFile);
} catch (IOException e) {
logger.error("导出失败", e);
}
}
return true;
}
/**
*
*/
private String analysisReportData(ReportExcelDto reportExcelDto) {
String jsonStr = reportExcelDto.getJsonStr();
String setParam = reportExcelDto.getSetParam();
List<JSONObject> dbObjectList = (List<JSONObject>) JSON.parse(jsonStr);
if (dbObjectList != null && dbObjectList.size() > 0) {
for (int x = 0; x < dbObjectList.size(); x++) {
analysisSheetCellData(dbObjectList.get(x), setParam);
}
}
//fastjson $ref 循环引用
return JSONObject.toJSONString(dbObjectList, SerializerFeature.DisableCircularReferenceDetect);
}
/**
* sheet data
*
* @param dbObject
*/
private void analysisSheet(JSONObject dbObject, String setParma) {
//data是一个二维数组
if (dbObject.containsKey("data") && null != dbObject.get("data")) {
List<JSONArray> data = (List<JSONArray>) dbObject.get("data");
//行
for (int r = 0; r < data.size(); r++) {
JSONArray jsonArray = data.get(r);
//列
for (int c = 0; c < jsonArray.size(); c++) {
//单元格
JSONObject cell = jsonArray.getJSONObject(c);
if (null != cell && cell.containsKey("v") && StringUtils.isNotBlank(cell.getString("v"))) {
String v = cell.getString("v");
DataSetDto dataSet = getDataSet(v, setParma);
if (null != dataSet) {
OriginalDataDto originalDataDto = dataSetService.getData(dataSet);
if (null != originalDataDto.getData()) {
if (originalDataDto.getData().size() == 1) {
//对象
JSONObject jsonObject = originalDataDto.getData().get(0);
String fieldLabel = jsonObject.getString(dataSet.getFieldLabel());
String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel);
dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("v", replace);
dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("m", replace);
} else {
//集合
JSONObject jsonObject = originalDataDto.getData().get(0);
String fieldLabel = jsonObject.getString(dataSet.getFieldLabel());
String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel);
dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("v", replace);
dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("m", replace);
}
}
}
}
}
}
System.out.println("aaaa");
}
}
/**
* sheet celldata
*
* @param dbObject
*/
private void analysisSheetCellData(JSONObject dbObject, String setParam) {
//清空data值
dbObject.remove("data");
//celldata是一个一维数组
if (dbObject.containsKey("celldata") && null != dbObject.get("celldata")) {
List<JSONObject> celldata = new ArrayList<>();
celldata.addAll((List<JSONObject>) dbObject.get("celldata"));
// 遍历已存在的单元格,查看是否存在动态参数
for (int i = 0; i < celldata.size(); i++) {
//单元格对象
JSONObject cellObj = celldata.get(i);
//fastjson深拷贝问题
String cellStr = cellObj.toJSONString();
//行号
Integer r = cellObj.getInteger("r");
//列号
Integer c = cellObj.getInteger("c");
JSONObject cell = cellObj.getJSONObject("v");
if (null != cell && cell.containsKey("v") && StringUtils.isNotBlank(cell.getString("v"))) {
String v = cell.getString("v");
DataSetDto dataSet = getDataSet(v, setParam);
if (null != dataSet) {
OriginalDataDto originalDataDto = dataSetService.getData(dataSet);
if (null != originalDataDto.getData()) {
List<JSONObject> data = originalDataDto.getData();
for (int j = 0; j < data.size(); j++) {
if (j == 0) {
//处理当前行
//第一行,作为渲染参照数据
JSONObject jsonObject = data.get(j);
String fieldLabel = jsonObject.getString(dataSet.getFieldLabel());
String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel);
dbObject.getJSONArray("celldata").getJSONObject(i).getJSONObject("v").put("v", replace);
dbObject.getJSONArray("celldata").getJSONObject(i).getJSONObject("v").put("m", replace);
} else {
//新增的行数据
JSONObject addCell = data.get(j);
//字段
String fieldLabel = addCell.getString(dataSet.getFieldLabel());
String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel);
//转字符串,解决深拷贝问题
JSONObject addCellData = JSONObject.parseObject(cellStr);
addCellData.put("r", r + j);
addCellData.put("c", c);
addCellData.getJSONObject("v").put("v", replace);
addCellData.getJSONObject("v").put("m", replace);
dbObject.getJSONArray("celldata").add(addCellData);
}
}
}
}
}
}
}
}
/**
* #{xxxx.xxxxx}
* @param v
* @return
*/
private DataSetDto getDataSet(String v, String setParam) {
DataSetDto dto = new DataSetDto();
if (v.contains("#{") && v.contains("}")) {
int start = v.indexOf("#{") + 2;
int end = v.indexOf("}");
if (start < end) {
String substring = v.substring(start, end);
if (substring.contains(".")) {
String[] split = substring.split("\\.");
dto.setSetCode( split[0]);
dto.setFieldLabel(split[1]);
getContextData(setParam, dto);
return dto;
}
}
}
return null;
}
/**
*
* @param setParam
* @param dto
*/
private void getContextData(String setParam, DataSetDto dto) {
if (StringUtils.isNotBlank(setParam)) {
JSONObject setParamJson = JSONObject.parseObject(setParam);
Map<String, Object> map = new HashMap<>();
// 查询条件
if (setParamJson.containsKey(dto.getSetCode())) {
JSONObject paramCondition = setParamJson.getJSONObject(dto.getSetCode());
paramCondition.forEach(map::put);
}
dto.setContextData(map);
}
}
}

@ -0,0 +1,134 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Color;
import org.apache.poi.xssf.usermodel.XSSFColor;
/**
* https://github.com/mengshukeji/LuckysheetServer
*
* @author Administrator
*/
@Slf4j
public class ColorUtil {
private static final String S = "0123456789ABCDEF";
public static Short getColorByStr(String colorStr) {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFPalette palette = workbook.getCustomPalette();
if (colorStr.toLowerCase().startsWith("rgb")) {
colorStr = colorStr.toLowerCase().replace("rgb(", "").replace(")", "");
String[] colors = colorStr.split(",");
if (colors.length == 3) {
try {
int red = Integer.parseInt(colors[0].trim(), 16);
int green = Integer.parseInt(colors[1].trim(), 16);
int blue = Integer.parseInt(colors[2].trim(), 16);
HSSFColor hssfColor = palette.findSimilarColor(red, green, blue);
return hssfColor.getIndex();
} catch (Exception ex) {
log.error(ex.toString());
return null;
}
}
return null;
}
if (colorStr.equals("#000")) {
colorStr = "#000000";
}
if (colorStr != null && colorStr.length() >= 6) {
try {
if (colorStr.length() == 8) {
colorStr = colorStr.substring(2);
}
if (colorStr.length() == 7) {
colorStr = colorStr.substring(1);
}
String str2 = colorStr.substring(0, 2);
String str3 = colorStr.substring(2, 4);
String str4 = colorStr.substring(4, 6);
int red = Integer.parseInt(str2, 16);
int green = Integer.parseInt(str3, 16);
int blue = Integer.parseInt(str4, 16);
HSSFColor hssfColor = palette.findSimilarColor(red, green, blue);
return hssfColor.getIndex();
} catch (Exception ex) {
log.error(ex.toString());
return null;
}
}
return null;
}
/**
* RGB
*
* @param r
* @param g
* @param b
* @return
*/
public static String convertRGBToHex(short r, short g, short b) {
String hex = "";
if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) {
int x, y, z;
x = r % 16;
r = (short) ((r - x) / 16);
y = g % 16;
g = (short) ((g - y) / 16);
z = b % 16;
b = (short) ((b - z) / 16);
hex = "#" + S.charAt(r) + S.charAt(x) + S.charAt(g) + S.charAt(y) + S.charAt(b) + S.charAt(z);
}
return hex;
}
/**
* @param cell
* @return RGB
* @description tintRBG
* @author zhouhang
* @date 2021/4/26
*/
public static String getFillColorHex(Cell cell) {
String fillColorString = null;
if (cell != null) {
CellStyle cellStyle = cell.getCellStyle();
Color color = cellStyle.getFillForegroundColorColor();
if (color instanceof XSSFColor) {
XSSFColor xssfColor = (XSSFColor) color;
byte[] argb = xssfColor.getARGB();
fillColorString = convertRGBToHex((short) (argb[1] & 0xFF), (short) (argb[2] & 0xFF), (short) (argb[3] & 0xFF));
// TODO: 2021/4/26 添加透明度
// if (xssfColor.hasTint()) {
// fillColorString += " * " + xssfColor.getTint();
// byte[] rgb = xssfColor.getRGBWithTint();
// fillColorString += " = [" + (argb[0] & 0xFF) + ", " + (rgb[0] & 0xFF) + ", " + (rgb[1] & 0xFF) + ", " + (rgb[2] & 0xFF) + "]";
// }
} else if (color instanceof HSSFColor) {
HSSFColor hssfColor = (HSSFColor) color;
short[] rgb = hssfColor.getTriplet();
fillColorString = convertRGBToHex((short) (rgb[0] & 0xFF), (short) (rgb[1] & 0xFF), (short) (rgb[2] & 0xFF));
//去除黑色背景
if (StringUtils.equals("#000000", fillColorString)) {
return null;
}
}
}
return fillColorString;
}
}

@ -0,0 +1,313 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.util;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* https://github.com/mengshukeji/LuckysheetServer
*
* @author cr
*/
public class ConstantUtil {
/**
*
*/
public static Map<Integer, String> ff_IntegerToName = new HashMap<Integer, String>();
/**
*
*/
public static Map<String, Integer> ff_NameToInteger = new HashMap<String, Integer>();
/**
* 36223714
*/
public static String[] number_type = null;
/**
* 36
*/
public static String[] number_format = null;
/**
*
*/
public static Map<String, Integer> number_format_map = new HashMap<String, Integer>();
static {
//格式
nf();
//字体
ff();
}
private static void nf() {
number_type = new String[]{
"General", "Decimal", "Decimal", "Decimal", "Decimal", "Currency", "Currency", "Currency", "Currency",
"Percentage", "Percentage", "Scientific", "Fraction", "Fraction", "Date", "Date", "Date", "Date",
"Time", "Time", "Time", "Time", "Time",
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
"Accounting", "Accounting", "Accounting", "Accounting", "Accounting",
"Currency", "Accounting", "Currency", "Time", "Time", "Time", "Scientific", "Text"
};
number_format = new String[]{
"General", "0", "0.00", "#,##0", "#,##0.00", "$#,##0;($#,##0)", "$#,##0;[Red]($#,##0)", "$#,##0.00;($#,##0.00)", "$#,##0.00;[Red]($#,##0.00)",
"0%", "0.00%", "0.00E+00", "# ?/?", "# ??/??", "m/d/yyyy", "d-mmm-yy", "d-mmm", "mmm-yy",
"h:mm AM/PM", "h:mm:ss AM/PM", "h:mm", "h:mm:ss", "m/d/yyyy h:mm",
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
"#,##0;(#,##0)", "#,##0;[Red](#,##0)", "#,##0.00;(#,##0.00)", "#,##0.00;[Red](#,##0.00)", "_ * #,##0_ ;_ * (#,##0)_ ;_ * \"-\"_ ;_ @_",
"_ $* #,##0_ ;_ $* (#,##0)_ ;_ $* \"-\"_ ;_ @_", "_ * #,##0.00_ ;_ * (#,##0.00)_ ;_ * \"-\"??_ ;_ @_", "_ $* #,##0.00_ ;_ $* (#,##0.00)_ ;_ $* \"-\"??_ ;_ @_", "mm:ss", "[h]:mm:ss", "mm:ss.0", "##0.0E+00", "@"
};
for (int x = 0; x < number_format.length; x++) {
if (number_format[x].length() > 0) {
number_format_map.put(number_format[x].toLowerCase(), x);
}
}
}
private static void ff() {
//0 微软雅黑、1 宋体Song、2 黑体ST Heiti、3 楷体ST Kaiti、 4仿宋ST FangSong、 5 新宋体ST Song
// 6 华文新魏、 7华文行楷、 8 华文隶书、 9 Arial、 10 Times New Roman 、11 Tahoma 、12 Verdana
ff_IntegerToName.put(0, "微软雅黑");
ff_IntegerToName.put(1, "宋体");
ff_IntegerToName.put(2, "黑体");
ff_IntegerToName.put(3, "楷体");
ff_IntegerToName.put(4, "仿宋");
ff_IntegerToName.put(5, "新宋体");
ff_IntegerToName.put(6, "华文新魏");
ff_IntegerToName.put(7, "华文行楷");
ff_IntegerToName.put(8, "华文隶书");
ff_IntegerToName.put(9, "Arial");
ff_IntegerToName.put(10, "Times New Roman");
ff_IntegerToName.put(11, "Tahoma");
ff_IntegerToName.put(12, "Verdana");
//0 微软雅黑、1 宋体Song、2 黑体ST Heiti、3 楷体ST Kaiti、 4仿宋ST FangSong、 5 新宋体ST Song
// 6 华文新魏、 7华文行楷、 8 华文隶书、 9 Arial、 10 Times New Roman 、11 Tahoma 、12 Verdana
ff_NameToInteger.put("微软雅黑", 0);
ff_NameToInteger.put("宋体", 1);
ff_NameToInteger.put("Song", 1);
ff_NameToInteger.put("黑体", 2);
ff_NameToInteger.put("ST Heiti", 2);
ff_NameToInteger.put("楷体", 3);
ff_NameToInteger.put("ST Kaiti", 3);
ff_NameToInteger.put("仿宋", 4);
ff_NameToInteger.put("ST FangSong", 4);
ff_NameToInteger.put("新宋体", 5);
ff_NameToInteger.put("ST Song", 5);
ff_NameToInteger.put("华文新魏", 6);
ff_NameToInteger.put("华文行楷", 7);
ff_NameToInteger.put("华文隶书", 8);
ff_NameToInteger.put("Arial", 9);
ff_NameToInteger.put("Times New Roman", 10);
ff_NameToInteger.put("Tahoma", 11);
ff_NameToInteger.put("Verdana", 12);
}
private static void borderType() {
//"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all"
// | "border-outside" | "border-inside" | "border-horizontal" | "border-vertical" | "border-none"
ff_IntegerToName.put(0, "微软雅黑");
ff_IntegerToName.put(1, "宋体");
ff_IntegerToName.put(2, "黑体");
ff_IntegerToName.put(3, "楷体");
ff_IntegerToName.put(4, "仿宋");
ff_IntegerToName.put(5, "新宋体");
ff_IntegerToName.put(6, "华文新魏");
ff_IntegerToName.put(7, "华文行楷");
ff_IntegerToName.put(8, "华文隶书");
ff_IntegerToName.put(9, "Arial");
ff_IntegerToName.put(10, "Times New Roman");
ff_IntegerToName.put(11, "Tahoma");
ff_IntegerToName.put(12, "Verdana");
//0 微软雅黑、1 宋体Song、2 黑体ST Heiti、3 楷体ST Kaiti、 4仿宋ST FangSong、 5 新宋体ST Song
// 6 华文新魏、 7华文行楷、 8 华文隶书、 9 Arial、 10 Times New Roman 、11 Tahoma 、12 Verdana
ff_NameToInteger.put("微软雅黑", 0);
ff_NameToInteger.put("宋体", 1);
ff_NameToInteger.put("Song", 1);
ff_NameToInteger.put("黑体", 2);
ff_NameToInteger.put("ST Heiti", 2);
ff_NameToInteger.put("楷体", 3);
ff_NameToInteger.put("ST Kaiti", 3);
ff_NameToInteger.put("仿宋", 4);
ff_NameToInteger.put("ST FangSong", 4);
ff_NameToInteger.put("新宋体", 5);
ff_NameToInteger.put("ST Song", 5);
ff_NameToInteger.put("华文新魏", 6);
ff_NameToInteger.put("华文行楷", 7);
ff_NameToInteger.put("华文隶书", 8);
ff_NameToInteger.put("Arial", 9);
ff_NameToInteger.put("Times New Roman", 10);
ff_NameToInteger.put("Tahoma", 11);
ff_NameToInteger.put("Verdana", 12);
}
/**
*
*
* @param fa
* @return
*/
public static Integer getNumberFormatMap(String fa) {
if (number_format_map.containsKey(fa.toLowerCase())) {
return number_format_map.get(fa.toLowerCase());
}
return -1;
}
/**
* poi 0 1 2
*
* @param i
* @return
*/
public static VerticalAlignment getVerticalType(int i) {
if (0 == i) {
return VerticalAlignment.CENTER;
} else if (1 == i) {
return VerticalAlignment.TOP;
} else if (2 == i) {
return VerticalAlignment.BOTTOM;
}
//默认居中
return VerticalAlignment.CENTER;
}
/**
* poi 0 1 2
*
* @param i
* @return
*/
public static HorizontalAlignment getHorizontaltype(int i) {
if (2 == i) {
return HorizontalAlignment.RIGHT;
} else if (1 == i) {
return HorizontalAlignment.LEFT;
} else if (0 == i) {
return HorizontalAlignment.CENTER;
}
//默认右
return HorizontalAlignment.RIGHT;
}
/**
*
* 0=0,1=452=-453=4=905=-90
*
* @param i
* @return
*/
public static short getRotation(int i) {
short t = 0;
switch (i) {
case 1:
t = 45;
break;
case 2:
t = -45;
break;
case 3:
t = 255;
break;
case 4:
t = 90;
break;
case 5:
t = -90;
break;
default:
t = 0;
}
return t;
}
private static SimpleDateFormat df_DateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Date stringToDateTime(String date) {
if (date == null || date.length() == 0) {
return null;
}
try {
return df_DateTime.parse(date);
} catch (ParseException e) {
return null;
}
}
private static SimpleDateFormat df_Date = new SimpleDateFormat("yyyy-MM-dd");
public static Date stringToDate(String date) {
if (date == null || date.length() == 0) {
return null;
}
try {
return df_Date.parse(date);
} catch (ParseException e) {
return null;
}
}
public static Date toDate(String numberString) {
try {
Double _d = Double.parseDouble(numberString);
String _s = toDate(_d, "yyyy-MM-dd HH:mm:ss");
if (numberString.indexOf(".") > -1) {
return stringToDate(_s);
} else {
return stringToDateTime(_s);
}
} catch (Exception ex) {
System.out.println(ex.toString() + " " + numberString);
}
return null;
}
private static final int SECONDS_PER_MINUTE = 60;
private static final int MINUTES_PER_HOUR = 60;
private static final int HOURS_PER_DAY = 24;
private static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
/**
*
**/
private static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
/**
*
*
* @parma numberString
* @parma format "hh:mm:ss"
**/
public static String toDate(double numberString, String format) {
SimpleDateFormat sdFormat = new SimpleDateFormat(format);
int wholeDays = (int) Math.floor(numberString);
int millisecondsInday = (int) ((numberString - wholeDays) * DAY_MILLISECONDS + 0.5);
Calendar calendar = new GregorianCalendar();
setCalendar(calendar, wholeDays, millisecondsInday, false);
return sdFormat.format(calendar.getTime());
}
private static void setCalendar(Calendar calendar, int wholeDays,
int millisecondsInDay, boolean use1904windowing) {
int startYear = 1900;
int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
if (use1904windowing) {
startYear = 1904;
dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
} else if (wholeDays < 61) {
// Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
// If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
dayAdjust = 0;
}
calendar.set(startYear, 0, wholeDays + dayAdjust, 0, 0, 0);
calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
}
}

@ -0,0 +1,28 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.util;
public class MSExcelUtil {
public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256;
public static final short EXCEL_ROW_HEIGHT_FACTOR = 20;
public static final int UNIT_OFFSET_LENGTH = 7;
public static final int[] UNIT_OFFSET_MAP = new int[]{0, 36, 73, 109, 146, 182, 219};
public static short pixel2WidthUnits(int pxs) {
short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR * (pxs / UNIT_OFFSET_LENGTH));
widthUnits += UNIT_OFFSET_MAP[(pxs % UNIT_OFFSET_LENGTH)];
return widthUnits;
}
public static int widthUnits2Pixel(short widthUnits) {
int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR) * UNIT_OFFSET_LENGTH;
int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR;
pixels += Math.floor((float) offsetWidthUnits / ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH));
return pixels;
}
public static int heightUnits2Pixel(short heightUnits) {
int pixels = (heightUnits / EXCEL_ROW_HEIGHT_FACTOR);
int offsetWidthUnits = heightUnits % EXCEL_ROW_HEIGHT_FACTOR;
pixels += Math.floor((float) offsetWidthUnits / ((float) EXCEL_ROW_HEIGHT_FACTOR / UNIT_OFFSET_LENGTH));
return pixels;
}
}

@ -0,0 +1,860 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.*;
/**
* https://github.com/mengshukeji/LuckysheetServer
* sheet
*
* @author Administrator
*/
@Slf4j
public class XlsSheetUtil {
/**
* sheet
*
* @param wb
* @param sheetNum
* @param dbObject
*/
public static void exportSheet(Workbook wb, int sheetNum, JSONObject dbObject) {
Sheet sheet = wb.createSheet();
//设置sheet位置名称
if (dbObject.containsKey("name") && dbObject.get("name") != null) {
wb.setSheetName(sheetNum, dbObject.get("name").toString());
} else {
wb.setSheetName(sheetNum, "sheet" + sheetNum);
}
//是否隐藏
if (dbObject.containsKey("hide") && dbObject.get("hide").toString().equals("1")) {
wb.setSheetHidden(sheetNum, true);
}
//是否当前选中页
if (dbObject.containsKey("status") && dbObject.get("status").toString().equals("1")) {
sheet.setSelected(true);
}
//循环数据
if (dbObject.containsKey("celldata") && dbObject.get("celldata") != null) {
//取到所有单元格集合
List<JSONObject> cells_json = (List<JSONObject>) dbObject.get("celldata");
Map<Integer, List<JSONObject>> cellMap = cellGroup(cells_json);
//循环每一行
for (Integer r : cellMap.keySet()) {
Row row = sheet.createRow(r);
//循环每一列
for (JSONObject col : cellMap.get(r)) {
createCell(wb, sheet, row, col);
}
}
}
if (dbObject.containsKey("config") && dbObject.getJSONObject("config").containsKey("borderInfo")) {
JSONArray borderInfo = dbObject.getJSONObject("config").getJSONArray("borderInfo");
setCellBoard(wb, borderInfo, sheet);
}
setColumAndRow(dbObject, sheet);
}
/**
*
*
* @param row
* @param dbObject
*/
private static void createCell(Workbook wb, Sheet sheet, Row row, JSONObject dbObject) {
if (dbObject.containsKey("c")) {
Integer c = getStrToInt(dbObject.get("c"));
if (c != null) {
Cell cell = row.createCell(c);
//取单元格中的v_json
if (dbObject.containsKey("v")) {
//获取v对象
Object obj = dbObject.get("v");
if (obj == null) {
//没有内容
return;
}
//如果v对象直接是字符串
if (obj instanceof String) {
if (((String) obj).length() > 0) {
cell.setCellValue(obj.toString());
}
return;
}
//转换v为对象(v是一个对象)
JSONObject v_json = (JSONObject) obj;
//样式
CellStyle style = wb.createCellStyle();
cell.setCellStyle(style);
//合并单元格
//参数1起始行 参数2终止行 参数3起始列 参数4终止列
//CellRangeAddress region1 = new CellRangeAddress(rowNumber, rowNumber, (short) 0, (short) 11);
//mc 合并单元格
if (v_json.containsKey("mc")) {
//是合并的单元格
JSONObject mc = v_json.getJSONObject("mc");
if (mc.containsKey("rs") && mc.containsKey("cs")) {
//合并的第一个单元格
if (mc.containsKey("r") && mc.containsKey("c")) {
Integer _rs = getIntByDBObject(mc, "rs") - 1;
Integer _cs = getIntByDBObject(mc, "cs") - 1;
Integer _r = getIntByDBObject(mc, "r");
Integer _c = getIntByDBObject(mc, "c");
CellRangeAddress region = new CellRangeAddress(_r.shortValue(), (_r.shortValue() + _rs.shortValue()), _c.shortValue(), (_c.shortValue() + _cs.shortValue()));
sheet.addMergedRegion(region);
}
} else {
//不是合并的第一个单元格
return;
}
}
//取v值 (在数据类型中处理)
//ct 单元格值格式 (fa,t)
setFormatByCt(wb, cell, style, v_json);
//font设置
setCellStyleFont(wb, style, v_json);
//bg 背景颜色
if (v_json.containsKey("bg")) {
String _v = getByDBObject(v_json, "bg");
Short _color = ColorUtil.getColorByStr(_v);
if (_color != null) {
style.setFillForegroundColor(_color);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
}
}
//vt 垂直对齐 垂直对齐方式0=居中1=上2=下)
if (v_json.containsKey("vt")) {
Integer _v = getIntByDBObject(v_json, "vt");
if (_v != null && _v >= 0 && _v <= 2) {
style.setVerticalAlignment(ConstantUtil.getVerticalType(_v));
}
} else {
//默认设置居中
style.setVerticalAlignment(ConstantUtil.getVerticalType(0));
}
//ht 水平对齐 水平对齐方式0=居中1=左对齐2=右对齐)
if (v_json.containsKey("ht")) {
Integer _v = getIntByDBObject(v_json, "ht");
if (_v != null && _v >= 0 && _v <= 2) {
style.setAlignment(ConstantUtil.getHorizontaltype(_v));
}
} else {
//默认设置左对齐
style.setAlignment(ConstantUtil.getHorizontaltype(1));
}
//tr 文字旋转 文字旋转角度0=0,1=452=-453=竖排文字4=905=-90
if (v_json.containsKey("tr")) {
Integer _v = getIntByDBObject(v_json, "tr");
if (_v != null) {
style.setRotation(ConstantUtil.getRotation(_v));
}
}
//tb 文本换行 0 截断、1溢出、2 自动换行
// 2setTextWrapped 0和1IsTextWrapped = true
if (v_json.containsKey("tb")) {
Integer _v = getIntByDBObject(v_json, "tb");
if (_v != null) {
if (_v >= 0 && _v <= 1) {
style.setWrapText(false);
} else {
style.setWrapText(true);
}
}
}
//f 公式
if (v_json.containsKey("f")) {
String _v = getByDBObject(v_json, "f");
if (_v.length() > 0) {
try {
if (_v.startsWith("=")) {
cell.setCellFormula(_v.substring(1));
} else {
cell.setCellFormula(_v);
}
} catch (Exception ex) {
log.error("公式 {};Error:{}", _v, ex.toString());
}
}
}
}
}
}
}
/**
*
*
* @param borderInfo
* @param sheet
*/
private static void setCellBoard(Workbook wb, JSONArray borderInfo, Sheet sheet) {
//一定要通过 cell.getCellStyle() 不然的话之前设置的样式会丢失
//设置边框
for (int i = 0; i < borderInfo.size(); i++) {
JSONObject borderInfoObject = (JSONObject) borderInfo.get(i);
if (borderInfoObject.get("rangeType").equals("cell")) {//单个单元格
JSONObject borderValueObject = borderInfoObject.getJSONObject("value");
JSONObject l = borderValueObject.getJSONObject("l");
JSONObject r = borderValueObject.getJSONObject("r");
JSONObject t = borderValueObject.getJSONObject("t");
JSONObject b = borderValueObject.getJSONObject("b");
int row_ = borderValueObject.getInteger("row_index");
int col_ = borderValueObject.getInteger("col_index");
Row row = sheet.getRow(row_);
if (null == row) {
row = sheet.createRow(row_);
}
Cell cell = row.getCell(col_);
CellStyle style;
if (null == cell) {
style = wb.createCellStyle();
cell = row.createCell(col_);
cell.setCellStyle(style);
} else {
style = cell.getCellStyle();
}
if (l != null) {
style.setBorderLeft(BorderStyle.valueOf(l.getShort("style"))); //左边框
Short color = ColorUtil.getColorByStr(l.getString("color"));
if (null != color) {
style.setLeftBorderColor(color);//左边框颜色
}
}
if (r != null) {
style.setBorderRight(BorderStyle.valueOf(r.getShort("style"))); //右边框
Short color = ColorUtil.getColorByStr(r.getString("color"));
if (null != color) {
style.setRightBorderColor(color);//右边框颜色
}
}
if (t != null) {
style.setBorderTop(BorderStyle.valueOf(t.getShort("style"))); //顶部边框
Short _vcolor = ColorUtil.getColorByStr(t.getString("color"));
if (null != _vcolor) {
style.setTopBorderColor(_vcolor);//顶部边框颜色
}
}
if (b != null) {
style.setBorderBottom(BorderStyle.valueOf(b.getShort("style"))); //底部边框
Short _vcolor = ColorUtil.getColorByStr(b.getString("color"));
if (_vcolor != null) {
//底部边框颜色
style.setBottomBorderColor(_vcolor);
}
}
} else if (borderInfoObject.get("rangeType").equals("range")) {
//选区
Short style_ = borderInfoObject.getShort("style");
String borderType = borderInfoObject.getString("borderType");
Short color = ColorUtil.getColorByStr(borderInfoObject.getString("color"));
JSONObject rangObject = (JSONObject) ((JSONArray) (borderInfoObject.get("range"))).get(0);
JSONArray rowList = rangObject.getJSONArray("row");
JSONArray columnList = rangObject.getJSONArray("column");
for (int row_ = rowList.getInteger(0); row_ < rowList.getInteger(rowList.size() - 1) + 1; row_++) {
for (int col_ = columnList.getInteger(0); col_ < columnList.getInteger(columnList.size() - 1) + 1; col_++) {
Row row = sheet.getRow(row_);
if (null == row) {
row = sheet.createRow(row_);
}
Cell cell = row.getCell(col_);
CellStyle style;
if (null == cell) {
style = wb.createCellStyle();
cell = row.createCell(col_);
cell.setCellStyle(style);
} else {
style = cell.getCellStyle();
}
//"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-horizontal" | "border-vertical"
// "border-outside" | "border-inside" | | "border-none"
if ("border-left".equals(borderType) || "border-all".equals(borderType)) {
style.setBorderLeft(BorderStyle.valueOf(style_)); //左边框
style.setLeftBorderColor(color);//左边框颜色
}
if ("border-right".equals(borderType) || "border-all".equals(borderType)) {
style.setBorderRight(BorderStyle.valueOf(style_)); //右边框
style.setRightBorderColor(color);//右边框颜色
}
if ("border-top".equals(borderType) || "border-all".equals(borderType)) {
style.setBorderTop(BorderStyle.valueOf(style_)); //顶部边框
style.setTopBorderColor(color);//顶部边框颜色
}
if ("border-bottom".equals(borderType) || "border-all".equals(borderType)) {
style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框
style.setBottomBorderColor(color);//底部边框颜色 }
}
if ("border-outside".equals(borderType)) {
//外圈边框
if (row_ == rowList.getInteger(0)) {
style.setBorderTop(BorderStyle.valueOf(style_)); //顶部边框
style.setTopBorderColor(color);//顶部边框颜色
}
if (col_ == columnList.getInteger(0)) {
style.setBorderLeft(BorderStyle.valueOf(style_)); //左边框
style.setLeftBorderColor(color);//左边框颜色
}
if (row_ == rowList.getInteger(rowList.size() - 1)) {
style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框
style.setBottomBorderColor(color);//底部边框颜色 }
}
if (col_ == columnList.getInteger(columnList.size() - 1)) {
style.setBorderRight(BorderStyle.valueOf(style_)); //右边框
style.setRightBorderColor(color);//右边框颜色
}
}
if ("border-horizontal".equals(borderType) || "border-inside".equals(borderType)) {
//内部横线
if (row_ >= rowList.getInteger(0)
&& row_ < rowList.getInteger(rowList.size() - 1)
&& col_ >= columnList.getInteger(0)
&& col_ <= columnList.getInteger(columnList.size() - 1)) {
style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框
style.setBottomBorderColor(color);//底部边框颜色 }
}
}
if ("border-vertical".equals(borderType) || "border-inside".equals(borderType)) {
//内部竖线
if (row_ >= rowList.getInteger(0)
&& row_ <= rowList.getInteger(rowList.size() - 1)
&& col_ >= columnList.getInteger(0)
&& col_ < columnList.getInteger(columnList.size() - 1)) {
style.setBorderRight(BorderStyle.valueOf(style_)); //右边框
style.setRightBorderColor(color);//右边框颜色
}
}
if ("border-none".equals(borderType)) {
style.setBorderLeft(BorderStyle.NONE); //左边框
style.setBorderRight(BorderStyle.NONE); //左边框
style.setBorderTop(BorderStyle.NONE); //左边框
style.setBorderBottom(BorderStyle.NONE); //左边框
}
}
}
}
}
}
/**
*
*
* @param dbObject
* @param sheet
*/
private static void setColumAndRow(JSONObject dbObject, Sheet sheet) {
if (dbObject.containsKey("config")) {
JSONObject config = dbObject.getJSONObject("config");
if (config.containsKey("columnlen")) {
JSONObject columnlen = config.getJSONObject("columnlen");
if (columnlen != null) {
for (String k : columnlen.keySet()) {
Integer _i = getStrToInt(k);
Integer _v = getStrToInt(columnlen.get(k).toString());
if (_i != null && _v != null) {
// sheet.setColumnWidth(_i, MSExcelUtil.heightUnits2Pixel(_v.shortValue()));
// TODO 乘以32有待商榷
sheet.setColumnWidth(_i, _v * 32);
}
}
}
}
if (config.containsKey("rowlen")) {
JSONObject rowlen = config.getJSONObject("rowlen");
if (rowlen != null) {
for (String k : rowlen.keySet()) {
Integer _i = getStrToInt(k);
Integer _v = getStrToInt(rowlen.get(k).toString());
if (_i != null && _v != null) {
Row row = sheet.getRow(_i);
if (row != null) {
// row.setHeightInPoints(MSExcelUtil.pixel2WidthUnits(_v.shortValue()));
row.setHeightInPoints(_v.shortValue());
}
}
}
}
}
}
}
/**
*
*
* @param wb
* @param style
* @param dbObject
*/
private static void setCellStyleFont(Workbook wb, CellStyle style, JSONObject dbObject) {
Font font = wb.createFont();
style.setFont(font);
//ff 字体
if (dbObject.containsKey("ff")) {
if (dbObject.get("ff") instanceof Integer) {
Integer _v = getIntByDBObject(dbObject, "ff");
if (_v != null && ConstantUtil.ff_IntegerToName.containsKey(_v)) {
font.setFontName(ConstantUtil.ff_IntegerToName.get(_v));
}
} else if (dbObject.get("ff") instanceof String) {
font.setFontName(getByDBObject(dbObject, "ff"));
}
}
//fc 字体颜色
if (dbObject.containsKey("fc")) {
String _v = getByDBObject(dbObject, "fc");
Short _color = ColorUtil.getColorByStr(_v);
if (_color != null) {
font.setColor(_color);
}
}
//bl 粗体
if (dbObject.containsKey("bl")) {
Integer _v = getIntByDBObject(dbObject, "bl");
if (_v != null) {
if (_v.equals(1)) {
//是否粗体显示
font.setBold(true);
} else {
font.setBold(false);
}
}
}
//it 斜体
if (dbObject.containsKey("it")) {
Integer _v = getIntByDBObject(dbObject, "it");
if (_v != null) {
if (_v.equals(1)) {
font.setItalic(true);
} else {
font.setItalic(false);
}
}
}
//fs 字体大小
if (dbObject.containsKey("fs")) {
Integer _v = getStrToInt(getObjectByDBObject(dbObject, "fs"));
if (_v != null) {
font.setFontHeightInPoints(_v.shortValue());
}
}
//cl 删除线 (导入没有) 0 常规 、 1 删除线
if (dbObject.containsKey("cl")) {
Integer _v = getIntByDBObject(dbObject, "cl");
if (_v != null) {
if (_v.equals(1)) {
font.setStrikeout(true);
}
}
}
//ul 下划线
if (dbObject.containsKey("ul")) {
Integer _v = getIntByDBObject(dbObject, "ul");
if (_v != null) {
if (_v.equals(1)) {
font.setUnderline(Font.U_SINGLE);
} else {
font.setUnderline(Font.U_NONE);
}
}
}
}
/**
* cell
*
* @param style
* @param dbObject json
* @param bs
* @param bc
*/
private static void setBorderStyle(CellStyle style, JSONObject dbObject, String bs, String bc) {
//bs 边框样式
if (dbObject.containsKey(bs)) {
Integer _v = getStrToInt(getByDBObject(dbObject, bs));
if (_v != null) {
//边框没有,不作改变
if (bs.equals("bs") || bs.equals("bs_t")) {
style.setBorderTop(BorderStyle.valueOf(_v.shortValue()));
}
if (bs.equals("bs") || bs.equals("bs_b")) {
style.setBorderBottom(BorderStyle.valueOf(_v.shortValue()));
}
if (bs.equals("bs") || bs.equals("bs_l")) {
style.setBorderLeft(BorderStyle.valueOf(_v.shortValue()));
}
if (bs.equals("bs") || bs.equals("bs_r")) {
style.setBorderRight(BorderStyle.valueOf(_v.shortValue()));
}
//bc 边框颜色
String _vcolor = getByDBObject(dbObject, bc);
if (_vcolor != null) {
Short _color = ColorUtil.getColorByStr(_vcolor);
if (_color != null) {
if (bc.equals("bc") || bc.equals("bc_t")) {
style.setTopBorderColor(_color);
}
if (bc.equals("bc") || bc.equals("bc_b")) {
style.setBottomBorderColor(_color);
}
if (bc.equals("bc") || bc.equals("bc_l")) {
style.setLeftBorderColor(_color);
}
if (bc.equals("bc") || bc.equals("bc_r")) {
style.setRightBorderColor(_color);
}
}
}
}
}
}
/**
* ct (fa,t)
*
* @param cell
* @param style
* @param dbObject
*/
private static void setFormatByCt(Workbook wb, Cell cell, CellStyle style, JSONObject dbObject) {
if (!dbObject.containsKey("v") && dbObject.containsKey("ct")) {
/*
{
"celldata": [{
"c": 0,
"r": 8,
"v": {
"ct": {
"s": [{
"v": "sdsdgdf\r\ndfgdfg\r\ndsfgdfgdf\r\ndsfgdfg"
}],
"t": "inlineStr",
"fa": "General"
}
}
}]
}
*/
JSONObject ct = dbObject.getJSONObject("ct");
if (ct.containsKey("s")) {
Object s = ct.get("s");
if (s instanceof List && ((List) s).size() > 0) {
JSONObject _s1 = (JSONObject) ((List) s).get(0);
if (_s1.containsKey("v") && _s1.get("v") instanceof String) {
dbObject.put("v", _s1.get("v"));
style.setWrapText(true);
}
}
}
}
//String v = ""; //初始化
if (dbObject.containsKey("v")) {
//v = v_json.get("v").toString();
//取到v后存到poi单元格对象
//设置该单元格值
//cell.setValue(v);
//String v=getByDBObject(v_json,"v");
//cell.setValue(v);
Object obj = getObjectByDBObject(dbObject, "v");
if (obj instanceof Number) {
cell.setCellValue(Double.valueOf(obj.toString()));
} else if (obj instanceof Double) {
cell.setCellValue((Double) obj);
} else if (obj instanceof Date) {
cell.setCellValue((Date) obj);
} else if (obj instanceof Calendar) {
cell.setCellValue((Calendar) obj);
} else if (obj instanceof RichTextString) {
cell.setCellValue((RichTextString) obj);
} else if (obj instanceof String) {
cell.setCellValue((String) obj);
} else {
cell.setCellValue(obj.toString());
}
}
if (dbObject.containsKey("ct")) {
JSONObject ct = dbObject.getJSONObject("ct");
if (ct.containsKey("fa") && ct.containsKey("t")) {
//t 0=bool1=datetime2=error3=null4=numeric5=string6=unknown
String fa = getByDBObject(ct, "fa"); //单元格格式format定义串
String t = getByDBObject(ct, "t"); //单元格格式type类型
Integer _i = ConstantUtil.getNumberFormatMap(fa);
switch (t) {
case "s": {
//字符串
if (_i >= 0) {
style.setDataFormat(_i.shortValue());
} else {
style.setDataFormat((short) 0);
}
cell.setCellType(CellType.STRING);
break;
}
case "d": {
//日期
Date _d = null;
String v = getByDBObject(dbObject, "m");
if (v.length() == 0) {
v = getByDBObject(dbObject, "v");
}
if (v.length() > 0) {
if (v.indexOf("-") > -1) {
if (v.indexOf(":") > -1) {
_d = ConstantUtil.stringToDateTime(v);
} else {
_d = ConstantUtil.stringToDate(v);
}
} else {
_d = ConstantUtil.toDate(v);
}
}
if (_d != null) {
//能转换为日期
cell.setCellValue(_d);
DataFormat format = wb.createDataFormat();
style.setDataFormat(format.getFormat(fa));
} else {
//不能转换为日期
if (_i >= 0) {
style.setDataFormat(_i.shortValue());
} else {
style.setDataFormat((short) 0);
}
}
break;
}
case "b": {
//逻辑
cell.setCellType(CellType.BOOLEAN);
if (_i >= 0) {
style.setDataFormat(_i.shortValue());
} else {
DataFormat format = wb.createDataFormat();
style.setDataFormat(format.getFormat(fa));
}
break;
}
case "n": {
//数值
// cell.setCellType(CellType.NUMERIC);
//数字转字符串
cell.setCellType(CellType.STRING);
if (_i >= 0) {
style.setDataFormat(_i.shortValue());
} else {
DataFormat format = wb.createDataFormat();
style.setDataFormat(format.getFormat(fa));
}
break;
}
case "u":
case "g": {
//general 自动类型
//cell.setCellType(CellType._NONE);
if (_i >= 0) {
style.setDataFormat(_i.shortValue());
} else {
DataFormat format = wb.createDataFormat();
style.setDataFormat(format.getFormat(fa));
}
break;
}
case "e": {
//错误
cell.setCellType(CellType.ERROR);
if (_i >= 0) {
style.setDataFormat(_i.shortValue());
} else {
DataFormat format = wb.createDataFormat();
style.setDataFormat(format.getFormat(fa));
}
break;
}
}
}
}
}
/**
*
*
* @param cells
* @return
*/
private static Map<Integer, List<JSONObject>> cellGroup(List<JSONObject> cells) {
Map<Integer, List<JSONObject>> cellMap = new HashMap<>(100);
for (JSONObject dbObject : cells) {
//行号
if (dbObject.containsKey("r")) {
Integer r = getStrToInt(dbObject.get("r"));
if (r != null) {
if (cellMap.containsKey(r)) {
cellMap.get(r).add(dbObject);
} else {
List<JSONObject> list = new ArrayList<>(10);
list.add(dbObject);
cellMap.put(r, list);
}
}
}
}
return cellMap;
}
/**
* k
*
* @param b
* @param k
* @return
*/
public static String getByDBObject(JSONObject b, String k) {
if (b.containsKey(k)) {
if (b.get(k) != null && b.get(k) instanceof String) {
return b.getString(k);
}
}
return null;
}
/**
* k
*
* @param b
* @param k
* @return
*/
public static Object getObjectByDBObject(JSONObject b, String k) {
if (b.containsKey(k)) {
if (b.get(k) != null) {
return b.get(k);
}
}
return "";
}
/**
* / null
*
* @param b
* @param k
* @return
*/
public static Integer getIntByDBObject(JSONObject b, String k) {
if (b.containsKey(k)) {
if (b.get(k) != null) {
try {
String _s = b.getString(k).replace("px", "");
Double _d = Double.parseDouble(_s);
return _d.intValue();
} catch (Exception ex) {
log.error(ex.getMessage());
return null;
}
}
}
return null;
}
/**
* int
*
* @param str
* @return
*/
private static Integer getStrToInt(Object str) {
try {
if (str != null) {
return Integer.parseInt(str.toString());
}
return null;
} catch (Exception ex) {
log.error("String:{};Error:{}", str, ex.getMessage());
return null;
}
}
private static Short getStrToShort(Object str) {
try {
if (str != null) {
return Short.parseShort(str.toString());
}
return null;
} catch (Exception ex) {
log.error("String:{};Error:{}", str, ex.getMessage());
return null;
}
}
}

@ -0,0 +1,453 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.anjiplus.template.gaea.business.enums.ExcelCenterStyleEnum;
import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.GridRecordDataModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
/**
* https://github.com/mengshukeji/LuckysheetServer
* 使poixls
*
* @author Administrator
*/
public class XlsUtil {
private final static String MODEL = "{\"c\":0,\"r\":0,\"v\":{\"m\":\"模板\",\"v\":\"模板\",\"bl\":1,\"ct\":{\"t\":\"g\",\"fa\":\"General\"}}}";
private final static String BORDER_MODEL = "{\"rangeType\":\"cell\",\"value\":{\"b\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"r\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"col_index\":5,\"t\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"row_index\":7,\"l\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1}}}";
/**
*
*/
private static final int DEFAULT_ROW_INDEX = 84;
/**
*
*/
private static final int DEFAULT_COLUMN_INDEX = 64;
/**
*
*
* @param outputStream
* @param isXlsx xlsx
* @param dbObjectList
*/
public static void exportXlsFile(OutputStream outputStream, Boolean isXlsx, List<JSONObject> dbObjectList) throws IOException {
Workbook wb = null;
if (isXlsx) {
wb = new XSSFWorkbook();
} else {
wb = new HSSFWorkbook();
}
if (dbObjectList != null && dbObjectList.size() > 0) {
for (int x = 0; x < dbObjectList.size(); x++) {
XlsSheetUtil.exportSheet(wb, x, dbObjectList.get(x));
}
}
wb.write(outputStream);
}
/**
* @param workbook 簿
* @return Map
* @description excel
* @author zhouhang
* @date 2021/4/20
*/
public static List<GridRecordDataModel> readExcel(Workbook workbook) {
List<GridRecordDataModel> list = new ArrayList<>();
Iterator<Sheet> sheetIterator = workbook.sheetIterator();
int sheetIndex = 0;
while (sheetIterator.hasNext()) {
Sheet sheet = sheetIterator.next();
//生成默认MODEL
GridRecordDataModel model;
if (Objects.equals(0, sheetIndex)) {
model = strToModel("", (sheetIndex + 1) + "", 1, sheetIndex);
} else {
model = strToModel("", (sheetIndex + 1) + "", 0, sheetIndex);
}
sheetIndex++;
//读取sheet页
readSheet(sheet, model, workbook);
//设置sheet页名称
model.getJson_data().put("name", sheet.getSheetName());
list.add(model);
}
return list;
}
public static GridRecordDataModel strToModel(String list_id, String index, int status, int order) {
String strSheet = "{\"row\":84,\"name\":\"reSheetName\",\"chart\":[],\"color\":\"\",\"index\":\"reIndex\",\"order\":reOrder,\"column\":60,\"config\":{},\"status\":reStatus,\"celldata\":[],\"ch_width\":4748,\"rowsplit\":[],\"rh_height\":1790,\"scrollTop\":0,\"scrollLeft\":0,\"visibledatarow\":[],\"visibledatacolumn\":[],\"jfgird_select_save\":[],\"jfgrid_selection_range\":{}}";
strSheet = strSheet.replace("reSheetName", "Sheet" + index).replace("reIndex", index).replace("reOrder", order + "").replace("reStatus", status + "");
JSONObject bson = JSONObject.parseObject(strSheet);
GridRecordDataModel model = new GridRecordDataModel();
model.setBlock_id("fblock");
model.setRow_col("5_5");
model.setIndex(index);
model.setIs_delete(0);
model.setJson_data(bson);
model.setStatus(status);
model.setOrder(order);
model.setList_id(list_id);
return model;
}
/**
* @param sheet sheet
* @param model
* @param workbook excel
* @description sheet
* @author zhouhang
* @date 2021/4/20
*/
private static void readSheet(Sheet sheet, GridRecordDataModel model, Workbook workbook) {
//excel数据集合
List<JSONObject> dataList = new ArrayList<>();
model.setDataList(dataList);
//获取行迭代器
Iterator<Row> rowIterator = sheet.rowIterator();
//获取合并单元格信息
Map<String, String> rangeMap = getRangeMap(sheet);
//记录最大列
int maxCellNumber = 0;
int maxRowNumber = 0;
//列宽
JSONObject columnLenObj = new JSONObject();
//行高
JSONObject rowLenObj = new JSONObject();
//读取文档
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
int rowLen = ((int) row.getHeight()) / 20;
if (rowLen == 0) {
rowLen = 30;
}
rowLenObj.put(row.getRowNum() + "", rowLen);
Iterator<Cell> cellIterator = row.cellIterator();
maxRowNumber = row.getRowNum();
while (cellIterator.hasNext()) {
//"{\"c\":0,\"r\":0,\"v\":{\"m\":\"模板\",\"v\":\"模板\",\"bl\":1,\"ct\":{\"t\":\"g\",\"fa\":\"General\"}}}";
JSONObject dataModel = JSONObject.parseObject(MODEL);
//初始化默认单元格内容
Cell cell = cellIterator.next();
int columnLen = sheet.getColumnWidth(cell.getColumnIndex()) / 25;
if (columnLen == 0) {
columnLen = 73;
}
columnLenObj.put(cell.getColumnIndex() + "", columnLen);
//修改最大列
maxCellNumber = Math.max(cell.getColumnIndex(), maxCellNumber);
//设置行列
dataModel.put("c", cell.getColumnIndex());
dataModel.put("r", row.getRowNum());
//获取单元格内容
switch (cell.getCellType()) {
case STRING:
dataModel.getJSONObject("v").put("m", cell.getStringCellValue());
dataModel.getJSONObject("v").put("v", cell.getStringCellValue());
break;
case NUMERIC:
dataModel.getJSONObject("v").put("m", cell.getNumericCellValue());
dataModel.getJSONObject("v").put("v", cell.getNumericCellValue());
break;
case BLANK:
dataModel.getJSONObject("v").put("m", "");
dataModel.getJSONObject("v").put("v", "");
break;
case BOOLEAN:
dataModel.getJSONObject("v").put("m", cell.getBooleanCellValue());
dataModel.getJSONObject("v").put("v", cell.getBooleanCellValue());
break;
case ERROR:
dataModel.getJSONObject("v").put("m", cell.getErrorCellValue());
dataModel.getJSONObject("v").put("v", cell.getErrorCellValue());
break;
default:
dataModel.getJSONObject("v").put("m", "");
dataModel.getJSONObject("v").put("v", "");
}
//设置单元格合并标记
dealWithCellMarge(rangeMap, row, cell, dataModel);
//设置单元格样式、合并单元格信息
dealWithExcelStyle(model, dataModel, cell, sheet, workbook);
dataList.add(dataModel);
}
}
//设置最大行、列
model.getJson_data().put("column", Math.max(maxCellNumber, DEFAULT_COLUMN_INDEX));
model.getJson_data().put("row", Math.max(maxRowNumber, DEFAULT_ROW_INDEX));
//设置行高、列宽
model.getJson_data().getJSONObject("config").put("columnlen", columnLenObj);
model.getJson_data().getJSONObject("config").put("rowlen", rowLenObj);
}
/**
* @param sheet sheet
* @return Map<String, String>
* @description MAP
* @author zhouhang
* @date 2021/4/21
*/
@NotNull
private static Map<String, String> getRangeMap(Sheet sheet) {
List<CellRangeAddress> rangeAddressList = sheet.getMergedRegions();
Map<String, String> rangeMap = new HashMap<>(rangeAddressList.size() * 5);
for (CellRangeAddress cellAddresses : rangeAddressList) {
for (int i = cellAddresses.getFirstRow(); i <= cellAddresses.getLastRow(); i++) {
for (int j = cellAddresses.getFirstColumn(); j <= cellAddresses.getLastColumn(); j++) {
if (i == cellAddresses.getFirstRow() && j == cellAddresses.getFirstColumn()) {
//单元格合并初始值特殊标记
rangeMap.put(i + "_" + j, cellAddresses.getFirstRow() + "_" + cellAddresses.getFirstColumn() + "_" + cellAddresses.getLastRow() + "_" + cellAddresses.getLastColumn());
} else {
rangeMap.put(i + "_" + j, cellAddresses.getFirstRow() + "_" + cellAddresses.getFirstColumn());
}
}
}
}
return rangeMap;
}
/**
* @param rangeMap
* @param row
* @param cell
* @param dataModel
* @description
* @author zhouhang
* @date 2021/4/21
*/
private static void dealWithCellMarge(Map<String, String> rangeMap, Row row, Cell cell, JSONObject dataModel) {
if (rangeMap.containsKey(row.getRowNum() + "_" + cell.getColumnIndex())) {
String margeValue = rangeMap.get(row.getRowNum() + "_" + cell.getColumnIndex());
JSONObject mcData = new JSONObject();
String[] s = margeValue.split("_");
mcData.put("r", Integer.parseInt(s[0]));
mcData.put("c", Integer.parseInt(s[1]));
if (s.length == 4) {
mcData.put("rs", Integer.parseInt(s[2]) - Integer.parseInt(s[0]) + 1);
mcData.put("cs", Integer.parseInt(s[3]) - Integer.parseInt(s[1]) + 1);
}
dataModel.getJSONObject("v").put("mc", mcData);
}
}
/**
* @param model sheet
* @param dataModel
* @param cell
* @param sheet sheet
* @param workbook excel
* @description
* @author zhouhang
* @date 2021/4/21
*/
private static void dealWithExcelStyle(GridRecordDataModel model, JSONObject dataModel, Cell cell, Sheet sheet, Workbook workbook) {
//设置单元格合并信息
dealWithExcelMerge(model, sheet);
//设置字体样式
setFontStyle(dataModel, workbook, cell);
//设置单元格样式
dealWithBorderStyle(model, cell, workbook);
}
/**
* @param model 线
* @param cell cell
* @param workbook workbook
* @description
* @author zhouhang
* @date 2021/4/22
*/
private static void dealWithBorderStyle(GridRecordDataModel model, Cell cell, Workbook workbook) {
CellStyle cellStyle = cell.getCellStyle();
//判断是否存在边框
if (cellStyle.getBorderTop().getCode() > 0 || cellStyle.getBorderBottom().getCode() > 0 ||
cellStyle.getBorderLeft().getCode() > 0 || cellStyle.getBorderRight().getCode() > 0) {
JSONObject border = JSONObject.parseObject(BORDER_MODEL);
border.getJSONObject("value").put("row_index", cell.getRowIndex());
border.getJSONObject("value").put("col_index", cell.getColumnIndex());
//xlsx
if (cellStyle instanceof XSSFCellStyle) {
XSSFCellStyle xssfCellStyle = (XSSFCellStyle) cellStyle;
if (Objects.equals((short) 0, cellStyle.getBorderTop().getCode())) {
border.getJSONObject("value").remove("t");
} else {
border.getJSONObject("value").getJSONObject("t").put("color", dealWithRbg(xssfCellStyle.getTopBorderXSSFColor().getRGB()));
}
if (Objects.equals((short) 0, cellStyle.getBorderRight().getCode())) {
border.getJSONObject("value").remove("r");
} else {
border.getJSONObject("value").getJSONObject("r").put("color", dealWithRbg(xssfCellStyle.getRightBorderXSSFColor().getRGB()));
}
if (Objects.equals((short) 0, cellStyle.getBorderLeft().getCode())) {
border.getJSONObject("value").remove("l");
} else {
border.getJSONObject("value").getJSONObject("l").put("color", dealWithRbg(xssfCellStyle.getLeftBorderXSSFColor().getRGB()));
}
if (Objects.equals((short) 0, cellStyle.getBorderBottom().getCode())) {
border.getJSONObject("value").remove("b");
} else {
border.getJSONObject("value").getJSONObject("b").put("color", dealWithRbg(xssfCellStyle.getBottomBorderXSSFColor().getRGB()));
}
} else if (cellStyle instanceof HSSFCellStyle) {
//xls
HSSFWorkbook hssfWorkbook = (HSSFWorkbook) workbook;
HSSFCellStyle hssfCellStyle = (HSSFCellStyle) cellStyle;
if (Objects.equals((short) 0, cellStyle.getBorderTop().getCode())) {
border.getJSONObject("value").remove("t");
} else {
HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getTopBorderColor());
border.getJSONObject("value").getJSONObject("t").put("color", dealWithRbgShort(color.getTriplet()));
}
if (Objects.equals((short) 0, cellStyle.getBorderRight().getCode())) {
border.getJSONObject("value").remove("r");
} else {
HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getRightBorderColor());
border.getJSONObject("value").getJSONObject("r").put("color", dealWithRbgShort(color.getTriplet()));
}
if (Objects.equals((short) 0, cellStyle.getBorderLeft().getCode())) {
border.getJSONObject("value").remove("l");
} else {
HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getLeftBorderColor());
border.getJSONObject("value").getJSONObject("l").put("color", dealWithRbgShort(color.getTriplet()));
}
if (Objects.equals((short) 0, cellStyle.getBorderBottom().getCode())) {
border.getJSONObject("value").remove("b");
} else {
HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getBottomBorderColor());
border.getJSONObject("value").getJSONObject("b").put("color", dealWithRbgShort(color.getTriplet()));
}
}
JSONArray borderInfo = model.getJson_data().getJSONObject("config").getJSONArray("borderInfo");
if (Objects.isNull(borderInfo)) {
borderInfo = new JSONArray();
model.getJson_data().getJSONObject("config").put("borderInfo", borderInfo);
}
borderInfo.add(border);
}
}
/**
* @param rgb RBG short
* @return rbg(0, 0, 0)
* @description RBG rbg(0,0,0)
* @author zhouhang
* @date 2021/4/26
*/
private static String dealWithRbgShort(short[] rgb) {
return getRbg(Objects.nonNull(rgb), rgb[0], rgb[1], rgb[2]);
}
@NotNull
private static String getRbg(boolean b2, short r, short b, short g) {
if (b2) {
return "rgb(" + (r & 0xFF) + ", " + (b & 0xFF) + ", " + (g & 0xFF) + ")";
} else {
return "rgb(0, 0, 0)";
}
}
/**
* @param rgb RBG byte
* @return rbg(0, 0, 0)
* @description RBG rbg(0,0,0)
* @author zhouhang
* @date 2021/4/26
*/
private static String dealWithRbg(byte[] rgb) {
if (Objects.isNull(rgb)) {
return "rgb(0, 0, 0)";
}
short[] shorts = new short[]{rgb[0], rgb[1], rgb[2]};
return getRbg(true, shorts[0], shorts[1], shorts[2]);
}
/**
* @param dataModel
* @param workbook workbook
* @param cell cell
* @description s
* @author zhouhang
* @date 2021/4/21
*/
private static void setFontStyle(JSONObject dataModel, Workbook workbook, Cell cell) {
CellStyle cellStyle = cell.getCellStyle();
Font font = workbook.getFontAt(cellStyle.getFontIndexAsInt());
JSONObject v = dataModel.getJSONObject("v");
//ht 水平对齐 水平对齐方式0=居中1=左对齐2=右对齐) excel:左1 中2 右3 未设置0
v.put("ht", ExcelCenterStyleEnum.getExcelCenterStyleByExcelCenterCode(cellStyle.getAlignment().getCode()).getOnlineExcelCode());
//bl 字体加粗设置
v.put("bl", font.getBold() ? 1 : 0);
//lt 斜体
v.put("it", font.getItalic() ? 1 : 0);
//ff 字体
v.put("ff", font.getFontName());
//fc 字体颜色
if (font instanceof HSSFFont) {
HSSFFont hssfFont = (HSSFFont) font;
HSSFColor hssfColor = hssfFont.getHSSFColor((HSSFWorkbook) workbook);
if (Objects.nonNull(hssfColor)) {
v.put("fc", ColorUtil.convertRGBToHex(hssfColor.getTriplet()[0], hssfColor.getTriplet()[1], hssfColor.getTriplet()[2]));
}
} else {
XSSFFont xssfFont = (XSSFFont) font;
XSSFColor xssfColor = xssfFont.getXSSFColor();
if (Objects.nonNull(xssfColor)) {
v.put("fc", "#" + xssfColor.getARGBHex().substring(2));
}
}
//fs 字体大小
v.put("fs", font.getFontHeightInPoints());
//cl 删除线
v.put("cl", font.getStrikeout() ? 1 : 0);
//ul 下划线
v.put("un", font.getUnderline());
//背景色
String fillColorHex = ColorUtil.getFillColorHex(cell);
if (Objects.nonNull(fillColorHex)) {
v.put("bg", fillColorHex);
}
}
/**
* @param model sheet
* @param sheet sheet
* @description
* @author zhouhang
* @date 2021/4/21
*/
private static void dealWithExcelMerge(GridRecordDataModel model, Sheet sheet) {
if (CollectionUtils.isNotEmpty(sheet.getMergedRegions())) {
//{"color":"","list_id":"","column":60,"index":"1","jfgird_select_save":[],"rh_height":1790,"visibledatacolumn":[],"scrollTop":0,"block_id":"fblock","rowsplit":[],"visibledatarow":[],"jfgrid_selection_range":{},"name":"Sheet1","celldata":[],"ch_width":4748,"row":84,"scrollLeft":0,"id":364598,"chart":[],"config":{},"order":0,"status":1}
JSONObject jsonObject = model.getJson_data();
JSONObject config = jsonObject.getJSONObject("config");
JSONObject merge = new JSONObject();
for (CellRangeAddress mergedRegion : sheet.getMergedRegions()) {
JSONObject mergeBase = new JSONObject();
mergeBase.put("r", mergedRegion.getFirstRow());
mergeBase.put("c", mergedRegion.getFirstColumn());
mergeBase.put("rs", mergedRegion.getLastRow() - mergedRegion.getFirstRow() + 1);
mergeBase.put("cs", mergedRegion.getLastColumn() - mergedRegion.getFirstColumn() + 1);
merge.put(mergedRegion.getFirstRow() + "_" + mergedRegion.getFirstColumn(), mergeBase);
}
config.put("merge", merge);
}
}
}

@ -53,4 +53,9 @@ public class ReportShareDto extends GaeaBaseDTO implements Serializable {
@ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG")
private Integer deleteFlag;
/** 分享码 */
private String sharePassword;
private boolean sharePasswordFlag = false;
}

@ -1,18 +1,18 @@
package com.anjiplus.template.gaea.business.modules.reportshare.dao.entity;
import lombok.Data;
import io.swagger.annotations.ApiModelProperty;
import com.anji.plus.gaea.curd.entity.GaeaBaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import javax.validation.constraints.*;
import lombok.Data;
import java.util.Date;
/**
* @description entity
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
@TableName(value="gaea_report_share")
@TableName(keepGlobalPrefix=true, value="gaea_report_share")
@Data
public class ReportShare extends GaeaBaseEntity {
/** 分享编码系统生成默认UUID */
@ -39,5 +39,12 @@ public class ReportShare extends GaeaBaseEntity {
/** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */
private Integer deleteFlag;
/** 分享码 */
@TableField(exist = false)
private String sharePassword;
@TableField(exist = false)
private boolean sharePasswordFlag;
}

@ -13,9 +13,11 @@ import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.Report
import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService;
import com.anjiplus.template.gaea.business.util.DateUtil;
import com.anjiplus.template.gaea.business.util.JwtUtil;
import com.anjiplus.template.gaea.business.util.MD5Util;
import com.anjiplus.template.gaea.business.util.UuidUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -51,12 +53,18 @@ public class ReportShareServiceImpl implements ReportShareService {
@Override
public ReportShareDto insertShare(ReportShareDto dto) {
//设置分享码
if (dto.isSharePasswordFlag()) {
dto.setSharePassword(UuidUtil.getRandomPwd(4));
}
ReportShareDto reportShareDto = new ReportShareDto();
ReportShare entity = new ReportShare();
BeanUtils.copyProperties(dto, entity);
insert(entity);
//将分享链接返回
reportShareDto.setShareUrl(entity.getShareUrl());
reportShareDto.setSharePassword(dto.getSharePassword());
return reportShareDto;
}
@ -69,6 +77,12 @@ public class ReportShareServiceImpl implements ReportShareService {
if (null == reportShare) {
throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID);
}
//解析jwt token获取密码
String password = JwtUtil.getPassword(reportShare.getShareToken());
if (StringUtils.isNotBlank(password)) {
//md5加密返回
reportShare.setSharePassword(MD5Util.encrypt(password));
}
return reportShare;
}
@ -101,7 +115,8 @@ public class ReportShareServiceImpl implements ReportShareService {
} else {
entity.setShareUrl(entity.getShareUrl() + SHARE_FLAG + shareCode);
}
entity.setShareValidTime(DateUtil.getFutureDateTmdHms(entity.getShareValidType()));
entity.setShareToken(JwtUtil.createToken(entity.getReportCode(), shareCode, entity.getShareValidTime()));
entity.setShareToken(JwtUtil.createToken(entity.getReportCode(), shareCode, entity.getSharePassword(), entity.getShareValidTime()));
}
}

@ -7,6 +7,7 @@ import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
import java.util.Map;
@ -19,11 +20,16 @@ public class JwtUtil {
private static final String JWT_SECRET = "aj-report";
public static String createToken(String reportCode, String shareCode, Date expires) {
return createToken(reportCode, shareCode, null, expires);
}
public static String createToken(String reportCode, String shareCode, String password, Date expires) {
String token = JWT.create()
.withIssuedAt(new Date())
.withExpiresAt(expires)
.withClaim("reportCode", reportCode)
.withClaim("shareCode", shareCode)
.withClaim("sharePassword", password)
.sign(Algorithm.HMAC256(JWT_SECRET));
return token;
}
@ -55,4 +61,15 @@ public class JwtUtil {
return claim.asString();
}
public static String getPassword(String token) {
Claim claim = getClaim(token).get("sharePassword");
if (null == claim) {
return null;
}
if (StringUtils.isNotBlank(claim.asString())) {
return claim.asString();
}
return null;
}
}

@ -1,5 +1,6 @@
package com.anjiplus.template.gaea.business.util;
import java.security.SecureRandom;
import java.util.UUID;
/**
@ -31,6 +32,24 @@ public class UuidUtil {
}
/**
*
* @param num
* @return
*/
public static String getRandomPwd(int num) {
StringBuilder builder = new StringBuilder();
// 因为已经把 4 种字符放进list了所以 i 取值从 4开始
// 产生随机数用于随机调用生成字符的函数
for (int i = 0; i < num; i++) {
SecureRandom random = new SecureRandom();
int funNum = random.nextInt(chars.length);
builder.append(chars[funNum]);
}
return builder.toString().toLowerCase();
}
public static String generateUuid() {
return UUID.randomUUID().toString().replace("-", "");
@ -38,7 +57,9 @@ public class UuidUtil {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(generateShortUuid());
// System.out.println(generateShortUuid());
System.out.println(getRandomPwd(4));
}
}
}

@ -37,6 +37,7 @@ spring:
breakAfterAcquireFailure: true # 数据库服务宕机自动重连机制
timeBetweenConnectErrorMillis: 300000 # 连接出错后重试时间间隔
flyway:
enabled: true #是否开启flyway默认true.
baseline-on-migrate: true
#数据库连接配置
url: ${spring.datasource.url}
@ -48,7 +49,7 @@ spring:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql打印
call-setters-on-nulls: true
mapperLocations:
- classpath*:/mapper/**/*.xml

@ -0,0 +1,33 @@
use
aj_report;
CREATE TABLE `gaea_report_excel`
(
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`report_code` varchar(100) DEFAULT NULL COMMENT '报表编码',
`set_codes` varchar(255) DEFAULT NULL COMMENT '数据集编码,以|分割',
`set_param` varchar(1024) DEFAULT NULL COMMENT '数据集查询参数',
`json_str` text COMMENT '报表json串',
`enable_flag` int(1) DEFAULT '1' COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG',
`delete_flag` int(1) DEFAULT '0' COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG',
`create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(255) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`version` int(8) DEFAULT NULL COMMENT '版本号',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `UNIQUE_REPORT_CODE` (`report_code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=215 DEFAULT CHARSET=utf8;
INSERT INTO `aj_report`.`access_authority`(`id`, `parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (234, 'report', 'bigScreenManage', '大屏报表', 'export', '导出大屏', 234, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
INSERT INTO `aj_report`.`access_authority`(`id`, `parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (235, 'report', 'bigScreenManage', '大屏报表', 'import', '导入大屏', 235, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
INSERT INTO `aj_report`.`access_authority`(`id`, `parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (236, 'report', 'excelManage', '表格报表', 'query', '查询报表', 236, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default , 'root', 'bigScreenManage', 'export');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default , 'root', 'bigScreenManage', 'import');
UPDATE `aj_report`.`gaea_report` SET `report_type` = 'report_screen' WHERE `report_code` in ('log_ajreport', 'car_ajreport', 'acc_ajreport');

@ -0,0 +1,22 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.ReportExcelMapper">
<resultMap type="com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel" id="ReportMap">
<!--jdbcType="{column.columnType}"-->
<result property="id" column="id" />
<result property="reportCode" column="report_code" />
<result property="setCodes" column="set_codes" />
<result property="setParam" column="set_param" />
<result property="jsonStr" column="json_str" />
<result property="enableFlag" column="enable_flag" />
<result property="deleteFlag" column="delete_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="version" column="version" />
</resultMap>
</mapper>

@ -5,5 +5,5 @@ const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '"http://127.0.0.1:9095"'
//BASE_API: '"http://10.108.26.197:9095"'
// BASE_API: '"http://10.108.26.197:9095"'
})

@ -5,6 +5,22 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>AJ-Report</title>
<link rel='stylesheet' href='./static/luckysheet/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='./static/luckysheet/plugins/plugins.css' />
<link rel='stylesheet' href='./static/luckysheet/css/luckysheet.css' />
<!-- <link rel='stylesheet' href='./static/luckysheet/assets/iconfont/iconfont.css' /> -->
<script src="./static/luckysheet/plugins/js/plugin.js"></script>
<script src="./static/luckysheet/luckysheet.umd.js"></script>
<!-- <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />-->
<!-- <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />-->
<!-- <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />-->
<!-- <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />-->
<!-- <script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>-->
<!-- <script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>-->
</head>
<body>

@ -22,11 +22,13 @@
"echarts-gl": "^1.1.1",
"element-ui": "^2.9.2",
"js-cookie": "2.2.0",
"jsbarcode": "^3.11.4",
"miment": "^0.0.9",
"moment": "^2.29.1",
"monaco-editor": "^0.20.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"qrcodejs2": "0.0.2",
"sortablejs": "^1.10.2",
"uninstall": "0.0.0",
"v-chart": "^1.0.0",

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 1513211 */
src: url('iconfont.woff2?t=1629797734566') format('woff2'),
url('iconfont.woff?t=1629797734566') format('woff'),
url('iconfont.ttf?t=1629797734566') format('truetype');
src: url("iconfont.woff2?t=1629797734566") format("woff2"),
url("iconfont.woff?t=1629797734566") format("woff"),
url("iconfont.ttf?t=1629797734566") format("truetype");
}
.iconfont {
@ -488,4 +488,3 @@
.iconjiantou-copy-copy:before {
content: "\e654";
}

@ -1,34 +1,111 @@
<template>
<div :class="[hasTreeFieldInQueryForm ? 'page-container' : 'app-container']">
<div v-if="hasTreeFieldInQueryForm" class="left-container">
<AnjiTree ref="queryFormTree" v-model.trim="queryParams[queryFormTreeField.field]" :is-open="queryFormTreeField.anjiTreeOption.isOpen" :enable-filter="queryFormTreeField.anjiTreeOption.enableFilter" :label-name="queryFormTreeField.label" :url="queryFormTreeField.anjiTreeOption.url" @node-click="handleTreeNodeCheck" />
<AnjiTree
ref="queryFormTree"
v-model.trim="queryParams[queryFormTreeField.field]"
:is-open="queryFormTreeField.anjiTreeOption.isOpen"
:enable-filter="queryFormTreeField.anjiTreeOption.enableFilter"
:label-name="queryFormTreeField.label"
:url="queryFormTreeField.anjiTreeOption.url"
@node-click="handleTreeNodeCheck"
/>
</div>
<div class="right-container">
<!-- 查询表单开始 -->
<el-form ref="formSearch" :model="queryParams" label-width="100px" v-permission="option.buttons.query.permission">
<el-form
ref="formSearch"
:model="queryParams"
label-width="100px"
v-permission="option.buttons.query.permission"
>
<el-row>
<el-col v-for="(item, index) in queryFormFieldExcludeTree" :key="item.field" :span="queryFormFieldSpan(item)">
<el-form-item v-if="index <= 2 || (index > 2 && queryParams.showMoreSearch)" :label="item.label" :rules="item.rules" :prop="item.field">
<el-col
v-for="(item, index) in queryFormFieldExcludeTree"
:key="item.field"
:span="queryFormFieldSpan(item)"
>
<el-form-item
v-if="index <= 2 || (index > 2 && queryParams.showMoreSearch)"
:label="item.label"
:rules="item.rules"
:prop="item.field"
>
<!-- 输入框 -->
<el-input v-if="item.inputType == 'input' || item.inputType == 'input-number'" v-model.trim="queryParams[item.field]" :placeholder="item.placeholder || '请输入'" :clearable="item.clearable !== false" :disabled="item.disabled" @change="(value) => queryFormChange(item.field, value)" />
<el-input
v-if="
item.inputType == 'input' || item.inputType == 'input-number'
"
v-model.trim="queryParams[item.field]"
:placeholder="item.placeholder || '请输入'"
:clearable="item.clearable !== false"
:disabled="item.disabled"
@change="value => queryFormChange(item.field, value)"
/>
<!-- 开关 -->
<el-switch v-else-if="item.inputType == 'switch'" v-model.trim="queryParams[item.field]" :disabled="item.disabled" :active-value="item.switchOption.disableValue" :inactive-value="item.switchOption.enableValue" active-color="#5887fb" inactive-color="#ccc" @change="(value) => queryFormChange(item.field, value)" />
<el-switch
v-else-if="item.inputType == 'switch'"
v-model.trim="queryParams[item.field]"
:disabled="item.disabled"
:active-value="item.switchOption.disableValue"
:inactive-value="item.switchOption.enableValue"
active-color="#5887fb"
inactive-color="#ccc"
@change="value => queryFormChange(item.field, value)"
/>
<!-- 下拉框 -->
<anji-select v-else-if="item.inputType == 'anji-select'" v-model.trim="queryParams[item.field]" :multiple="item.anjiSelectOption.multiple" :dict-code="item.anjiSelectOption.dictCode" :url="item.anjiSelectOption.url" :method="item.anjiSelectOption.method" :query-param="item.anjiSelectOption.queryParam" :option="item.anjiSelectOption.option" :label="item.anjiSelectOption.label" :disabled-options="item.anjiSelectOption.disabledOptions" :disabled="item.disabled"
:merge-label="item.anjiSelectOption.mergeLabel" @change="(value) => queryFormChange(item.field, value)" />
<anji-select
v-else-if="item.inputType == 'anji-select'"
v-model.trim="queryParams[item.field]"
:multiple="item.anjiSelectOption.multiple"
:dict-code="item.anjiSelectOption.dictCode"
:url="item.anjiSelectOption.url"
:method="item.anjiSelectOption.method"
:query-param="item.anjiSelectOption.queryParam"
:option="item.anjiSelectOption.option"
:label="item.anjiSelectOption.label"
:disabled-options="item.anjiSelectOption.disabledOptions"
:disabled="item.disabled"
:merge-label="item.anjiSelectOption.mergeLabel"
@change="value => queryFormChange(item.field, value)"
/>
<!-- 日期时间框 -->
<el-date-picker v-else-if="item.inputType.indexOf('date') >= 0" v-model="queryParams[item.field]" style="width: 100%" :placeholder="item.placeholder || '请选择'" :type="item.inputType" :clearable="item.clearable !== false" @change="(value) => queryFormChange(item.field, value)" />
<el-date-picker
v-else-if="item.inputType.indexOf('date') >= 0"
v-model="queryParams[item.field]"
style="width: 100%"
:placeholder="item.placeholder || '请选择'"
:type="item.inputType"
:clearable="item.clearable !== false"
@change="value => queryFormChange(item.field, value)"
/>
<!-- 待扩展的表单类型请自行扩展 -->
<el-input v-else placeholder="组件不支持此类型表单请至组件内部自行扩展" disabled />
<el-input
v-else
placeholder="组件不支持此类型表单请至组件内部自行扩展"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="6" style="text-align: center">
<el-button type="primary" @click="handleQueryForm('query')"></el-button>
<el-button type="primary" @click="handleQueryForm('query')"
>查询</el-button
>
<el-button type="danger" @click="handleResetForm()"></el-button>
<a style="margin-left: 8px" @click="handleToggleMoreSearch">
{{ queryParams.showMoreSearch == true ? '收起' : '展开' }}
<i :class="queryParams.showMoreSearch ? 'el-icon-arrow-up' : 'el-icon-arrow-down'" />
<a
v-if="queryFormFieldExcludeTree.length > 3"
style="margin-left: 8px"
@click="handleToggleMoreSearch"
>
{{ queryParams.showMoreSearch == true ? "收起" : "展开" }}
<i
:class="
queryParams.showMoreSearch
? 'el-icon-arrow-up'
: 'el-icon-arrow-down'
"
/>
</a>
</el-col>
</el-row>
@ -37,17 +114,50 @@
<!-- 批量操作 -->
<slot name="buttonLeftOnTable" />
<el-button v-if="option.buttons.add.isShow == undefined ? true : option.buttons.add.isShow" v-permission="option.buttons.add.permission" type="primary" icon="el-icon-plus" @click="handleOpenEditView('add')"></el-button>
<el-button v-if="option.buttons.delete.isShow == undefined ? true : option.buttons.delete.isShow" v-permission="option.buttons.delete.permission" :disabled="disableBatchDelete" type="danger" icon="el-icon-delete" @click="handleDeleteBatch()"></el-button>
<el-button
v-if="
option.buttons.add.isShow == undefined
? true
: option.buttons.add.isShow
"
v-permission="option.buttons.add.permission"
type="primary"
icon="el-icon-plus"
@click="handleOpenEditView('add')"
>新增</el-button
>
<el-button
v-if="
option.buttons.delete.isShow == undefined
? true
: option.buttons.delete.isShow
"
v-permission="option.buttons.delete.permission"
:disabled="disableBatchDelete"
type="danger"
icon="el-icon-delete"
@click="handleDeleteBatch()"
>删除</el-button
>
<!-- 表格开始 -->
<el-table :data="records" border @selection-change="handleSelectionChange" @sort-change="handleSortChange">
<el-table
class="anji_curd_table"
:data="records"
border
@selection-change="handleSelectionChange"
@sort-change="handleSortChange"
>
<!--多选-->
<el-table-column fixed type="selection" width="50" align="center" />
<!--隐藏列-->
<el-table-column v-if="tableExpandColumns.length > 0" type="expand">
<template slot-scope="scope">
<p v-for="item in tableExpandColumns" :key="item.field" class="table-expand-item">
<p
v-for="item in tableExpandColumns"
:key="item.field"
class="table-expand-item"
>
<span class="titel"> {{ item.label }}: </span>
<span>{{ scope.row[item.field] }}</span>
</p>
@ -56,28 +166,65 @@
<!--序号-->
<el-table-column label="序号" min-width="50" align="center">
<template slot-scope="scope">
{{ queryParams.pageSize * (queryParams.pageNumber - 1) + scope.$index + 1 }}
{{
queryParams.pageSize * (queryParams.pageNumber - 1) +
scope.$index +
1
}}
</template>
</el-table-column>
<template v-for="item in option.columns">
<el-table-column v-if="item.tableHide != true && item.columnType != 'expand'" :key="item.field" :prop="item.field" :label="fieldLabel(item)" :min-width="item.minWidth || 110" :sortable="item.sortable" :show-overflow-tooltip="true" align="center">
<el-table-column
v-if="item.tableHide != true && item.columnType != 'expand'"
:key="item.field"
:prop="item.field"
:label="fieldLabel(item)"
:min-width="item.minWidth || 110"
:sortable="item.sortable"
:show-overflow-tooltip="true"
align="center"
>
<template slot-scope="scope">
<div v-if="item.columnType == 'imgPreview'">
<!-- 图片缩略图-->
<el-image style="width: 25%; height: 50%" fit="contain" :src="scope.row[item.field]" :preview-src-list="[scope.row[item.field]]" />
<el-image
style="width: 25%; height: 50%"
fit="contain"
:src="scope.row[item.field]"
:preview-src-list="[scope.row[item.field]]"
/>
</div>
<div v-else>
<span v-if="item.inputType == 'switch' && !item.colorStyle">
<el-switch v-model.trim="scope.row[item.field]" :active-value="1" :inactive-value="0" active-color="#5887fb" inactive-color="#ccc" @change="switchChange(scope.row, item.switchOption)" />
<el-switch
v-model.trim="scope.row[item.field]"
:active-value="1"
:inactive-value="0"
active-color="#5887fb"
inactive-color="#ccc"
@change="switchChange(scope.row, item.switchOption)"
/>
</span>
<!-- 带单位 -->
<span v-else-if="item.inputType == 'anji-input'">{{ fieldValueByAnjiInput(scope.row[item.field], item) }}</span>
<span v-else-if="item.inputType == 'anji-input'">{{
fieldValueByAnjiInput(scope.row[item.field], item)
}}</span>
<!--表格 a 合并 b上-->
<span v-else-if="item.mergeColumn">{{ scope.row[item.field] }}({{ scope.row[item.mergeColumn] }})</span>
<span v-else-if="item.mergeColumn"
>{{ scope.row[item.field] }}({{
scope.row[item.mergeColumn]
}})</span
>
<!-- 没有单位 -->
<span v-else-if="item.colorStyle" :class="item.colorStyle[scope.row[item.editField]]">{{ fieldValueByRowRenderer(scope.row, item) }}</span>
<span v-else>{{ fieldValueByRowRenderer(scope.row, item) }}</span>
<span
v-else-if="item.colorStyle"
:class="item.colorStyle[scope.row[item.editField]]"
>{{ fieldValueByRowRenderer(scope.row, item) }}</span
>
<span v-else>{{
fieldValueByRowRenderer(scope.row, item)
}}</span>
<!-- 正常展示模式
<div v-if="!item.custom">
是第一列数据 && 需要高亮字段不为false 高亮并且可以点击
@ -92,18 +239,76 @@
</el-table-column>
</template>
<!--操作栏-->
<el-table-column align="center" fixed="right" label="操作" :width="option.buttons.customButton && option.buttons.customButton.operationWidth ? option.buttons.customButton.operationWidth : 100">
<el-table-column
align="center"
fixed="right"
label="操作"
:width="
option.buttons.customButton &&
option.buttons.customButton.operationWidth
? option.buttons.customButton.operationWidth
: 100
"
>
<template slot-scope="scope">
<slot name="edit" :msg="scope.row" />
<el-button v-if="(option.buttons.query.isShow == undefined ? true : option.buttons.query.isShow) && hasPermission(option.buttons.edit.permission) == false" type="text" size="small" @click="handleOpenEditView('view', scope.row)" v-permission="option.buttons.query.permission" >查看</el-button>
<el-button v-if="option.buttons.edit.isShow == undefined ? true : option.buttons.edit.isShow" type="text" size="small" @click="handleOpenEditView('edit', scope.row)" v-permission="option.buttons.edit.permission" >编辑</el-button>
<el-button v-if="hasRowCustomButton == false && option.buttons.delete.isShow == undefined ? true : option.buttons.edit.isShow" type="text" size="small" @click="handleDeleteBatch(scope.row)" v-permission="option.buttons.delete.permission" >删除</el-button>
<el-button
v-if="
(option.buttons.query.isShow == undefined
? true
: option.buttons.query.isShow) &&
hasPermission(option.buttons.edit.permission) == false
"
type="text"
size="small"
@click="handleOpenEditView('view', scope.row)"
v-permission="option.buttons.query.permission"
>查看</el-button
>
<el-button
v-if="
option.buttons.edit.isShow == undefined
? true
: option.buttons.edit.isShow
"
type="text"
size="small"
@click="handleOpenEditView('edit', scope.row)"
v-permission="option.buttons.edit.permission"
>编辑</el-button
>
<el-button
v-if="
hasRowCustomButton == false &&
option.buttons.delete.isShow == undefined
? true
: option.buttons.edit.isShow
"
type="text"
size="small"
@click="handleDeleteBatch(scope.row)"
v-permission="option.buttons.delete.permission"
>删除</el-button
>
<el-dropdown v-if="hasRowCustomButton" trigger="click">
<span class="el-dropdown-link"> 更多<i class="el-icon-caret-bottom el-icon--right" /> </span>
<span class="el-dropdown-link">
更多<i class="el-icon-caret-bottom el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item class="clearfix">
<slot name="rowButton" :msg="scope.row" />
<el-button v-if="option.buttons.delete.isShow == undefined ? true : option.buttons.edit.isShow" type="text" size="small" @click="handleDeleteBatch(scope.row)" v-permission="option.buttons.delete.permission" >删除</el-button>
<el-button
v-if="
option.buttons.delete.isShow == undefined
? true
: option.buttons.edit.isShow
"
type="text"
size="small"
@click="handleDeleteBatch(scope.row)"
v-permission="option.buttons.delete.permission"
>删除</el-button
>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@ -111,7 +316,17 @@
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination v-show="total > 0" background :current-page.sync="queryParams.pageNumber" :page-sizes="$pageSizeAll" :page-size="queryParams.pageSize" layout="total, prev, pager, next, jumper, sizes" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
<el-pagination
v-show="total > 0"
background
:current-page.sync="queryParams.pageNumber"
:page-sizes="$pageSizeAll"
:page-size="queryParams.pageSize"
layout="total, prev, pager, next, jumper, sizes"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<div>
<slot name="tableSelectionBtn" :selection="checkRecords" />
</div>
@ -119,7 +334,14 @@
<!-- 表格结束 -->
<EditDialog ref="edit" :option="option" :model-type="editDialogModelType" :visible="editDialogOpen" :row-data="editDialogRowData" @closeEvent="editDialogClosedEvent">
<EditDialog
ref="edit"
:option="option"
:model-type="editDialogModelType"
:visible="editDialogOpen"
:row-data="editDialogRowData"
@closeEvent="editDialogClosedEvent"
>
<template v-slot:customCard>
<slot name="cardInEditPage" />
</template>
@ -132,13 +354,13 @@
</div>
</template>
<script>
import AnjiTree from '@/components/AnjiPlus/anji-tree.vue'
import EditDialog from './edit'
import request from '@/utils/request'
import AnjiTree from "@/components/AnjiPlus/anji-tree.vue";
import EditDialog from "./edit";
import request from "@/utils/request";
export default {
components: {
EditDialog,
AnjiTree,
AnjiTree
},
props: {
option: {
@ -153,14 +375,14 @@ export default {
query: {},
edit: {},
delete: {},
add: {},
add: {}
},
//
columns: [],
queryFormChange: (fileName, val) => {},
}
},
},
queryFormChange: (fileName, val) => {}
};
}
}
},
data() {
return {
@ -169,8 +391,8 @@ export default {
showMoreSearch: false, //
pageNumber: 1,
pageSize: 10,
order: '',
sort: '',
order: "",
sort: ""
},
checkRecords: [], //
@ -180,73 +402,73 @@ export default {
//
editDialogOpen: false, //
editDialogRowData: {}, //
editDialogModelType: 'view', //
editDialogModelType: "view", //
hasRowCustomButton: false, //
}
hasRowCustomButton: false //
};
},
computed: {
//
queryFormTreeField() {
var treeField = this.option.queryFormFields.find(
(item) => item['inputType'] == 'anji-tree'
)
return treeField
item => item["inputType"] == "anji-tree"
);
return treeField;
},
//
hasTreeFieldInQueryForm() {
return this.isNotBlank(this.queryFormTreeField)
return this.isNotBlank(this.queryFormTreeField);
},
//
queryFormFieldExcludeTree() {
var treeFields = this.option.queryFormFields.filter(
(item) => item['inputType'] != 'anji-tree'
)
return treeFields
item => item["inputType"] != "anji-tree"
);
return treeFields;
},
//
primaryKeyFieldName() {
var primaryKey = this.option.columns.find(
(item) => item['primaryKey'] == true
)
item => item["primaryKey"] == true
);
if (primaryKey != null) {
return primaryKey['field']
return primaryKey["field"];
} else {
return null
return null;
console.warn(
'在columns中查找primaryKey=true失败会导致查询详情和删除失败'
)
"在columns中查找primaryKey=true失败会导致查询详情和删除失败"
);
}
},
//
tableExpandColumns() {
var expandColumns = this.option.columns.filter(
(item) => item['columnType'] == 'expand'
)
return expandColumns
item => item["columnType"] == "expand"
);
return expandColumns;
},
//
disableBatchDelete() {
return this.checkRecords.length <= 0
},
return this.checkRecords.length <= 0;
}
},
created() {
// input
this.option.queryFormFields.forEach((item) => {
this.option.queryFormFields.forEach(item => {
//
this.$set(this.queryParams, item.field, item.defaultValue || null)
})
this.$set(this.queryParams, item.field, item.defaultValue || null);
});
//
this.handleQueryForm('query')
this.queryFormChange()
this.handleQueryForm("query");
this.queryFormChange();
},
mounted() {
if (this.$scopedSlots['rowButton'] != null) {
this.hasRowCustomButton = true
if (this.$scopedSlots["rowButton"] != null) {
this.hasRowCustomButton = true;
} else {
this.hasRowCustomButton = false
this.hasRowCustomButton = false;
}
},
methods: {
@ -254,9 +476,9 @@ export default {
// console.log(item)
if (item.span != null) {
return item.span
return item.span;
} else {
return 6
return 6;
}
// let rowLength = this.option.queryFormFields.length;
// console.log(rowLength, "ss")
@ -272,169 +494,169 @@ export default {
},
//
handleToggleMoreSearch() {
this.queryParams.showMoreSearch = !this.queryParams.showMoreSearch
this.queryParams.showMoreSearch = !this.queryParams.showMoreSearch;
},
//
handleSortChange(column) {
// {column: {}, prop: "orgCode", order: "ascending"}
if (column == null || column.prop == null) {
console.warn('排序字段名prop为空无法排序')
return
console.warn("排序字段名prop为空无法排序");
return;
}
var sort = column.prop //
var order = column.order == 'ascending' ? 'ASC' : 'DESC'
this.queryParams['sort'] = sort
this.queryParams['order'] = order
this.handleQueryForm('query')
var sort = column.prop; //
var order = column.order == "ascending" ? "ASC" : "DESC";
this.queryParams["sort"] = sort;
this.queryParams["order"] = order;
this.handleQueryForm("query");
},
//
handleQueryForm(from) {
//
if (from == 'query') {
if (from == "query") {
if (this.hasTreeFieldInQueryForm) {
delete this.queryParams[this.queryFormTreeField.field]
delete this.queryParams[this.queryFormTreeField.field];
}
}
//
if (from == 'tree') {
if (from == "tree") {
if (this.hasTreeFieldInQueryForm) {
var treeVal = this.queryParams[this.queryFormTreeField.field]
var treeVal = this.queryParams[this.queryFormTreeField.field];
this.queryParams = {
pageNumber: 1,
pageSize: 10,
}
this.queryParams[this.queryFormTreeField.field] = treeVal
pageSize: 10
};
this.queryParams[this.queryFormTreeField.field] = treeVal;
}
}
//
if (
this.isBlank(this.queryParams['order']) &&
this.isBlank(this.queryParams["order"]) &&
this.isNotBlank(this.option.buttons.query.order)
) {
this.queryParams['sort'] = this.option.buttons.query.sort
this.queryParams['order'] = this.option.buttons.query.order
this.queryParams["sort"] = this.option.buttons.query.sort;
this.queryParams["order"] = this.option.buttons.query.order;
}
this.queryParams.pageNumber = 1
this.handleQueryPageList()
this.queryParams.pageNumber = 1;
this.handleQueryPageList();
},
//
async handleQueryPageList() {
var params = this.queryParams
var params = this.queryParams;
// urlcode var params = this.urlEncodeObject(this.queryParams, 'order,sort')
const { data, code } = await this.option.buttons.query.api(params)
if (code != '200') return
this.records = data.records
this.total = data.total
const { data, code } = await this.option.buttons.query.api(params);
if (code != "200") return;
this.records = data.records;
this.total = data.total;
},
//
handleResetForm() {
this.queryParams = {
pageNumber: 1,
pageSize: 10,
}
pageSize: 10
};
// this.$refs['queryForm'].resetFields()
// this.records = []
// this.total = 0
},
//
handleTreeNodeCheck() {
this.handleQueryForm('tree')
this.handleQueryForm("tree");
//
var treeFieldName = this.queryFormTreeField['field']
var treeFieldName = this.queryFormTreeField["field"];
for (var i = 0; i < this.option.columns.length; i++) {
var item = this.option.columns[i]
var item = this.option.columns[i];
if (
item['editField'] == treeFieldName ||
item['field'] == treeFieldName
item["editField"] == treeFieldName ||
item["field"] == treeFieldName
) {
this.$set(
this.option.columns[i],
'defaultValue',
"defaultValue",
this.queryParams[treeFieldName]
)
break
);
break;
}
}
},
//
handleOpenEditView(modelType, row) {
if (modelType == 'view' || modelType == 'edit') {
this.editDialogRowData = row
if (modelType == "view" || modelType == "edit") {
this.editDialogRowData = row;
}
this.editDialogModelType = modelType
if (modelType == 'add') {
this.editDialogModelType = modelType;
if (modelType == "add") {
//
this.editDialogOpen = true
this.editDialogOpen = true;
}
const obj = {
type: modelType,
value: row,
}
this.$emit('handleCustomValue', obj)
value: row
};
this.$emit("handleCustomValue", obj);
},
//
editDialogClosedEvent(value) {
//
this.editDialogOpen = false
this.editDialogOpen = false;
//
if (
this.hasTreeFieldInQueryForm &&
this.$refs.queryFormTree != null &&
!value
) {
this.$refs.queryFormTree.queryData()
this.$refs.queryFormTree.queryData();
}
this.handleQueryPageList()
this.handleQueryPageList();
//
this.$refs.edit.$refs.mainForm.$refs.editForm.resetFields()
this.$refs.edit.$refs.mainForm.$refs.editForm.resetFields();
},
//
handleDeleteBatch(row) {
var ids = []
var ids = [];
if (row != null) {
ids.push(row[this.primaryKeyFieldName]) //
ids.push(row[this.primaryKeyFieldName]); //
} else {
//
ids = this.checkRecords.map((item) => item[this.primaryKeyFieldName])
ids = this.checkRecords.map(item => item[this.primaryKeyFieldName]);
}
this.$confirm('删除确认', '确认要删除吗?', {
type: 'warning',
confirmButtonClass: 'delete_sure',
cancelButtonClass: 'el-button--danger is-plain',
this.$confirm("删除确认", "确认要删除吗?", {
type: "warning",
confirmButtonClass: "delete_sure",
cancelButtonClass: "el-button--danger is-plain"
})
.then(() => {
this.option.buttons.delete.api(ids).then((res) => {
this.option.buttons.delete.api(ids).then(res => {
// {code: "200", message: "", data: true}
this.checkRecords = []
this.checkRecords = [];
//
if (
this.hasTreeFieldInQueryForm &&
this.$refs.queryFormTree != null
) {
this.$refs.queryFormTree.queryData()
this.$refs.queryFormTree.queryData();
}
this.handleQueryPageList()
})
})
.catch((e) => {
e
this.handleQueryPageList();
});
})
.catch(e => {
e;
});
},
//
handleSelectionChange(val) {
this.checkRecords = val
this.checkRecords = val;
},
//
handleCurrentChange(pageNumber) {
this.queryParams.pageNumber = pageNumber
this.handleQueryPageList()
this.queryParams.pageNumber = pageNumber;
this.handleQueryPageList();
},
// size
handleSizeChange(val) {
this.queryParams.pageNumber = 1
this.queryParams.pageSize = val
this.handleQueryPageList()
this.queryParams.pageNumber = 1;
this.queryParams.pageSize = val;
this.handleQueryPageList();
},
// table
thumbnailUrl(row, field) {
@ -453,66 +675,66 @@ export default {
//
fieldLabel(columnConfig) {
if (columnConfig == null) {
return ''
return "";
}
if (
columnConfig.inputType == 'anji-input' &&
columnConfig.inputType == "anji-input" &&
columnConfig.anjiInput != null
) {
return `${columnConfig.label}(${columnConfig.anjiInput.unit})`
return `${columnConfig.label}(${columnConfig.anjiInput.unit})`;
} else {
return columnConfig.label
return columnConfig.label;
}
},
//
fieldValueByAnjiInput(value, columnConfig) {
if (columnConfig == null) {
return value
return value;
}
if (
columnConfig.inputType == 'anji-input' &&
columnConfig.inputType == "anji-input" &&
columnConfig.anjiInput != null
) {
return value / columnConfig.anjiInput.conversion
return value / columnConfig.anjiInput.conversion;
} else {
return value
return value;
}
},
//
fieldValueByRowRenderer(row, columnConfig) {
if (
columnConfig == null ||
typeof columnConfig.fieldTableRowRenderer != 'function'
typeof columnConfig.fieldTableRowRenderer != "function"
) {
return row[columnConfig.field]
return row[columnConfig.field];
} else {
return columnConfig.fieldTableRowRenderer(row)
return columnConfig.fieldTableRowRenderer(row);
}
},
// crudsaveForm
getMainEntity() {
return this.$refs.edit.getSaveForm()
return this.$refs.edit.getSaveForm();
},
setMainEntity(object) {
this.$refs.edit.setSaveForm(object)
this.$refs.edit.setSaveForm(object);
},
async switchChange(val, api) {
request({
url: api.url,
method: 'put',
method: "put",
headers: { noPrompt: false },
data: [val.id],
}).then((response) => {
this.handleQueryPageList()
})
data: [val.id]
}).then(response => {
this.handleQueryPageList();
});
},
queryFormChange(fileName, fieldVal) {
if (typeof this.option.queryFormChange == 'function') {
this.option.queryFormChange(this.queryParams, fileName, fieldVal)
if (typeof this.option.queryFormChange == "function") {
this.option.queryFormChange(this.queryParams, fileName, fieldVal);
}
},
},
}
}
}
};
</script>
<style scoped lang="scss">
@ -578,5 +800,9 @@ export default {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 20px;
}
.anji_curd_table {
margin-top: 20px;
}
</style>

@ -316,3 +316,8 @@ export default {
}
};
</script>
<style scoped>
.filter-item {
width: 100%;
}
</style>

@ -28,7 +28,8 @@ export default {
name: "GetDictionary",
props: {
dictKey: String, // code
updataDict: String //
updataDict: String, //
value: String
},
data() {
return {
@ -43,18 +44,18 @@ export default {
this.getSystem();
}
},
updataDict: {
immediate: true,
handler() {
this.dictionary = this.updataDict;
}
value: {
handler(val) {
this.dictionary = val;
},
deep: true
}
},
created() {
this.getSystem();
},
mounted() {
this.dictionary = this.updataDict;
this.dictionary = this.value;
},
methods: {
//

@ -106,7 +106,6 @@ export default {
analysisChartsData(params, data) {
// widget-barchart 柱线图、widget-linechart 折线图、 widget-barlinechart 柱线图
// widget-piechart 饼图、widget-funnel 漏斗图
// widget-gauge 仪表盘
// widget-text 文本框
// widge-table 表格(数据不要转)
// widget-stackchart 堆叠图
@ -122,9 +121,7 @@ export default {
chartType == "widget-funnel"
) {
return this.piechartFn(params.chartProperties, data);
} else if (chartType == "widget-gauge") {
return this.gaugeFn(params.chartProperties, data);
} else if (chartType == "widget-text") {
} else if (chartType == "widget-text") {
return this.widgettext(params.chartProperties, data)
} else if (chartType == "widget-stackchart") {
return this.stackChartFn(params.chartProperties, data)
@ -169,11 +166,11 @@ export default {
//x轴字段、y轴字段名
const xAxisField = Object.keys(chartProperties)[types.indexOf('xAxis')]
const yAxisField = Object.keys(chartProperties)[types.indexOf('yAxis')]
const dataField = Object.keys(chartProperties)[types.indexOf('bar')]
//x轴数值去重y轴去重
const xAxisList = this.setUnique(data.map(item => item[xAxisField]))
const yAxisList = this.setUnique(data.map(item => item[yAxisField]))
const dataGroup = this.setGroupBy(data, yAxisField)
for (const key in chartProperties) {
if (chartProperties[key] !== 'yAxis' && !chartProperties[key].startsWith('xAxis')) {
Object.keys(dataGroup).forEach(item => {
@ -184,7 +181,7 @@ export default {
series.push({
name: yAxisList[item],
type: chartProperties[key],
data,
data: data,
})
})
}
@ -210,25 +207,6 @@ export default {
}
return ananysicData;
},
gaugeFn(chartProperties, data) {
const ananysicData = [];
for (let i = 0; i < data.length; i++) {
const obj = {};
for (const key in chartProperties) {
const value = chartProperties[key];
if (value === "name") {
obj["name"] = data[i][key];
} else {
obj["value"] = data[i][key];
}
}
if (!obj["unit"]) {
obj["unit"] = "%";
}
ananysicData.push(obj);
}
return ananysicData[0];
},
widgettext(chartProperties, data) {
const ananysicData = [];
for (let i = 0; i < data.length; i++) {

@ -49,7 +49,7 @@ export const constantRouterMap = [
{ path: 'resultset', name: 'resultset', component: () => import('@/views/report/resultset/index'), meta: { title: '数据集', icon: 'iconAPIwangguan', keepAlive: true, requireAuth: true, permission: 'resultsetManage'} },
{ path: 'report', name: 'reportIndex', component: () => import('@/views/report/report/index'), meta: { title: '报表管理', icon: 'iconnavicon-ywcs', keepAlive: true, requireAuth: true, permission: 'reportManage'} },
{ path: 'bigscreen', name: 'bigscreen', component: () => import('@/views/report/bigscreen/index'), meta: { title: '大屏报表', icon: 'iconchufaqipeizhi-hui', keepAlive: true, requireAuth: true, permission: 'bigScreenManage'}, },
//{ path: 'excelreport', name: 'excelreport', component: () => import('@/views/report/excelreport/index'), meta: { title: '表格报表', icon: 'iconliebiao', keepAlive: true, requireAuth: true, permission: 'excelManage'} },
{ path: 'excelreport', name: 'excelreport', component: () => import('@/views/report/excelreport/index'), meta: { title: '表格报表', icon: 'iconliebiao', keepAlive: true, requireAuth: true, permission: 'excelManage'} },
]
},
{
@ -62,6 +62,8 @@ export const constantRouterMap = [
},
{ path: '/bigscreen/viewer', component: () => import('@/views/report/bigscreen/viewer'), hidden: true, meta: { requireAuth: true }},
{ path: '/bigscreen/designer', component: () => import('@/views/report/bigscreen/designer'), hidden: true, meta: { requireAuth: true }},
{ path: '/excelreport/viewer', component: () => import('@/views/report/excelreport/viewer'), hidden: true, meta: { requireAuth: true }},
{ path: '/excelreport/designer', component: () => import('@/views/report/excelreport/designer'), hidden: true, meta: { requireAuth: true }},
{ path: '/404', component: () => import('@/views/404'), hidden: true },
{ path: '*', redirect: '/login', hidden: true },
/*

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save