!44 update 0.9.6

Merge pull request !44 from Foming/dev
V0.9.6
Foming 3 years ago committed by Gitee
commit 35fca11777
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F

@ -12,8 +12,6 @@
####   [在线体验](https://report.anji-plus.com/index.html "链接"): https://report.anji-plus.com/index.html  体验账号guest 密码guest ####   [在线体验](https://report.anji-plus.com/index.html "链接"): https://report.anji-plus.com/index.html  体验账号guest 密码guest
#### &emsp; [在线文档](https://report.anji-plus.com/report-doc/ "doc"): https://report.anji-plus.com/report-doc/ <br>
#### &emsp; [在线提问](https://gitee.com/anji-plus/report/issues "issue"): https://gitee.com/anji-plus/report/issues <br> #### &emsp; [在线提问](https://gitee.com/anji-plus/report/issues "issue"): https://gitee.com/anji-plus/report/issues <br>
## 发行版本 ## 发行版本
@ -26,15 +24,11 @@
&emsp;&emsp; 大屏设计AJ-Report是一个可视化拖拽编辑的直观酷炫具有科技感的图表工具全开源项目。 内置的基础功能包括数据源,数据集,报表管理,项目部分截图如下。<br> &emsp;&emsp; 大屏设计AJ-Report是一个可视化拖拽编辑的直观酷炫具有科技感的图表工具全开源项目。 内置的基础功能包括数据源,数据集,报表管理,项目部分截图如下。<br>
![操作](https://images.gitee.com/uploads/images/2021/0703/094742_c0243f70_1728982.gif "2021-07-03_09-43-50.gif") ![shipin](../picture/shipin.gif)
![视频](https://report.anji-plus.com/report-doc/static/Rhea.mp4) <br>
**[更多社区大屏案例](https://report.anji-plus.com/report-doc/guide/bigScreenCase.html)** <br>
## 数据流程图 ## 数据流程图
![An image](https://images.gitee.com/uploads/images/2021/0630/160451_31bb9052_1728982.png) ![liucheng](../picture/liucheng.png)
## 打包目录 ## 打包目录
@ -45,7 +39,7 @@
│ ├── start.sh │ ├── start.sh
│ └── stop.sh │ └── stop.sh
├── conf 配置文件目录 ├── conf 配置文件目录
│ └── bootstrap-dev.yml │ └── bootstrap.yml
├── logs 启动日志目录 ├── logs 启动日志目录
├── cache 本地缓存目录 ├── cache 本地缓存目录
├── lib 自定义扩展包&report-core核心包 ├── lib 自定义扩展包&report-core核心包

@ -1,7 +1,22 @@
## 案例一 ## 案例一
由社区 **[~无痕~@tengzhouboy](https://gitee.com/tengzhouboy)** 提供 <br> 由社区 **[~无痕~@tengzhouboy](https://gitee.com/tengzhouboy)** 提供 <br>
[AJ-Report分享链接](https://report.anji-plus.com/index.html#/aj/mtwbjPot) <br> [AJ-Report分享链接](https://report.anji-plus.com/index.html#/aj/mtwbjPot) <br>
![img.png](../picture/bigScreenCase/img.png) <br> ![img.png](../picture/bigScreenCase/img.png) <br>
## 案例二
由社区 **[心瘾丶 @yi_shan_liu](https://gitee.com/yi_shan_liu)** 提供<br>
[AJ-Report分享链接](https://report.anji-plus.com/index.html#/aj/hkBJgLW0) <br>
![img1](../picture/bigScreenCase/img1.png) <br>
[AJ-Report分享链接](https://report.anji-plus.com/index.html#/aj/Hgfi4pj5) <br>
![img2](../picture/bigScreenCase/img2.png) <br>
[AJ-Report分享链接](https://report.anji-plus.com/index.html#/aj/zJa5Wwey) <br>
![img3](../picture/bigScreenCase/img3.png) <br>
[AJ-Report分享链接](https://report.anji-plus.com/index.html#/aj/D0cpO4re) <br>
![img4](../picture/bigScreenCase/img4.png) <br>

@ -5,4 +5,5 @@
<a href='http://www.fgkb.net/'><img src="https://report.anji-plus.com/file/download/9ee5b709-5033-4cd5-a784-ebd2877fd373" width = "130" height = "50" /> </a> <a href='http://www.fgkb.net/'><img src="https://report.anji-plus.com/file/download/9ee5b709-5033-4cd5-a784-ebd2877fd373" width = "130" height = "50" /> </a>
<a href='http://www.turingoal.com/'><img src="https://report.anji-plus.com/file/download/cda7bf68-376b-45dc-9a55-c52b21e4a8c8" width = "130" height = "50" /> </a> <a href='http://www.turingoal.com/'><img src="https://report.anji-plus.com/file/download/cda7bf68-376b-45dc-9a55-c52b21e4a8c8" width = "130" height = "50" /> </a>
<a href='http://www.plian.net/'><img src="https://report.anji-plus.com/file/download/7838f2c2-fdce-4ca7-8373-14d13dcda5cc" width = "130" height = "50" /> </a> <a href='http://www.plian.net/'><img src="https://report.anji-plus.com/file/download/7838f2c2-fdce-4ca7-8373-14d13dcda5cc" width = "130" height = "50" /> </a>
<a href='https://www.gykjweb.com/'><img src="https://report.anji-plus.com/file/download/d13b03f5-0c20-4878-9a79-f3c76b44bfd9" width = "130" height = "130" /> </a> <a href='https://www.gykjweb.com/'><img src="https://report.anji-plus.com/file/download/d13b03f5-0c20-4878-9a79-f3c76b44bfd9" width = "130" height = "130" /> </a> <br>
<a href='https://www.zjjcl.cn/'><img src="https://report.anji-plus.com/file/download/8df07663-60c9-4e32-a0f2-0ea7d5c46ff9" width = "130" height = "50" /> </a>

@ -1,6 +1,6 @@
## 图表和数据集之间的关系 ## 图表和数据集之间的关系
图表和数据集是强关联关系一个图表需要什么样的数据才能进行展示下面都有说明以柱状图举例只能用俩个字段的数据集进行数据展示那使用数据集有2个以上字段那肯定图表无法正常展示反之有个数据集是3个字段那就找能展示3个字段的图表千万别搞小聪明定了好多个字段的数据集然后从里面挑几个字段进行展示不要么干。<br> 图表和数据集是强关联关系一个图表需要什么样的数据才能进行展示下面都有说明以柱状图举例只能用俩个字段的数据集进行数据展示那使用数据集有2个以上字段那肯定图表无法正常展示反之有个数据集是3个字段那就找能展示3个字段的图表千万别搞小聪明定了好多个字段的数据集然后从里面挑几个字段进行展示不要么干。<br>
## 文本框 ## 文本框
@ -42,7 +42,7 @@
![img](../picture/dashboard/img_22.png) <br> ![img](../picture/dashboard/img_22.png) <br>
表格字段对应的数据只选择“文本数字”。<br> 表格字段对应的数据只选择“文本数字”。<br>
![img14](../picture/dashboard/img_23.png) <br> ![img14](../picture/dashboard/img_23.png) <br>
**注意:** 多个字段的时候,需要在“配置-新增”添加你选择数据集所对应的字段,类似于映射关系。 <br> **注意:** 多个字段的时候,需要在“配置-新增”添加你选择数据集所对应的字段,即“配置”中“表体设置”的“key值”要和你“动态数据对应的字段名”保持一致类似于映射关系。 <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
## 内联框架 ## 内联框架
@ -52,6 +52,7 @@
## 柱状图 ## 柱状图
柱状图数据集对应字典值需要选择一个“X轴”、“柱状”只需要2个字段 <br> 柱状图数据集对应字典值需要选择一个“X轴”、“柱状”只需要2个字段 <br>
![img_13](../picture/charts/img_13.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 数据格式 ### 数据格式
@ -65,7 +66,7 @@
## 折线图 ## 折线图
折线图数据集对应字典值需要选择一个“X轴”、“折线”只需要2个字段 <br> 折线图数据集对应字典值需要选择一个“X轴”、“折线”只需要2个字段 <br>
![img_8.png](../picture/dashboard/img_8.png) <br> ![img14.png](../picture/charts/img_14.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 数据格式 ### 数据格式
@ -74,14 +75,24 @@
## 柱线图 ## 柱线图
柱线图数据集对应字典值需要选择一个“X轴”、“柱状”、“折线”需要3个字段 <br> 柱线图数据集对应字典值需要选择一个“X轴”、“柱状”、“折线”需要3个字段,图例名称用 | 进行分隔。<br>
![img9](../picture/dashboard/img_9.png) <br> ![img15](../picture/charts/img_15.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 数据格式 ### 数据格式
![img5](../picture/charts/img_4.png) <br> ![img5](../picture/charts/img_4.png) <br>
## 多柱线图
多柱线图对应数据字典需要选择一个“X轴”剩下的字段可任意选择为“柱状”、“折线”图例名称用 | 进行分隔。<br>
![img16](../picture/charts/img_16.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 数据格式
![img17](../picture/charts/img_17.png) <br>
## 饼图 ## 饼图
饼图的数据集选择的时候只能选择饼图对应的字典即“Name”、“Value”不明白可以参考静态数据 <br> 饼图的数据集选择的时候只能选择饼图对应的字典即“Name”、“Value”不明白可以参考静态数据 <br>
@ -95,7 +106,7 @@
## 漏斗图 ## 漏斗图
![img13](../picture/dashboard/img_13.png) <br> ![img18](../picture/charts/img_18.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 数据格式 ### 数据格式
@ -127,7 +138,7 @@
## 百分百图 ## 百分百图
![img16](../picture/dashboard/img_16.png) <br> ![img19](../picture/charts/img_19.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 数据格式 ### 数据格式
@ -146,7 +157,7 @@
![img.17](../picture/dashboard/img_17.png) <br> ![img.17](../picture/dashboard/img_17.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>** **如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
## 数据格式 ### 数据格式
![img4](../picture/charts/img_3.png) <br> ![img4](../picture/charts/img_3.png) <br>
@ -185,4 +196,13 @@
## 装饰饼图 ## 装饰饼图
装饰用,可单独使用或者配合文本框等图表组件来使整个大屏立体、丰满。<br> 装饰用,可单独使用或者配合文本框等图表组件来使整个大屏立体、丰满。<br>
![img12](../picture/charts/img_12.png) <br> ![img12](../picture/charts/img_12.png) <br>
## 词云图
最大最小角度都为0时则文字显示为正。所有词云颜色皆是随机产生动态数据每请求一次数据所有词云颜色皆改变一次。<br>
![img20](../picture/charts/img_20.png) <br>
### 数据格式
和饼图、南丁格尔玫瑰图数据保持一致。<br>

@ -1,7 +1,11 @@
![img5](../picture/dateset/img_5.png) ![img5](../picture/dateset/img_5.png) <br>
[数据源数据集用法总结](https://my.oschina.net/u/4517014/blog/5270828) <br>
## SQL数据集 ## SQL数据集
尽量不要使用 “select *”,以及展示很大的数据量,图表不一定能展示、页面可能会卡死 <br>
### Mysql数据集 ### Mysql数据集
在数据源处添加了mysql的数据源后即可使用。<br> 在数据源处添加了mysql的数据源后即可使用。<br>

@ -1,5 +1,7 @@
## 介绍 ## 介绍
[数据源数据集用法总结](https://my.oschina.net/u/4517014/blog/5270828) <br>
- 支持多数据源内置mysql、elasticsearch、kudu等多种驱动 <br> - 支持多数据源内置mysql、elasticsearch、kudu等多种驱动 <br>
- 可动态扩展 - 可动态扩展
![source.png](../picture/datasource/img_1.png) ![source.png](../picture/datasource/img_1.png)
@ -23,10 +25,26 @@
## 扩展 ## 扩展
- 以kudu impala 为例在lib文件夹下加入kudu impala相关的JDBC连接相关的包如图在数据库中新增数据源类型参考数据源类型(上方) ### JDBC驱动类数据源添加
- 第一种在report-core/lib目录下添加 <br>
按照同样的层级将驱动包放置使用build.sh脚本进行打包前端页面选择jdbc数据源填上对应的驱动类即可使用。<br>
**注意:** 此方式添加的jar包只能使用build.sh进行编译后才会生效。<br>
<br>
- 第二种在pom.xml中添加 <br>
使用build.sh脚本编译或者maven package编译都可以前端页面选择jdbc数据源填上对应驱动。<br>
<br>
### 非JDBC驱动类数据源添加
![An image](../picture/datasource/kudu-impala-lib.png) 例如原生ES、Redis之类。<br>
1、在源码中编写解析代码(datasource) <br>
2、使用页面生成数据字典 <br>
3、添加对应驱动包<br>

@ -1,53 +1,74 @@
## 其他
- 禁用flyway及切换底层数据库方案 <br>
[链接](https://my.oschina.net/u/4517014/blog/5269319) <br>
- 数据源数据集用法总结 <br>
[链接](https://my.oschina.net/u/4517014/blog/5270828) <br>
- 使用Maven Install打包时报错 <br> - 使用Maven Install打包时报错 <br>
![img.png](../picture/qusetion/img.png) <br> ![img.png](../picture/qusetion/img.png) <br>
请使用Maven Package进行打包 <br> 使用Maven Package进行打包 <br>
<br>
### 版本问题:[开发环境参考](https://report.anji-plus.com/report-doc/guide/quicklyDevelop.html) ## 版本问题:[开发环境参考](https://report.anji-plus.com/report-doc/guide/quicklyDevelop.html)
- 底层数据库为Mysql8.0+时flyway执行SQL报错<br> - 底层数据库为Mysql8.0+时flyway执行SQL报错<br>
- Node.js是V16版本时 npm install失败 <br> - Node.js是V16版本时 npm install失败 <br>
- jdk使用1.7或者11及以上时编译打包不过 <br> - jdk使用1.7或者11及以上时编译打包不过 <br>
![img](../picture/qusetion/img_1.png) <br> <br>
![img](../picture/qusetion/img_4.png) <br>
<br>
## 访问相关
- MssSqlServer 2014及其上下版本数据源测试不过。以2014版本为例。 <br> - 浏览器兼容性 <br>
![img](../picture/qusetion/img_2.png) <br> 当前未对部分浏览器做兼容性适配,推荐使用谷歌浏览器进行访问。<br>
将1.2.6改成1.2.0 <br> 已知IE白屏、部分版本的火狐浏览器拖动组件出现跳转新页面及无法返回的情况 <br>
- 浏览器兼容性 当前未对部分浏览器做兼容性适配,推荐使用谷歌浏览器进行访问。<br> <br>
- 部署完进入系统点击预览大屏大屏提示“执行sql失败“ <br> - 部署完进入系统点击预览大屏大屏提示“执行sql失败“ <br>
![img](../picture/qusetion/img_3.png) <br> ![img](../picture/qusetion/img_3.png) <br>
请先重置mysql数据源将mysql数据源的账号密码修改为你当前系统的账号密码。<br> 请先重置mysql数据源将mysql数据源的账号密码修改为你当前系统的账号密码。<br>
- flyway执行报错1.0.10sql失败 <br> <br>
错误提示Caused by: org.flywaydb.core.api.FlywayException: Validate failed: Detected failed <br>
migration to version 1.0.10 (create report share) <br>
请参考此 [Issue](https://gitee.com/anji-plus/report/issues/I47JNE) 解决此问题 <br>
- 禁用flyway及切换底层数据库方案 <br> - 页面提示“404” <br>
[链接](https://my.oschina.net/u/4517014/blog/5269319) <br> 1、确保访问地址无误根据部署方式的不同9095/9528 端口皆可以进入项目,如果一个不行试另一个端口 <br>
2、确定前端是否启动 <br>
3、确定后端是否启动 br>
- 数据源数据集用法总结 <br> <br>
[链接](https://my.oschina.net/u/4517014/blog/5270828) <br>
### 执行源码编译脚本build.sh报错 ## 执行源码编译脚本build.sh报错
- 提示:“*** report-ui/dist/* *** No such file or directory” <br> - 提示:“*** report-ui/dist/* *** No such file or directory” <br>
前端编译失败。<br> 前端编译失败。<br>
99%的原因是Node.js版本过高高于14导致前端编译失败Nodejs在编译执行初始化时会去下载一些依赖如果依赖下载不来也会导致失败。<br> 大部分原因是Node.js版本过高高于V14导致前端编译失败。 <br>
剩下极少数情况可能是你编译的linux系统问题。<br> 另一部分是Nodejs在编译执行初始化时会去下载一些依赖如果依赖下载不下来也会导致失败。<br>
<br>
- 提示“report-core/target/aj-report-*.zip *** No such file or directory” <br> - 提示“report-core/target/aj-report-*.zip *** No such file or directory” <br>
后端编译失败。<br> 后端编译失败。<br>
可能原因有Mvn版本过低/过高,导致后端编译失败 <br> 可能原因有Maven版本过低/过高,导致后端编译失败 <br>
<br>
- 使用eclipse进行源码编译时失败 <br> - 使用eclipse进行源码编译时失败 <br>
失败的提示有很多这里建议换成IDEA <br> 失败的提示有很多这里建议换成IDEA <br>
<br>
- 使用IDEA进行源码编译时提示“*** openjdk-***” <br> - 使用IDEA进行源码编译时提示“*** openjdk-***” <br>
请使用jdk1.8 请使用jdk1.8
### 启动服务报错 <br>
## 启动服务相关
- 提示“xxx The driver has not received any packets from the server” <br> - 提示“xxx The driver has not received any packets from the server” <br>
连不上mysql。<br> 连不上mysql。<br>
@ -55,11 +76,37 @@
2、mysql版本不兼容详细看上面关于版本兼容性 <br> 2、mysql版本不兼容详细看上面关于版本兼容性 <br>
3、bootstrap.yml中配置的mysql地址ip不对 <br> 3、bootstrap.yml中配置的mysql地址ip不对 <br>
<br>
- flyway执行报错1.0.10sql失败 <br>
错误提示Caused by: org.flywaydb.core.api.FlywayException: Validate failed: Detected failed <br>
migration to version 1.0.10 (create report share) <br>
请参考此 [Issue](https://gitee.com/anji-plus/report/issues/I47JNE) 解决此问题 <br>
<br>
## 数据集相关
- 系统异常,后台日志显示“** Data too long for colum **<br>
1、建议不要使用 "select *" <br>
2、一张图表能承载的数据量是有限的太多则图表展示不出来、页面卡死等 <br>
3、必须使用 "select *" ,或者展示很多数据。解决方法,将测试预览的值删掉只剩一条,注意数据的结构 [{}] <br>
## 大屏图表组件相关
- 访问白屏 <br>
设计完大屏,保存后进行预览,发现背景全白 <br>
1、回到编辑页面查看大屏背景颜色是否设置 <br>
2、查看大屏的宽高如果宽高都是0大屏宽高在设计时有概率性变成0不知原因大屏背景图片颜色皆无法显示 <br>
3、大屏宽高改成 1920 1080 <br>
<br>
- 文本框颜色无法改变 <br>
使用文本框,改变颜色,无法改变。已知有概率性的出现无法修改文本框颜色的情况,因为无法重现,暂时不能排查到是哪里问题。解决方法有以下 <br>
1、保存退出大屏重新进入大屏修改文本框颜色 <br>
2、删掉文本框重新拖动一个 <br>
- 提示“404” <br>
1、确保访问地址无误根据部署方式的不同9095/9528 端口皆可以进入项目,如果一个不行试另一个端口 <br>
2、确定前端是否启动 <br>
3、确定后端是否启动 br>

@ -23,7 +23,7 @@
## 上传功能 ## 上传功能
使用上传功能,必须修改此内容 <br> 使用上传功能,必须修改此内容注意路径格式比如Win是 \ ,linux是 / <br>
![file.png](../picture/quickly/img_15.png) <br> ![file.png](../picture/quickly/img_15.png) <br>
## 启动 ## 启动

@ -1,5 +1,6 @@
**前后端分离:请对自己有动手能力的小伙伴进行尝试** **前后端分离:** <br>
**请根据自己的实际情况对下面的步骤和内容进行调整** **请对自己有动手能力的小伙伴进行尝试** <br>
**请根据自己的实际情况对下面的步骤和内容进行调整** <br>
``` ```
linux linux
@ -42,11 +43,12 @@ report-core --> src --> main --> resources --> bootstrap.yml <br>
### 上传功能 ### 上传功能
使用上传功能,必须修改此内容 <br> 使用上传功能,必须修改此内容注意路径格式比如Win是 \ ,linux是 / <br>
![file.png](../picture/quickly/img_15.png) <br> ![file.png](../picture/quickly/img_15.png) <br>
### maven打包 ### maven打包
**打包之前如果系统用的不止mysql数据源需要自己在pom文件中加入对应的数据库的驱动登陆系统之后数据源提示无驱动则选择通用JDBC数据源这里不做演示了** <br>
使用 maven package <br> 使用 maven package <br>
**注**不要使用maven install <br> **注**不要使用maven install <br>
![img10](../picture/quickly/img_10.png) <br> ![img10](../picture/quickly/img_10.png) <br>

@ -47,7 +47,7 @@ git clone https://gitee.com/anji-plus/report.git <br>
## 上传功能 ## 上传功能
使用上传功能,必须修改此内容 <br> 使用上传功能,必须修改此内容注意路径格式比如Win是 \ ,linux是 / <br>
![file.png](../picture/quickly/img_15.png) ![file.png](../picture/quickly/img_15.png)
## 启动 ## 启动

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@ -29,8 +29,27 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.15.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId> <artifactId>spring-boot-starter-cache</artifactId>

@ -23,4 +23,4 @@ fi
JAVA_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k " JAVA_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k "
nohup java $JAVA_OPTS -Xbootclasspath/a:$LIB_JARS -jar -Dspring.config.location=$CONF_DIR/bootstrap.yml $LIB_DIR/aj-report-*.jar >/dev/null 2>&1 & nohup java $JAVA_OPTS -Xbootclasspath/a:$LIB_JARS -jar -Dspring.config.location=$CONF_DIR/bootstrap.yml $LIB_DIR/aj-report-*.jar >/dev/null 2>&1 &
echo "The AJ-Report started!" echo "AJ-Report 正在后台执行请查看aj-report.log日志(tail -F ../logs/aj-report.log),确定软件运行情况"

@ -4,8 +4,10 @@ package com.anjiplus.template.gaea.business.filter;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.anji.plus.gaea.bean.ResponseBean; import com.anji.plus.gaea.bean.ResponseBean;
import com.anji.plus.gaea.cache.CacheHelper; import com.anji.plus.gaea.cache.CacheHelper;
import com.anji.plus.gaea.constant.GaeaConstant;
import com.anji.plus.gaea.utils.JwtBean; import com.anji.plus.gaea.utils.JwtBean;
import com.anjiplus.template.gaea.business.constant.BusinessConstant; import com.anjiplus.template.gaea.business.constant.BusinessConstant;
import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.GaeaUserDto;
import com.anjiplus.template.gaea.business.util.JwtUtil; import com.anjiplus.template.gaea.business.util.JwtUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
@ -14,13 +16,20 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import javax.servlet.*; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.anji.plus.gaea.constant.GaeaConstant.URL_REPLACEMENT;
/** /**
* *
@ -33,6 +42,7 @@ public class TokenFilter implements Filter {
private static final Pattern PATTERN = Pattern.compile(".*().*"); private static final Pattern PATTERN = Pattern.compile(".*().*");
private static final String USER_GUEST = "guest"; private static final String USER_GUEST = "guest";
private static final String SLASH = "/"; private static final String SLASH = "/";
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Autowired @Autowired
private CacheHelper cacheHelper; private CacheHelper cacheHelper;
@ -115,32 +125,53 @@ public class TokenFilter implements Filter {
} }
String gaeaUserJsonStr = cacheHelper.stringGet(userKey); String gaeaUserJsonStr = cacheHelper.stringGet(userKey);
//判断接口权限
//请求路径
String requestUrl = request.getRequestURI();
String methodValue = request.getMethod();
//请求方法+#+请求路径
String urlKey = methodValue + GaeaConstant.URL_SPLIT + requestUrl;
GaeaUserDto gaeaUserDto = JSONObject.parseObject(gaeaUserJsonStr, GaeaUserDto.class);
List<String> authorities = gaeaUserDto.getAuthorities();
Map<String, String> applicationNameAllAuthorities = cacheHelper.hashGet(BusinessConstant.GAEA_SECURITY_AUTHORITIES);
AtomicBoolean authFlag = new AtomicBoolean(false);
//查询当前请求是否在对应的权限里。即:先精确匹配(保证当前路由是需要精确匹配还是模糊匹配,防止精确匹配的被模糊匹配)
// 比如:/user/info和/user/**同时存在,/user/info,被/user/**匹配掉
if (applicationNameAllAuthorities.containsKey(urlKey)) {
String permissionCode = applicationNameAllAuthorities.get(urlKey);
if (authorities.contains(permissionCode)) {
authFlag.set(true);
}
} else {
List<String> collect = applicationNameAllAuthorities.keySet().stream()
.filter(key -> StringUtils.isNotBlank(key) && key.contains(URL_REPLACEMENT))
.filter(key -> antPathMatcher.match(key, urlKey)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(collect)) {
authFlag.set(true);
}else {
collect.forEach(key -> {
String permissionCode = applicationNameAllAuthorities.getOrDefault(key, "");
if (authorities.contains(permissionCode)) {
authFlag.set(true);
}
});
}
}
if (!authFlag.get()) {
//无权限
authError(response);
return;
}
// 延长有效期 // 延长有效期
cacheHelper.stringSetExpire(tokenKey, token, 3600); cacheHelper.stringSetExpire(tokenKey, token, 3600);
cacheHelper.stringSetExpire(userKey, gaeaUserJsonStr, 3600); cacheHelper.stringSetExpire(userKey, gaeaUserJsonStr, 3600);
//在线体验版本
if (USER_GUEST.equals(loginName)
&& !uri.endsWith("/dataSet/testTransform")
&& !uri.endsWith("/reportDashboard/getData")
&& !uri.startsWith("/dict")
&& !uri.endsWith("/reportExcel/preview")
) {
//不允许删除
String method = request.getMethod();
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;
}
}
//执行 //执行
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
} }
@ -180,4 +211,10 @@ public class TokenFilter implements Filter {
response.setContentType(ContentType.APPLICATION_JSON.getMimeType()); response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().print(JSONObject.toJSONString(responseBean)); response.getWriter().print(JSONObject.toJSONString(responseBean));
} }
private void authError(HttpServletResponse response) throws IOException {
ResponseBean responseBean = ResponseBean.builder().code("User.no.authority").message("没有权限").build();
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().print(JSONObject.toJSONString(responseBean));
}
} }

@ -0,0 +1,77 @@
package com.anjiplus.template.gaea.business.filter;
import com.anji.plus.gaea.constant.GaeaConstant;
import org.apache.catalina.util.ParameterMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.ognl.IteratorEnumeration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
/**
* @author: Raod
* @since: 2022-01-26
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
public class UrlDecodeFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
ParameterMap<String, String[]> parameterMap = (ParameterMap) httpServletRequest.getParameterMap();
ParamHttpServletRequestWrapper wrapper = new ParamHttpServletRequestWrapper(httpServletRequest, parameterMap);
Enumeration<String> parameterNames = wrapper.getParameterNames();
while (parameterNames.hasMoreElements()) {
String paramName = parameterNames.nextElement();
String parameter = httpServletRequest.getParameter(paramName);
if (StringUtils.isNotBlank(parameter)) {
String decode = URLDecoder.decode(parameter, GaeaConstant.CHARSET_UTF8);
parameterMap.setLocked(false);
parameterMap.put(paramName, new String[]{decode});
}
}
filterChain.doFilter(wrapper, servletResponse);
}
/**
*
*/
class ParamHttpServletRequestWrapper extends HttpServletRequestWrapper {
private ParameterMap<String, String[]> parameterMap;
public ParamHttpServletRequestWrapper(HttpServletRequest request, ParameterMap<String, String[]> parameterMap) {
super(request);
this.parameterMap = parameterMap;
}
@Override
public Map<String, String[]> getParameterMap() {
return parameterMap;
}
@Override
public Enumeration<String> getParameterNames() {
Set<String> keySet = parameterMap.keySet();
IteratorEnumeration iteratorEnumeration = new IteratorEnumeration(keySet.iterator());
return iteratorEnumeration;
}
@Override
public String[] getParameterValues(String name) {
return parameterMap.get(name);
}
}
}

@ -7,9 +7,12 @@ import com.anji.plus.gaea.bean.ResponseBean;
import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService; import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService;
import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto;
import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ReportDashboardObjectDto; import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ReportDashboardObjectDto;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto;
import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -31,6 +34,9 @@ public class ReportDashboardController {
@Autowired @Autowired
private ReportDashboardService reportDashboardService; private ReportDashboardService reportDashboardService;
@Autowired
private ReportShareService reportShareService;
/** /**
* *
* @param reportCode * @param reportCode
@ -93,4 +99,10 @@ public class ReportDashboardController {
return ResponseBean.builder().build(); return ResponseBean.builder().build();
} }
@PostMapping("/share")
@GaeaAuditLog(pageTitle = "分享")
public ResponseBean share(@Validated @RequestBody ReportShareDto dto) {
return ResponseBean.builder().data(reportShareService.insertShare(dto)).build();
}
} }

@ -16,6 +16,7 @@ import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashb
import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService;
import com.anjiplus.template.gaea.business.modules.file.util.FileUtils; import com.anjiplus.template.gaea.business.modules.file.util.FileUtils;
import com.anjiplus.template.gaea.business.modules.report.service.ReportService;
import com.anjiplus.template.gaea.business.util.DateUtil; import com.anjiplus.template.gaea.business.util.DateUtil;
import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetDto; import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetDto;
import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetValueDto; import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetValueDto;
@ -26,6 +27,7 @@ import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSe
import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto; 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.dataset.service.DataSetService;
import com.anjiplus.template.gaea.business.util.FileUtil; import com.anjiplus.template.gaea.business.util.FileUtil;
import com.anjiplus.template.gaea.business.util.RequestUtil;
import com.anjiplus.template.gaea.business.util.UuidUtil; import com.anjiplus.template.gaea.business.util.UuidUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -51,6 +53,7 @@ import java.io.File;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
/** /**
* @author Raod * @author Raod
@ -74,6 +77,9 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
@Autowired @Autowired
private GaeaFileService gaeaFileService; private GaeaFileService gaeaFileService;
@Autowired
private ReportService reportService;
@Value("${customer.file.downloadPath:''}") @Value("${customer.file.downloadPath:''}")
private String fileDownloadPath; private String fileDownloadPath;
@ -272,6 +278,13 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
FileUtil.delete(path); FileUtil.delete(path);
log.info("删除临时文件:{}{}", zipPath, path); log.info("删除临时文件:{}{}", zipPath, path);
//异步统计下载次数
CompletableFuture.runAsync(() -> {
log.info("=======>ip:{} 下载模板:{}", RequestUtil.getIpAddr(request), reportCode);
reportService.downloadStatistics(reportCode);
});
return body; return body;
} }
@ -316,11 +329,15 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
LambdaQueryWrapper<GaeaFile> queryWrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GaeaFile> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(GaeaFile::getFileId, fileName); queryWrapper.eq(GaeaFile::getFileId, fileName);
GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper); GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper);
String uploadPath;
if (null == gaeaFile) { if (null == gaeaFile) {
GaeaFile upload = gaeaFileService.upload(imageFile, fileName); GaeaFile upload = gaeaFileService.upload(imageFile, fileName);
log.info("存入图片: {}", upload.getFilePath()); log.info("存入图片: {}", upload.getFilePath());
fileMap.put(fileName, upload.getUrlPath()); uploadPath = upload.getUrlPath();
}else {
uploadPath = gaeaFile.getUrlPath();
} }
fileMap.put(fileName, uploadPath);
} }
} }

@ -9,12 +9,12 @@ import com.anjiplus.template.gaea.business.modules.report.controller.dto.ReportD
import com.anjiplus.template.gaea.business.modules.report.controller.param.ReportParam; import com.anjiplus.template.gaea.business.modules.report.controller.param.ReportParam;
import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
import com.anjiplus.template.gaea.business.modules.report.service.ReportService; import com.anjiplus.template.gaea.business.modules.report.service.ReportService;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto;
import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* TODO * TODO
@ -28,9 +28,6 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/report") @RequestMapping("/report")
public class ReportController extends GaeaBaseController<ReportParam, Report, ReportDto> { public class ReportController extends GaeaBaseController<ReportParam, Report, ReportDto> {
@Autowired
private ReportShareService reportShareService;
@Autowired @Autowired
private ReportService reportService; private ReportService reportService;
@ -56,11 +53,4 @@ public class ReportController extends GaeaBaseController<ReportParam, Report, Re
reportService.delReport(reportDto); reportService.delReport(reportDto);
return ResponseBean.builder().build(); return ResponseBean.builder().build();
} }
@PostMapping("/share")
@Permission(code = "share", name = "分享")
@GaeaAuditLog(pageTitle = "分享")
public ResponseBean share(@Validated @RequestBody ReportShareDto dto) {
return ResponseBean.builder().data(reportShareService.insertShare(dto)).build();
}
} }

@ -6,7 +6,6 @@ import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
/** /**
* TODO
* *
* @author chenkening * @author chenkening
* @date 2021/3/26 10:34 * @date 2021/3/26 10:34
@ -50,4 +49,11 @@ public class ReportDto extends GaeaBaseDTO implements Serializable {
/** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */
private Integer deleteFlag; private Integer deleteFlag;
/** 报表作者 */
private String reportAuthor;
/** 下载次数 */
private Long downloadCount;
} }

@ -20,6 +20,10 @@ public class ReportParam extends PageParam implements Serializable{
@Query(QueryEnum.LIKE) @Query(QueryEnum.LIKE)
private String reportName; private String reportName;
/** 报表作者 */
@Query(QueryEnum.LIKE)
private String reportAuthor;
/** 报表编码 */ /** 报表编码 */
@Query(QueryEnum.LIKE) @Query(QueryEnum.LIKE)
private String reportCode; private String reportCode;
@ -27,4 +31,6 @@ public class ReportParam extends PageParam implements Serializable{
/** 报表类型 */ /** 报表类型 */
@Query(QueryEnum.EQ) @Query(QueryEnum.EQ)
private String reportType; private String reportType;
} }

@ -36,6 +36,12 @@ public class Report extends GaeaBaseEntity {
@ApiModelProperty(value = "报表缩略图") @ApiModelProperty(value = "报表缩略图")
private String reportImage; private String reportImage;
@ApiModelProperty(value = "报表作者")
private String reportAuthor;
@ApiModelProperty(value = "下载次数")
private Long downloadCount;
@ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG")
private Integer enableFlag; private Integer enableFlag;

@ -6,7 +6,6 @@ import com.anjiplus.template.gaea.business.modules.report.controller.param.Repor
import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
/** /**
* TODO
* *
* @author chenkening * @author chenkening
* @date 2021/3/26 10:35 * @date 2021/3/26 10:35
@ -14,4 +13,10 @@ import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
public interface ReportService extends GaeaBaseService<ReportParam, Report> { public interface ReportService extends GaeaBaseService<ReportParam, Report> {
void delReport(ReportDto reportDto); void delReport(ReportDto reportDto);
/**
* +1
* @param reportCode
*/
void downloadStatistics(String reportCode);
} }

@ -34,6 +34,27 @@ public class ReportServiceImpl implements ReportService {
//... //...
} }
/**
* +1
*
* @param reportCode
*/
@Override
public void downloadStatistics(String reportCode) {
Report report = selectOne("report_code", reportCode);
if (null != report) {
Long downloadCount = report.getDownloadCount();
if (null == downloadCount) {
downloadCount = 0L;
}else {
downloadCount++;
}
report.setDownloadCount(downloadCount);
update(report);
}
}
@Override @Override
public void processBeforeOperation(Report entity, BaseOperationEnum operationEnum) throws BusinessException { public void processBeforeOperation(Report entity, BaseOperationEnum operationEnum) throws BusinessException {

@ -22,6 +22,7 @@ import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.Re
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.ReportExcelMapper; 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.dao.entity.ReportExcel;
import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService; import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService;
import com.anjiplus.template.gaea.business.modules.reportexcel.util.CellType;
import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsSheetUtil; import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsSheetUtil;
import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsUtil; import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -254,67 +255,333 @@ public class ReportExcelServiceImpl implements ReportExcelService {
if (dbObject.containsKey("celldata") && null != dbObject.get("celldata")) { if (dbObject.containsKey("celldata") && null != dbObject.get("celldata")) {
List<JSONObject> celldata = new ArrayList<>(); List<JSONObject> celldata = new ArrayList<>();
celldata.addAll((List<JSONObject>) dbObject.get("celldata")); celldata.addAll((List<JSONObject>) dbObject.get("celldata"));
//整理celldata数据转换为map格式方便后续使用单元格位置获取对应的cell对象
Map<String,JSONObject> cellDataMap = cellDataList2Map(celldata);
//清除原有的数据
dbObject.getJSONArray("celldata").clear();
//获取配置项中的合并属性
JSONObject merge = dbObject.getJSONObject("config").getJSONObject("merge");
if(merge != null) merge.clear();
//定义存储每一列动态扩展的行数
Map<Integer,Integer> colAddCntMap = new HashMap<>();
// 遍历已存在的单元格,查看是否存在动态参数 // 遍历已存在的单元格,查看是否存在动态参数
for (int i = 0; i < celldata.size(); i++) { for (int i = 0; i < celldata.size(); i++) {
//单元格对象 //单元格对象
JSONObject cellObj = celldata.get(i); JSONObject cellObj = celldata.get(i);
//fastjson深拷贝问题 //fastjson深拷贝问题
String cellStr = cellObj.toJSONString(); String cellStr = cellObj.toJSONString();
analysisCellData(cellObj,setParam,colAddCntMap,cellStr,merge, dbObject,cellDataMap);
}
}
}
//行号 /**
Integer r = cellObj.getInteger("r"); * cellData
//列号 * @param cellObject
Integer c = cellObj.getInteger("c"); */
JSONObject cell = cellObj.getJSONObject("v"); public void analysisCellData(JSONObject cellObject,String setParam,Map<Integer,Integer> colAddCntMap,String cellStr,
if (null != cell && cell.containsKey("v") && StringUtils.isNotBlank(cell.getString("v"))) { JSONObject merge,JSONObject dbObject,Map<String,JSONObject> cellDataMap){
String v = cell.getString("v"); //获取行号
DataSetDto dataSet = getDataSet(v, setParam); Integer cellR = cellObject.getInteger("r");
if (null != dataSet) { //获取列数
OriginalDataDto originalDataDto = dataSetService.getData(dataSet); Integer cellC = cellObject.getInteger("c");
if (null != originalDataDto.getData()) { //获取此行已经动态增加的行数默认0行
List<JSONObject> data = originalDataDto.getData(); int cnt = colAddCntMap.get(cellC) == null ? 0 : colAddCntMap.get(cellC);
//获取单元格类型
for (int j = 0; j < data.size(); j++) { CellType cellType = getCellType(cellObject);
if (j == 0) { switch (cellType){
//处理当前行 case BLACK:
//第一行,作为渲染参照数据 //空数据单元格不处理
JSONObject jsonObject = data.get(j); break;
String fieldLabel = jsonObject.getString(dataSet.getFieldLabel()); case DYNAMIC_MERGE:
case DYNAMIC:
//处理动态单元格
String v = cellObject.getJSONObject("v").getString("v");
DataSetDto dataSet = getDataSet(v, setParam);
handleDynamicCellObject(dataSet,v,cellStr,cnt,cellR,cellC,merge,dbObject,colAddCntMap);
break;
default:
//处理静态单元格
handleStaticCellObject(cellStr,dbObject,cnt,cellR,cellC,cellDataMap,setParam,merge,colAddCntMap,cellType);
break;
}
}
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); * @param dataSet
} else { * @param v
//新增的行数据 * @param cellStr
JSONObject addCell = data.get(j); * @param cnt
//字段 * @param r
String fieldLabel = addCell.getString(dataSet.getFieldLabel()); * @param c
String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel); * @param merge
* @param dbObject
* @param colAddCntMap
*/
public void handleDynamicCellObject(DataSetDto dataSet,String v,String cellStr,int cnt,int r,int c,
JSONObject merge,JSONObject dbObject,Map<Integer,Integer> colAddCntMap){
//获取动态数据
OriginalDataDto originalDataDto = dataSetService.getData(dataSet);
List<JSONObject> cellDynamicData = originalDataDto.getData();
if(cellDynamicData != null){
//循环数据赋值
for (int j = 0; j < cellDynamicData.size(); j++) {
//新增的行数据
JSONObject addCell = cellDynamicData.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", cnt + r + j); //行数增加
addCellData.put("c", c);
addCellData.getJSONObject("v").put("v", replace);
addCellData.getJSONObject("v").put("m", replace);
JSONObject cellMc = addCellData.getJSONObject("v").getJSONObject("mc");
//判断是否是合并单元格
if(null != cellMc){
//处理合并单元格
Integer rs = cellMc.getInteger("rs");
cellMc.put("r", cnt + r + rs*j); //行数增加
cellMc.put("c", c);
addCellData.put("r", cnt + r + rs*j);
//合并单元格需要处理config.merge
merge.put(cellMc.getString("r")+"_"+cellMc.getString("c"),cellMc);
//处理单元格扩展之后此列扩展的总行数
colAddCntMap.put(c,cnt + rs * cellDynamicData.size() - 1);
}else{
//处理单元格扩展之后此列扩展的总行数
colAddCntMap.put(c,cnt + cellDynamicData.size() - 1);
}
dbObject.getJSONArray("celldata").add(addCellData);
}
}
}
//转字符串,解决深拷贝问题 /**
JSONObject addCellData = JSONObject.parseObject(cellStr); *
* @param cellStr
* @param dbObject
* @param cnt
* @param r
* @param c
* @param cellDataMap
* @param setParam
* @param merge
* @param colAddCntMap
* @param cellType
*/
public void handleStaticCellObject(String cellStr,JSONObject dbObject,int cnt,int r,int c,
Map<String,JSONObject> cellDataMap,String setParam,
JSONObject merge,Map<Integer,Integer> colAddCntMap,CellType cellType){
//转字符串,解决深拷贝问题
JSONObject addCellData = JSONObject.parseObject(cellStr);
int rows = 0;
switch(cellType){
case STATIC:
case STATIC_MERGE:
//静态不扩展单元格只需要初始化位置就可以
initCellPosition(addCellData,cnt,merge);
break;
case STATIC_AUTO:
//获取静态单元格右侧动态单元格的总行数
rows = getRightDynamicCellRows(addCellData,cellDataMap,setParam,rows,cellType);
initCellPosition(addCellData,cnt,merge);
if(rows > 1){
//需要把这个静态扩展单元格 改变为 静态合并扩展单元格,就是增加合并属性 mc 以及merge配置
JSONObject mc = new JSONObject();
mc.put("rs",rows);
mc.put("cs",1);
mc.put("r",addCellData.getIntValue("r"));
mc.put("c",addCellData.getIntValue("c"));
addCellData.getJSONObject("v").put("mc",mc);
//合并单元格需要处理config.merge
merge.put((mc.getInteger("r")) + "_" + mc.getString("c"),mc);
//处理单元格扩展之后此列扩展的总行数
colAddCntMap.put(c,cnt + rows - 1);
}
break;
case STATIC_MERGE_AUTO:
//获取静态单元格右侧动态单元格的总行数
rows = getRightDynamicCellRows(addCellData,cellDataMap,setParam,rows,cellType);
initCellPosition(addCellData,cnt,merge);
if(rows > 0){
//需要修改单元格mc中的rs
JSONObject cellMc = addCellData.getJSONObject("v").getJSONObject("mc");
int addCnt = cellMc.getInteger("rs");
cellMc.put("rs",rows);
//合并单元格需要处理config.merge
merge.put((cellMc.getInteger("r")) + "_" + cellMc.getString("c"),cellMc);
//处理单元格扩展之后此列扩展的总行数
colAddCntMap.put(c,cnt + rows - addCnt);
}
break;
}
dbObject.getJSONArray("celldata").add(addCellData);
}
addCellData.put("r", r + j); /**
addCellData.put("c", c); *
addCellData.getJSONObject("v").put("v", replace); * @param addCellData
addCellData.getJSONObject("v").put("m", replace); * @param cnt
dbObject.getJSONArray("celldata").add(addCellData); * @param merge
*/
public void initCellPosition(JSONObject addCellData,int cnt,JSONObject merge){
addCellData.put("r", cnt + addCellData.getInteger("r"));//行数增加
//是否是合并单元格
JSONObject mc = addCellData.getJSONObject("v").getJSONObject("mc");
if(mc != null){
mc.put("r",addCellData.getInteger("r"));
initCellMerge(merge,mc);
}
}
} /**
*
* @param merge
* @param mc
*/
public void initCellMerge(JSONObject merge,JSONObject mc){
merge.put((mc.getInteger("r"))+"_"+mc.getString("c"),mc);
}
} /**
*
* @param addCellData
* @param cellDataMap
* @param setParam
* @param sumRows
* @param cellType
* @return
*/
public int getRightDynamicCellRows(JSONObject addCellData,Map<String,JSONObject> cellDataMap,String setParam,int sumRows,CellType cellType){
//1、获取此单元格右侧关联的所有单元格
List<JSONObject> rightCellList = getRightDynamicCell(addCellData,cellDataMap,cellType);
//2、循环获取每个单元格的扩展行数
for (JSONObject rightCell : rightCellList) {
//首先判断这个单元格是否也是【静态扩展单元格】
CellType rightCellType = getCellType(rightCell);
switch (rightCellType){
case STATIC_AUTO:
case STATIC_MERGE_AUTO:
//递归查找
sumRows = getRightDynamicCellRows(rightCell,cellDataMap,setParam,sumRows,rightCellType);
break;
case BLACK:
case STATIC:
sumRows++;
break;
case STATIC_MERGE:
sumRows += rightCell.getJSONObject("v").getJSONObject("mc").getInteger("rs");
break;
default:
List<JSONObject> cellDynamicData = getDynamicDataList(rightCell.getJSONObject("v").getString("v"),setParam);
if(cellDynamicData != null && cellDynamicData.size() > 1){
int size = cellDynamicData.size();
sumRows += size;
}else{
sumRows++;
}
break;
}
}
return sumRows;
}
} /**
*
* @param addCellData
* @param cellDataMap
* @param cellType
* @return
*/
public List<JSONObject> getRightDynamicCell(JSONObject addCellData,Map<String,JSONObject> cellDataMap,CellType cellType){
//静态数据合并单元格需要根据右侧的单元格进行自动向下扩展
//1、先获取右侧一列的关联的单元格根据自身的位置以及自己合并的合并的信息推断
//如果自己位置是 25并且本身合并 行数2列数3则需要推断出两个单元格的位置
//分别是28 和 38
Integer cellR = addCellData.getInteger("r");
Integer cellC = addCellData.getInteger("c");
Integer cellRs = 0;
Integer cellCs = 0;
switch (cellType){
case STATIC_AUTO:
cellRs = 1;
cellCs = 1;
break;
case STATIC_MERGE_AUTO:
cellRs = addCellData.getJSONObject("v").getJSONObject("mc").getInteger("rs");
cellCs = addCellData.getJSONObject("v").getJSONObject("mc").getInteger("cs");
break;
}
List<JSONObject> rightCells = new ArrayList<>();
for(int nums = 0;nums < cellRs;nums++){
int r = cellR + nums;
int c = cellC + cellCs;
String key = r + "," + c;
if(cellDataMap.containsKey(key)){
JSONObject cellData = cellDataMap.get(r + "," + c);
rightCells.add(cellData);
}
}
return rightCells;
}
/**
*
* @param cellObject
* @return
*/
public CellType getCellType(JSONObject cellObject){
JSONObject cellV1 = cellObject.getJSONObject("v");
if (null != cellV1 && cellV1.containsKey("v") && StringUtils.isNotBlank(cellV1.getString("v"))) {
String cellV2 = cellObject.getJSONObject("v").getString("v");
String auto = cellObject.getJSONObject("v").getString("auto");
JSONObject mc = cellObject.getJSONObject("v").getJSONObject("mc");
if(cellV2.contains("#{") && cellV2.contains("}") ){
//动态单元格
if(mc != null){
return CellType.DYNAMIC_MERGE;
}else{
return CellType.DYNAMIC;
}
}else{
//静态单元格
if(mc != null && "1".equals(auto)){
return CellType.STATIC_MERGE_AUTO;
}else {
if("1".equals(auto)){
return CellType.STATIC_AUTO;
}else if(mc != null){
return CellType.STATIC_MERGE;
}else{
return CellType.STATIC;
} }
} }
} }
}else{
return CellType.BLACK;
} }
} }
/**
* listmap便使cell
* @param cellDataList
* @return
*/
public Map<String,JSONObject> cellDataList2Map(List<JSONObject> cellDataList){
Map<String,JSONObject> cellDataMap = new HashMap<>();
for (JSONObject cellData : cellDataList) {
String r = cellData.getString("r");
String c = cellData.getString("c");
cellDataMap.put(r + "," + c, cellData);
}
return cellDataMap;
}
/** /**
* #{xxxx.xxxxx} * #{xxxx.xxxxx}
@ -341,6 +608,27 @@ public class ReportExcelServiceImpl implements ReportExcelService {
return null; return null;
} }
/**
*
* @param v
* @param setParam
* @return
*/
private List<JSONObject> getDynamicDataList(String v, String setParam){
if(StringUtils.isNotBlank(v)){
DataSetDto dataSet = getDataSet(v,setParam);
if(dataSet != null){
OriginalDataDto originalDataDto = dataSetService.getData(dataSet);
List<JSONObject> cellDynamicData = originalDataDto.getData();
return cellDynamicData;
}else{
return null;
}
}else{
return null;
}
}
/** /**
* *
* @param setParam * @param setParam

@ -0,0 +1,39 @@
package com.anjiplus.template.gaea.business.modules.reportexcel.util;
/**
*
*/
public enum CellType {
DYNAMIC_MERGE("DYNAMIC_MERGE","动态合并单元格"),
DYNAMIC("DYNAMIC","动态单元格"),
STATIC("STATIC","静态单元格"),
STATIC_AUTO("STATIC_AUTO","静态扩展单元格"),
STATIC_MERGE("STATIC_MERGE","静态合并单元格"),
STATIC_MERGE_AUTO("STATIC_MERGE_AUTO","静态合并扩展单元格"),
BLACK("BLACK","空白单元格");
private String code;
private String name;
CellType(String code,String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public void setCode(String code) {
this.code = code;
}
public void setName(String name) {
this.name = name;
}
}

@ -653,7 +653,7 @@ public class XlsSheetUtil {
} else { } else {
style.setDataFormat((short) 0); style.setDataFormat((short) 0);
} }
cell.setCellType(CellType.STRING); cell.setCellType(org.apache.poi.ss.usermodel.CellType.STRING);
break; break;
} }
case "d": { case "d": {
@ -692,7 +692,7 @@ public class XlsSheetUtil {
} }
case "b": { case "b": {
//逻辑 //逻辑
cell.setCellType(CellType.BOOLEAN); cell.setCellType(org.apache.poi.ss.usermodel.CellType.BOOLEAN);
if (_i >= 0) { if (_i >= 0) {
style.setDataFormat(_i.shortValue()); style.setDataFormat(_i.shortValue());
} else { } else {
@ -705,7 +705,7 @@ public class XlsSheetUtil {
//数值 //数值
// cell.setCellType(CellType.NUMERIC); // cell.setCellType(CellType.NUMERIC);
//数字转字符串 //数字转字符串
cell.setCellType(CellType.STRING); cell.setCellType(org.apache.poi.ss.usermodel.CellType.STRING);
if (_i >= 0) { if (_i >= 0) {
style.setDataFormat(_i.shortValue()); style.setDataFormat(_i.shortValue());
} else { } else {
@ -728,7 +728,7 @@ public class XlsSheetUtil {
} }
case "e": { case "e": {
//错误 //错误
cell.setCellType(CellType.ERROR); cell.setCellType(org.apache.poi.ss.usermodel.CellType.ERROR);
if (_i >= 0) { if (_i >= 0) {
style.setDataFormat(_i.shortValue()); style.setDataFormat(_i.shortValue());
} else { } else {

@ -0,0 +1,50 @@
package com.anjiplus.template.gaea.business.util;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* @author: Raod
* @since: 2022-01-21
*/
public class RequestUtil {
/**ip
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
//多次反向代理后会有多个ip值第一个ip才是真实ip
int index = XFor.indexOf(",");
if(index != -1){
return XFor.substring(0,index);
}else{
return XFor;
}
}
XFor = Xip;
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
return XFor;
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return XFor;
}
}

@ -0,0 +1,68 @@
use
aj_report;
-- 增加字段
ALTER TABLE `aj_report`.`gaea_report` ADD COLUMN `report_author` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表作者' AFTER `report_desc`;
ALTER TABLE `aj_report`.`gaea_report` ADD COLUMN `download_count` bigint(11) NULL DEFAULT NULL COMMENT '报表下载次数' AFTER `report_author`;
-- root权限更新
delete from access_role_authority where role_code = 'root';
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'authorityManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'authorityManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'authorityManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'authorityManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'roleManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'roleManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'roleManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'roleManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'roleManage', 'grantAuthority');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'userManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'userManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'userManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'userManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'userManage', 'resetPassword');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'userManage', 'grantRole');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'datasourceManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'datasourceManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'datasourceManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'datasourceManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'resultsetManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'resultsetManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'resultsetManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'resultsetManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'reportManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'reportManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'reportManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'reportManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'bigScreenManage', 'share');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'bigScreenManage', 'view');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'bigScreenManage', 'design');
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');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'excelManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'excelManage', 'view');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'excelManage', 'export');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'fileManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'fileManage', 'upload');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'fileManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'fileManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictManage', 'delete');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictManage', 'fresh');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictItemManage', 'query');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictItemManage', 'insert');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictItemManage', 'update');
INSERT INTO `aj_report`.`access_role_authority`(`id`, `role_code`, `target`, `action`) VALUES (default, 'root', 'dictItemManage', 'delete');
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 (237, 'report', 'excelManage', '表格报表', 'insert', '新建表格', 237, 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 (238, 'report', 'excelManage', '表格报表', 'update', '更新表格', 238, 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 (239, 'report', 'excelManage', '表格报表', 'view', '查看表格', 239, 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 (240, 'report', 'excelManage', '表格报表', 'export', '导出表格', 240, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);

@ -1,36 +0,0 @@
import request from '@/api/axios'
// 查询字典
export function queryForCodeSelect(params={}) {
return request({
url: '/auth-service/dict/queryForCodeSelect',
method: 'post',
data: params
})
}
// 查询标题
export function querytitleByCategory(params) {
return request({
url: '/auth-service/help/querytitleByCategory',
method: 'post',
data: params
})
}
// 关键词查询
export function searchKeyWord(params = {}) {
return request({
url: '/auth-service/help/searchKeyWord',
method: 'post',
data: params
})
}
export function queryById(data) {
return request({
url: '/auth-service/help/queryById',
method: 'post',
data
})
}

@ -10,7 +10,7 @@ export function reportShareList(params) {
export function reportShareAdd(data) { export function reportShareAdd(data) {
return request({ return request({
url: 'report/share', url: 'reportDashboard/share',
method: 'post', method: 'post',
data data
}) })

@ -54,6 +54,12 @@
<div class="content unicode" style="display: block;"> <div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe7af;</span>
<div class="name">词云图</div>
<div class="code-name">&amp;#xe7af;</div>
</li>
<li class="dib"> <li class="dib">
<span class="icon iconfont">&#xe618;</span> <span class="icon iconfont">&#xe618;</span>
<div class="name">导出</div> <div class="name">导出</div>
@ -786,9 +792,9 @@
<pre><code class="language-css" <pre><code class="language-css"
>@font-face { >@font-face {
font-family: 'iconfont'; font-family: 'iconfont';
src: url('iconfont.woff2?t=1629797734566') format('woff2'), src: url('iconfont.woff2?t=1643094287456') format('woff2'),
url('iconfont.woff?t=1629797734566') format('woff'), url('iconfont.woff?t=1643094287456') format('woff'),
url('iconfont.ttf?t=1629797734566') format('truetype'); url('iconfont.ttf?t=1643094287456') format('truetype');
} }
</code></pre> </code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3> <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -814,6 +820,15 @@
<div class="content font-class"> <div class="content font-class">
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont iconciyuntu"></span>
<div class="name">
词云图
</div>
<div class="code-name">.iconciyuntu
</div>
</li>
<li class="dib"> <li class="dib">
<span class="icon iconfont icondaochu"></span> <span class="icon iconfont icondaochu"></span>
<div class="name"> <div class="name">
@ -1912,6 +1927,14 @@
<div class="content symbol"> <div class="content symbol">
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconciyuntu"></use>
</svg>
<div class="name">词云图</div>
<div class="code-name">#iconciyuntu</div>
</li>
<li class="dib"> <li class="dib">
<svg class="icon svg-icon" aria-hidden="true"> <svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icondaochu"></use> <use xlink:href="#icondaochu"></use>

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 1513211 */ font-family: "iconfont"; /* Project id 1513211 */
src: url("iconfont.woff2?t=1629797734566") format("woff2"), src: url('iconfont.woff2?t=1643094287456') format('woff2'),
url("iconfont.woff?t=1629797734566") format("woff"), url('iconfont.woff?t=1643094287456') format('woff'),
url("iconfont.ttf?t=1629797734566") format("truetype"); url('iconfont.ttf?t=1643094287456') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.iconciyuntu:before {
content: "\e7af";
}
.icondaochu:before { .icondaochu:before {
content: "\e618"; content: "\e618";
} }
@ -488,3 +492,4 @@
.iconjiantou-copy-copy:before { .iconjiantou-copy-copy:before {
content: "\e654"; content: "\e654";
} }

File diff suppressed because one or more lines are too long

@ -5,6 +5,13 @@
"css_prefix_text": "icon", "css_prefix_text": "icon",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "23043843",
"name": "词云图",
"font_class": "ciyuntu",
"unicode": "e7af",
"unicode_decimal": 59311
},
{ {
"icon_id": "14325372", "icon_id": "14325372",
"name": "导出", "name": "导出",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,761 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"adcode": 710000,
"name": "台湾省",
"center": [
121.509062,
25.044332
],
"centroid": [
120.971485,
23.749452
],
"childrenNum": 0,
"level": "province",
"acroutes": [
100000
],
"parent": {
"adcode": 100000
}
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
120.443558,
22.441245
],
[
120.517584,
22.408536
],
[
120.569903,
22.361728
],
[
120.640505,
22.241347
],
[
120.659209,
22.15432
],
[
120.662001,
22.066983
],
[
120.651464,
22.033165
],
[
120.667691,
21.983168
],
[
120.70157,
21.927065
],
[
120.743246,
21.915569
],
[
120.78155,
21.923957
],
[
120.85468,
21.883333
],
[
120.87291,
21.897387
],
[
120.866482,
21.98436
],
[
120.907315,
22.033208
],
[
120.904154,
22.119757
],
[
120.914955,
22.302718
],
[
120.981658,
22.528305
],
[
121.015009,
22.584168
],
[
121.033292,
22.650725
],
[
121.078498,
22.669656
],
[
121.170544,
22.723133
],
[
121.210481,
22.770665
],
[
121.237931,
22.836327
],
[
121.324708,
22.945666
],
[
121.354687,
23.01006
],
[
121.370388,
23.084347
],
[
121.409535,
23.102669
],
[
121.430294,
23.137196
],
[
121.415015,
23.195973
],
[
121.440358,
23.272096
],
[
121.479558,
23.3223
],
[
121.497788,
23.419789
],
[
121.521497,
23.483198
],
[
121.523078,
23.538708
],
[
121.587778,
23.76102
],
[
121.621604,
23.92075
],
[
121.659381,
24.006893
],
[
121.639992,
24.064276
],
[
121.643838,
24.097713
],
[
121.678085,
24.133906
],
[
121.689044,
24.174401
],
[
121.809172,
24.339055
],
[
121.826717,
24.423579
],
[
121.867498,
24.478978
],
[
121.885464,
24.529677
],
[
121.892524,
24.617912
],
[
121.862598,
24.671515
],
[
121.837993,
24.76015
],
[
121.845053,
24.836269
],
[
121.932883,
24.938645
],
[
122.012178,
25.001469
],
[
121.980776,
25.03079
],
[
121.947425,
25.031955
],
[
121.917077,
25.137908
],
[
121.842155,
25.135332
],
[
121.782407,
25.160425
],
[
121.750531,
25.160716
],
[
121.707327,
25.191493
],
[
121.700319,
25.226913
],
[
121.655324,
25.241859
],
[
121.623026,
25.294694
],
[
121.584986,
25.308926
],
[
121.535038,
25.307515
],
[
121.444415,
25.270624
],
[
121.413487,
25.238912
],
[
121.371864,
25.159885
],
[
121.319281,
25.140691
],
[
121.209322,
25.127104
],
[
121.133135,
25.078728
],
[
121.102102,
25.075153
],
[
121.024704,
25.040479
],
[
121.009688,
24.993649
],
[
120.960899,
24.940227
],
[
120.908475,
24.852012
],
[
120.892299,
24.767526
],
[
120.823753,
24.688321
],
[
120.762371,
24.658335
],
[
120.688661,
24.600678
],
[
120.64277,
24.490172
],
[
120.589187,
24.432354
],
[
120.546299,
24.370413
],
[
120.521009,
24.312038
],
[
120.470534,
24.24259
],
[
120.451461,
24.182691
],
[
120.392029,
24.11824
],
[
120.316158,
23.984881
],
[
120.278276,
23.927798
],
[
120.245768,
23.840553
],
[
120.175377,
23.807385
],
[
120.102773,
23.700981
],
[
120.094817,
23.587466
],
[
120.121741,
23.504664
],
[
120.107831,
23.341264
],
[
120.081434,
23.29191
],
[
120.018947,
23.073115
],
[
120.029537,
23.048623
],
[
120.131382,
23.002118
],
[
120.149138,
22.896715
],
[
120.200403,
22.721101
],
[
120.274272,
22.560181
],
[
120.297191,
22.531315
],
[
120.443558,
22.441245
]
]
],
[
[
[
124.542984,
25.903911
],
[
124.586346,
25.913777
],
[
124.572805,
25.93974
],
[
124.541825,
25.931031
],
[
124.542984,
25.903911
]
]
],
[
[
[
123.445286,
25.725966
],
[
123.472104,
25.713024
],
[
123.508933,
25.723237
],
[
123.514834,
25.751226
],
[
123.483063,
25.768587
],
[
123.444496,
25.746514
],
[
123.445286,
25.725966
]
]
],
[
[
[
119.64597,
23.55091
],
[
119.701081,
23.550657
],
[
119.678057,
23.600041
],
[
119.610089,
23.603953
],
[
119.594388,
23.577245
],
[
119.566306,
23.584732
],
[
119.562565,
23.530377
],
[
119.573788,
23.505885
],
[
119.609141,
23.503864
],
[
119.64597,
23.55091
]
]
],
[
[
[
123.667207,
25.914066
],
[
123.707092,
25.916873
],
[
123.678008,
25.938667
],
[
123.667207,
25.914066
]
]
],
[
[
[
119.506031,
23.625567
],
[
119.505241,
23.575814
],
[
119.472416,
23.557136
],
[
119.523207,
23.563699
],
[
119.525578,
23.624895
],
[
119.506031,
23.625567
]
]
],
[
[
[
119.49739,
23.386683
],
[
119.495125,
23.350156
],
[
119.516885,
23.349903
],
[
119.49739,
23.386683
]
]
],
[
[
[
119.557454,
23.666474
],
[
119.604083,
23.616989
],
[
119.615516,
23.660925
],
[
119.586485,
23.675974
],
[
119.557454,
23.666474
]
]
],
[
[
[
121.46823,
22.676644
],
[
121.476502,
22.64166
],
[
121.513541,
22.631833
],
[
121.5147,
22.67639
],
[
121.46823,
22.676644
]
]
],
[
[
[
121.510538,
22.087185
],
[
121.507693,
22.048523
],
[
121.534089,
22.022146
],
[
121.594522,
21.995382
],
[
121.604586,
22.022699
],
[
121.575028,
22.037122
],
[
121.575607,
22.084421
],
[
121.510538,
22.087185
]
]
],
[
[
[
122.097533,
25.500168
],
[
122.093581,
25.47183
],
[
122.124825,
25.475932
],
[
122.097533,
25.500168
]
]
],
[
[
[
119.421467,
23.216684
],
[
119.421309,
23.18935
],
[
119.453396,
23.217697
],
[
119.421467,
23.216684
]
]
],
[
[
[
120.355042,
22.327259
],
[
120.395454,
22.342287
],
[
120.383072,
22.355573
],
[
120.355042,
22.327259
]
]
]
]
}
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,139 @@
<template>
<el-autocomplete
v-model.trim="inputValue"
:debounce="500"
class="inline-input"
:fetch-suggestions="querySearch"
:disabled="disabled"
@select="handleSelect"
@input="changeInput"
>
<template slot-scope="{ item }">
<div class="name">{{ getItemLabel(item, item.value) }}</div>
<span class="addr">{{ item[option] }}</span>
</template>
</el-autocomplete>
</template>
<script>
import request from "@/utils/request";
export default {
props: {
disabled: {
type: Boolean,
default: () => {
return false;
}
},
value: {
type: String,
default: () => {
return "";
}
},
url: {
type: String,
default: () => {
return "";
}
},
appointValue: {
type: String,
default: () => {
return "";
}
},
label: {
type: String,
default: () => {
return "";
}
},
option: {
type: String,
default: () => {
return "";
}
}
},
data() {
return {
restaurants: [],
inputValue: ""
};
},
watch: {
value(val) {
this.echoInput(val);
}
},
mounted() {
this.echoInput(this.value);
},
methods: {
getItemLabel(item, value) {
if (this.label.indexOf("${") < 0 && this.label.indexOf("}" < 0)) {
return item[this.label];
}
let reg = /\$\{[a-zA-Z0-9]*\}/g;
let list = this.label.match(reg);
console.log(list);
// ["${id}", "${text}"]
let result = this.label;
for (let i = 0; i < list.length; i++) {
let sub = list[i];
let key = sub.replace("${", "").replace("}", "");
result = result.replace(sub, item[key]);
}
return value + " " + result;
},
querySearch(queryString, cb) {
request({ url: this.url }).then(res => {
if (res.code == 200 && res.data) {
this.restaurants = res.data;
} else {
this.restaurants = [];
}
this.restaurants = JSON.parse(
JSON.stringify(this.restaurants).replace(
new RegExp(this.appointValue, "g"),
"value"
)
);
let results = queryString
? this.restaurants.filter(this.createFilter(queryString))
: this.restaurants;
cb(results);
});
},
createFilter(queryString) {
return restaurant => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) ===
0
);
};
},
handleSelect(item) {
this.$emit("input", item.value);
this.$emit("change", item.value, item);
},
changeInput(val) {
this.$emit("input", val);
this.$emit("change", val);
},
//
echoInput(value) {
if (!value) {
this.inputValue = "";
} else {
this.inputValue = value;
}
}
}
};
</script>
<style lang="less" scoped>
.inline-input {
width: 100%;
}
</style>

@ -0,0 +1,313 @@
<template>
<div>
<el-row>
<el-col v-if="selectIsHide('country')" :span="4">
<el-select
v-model.trim="countryCode"
filterable
placeholder="请选择国家"
:disabled="disabled"
clearable
@change="countryChange"
>
<el-option
v-for="(option, i) in countryArr"
:key="i"
:value="option.value"
:label="option.label"
/>
</el-select>
</el-col>
<el-col v-if="selectIsHide('province')" :span="7">
<el-select
v-model.trim="provinceCode"
filterable
placeholder="请选择省"
:disabled="disabled"
clearable
@change="provinceChange"
>
<el-option
v-for="(option, i) in casCaredArr"
:key="i"
:value="option.value"
:label="option.label"
/>
</el-select>
</el-col>
<el-col v-if="selectIsHide('city')" :span="7">
<el-select
v-model.trim="cityCode"
filterable
placeholder="请选择市"
:disabled="disabled"
clearable
@change="cityChange"
>
<el-option
v-for="(option, x) in cityArr"
:key="x"
:value="option.value"
:label="option.label"
/>
</el-select>
</el-col>
<el-col v-if="selectIsHide('area')" :span="6">
<el-select
v-model.trim="areaCode"
filterable
placeholder="请选择区"
:disabled="disabled"
clearable
@change="districtChange"
>
<el-option
v-for="(option, y) in districtArr"
:key="y"
:value="option.value"
:label="option.label"
/>
</el-select>
</el-col>
</el-row>
</div>
</template>
<script>
import axios from "axios";
import { getToken } from "@/utils/auth";
export default {
name: "Cselect",
props: {
url: {
type: String,
default: () => "/meta/metaAreaInfo/countryTree"
},
value: null,
singleDisplay: String,
disabled: Boolean
},
data() {
return {
countryArr: [],
casCaredArr: [],
cityArr: [],
districtArr: [],
countryCode: "", // code
provinceCode: "", // code
cityCode: "", // code
areaCode: "", // code
countryName: "",
provinceName: "",
cityName: "",
areaName: ""
};
},
watch: {
value(value) {
this.echoSelect(value);
this.initData();
}
},
mounted() {
this.initData();
this.echoSelect(this.value);
},
methods: {
// singleDisplay country province city area
selectIsHide(val) {
if (this.singleDisplay === undefined) {
return true;
} else {
return !(this.singleDisplay.indexOf(val) >= 0);
}
},
//
initData() {
this.queryData();
},
queryData() {
axios({
url: process.env.VUE_APP_BASE_API + this.url,
methods: "get",
headers: {
Authorization: getToken(),
systemCode: process.env.VUE_APP_SYSTEM_CODE
}
}).then(res => {
const data = res.data;
if (data.code != 200 || data.data.length == 0) return;
this.countryArr = data.data;
!this.selectIsHide("country") &&
(this.casCaredArr = data.data[0].children);
this.updateCountry();
this.updateCity();
this.updateDistrict();
});
},
updateCountry() {
for (let i in this.countryArr) {
let obj = this.countryArr[i];
if (obj.value == this.countryCode) {
this.casCaredArr = obj.children;
break;
}
}
},
updateCity() {
for (let i in this.casCaredArr) {
let obj = this.casCaredArr[i];
if (obj.value) {
if (obj.value == this.provinceCode) {
this.cityArr = obj.children;
break;
}
}
}
},
updateDistrict() {
for (let i in this.cityArr) {
let obj = this.cityArr[i];
if (obj.value == this.cityCode) {
this.districtArr = obj.children;
break;
}
}
},
//
countryChange(val) {
if (val) {
this.updateCountry();
this.provinceCode = "";
this.cityCode = "";
this.areaCode = "";
const casCared = this.countryArr.find((n, index) => {
if (n.value == val) {
return n;
}
});
this.countryName = casCared.label;
const obj = {
countryName: this.countryName,
countryCode: this.countryCode,
provinceCode: this.provinceCode,
cityCode: this.cityCode,
areaCode: this.areaCode,
provinceName: this.provinceName,
cityName: this.cityName,
areaName: this.areaName
};
this.$emit("input", obj);
this.$emit("change", obj);
} else {
this.$emit("input", {});
this.$emit("change", {});
}
},
//
provinceChange(val) {
if (val) {
this.updateCity();
this.cityCode = "";
this.areaCode = "";
const casCared = this.casCaredArr.find((n, index) => {
if (n.value == val) {
return n;
}
});
this.provinceName = casCared.label;
const obj = {
countryName: this.countryName,
countryCode: this.countryCode,
provinceCode: this.provinceCode,
cityCode: this.cityCode,
areaCode: this.areaCode,
provinceName: this.provinceName,
cityName: this.cityName,
areaName: this.areaName
};
this.$emit("input", obj);
this.$emit("change", obj);
} else {
this.$emit("input", {});
this.$emit("change", {});
}
},
//
cityChange(val) {
if (val) {
this.areaCode = "";
this.updateDistrict();
const city = this.cityArr.find((n, index) => {
if (n.value == val) {
return n;
}
});
this.cityName = city.label;
const obj = {
countryName: this.countryName,
countryCode: this.countryCode,
provinceCode: this.provinceCode,
cityCode: this.cityCode,
areaCode: this.areaCode,
provinceName: this.provinceName,
cityName: this.cityName,
areaName: this.areaName
};
this.$emit("input", obj);
this.$emit("change", obj);
} else {
this.$emit("input", {});
this.$emit("change", {});
}
},
//
districtChange(val) {
if (val) {
const district = this.districtArr.find((n, index) => {
if (n.value == val) {
return n;
}
});
this.areaName = district.label;
const obj = {
countryName: this.countryName,
countryCode: this.countryCode,
provinceCode: this.provinceCode,
cityCode: this.cityCode,
areaCode: this.areaCode,
provinceName: this.provinceName,
cityName: this.cityName,
areaName: this.areaName
};
this.$emit("input", obj);
this.$emit("change", obj);
} else {
this.$emit("input", {});
this.$emit("change", {});
}
},
echoSelect(value) {
if (!value) {
this.countryCode = "";
this.provinceCode = "";
this.cityCode = "";
this.areaCode = "";
this.countryName = "";
this.provinceName = "";
this.cityName = "";
this.areaName = "";
} else {
this.countryName = this.value.countryName;
this.countryCode = this.value.countryCode;
this.provinceCode = this.value.provinceCode;
this.cityCode = this.value.cityCode;
this.areaCode = this.value.areaCode || this.value.regionCode;
this.provinceName = this.value.provinceName;
this.cityName = this.value.cityName;
this.areaName = this.value.areaName || this.value.regionName;
}
}
}
};
</script>

@ -0,0 +1,126 @@
<template>
<el-checkbox-group v-model="selectValue" class="filter-item" @change="change">
<el-checkbox
v-for="item in options"
:key="item.id"
:label="item.id"
:disabled="disabled"
>{{ item.text }}</el-checkbox
>
</el-checkbox-group>
</template>
<script>
import request from "@/utils/request";
export default {
props: {
dictCode: null, // dictCodeurl
url: null,
value: null,
placeholder: null,
label: {
type: String,
default: "text"
},
option: {
type: String,
default: "id"
},
multiple: null,
localOptions: null,
disabled: null,
clearable: {
type: Boolean,
default: true
},
collapseTags: {
type: Boolean,
default: false
}
},
data() {
return {
options: null,
selectValue: []
};
},
computed: {
// dictCodeurlurl
requestUrl() {
if (this.url != null && this.url.trim() != "") {
return this.url;
}
if (this.dictCode != null && this.dictCode.trim() != "") {
return `/tms/gaeaDict/select/${this.dictCode}`;
}
return null;
}
},
watch: {
value: function(val, oldVal) {
this.echoCheckboxValue(val);
}
},
mounted() {
this.echoCheckboxValue(this.value);
if (this.requestUrl == null) {
this.options = this.localOptions;
return;
}
this.queryData();
},
methods: {
change(value) {
const strValue = value.join(",");
if (value === "") {
value = null;
}
this.$emit("input", strValue);
this.$emit("change", strValue, this.options);
},
// localStorage gaeaDict
getOptionsFromLocalStorage() {
let dicts = JSON.parse(localStorage.getItem("gaeaDict"));
let options = [];
if (!dicts.hasOwnProperty(this.dictCode)) {
return [];
}
let dictItems = dicts[this.dictCode];
for (let i = 0; i < dictItems.length; i++) {
let dictItem = dictItems[i];
options.push({ id: dictItem.id.toString(), text: dictItem.text });
}
return options;
},
queryData() {
// localStorageApp.vue
let options = this.getOptionsFromLocalStorage();
if (this.isNotBlank(options)) {
this.options = options;
return;
}
// localStorage
if (this.requestUrl == null) {
return;
}
request({
url: this.requestUrl,
params: {
multiple: this.multiple == null ? null : 1
}
}).then(response => {
this.options = response.data;
});
},
//
echoCheckboxValue(val) {
if (!val) {
this.selectValue = [];
} else {
const arr = val.split(",");
this.selectValue = arr;
}
}
}
};
</script>

@ -0,0 +1,50 @@
<!--
* @Descripttion: 右键菜单
* @version:
* @Author: qianlishi
* @Date: 2021-10-21 15:52:03
* @LastEditors: qianlishi
* @LastEditTime: 2021-10-21 19:40:05
-->
<template>
<div v-show="visible" class="contentmenu" :style="styleObj">
<slot />
</div>
</template>
<script>
export default {
props: {
styleObj: Object,
visible: Boolean,
},
data() {
return {}
},
watch: {
visible(value) {
if (value) {
document.body.addEventListener('click', this.closeMenu)
} else {
document.body.removeEventListener('click', this.closeMenu)
}
},
},
methods: {
closeMenu() {
this.$emit('update:visible', false)
},
},
}
</script>
<style lang="scss" scoped>
.contentmenu {
position: fixed;
z-index: 99999;
list-style: none;
-webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
padding: 0;
background: #fff;
cursor: pointer;
}
</style>

@ -0,0 +1,97 @@
<template>
<el-cascader v-model="selectValue" style="width: 100%" :props="{ lazy: true, lazyLoad: lazyLoad, label: 'text', value: 'id' }" :options="countryCity" />
</template>
<script>
import { mapGetters } from 'vuex'
export default {
props: {
value: null,
},
computed: {
...mapGetters(['countryCity']),
selectValue: {
get: function() {
return [...this.value]
},
set: function(val) {
this.$emit('update:value', val)
},
},
},
mounted() {
if (this.value && this.value.length > 0) {
this.initCity()
} else {
this.$store.dispatch('dict/add_countryCity', { level: 0 })
}
},
methods: {
getCityName() {
const value = this.selectValue
const country = this.countryCity.find((item) => item.id === value[0])
const province = country.children.find((item) => item.id === value[1])
const city = province.children.find((item) => item.id === value[2])
const region = city.children.find((item) => item.id === value[3])
return [country.text, province.text, city.text, region.text]
},
//
initCity() {
const value = this.value
// console.log(value)
if (!value) {
return
}
const country = this.countryCity.find((item) => item.id === value[0])
console.log(country)
if (!country || !country.children) {
this.getData().then((list) => {
this.getData({ country: value[0], level: 1 }).then((list) => {
this.getData({ country: value[0], province: value[1], level: 2 }).then((list) => {
this.getData({ country: value[0], province: value[1], city: value[2], level: 3, update: true }).then((list) => {})
})
})
})
} else {
const province = country.children.find((item) => item.id === value[1])
if (!province || !province.children) {
this.getData({ country: value[0], level: 1 }).then((list) => {
this.getData({ country: value[0], province: value[1], level: 2 }).then((list) => {
this.getData({ country: value[0], province: value[1], city: value[2], level: 3, update: true }).then((list) => {})
})
})
} else {
const city = province.children.find((item) => item.id === value[2])
if (!city || !city.children) {
this.getData({ country: value[0], province: value[1], level: 2 }).then((list) => {
this.getData({ country: value[0], province: value[1], city: value[2], level: 3, update: true }).then((list) => {})
})
} else {
const region = city.children.find((item) => item.id === value[3])
if (!region) {
this.getData({ country: value[0], province: value[1], city: value[2], level: 3, update: true }).then((list) => {})
}
}
}
}
},
getData(params) {
return this.$store.dispatch('dict/add_countryCity', params)
},
lazyLoad(node, resolve) {
console.log(node)
const { level, path, data } = node
if (data && data.children) {
resolve(data.children)
} else {
if (level === 0) {
return
}
const params = { country: path[0], province: path[1], city: path[2], level }
this.$store.dispatch('dict/add_countryCity', params).then((list) => resolve(list))
}
},
},
}
</script>

File diff suppressed because it is too large Load Diff

@ -1,11 +1,8 @@
<!--
* @Author: lide1202@hotmail.com
* @Date: 2021-5-4 11:04:24
* @Last Modified by: lide1202@hotmail.com
* @Last Modified time: 2021-5-6 11:04:24
!-->
<template> <template>
<div v-if="option['hide'] == null || option['hide'] == false" class="anji-card"> <div
v-if="option['hide'] == null || option['hide'] == false"
class="anji-card"
>
<div class="card-head"> <div class="card-head">
{{ option.title }} {{ option.title }}
<div class="main-card-header-button"> <div class="main-card-header-button">
@ -15,30 +12,91 @@
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
<el-form ref="editForm" :model="editForm" :label-width="option.labelWidth || '100px'"> <el-form
ref="editForm"
:model="editForm"
:label-width="option.labelWidth || '100px'"
>
<!--:disabled="modelType == 'view'"--> <!--:disabled="modelType == 'view'"-->
<template v-for="group in columnGroups"> <template v-for="group in columnGroups">
<el-divider v-if="groupModel" :key="group" content-position="left">{{ group }}</el-divider> <el-divider v-if="groupModel" :key="group" content-position="left">{{
group
}}</el-divider>
<el-row :key="group" class="form_table"> <el-row :key="group" class="form_table">
<template v-for="item in groupFormFields[group]"> <template v-for="item in groupFormFields[group]">
<el-col v-if="fieldIsHide(item.editHide) == false" :key="item.editField" :span="item.rowColSpan == null ? cardRowColSpan : item.rowColSpan"> <el-col
<el-form-item :label="item.label" :rules="item.rules" :prop="item.editField" :disabled="item.disabled"> v-if="fieldIsHide(item.editHide) == false"
:key="item.editField"
:span="
item.rowColSpan == null ? cardRowColSpan : item.rowColSpan
"
>
<el-form-item
:label="item.label"
:rules="item.rules"
:prop="item.editField"
:disabled="item.disabled"
>
<!-- 输入框 --> <!-- 输入框 -->
<span v-if="item.tips != '' && item.tips != null" :style="{ 'margin-left': '-13px' }" class="input_tips"> <span
<el-tooltip class="item" effect="dark" :content="item.tips" placement="top-start"> v-if="item.tips != '' && item.tips != null"
:style="{ 'margin-left': '-13px' }"
class="input_tips"
>
<el-tooltip
class="item"
effect="dark"
:content="item.tips"
placement="top-start"
>
<svg-icon icon-class="tishi-yiwen" /> <svg-icon icon-class="tishi-yiwen" />
</el-tooltip> </el-tooltip>
</span> </span>
<el-input v-if="item.inputType == 'input'" v-model.trim="editForm[item.editField]" :placeholder="item.placeholder || '请输入'" :clearable="item.clearable !== false" :disabled="fieldIsDisable(item.disabled)" @change="(value) => formChange(item.editField, value, null)" /> <el-input
v-if="item.inputType == 'input'"
v-model.trim="editForm[item.editField]"
:placeholder="item.placeholder || '请输入'"
:clearable="item.clearable !== false"
:disabled="fieldIsDisable(item.disabled)"
@change="value => formChange(item.editField, value, null)"
/>
<!-- 开关 --> <!-- 开关 -->
<el-switch v-else-if="item.inputType == 'switch'" v-model.trim="editForm[item.editField]" :disabled="fieldIsDisable(item.disabled)" :active-value="1" :inactive-value="0" inactive-color="#ccc" active-color="#5887fb" @change="(value) => formChange(item.editField, value, null)" /> <el-switch
<el-input-number v-else-if="item.inputType == 'input-number'" v-model.trim="editForm[item.editField]" :min="item.inputNumberOption.min" :max="item.inputNumberOption.max" :placeholder="item.placeholder || '请输入'" :clearable="item.clearable !== false" :disabled="fieldIsDisable(item.disabled)" @change="(value) => formChange(item.editField, value, null)" /> v-else-if="item.inputType == 'switch'"
v-model.trim="editForm[item.editField]"
:disabled="fieldIsDisable(item.disabled)"
:active-value="1"
:inactive-value="0"
inactive-color="#ccc"
active-color="#5887fb"
@change="value => formChange(item.editField, value, null)"
/>
<el-input-number
v-else-if="item.inputType == 'input-number'"
v-model.trim="editForm[item.editField]"
:min="item.inputNumberOption.min"
:max="item.inputNumberOption.max"
:placeholder="item.placeholder || '请输入'"
:clearable="item.clearable !== false"
:disabled="fieldIsDisable(item.disabled)"
@change="value => formChange(item.editField, value, null)"
/>
<!-- 自定义input --> <!-- 自定义input -->
<anji-input v-else-if="item.inputType == 'anji-input'" v-model.trim="editForm[item.editField]" :unit="item.anjiInput.unit" :conversion="item.anjiInput.conversion" :keep-point="item.anjiInput.keepPoint" :rounding="item.anjiInput.rounding" :placeholder="item.placeholder || '请输入'" :clearable="item.clearable !== false" :disabled="fieldIsDisable(item.disabled)" @change="(value) => formChange(item.editField, value, null)" /> <anji-input
v-else-if="item.inputType == 'anji-input'"
v-model.trim="editForm[item.editField]"
:unit="item.anjiInput.unit"
:default-unit="item.anjiInput.defaultUnit"
:placeholder="item.placeholder || '请输入'"
:clearable="item.clearable !== false"
:disabled="fieldIsDisable(item.disabled)"
@change="value => formChange(item.editField, value, null)"
/>
<!-- 下拉框 --> <!-- 下拉框 -->
<anji-select <anji-select
v-else-if="item.inputType == 'anji-select'" v-else-if="item.inputType == 'anji-select'"
v-model.trim="editForm[item.editField]" v-model.trim="editForm[item.editField]"
:allow-create="item.anjiSelectOption.allowCreate"
:multiple="item.anjiSelectOption.multiple" :multiple="item.anjiSelectOption.multiple"
:disabled="fieldIsDisable(item.disabled)" :disabled="fieldIsDisable(item.disabled)"
:dict-code="item.anjiSelectOption.dictCode" :dict-code="item.anjiSelectOption.dictCode"
@ -51,21 +109,93 @@
:label="item.anjiSelectOption.label" :label="item.anjiSelectOption.label"
:remote-filter="item.anjiSelectOption.remoteFilter" :remote-filter="item.anjiSelectOption.remoteFilter"
:disabled-options="item.anjiSelectOption.disabledOptions" :disabled-options="item.anjiSelectOption.disabledOptions"
@change="(value, option) => formChange(item.editField, value, option)" :select-keyword="item.anjiSelectOption.selectKeyword"
@change="
(value, option) =>
formChange(item.editField, value, option)
"
/> />
<!-- 日期时间框 --> <!-- 日期时间框 -->
<el-date-picker v-else-if="item.inputType.indexOf('date') >= 0" v-model="editForm[item.editField]" style="width: 100%" :placeholder="item.placeholder || '请选择'" :type="item.inputType" :format="item.format" :value-format="item.valueFormat" :disabled="fieldIsDisable(item.disabled)" :clearable="item.clearable !== false" @change="(value) => formChange(item.editField, value, null)" /> <el-date-picker
v-else-if="item.inputType.indexOf('date') >= 0"
v-model="editForm[item.editField]"
style="width: 100%"
:placeholder="item.placeholder || '请选择'"
:type="item.inputType"
:format="item.format"
:value-format="item.valueFormat"
:disabled="fieldIsDisable(item.disabled)"
:clearable="item.clearable !== false"
@change="value => formChange(item.editField, value, null)"
/>
<!-- checkbox --> <!-- checkbox -->
<anji-checkbox v-else-if="item.inputType == 'checkbox'" v-model.trim="editForm[item.editField]" :dict-code="item.anjiCheckbox.dictCode" :label="item.anjiCheckbox.label" :disabled="fieldIsDisable(item.disabled)" @change="(value, options) => formChange(item.editField, value, options)" /> <anji-checkbox
v-else-if="item.inputType == 'checkbox'"
v-model.trim="editForm[item.editField]"
:dict-code="item.anjiCheckbox.dictCode"
:url="item.anjiCheckbox.url"
:label="item.anjiCheckbox.label"
:disabled="fieldIsDisable(item.disabled)"
@change="
(value, options) =>
formChange(item.editField, value, options)
"
/>
<!-- 城市三级联动 --> <!-- 城市三级联动 -->
<anji-cascader v-else-if="item.inputType == 'anji-cascader'" v-model.trim="editForm[item.editField]" :disabled="fieldIsDisable(item.disabled)" :url="item.anjiCascader.url" @change="(value) => formChange(item.editField, value, null)" /> <anji-cascader
v-else-if="item.inputType == 'anji-cascader'"
v-model.trim="editForm[item.editField]"
:disabled="fieldIsDisable(item.disabled)"
:single-display="item.anjiCascader.singleDisplay"
:url="item.anjiCascader.url"
@change="value => formChange(item.editField, value, null)"
/>
<!-- 上传组件 --> <!-- 上传组件 -->
<anji-upload v-else-if="item.inputType == 'anji-upload'" v-model.trim="editForm[item.editField]" :up-load-url="item.anjiUpload.upLoadUrl" :view-url="item.anjiUpload.viewUrl" :upload-type="item.anjiUpload.uploadType" :limit="item.anjiUpload.limit" @change="(value) => formChange(item.editField, value, null)" /> <anji-upload
v-else-if="item.inputType == 'anji-upload'"
v-model.trim="editForm[item.editField]"
:up-load-url="item.anjiUpload.upLoadUrl"
:view-url="item.anjiUpload.viewUrl"
:upload-type="item.anjiUpload.uploadType"
:limit="item.anjiUpload.limit"
@change="value => formChange(item.editField, value, null)"
/>
<!-- input自带输入建议 --> <!-- input自带输入建议 -->
<anji-autocomplete v-else-if="item.inputType == 'anji-autocomplete'" v-model.trim="editForm[item.editField]" :disabled="fieldIsDisable(item.disabled)" :label="item.anjiAutocomplete.label" :option="item.anjiAutocomplete.option" :appoint-value="item.anjiAutocomplete.appointValue" :url="item.anjiAutocomplete.url" @change="(value, option) => formChange(item.editField, value, option)" /> <anji-autocomplete
v-else-if="item.inputType == 'anji-autocomplete'"
v-model.trim="editForm[item.editField]"
:disabled="fieldIsDisable(item.disabled)"
:label="item.anjiAutocomplete.label"
:option="item.anjiAutocomplete.option"
:appoint-value="item.anjiAutocomplete.appointValue"
:url="item.anjiAutocomplete.url"
@change="
(value, option) =>
formChange(item.editField, value, option)
"
/>
<!-- textarea --> <!-- textarea -->
<el-input v-else-if="item.inputType == 'textarea'" v-model.trim="editForm[item.editField]" :placeholder="item.placeholder || '请输入'" :clearable="item.clearable !== false" :disabled="fieldIsDisable(item.disabled)" type="textarea" :rows="2" @change="(value) => formChange(item.editField, value, null)" /> <el-input
<el-input v-else placeholder="组件不支持此类型表单请至组件内部自行扩展" disabled /> v-else-if="item.inputType == 'textarea'"
v-model.trim="editForm[item.editField]"
:placeholder="item.placeholder || '请输入'"
:clearable="item.clearable !== false"
:disabled="fieldIsDisable(item.disabled)"
type="textarea"
:rows="2"
@change="value => formChange(item.editField, value, null)"
/>
<!-- 城市四级联动 -->
<anji-fourlevel
v-else-if="item.inputType == 'anji-country'"
v-model.trim="editForm[item.editField]"
@change="value => formChange(item.editField, value, null)"
/>
<el-input
v-else
placeholder="组件不支持此类型表单请至组件内部自行扩展"
disabled
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</template> </template>
@ -87,97 +217,103 @@ export default {
type: [Object], type: [Object],
default: () => { default: () => {
return { return {
title: '', // title: "", //
labelWidth: '', // label labelWidth: "", // label
queryFormFields: [], // queryFormFields: [], //
buttons: { buttons: {
// //
query: {}, query: {},
edit: {}, edit: {},
delete: {}, delete: {},
add: {}, add: {}
}, },
columns: [], // columns: [], //
formChange: (formData, fieldName, fieldVal, fieldExtend) => {}, // formChange: (formData, fieldName, fieldVal, fieldExtend) => {} //
} };
}, }
}, },
// relateDatarelateData // relateDatarelateData
relateData: { relateData: {
type: [Object], type: [Object],
default: () => { default: () => {
return {} return {};
}, }
}, },
value: { value: {
type: [Object], type: [Object],
default: () => { default: () => {
return {} return {};
}, }
}, }
}, },
data() { data() {
return { return {
cardRowColNum: 2, // cardRowColNum: this.option.rowColForm || 2, //
editForm: {}, // editForm: {} //
} };
}, },
computed: { computed: {
// //
primaryKeyFieldName() { primaryKeyFieldName() {
var primaryKey = this.option.columns.find((item) => item['primaryKey'] == true) let primaryKey = this.option.columns.find(
item => item["primaryKey"] == true
);
if (primaryKey != null) { if (primaryKey != null) {
return primaryKey['field'] return primaryKey["field"];
} else { } else {
return null return null;
console.warn('在columns中查找primaryKey=true失败会导致查询详情和删除失败') console.warn(
"在columns中查找primaryKey=true失败会导致查询详情和删除失败"
);
} }
}, },
// //
joinColumn() { joinColumn() {
var columnName = this.option.joinColumn let columnName = this.option.joinColumn;
if (this.isBlank(columnName)) { if (this.isBlank(columnName)) {
console.warn('在joinEntity中查找joinColumn属性失败会导致查询详情和删除失败') console.warn(
columnName = '' "在joinEntity中查找joinColumn属性失败会导致查询详情和删除失败"
);
columnName = "";
} }
return columnName return columnName;
}, },
// keyfield editField // keyfield editField
formFields() { formFields() {
if (this.option.columns == null) { if (this.option.columns == null) {
return [] return [];
} }
var fields = this.deepClone(this.option.columns) let fields = this.deepClone(this.option.columns);
fields = fields.map((item) => { fields = fields.map(item => {
if (this.isBlank(item['editField'])) { if (this.isBlank(item["editField"])) {
item['editField'] = item['field'] item["editField"] = item["field"];
} }
// //
if (this.isBlank(item['group'])) { if (this.isBlank(item["group"])) {
item['group'] = '其它' item["group"] = "其它";
} }
return item return item;
}) });
return fields return fields;
}, },
// col // col
cardRowColSpan() { cardRowColSpan() {
return 24 / this.cardRowColNum return 24 / this.cardRowColNum;
}, },
// //
columnGroups() { columnGroups() {
if (this.isBlank(this.formFields)) { if (this.isBlank(this.formFields)) {
return [] return [];
} else { } else {
// hide != true // hide != true
var groups = this.formFields let groups = this.formFields
.map((item) => { .map(item => {
return item['group'] return item["group"];
}) })
.filter((currentValue, index, arr) => { .filter((currentValue, index, arr) => {
return arr.indexOf(currentValue) == index return arr.indexOf(currentValue) == index;
}) });
return groups return groups;
} }
}, },
/* { /* {
@ -187,167 +323,176 @@ export default {
groupFormFields() { groupFormFields() {
if (this.showDialog) { if (this.showDialog) {
// //
var groupFormFields = {} let groupFormFields = {};
this.columnGroups.forEach((value, index, array) => { this.columnGroups.forEach((value, index, array) => {
groupFormFields[value] = [] groupFormFields[value] = [];
}) });
// //
this.formFields.forEach((item, index, array) => { this.formFields.forEach((item, index, array) => {
groupFormFields[item['group']].push(item) groupFormFields[item["group"]].push(item);
}) });
return groupFormFields return groupFormFields;
} }
return [] return [];
}, },
groupModel() { groupModel() {
return this.columnGroups.length > 1 return this.columnGroups.length > 1;
}, }
}, },
created() { created() {
// v-modelvaluethis.editForm // v-modelvaluethis.editForm
this.$watch( this.$watch(
function () { function() {
return this.value return this.value;
}, },
function (newVal, oldVal) { function(newVal, oldVal) {
this.editForm = newVal this.editForm = newVal;
// v-modelform // v-modelform
this.formChange() this.formChange();
} }
) );
// relateDatagoodsgoodsCode // relateDatagoodsgoodsCode
this.$watch( this.$watch(
function () { function() {
return this.relateData[this.joinColumn] return this.relateData[this.joinColumn];
}, },
function (newVal, oldVal) { function(newVal, oldVal) {
// ()this.relateData = {} // ()this.relateData = {}
if (this.isBlank(this.relateData)) { if (this.isBlank(this.relateData)) {
this.cardRowColNum = 2 this.cardRowColNum = 2;
this.editForm = {} this.editForm = {};
return return;
} }
// //
if (this.isNotBlank(newVal)) { if (this.isNotBlank(newVal)) {
this.queryDetail() this.queryDetail();
} }
} }
) );
}, },
mounted() { mounted() {
// v-model // v-model
if (this.isNotBlank(this.value)) { if (this.isNotBlank(this.value)) {
this.editForm = this.value this.editForm = this.value;
this.formChange() this.formChange();
} }
// //
if (this.isNotBlank(this.relateData) && this.isNotBlank(this.relateData[this.joinColumn])) { if (
this.queryDetail() this.isNotBlank(this.relateData) &&
this.isNotBlank(this.relateData[this.joinColumn])
) {
this.queryDetail();
} }
}, },
methods: { methods: {
// true/false/ 'hideOnAdd hideOnView hideOnEdit' // true/false/ 'hideOnAdd hideOnView hideOnEdit'
fieldIsHide(editHide) { fieldIsHide(editHide) {
if (typeof editHide == 'boolean') { if (typeof editHide == "boolean") {
return editHide return editHide;
} }
if (typeof editHide == 'string') { if (typeof editHide == "string") {
if (this.modelType == 'add') { if (this.modelType == "add") {
return editHide.indexOf('hideOnAdd') >= 0 return editHide.indexOf("hideOnAdd") >= 0;
} }
if (this.modelType == 'view') { if (this.modelType == "view") {
return editHide.indexOf('hideOnView') >= 0 return editHide.indexOf("hideOnView") >= 0;
} }
if (this.modelType == 'edit') { if (this.modelType == "edit") {
return editHide.indexOf('hideOnEdit') >= 0 return editHide.indexOf("hideOnEdit") >= 0;
} }
} }
return false return false;
}, },
// true/false/ 'disableOnAdd disableOnView disableOnEdit' // true/false/ 'disableOnAdd disableOnView disableOnEdit'
fieldIsDisable(disable) { fieldIsDisable(disable) {
if (typeof disable == 'boolean') { if (typeof disable == "boolean") {
return disable return disable;
} }
if (typeof disable == 'string') { if (typeof disable == "string") {
if (this.modelType == 'add') { if (this.modelType == "add") {
return disable.indexOf('disableOnAdd') >= 0 return disable.indexOf("disableOnAdd") >= 0;
} }
if (this.modelType == 'view') { if (this.modelType == "view") {
return disable.indexOf('disableOnView') >= 0 return disable.indexOf("disableOnView") >= 0;
} }
if (this.modelType == 'edit') { if (this.modelType == "edit") {
return disable.indexOf('disableOnEdit') >= 0 return disable.indexOf("disableOnEdit") >= 0;
} }
} }
return false return false;
}, },
// //
handleSetRowColNum(num) { handleSetRowColNum(num) {
this.cardRowColNum = num this.cardRowColNum = num;
this.$emit('changeRowColNum', num) this.$emit("changeRowColNum", num);
}, },
async queryDetail() { async queryDetail() {
var queryParams = this.relateData let queryParams = this.relateData;
const { data, code } = await this.option.buttons.queryByPrimarykey.api(queryParams) const { data, code } = await this.option.buttons.queryByPrimarykey.api(
if (code != '200') return queryParams
this.editForm = data );
this.formChange() if (code != "200") return;
this.editForm = data;
this.formChange();
}, },
// //
validate(callback) { validate(callback) {
this.$refs.editForm.validate(async (valid, obj) => { this.$refs.editForm.validate(async (valid, obj) => {
if (callback != null) { if (callback != null) {
callback(valid) callback(valid);
} }
}) });
}, },
handleSave(callback) { handleSave(callback) {
this.$refs.editForm.validate(async (valid, obj) => { this.$refs.editForm.validate(async (valid, obj) => {
if (valid) { if (valid) {
if (this.modelType == 'add') { if (this.modelType == "add") {
// edit-from // edit-from
if (typeof this.option.beforeInsert == 'function') { if (typeof this.option.beforeInsert == "function") {
this.option.beforeInsert(this.relateData, this.editForm) this.option.beforeInsert(this.relateData, this.editForm);
} }
const { code, message } = await this.option.buttons.add.api(this.editForm) const { code, message } = await this.option.buttons.add.api(
if (code == '200') { this.editForm
);
if (code == "200") {
if (callback != null) { if (callback != null) {
callback() callback();
} }
} else { } else {
console.log(`提交表单调用新增接口失败:${message}`) console.log(`提交表单调用新增接口失败:${message}`);
} }
} else { } else {
// edit-from // edit-from
if (typeof this.option.beforeUpdate == 'function') { if (typeof this.option.beforeUpdate == "function") {
this.option.beforeUpdate(this.relateData, this.editForm) this.option.beforeUpdate(this.relateData, this.editForm);
} }
const { code, message } = await this.option.buttons.edit.api(this.editForm) const { code, message } = await this.option.buttons.edit.api(
if (code == '200') { this.editForm
);
if (code == "200") {
if (callback != null) { if (callback != null) {
callback() callback();
} }
} else { } else {
console.log(`提交表单调用更新接口失败:${message}`) console.log(`提交表单调用更新接口失败:${message}`);
} }
} }
} else { } else {
console.log('表单校验失败') console.log("表单校验失败");
} }
}) });
}, },
// v-model // v-model
formChange(fieldName, fieldVal, fieldExtend) { formChange(fieldName, fieldVal, fieldExtend) {
this.$emit('input', this.editForm) this.$emit("input", this.editForm);
// optionformChange // optionformChange
if (typeof this.option.formChange == 'function') { if (typeof this.option.formChange == "function") {
this.option.formChange(this.editForm, fieldName, fieldVal, fieldExtend) this.option.formChange(this.editForm, fieldName, fieldVal, fieldExtend);
} }
}, }
}, }
} };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

@ -1,129 +1,180 @@
<!--
* @Author: lide1202@hotmail.com
* @Date: 2021-5-4 11:04:24
* @Last Modified by: lide1202@hotmail.com
* @Last Modified time: 2021-5-6 11:04:24
!-->
<template> <template>
<div v-if="option['hide'] == null || option['hide'] == false" <div
class="anji-card"> v-if="option['hide'] == null || option['hide'] == false"
class="anji-card"
>
<div class="card-head">{{ option.title }}</div> <div class="card-head">{{ option.title }}</div>
<div class="card-body"> <div class="card-body">
<el-form ref="form" <el-form ref="form" :model="form">
:model="form">
<!-- 表格开始 --> <!-- 表格开始 -->
<el-table :data="formRecordsUndelete" <el-table
border :data="formRecordsUndelete"
:row-class-name="tableRowClassAdapter" border
@selection-change="handleSelectionChange" :row-class-name="tableRowClassAdapter"
@row-click="handleTableRowClick"> @selection-change="handleSelectionChange"
<!-- <el-table-column fixed type="selection" width="50" align="center" /> --> @row-click="handleTableRowClick"
>
<el-table-column label="序号" <el-table-column label="序号" min-width="50" align="center">
min-width="50"
align="center">
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.$index + 1 }} {{ scope.$index + 1 }}
</template> </template>
</el-table-column> </el-table-column>
<template v-for="item in option.columns"> <template v-for="item in option.columns">
<el-table-column v-if="fieldIsHide(item.tableHide) != true && item.columnType != 'expand'" <el-table-column
:key="item.field" v-if="
:label="item.label" fieldIsHide(item.tableHide) != true &&
:min-width="item.minWidth || 110" item.columnType != 'expand'
align="center"> "
:key="item.field"
:label="item.label"
:min-width="item.minWidth || 110"
align="center"
>
<template slot-scope="scope"> <template slot-scope="scope">
<el-form-item :prop="'records.' + scope.$index + '.' + item.field" <el-form-item
:rules="item.rules"> :prop="'records.' + scope.$index + '.' + item.field"
:rules="item.rules"
>
<!-- 输入框 --> <!-- 输入框 -->
<el-input v-if="item.inputType == 'input'" <el-input
v-model="scope.row[item.field]" v-if="item.inputType == 'input'"
size="small" v-model="scope.row[item.field]"
:placeholder="item.placeholder || '请输入'" size="small"
:clearable="item.clearable !== false" :placeholder="item.placeholder || '请输入'"
:disabled="saveButtonStatus[scope.$index] == 'inShow' || item.disabled" :clearable="item.clearable !== false"
@change="(value) => tableRowChange(scope.$index, item.field, value)" /> :disabled="
saveButtonStatus[scope.$index] == 'inShow' ||
item.disabled
"
@change="
value => tableRowChange(scope.$index, item.field, value)
"
/>
<!-- 开关 --> <!-- 开关 -->
<el-switch v-else-if="item.inputType == 'switch'" <el-switch
v-model="scope.row[item.field]" v-else-if="item.inputType == 'switch'"
:disabled="saveButtonStatus[scope.$index] == 'inShow' || item.disabled" v-model="scope.row[item.field]"
:active-value="item.switchOption.disableValue" :disabled="
:inactive-value="item.switchOption.enableValue" saveButtonStatus[scope.$index] == 'inShow' ||
@change="(value) => tableRowChange(scope.$index, item.field, value)" item.disabled
active-color="#5887fb" "
inactive-color="#ccc"> :active-value="item.switchOption.disableValue"
:inactive-value="item.switchOption.enableValue"
@change="
value => tableRowChange(scope.$index, item.field, value)
"
active-color="#5887fb"
inactive-color="#ccc"
>
</el-switch> </el-switch>
<el-input v-else-if="item.inputType == 'input-number'" <el-input
v-model="scope.row[item.field]" v-else-if="item.inputType == 'input-number'"
size="small" v-model="scope.row[item.field]"
:min="item.inputNumberOption.min" size="small"
:max="item.inputNumberOption.max" :min="item.inputNumberOption.min"
:placeholder="item.placeholder || '请输入'" :max="item.inputNumberOption.max"
:clearable="item.clearable !== false" :placeholder="item.placeholder || '请输入'"
:disabled="saveButtonStatus[scope.$index] == 'inShow' || item.disabled" :clearable="item.clearable !== false"
@change="(value) => tableRowChange(scope.$index, item.field, value)" /> :disabled="
saveButtonStatus[scope.$index] == 'inShow' ||
item.disabled
"
@change="
value => tableRowChange(scope.$index, item.field, value)
"
/>
<!-- 自定义input --> <!-- 自定义input -->
<anji-input v-else-if="item.inputType == 'anji-input'" <anji-input
v-model.trim="scope.row[item.field]" v-else-if="item.inputType == 'anji-input'"
:default-value="item.defaultValue" v-model.trim="scope.row[item.field]"
:unit="item.anjiInput.unit" :default-value="item.defaultValue"
:conversion="item.anjiInput.conversion" :unit="item.anjiInput.unit"
:placeholder="item.placeholder || '请输入'" :conversion="item.anjiInput.conversion"
:clearable="item.clearable !== false" :placeholder="item.placeholder || '请输入'"
:disabled="saveButtonStatus[scope.$index] == 'inShow' || item.disabled" :clearable="item.clearable !== false"
@change="(value) => tableRowChange(scope.$index, item.field, value)" /> :disabled="
saveButtonStatus[scope.$index] == 'inShow' ||
item.disabled
"
@change="
value => tableRowChange(scope.$index, item.field, value)
"
/>
<!-- 下拉框 --> <!-- 下拉框 -->
<anji-select v-else-if="item.inputType == 'anji-select'" <anji-select
v-model.trim="scope.row[item.field]" v-else-if="item.inputType == 'anji-select'"
:multiple="item.anjiSelectOption.multiple" v-model.trim="scope.row[item.field]"
:default-value="item.defaultValue" :multiple="item.anjiSelectOption.multiple"
:dict-code="item.anjiSelectOption.dictCode" :default-value="item.defaultValue"
:url="item.anjiSelectOption.url" :dict-code="item.anjiSelectOption.dictCode"
:method="item.anjiSelectOption.method" :url="item.anjiSelectOption.url"
:query-param="item.anjiSelectOption.queryParam" :method="item.anjiSelectOption.method"
:option="item.anjiSelectOption.option" :query-param="item.anjiSelectOption.queryParam"
:label="item.anjiSelectOption.label" :option="item.anjiSelectOption.option"
:disabled-options="item.anjiSelectOption.disabledOptions" :label="item.anjiSelectOption.label"
:disabled="saveButtonStatus[scope.$index] == 'inShow' || item.disabled" :disabled-options="item.anjiSelectOption.disabledOptions"
@change="(value, option) => tableRowChange(scope.$index, item.field, value, option)" /> :disabled="
saveButtonStatus[scope.$index] == 'inShow' ||
item.disabled
"
@change="
(value, option) =>
tableRowChange(scope.$index, item.field, value, option)
"
/>
<!-- 日期时间框 --> <!-- 日期时间框 -->
<el-date-picker v-else-if="item.inputType.indexOf('date') >= 0" <el-date-picker
v-model="scope.row[item.field]" v-else-if="item.inputType.indexOf('date') >= 0"
style="width: 100%" v-model="scope.row[item.field]"
:placeholder="item.placeholder || '请选择'" style="width: 100%"
:type="item.inputType" :placeholder="item.placeholder || '请选择'"
:clearable="item.clearable !== false" :type="item.inputType"
:disabled="saveButtonStatus[scope.$index] == 'inShow' || item.disabled" :clearable="item.clearable !== false"
@change="(value) => tableRowChange(scope.$index, item.field, value)" /> :disabled="
saveButtonStatus[scope.$index] == 'inShow' ||
item.disabled
"
@change="
value => tableRowChange(scope.$index, item.field, value)
"
/>
<!-- 待扩展的表单类型请自行扩展 --> <!-- 待扩展的表单类型请自行扩展 -->
<el-input v-else <el-input
placeholder="组件不支持此类型表单请至组件内部自行扩展" v-else
disabled /> placeholder="组件不支持此类型表单请至组件内部自行扩展"
disabled
/>
</el-form-item> </el-form-item>
</template> </template>
</el-table-column> </el-table-column>
</template> </template>
<el-table-column fixed="right" <el-table-column fixed="right" label="操作" width="100">
label="操作"
width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" <el-button
size="small" type="text"
@click="handleAddOrUpdate(scope.row, scope.$index)">{{ getRowEditButton(scope.$index) }}</el-button> size="small"
<el-button type="text" @click="handleAddOrUpdate(scope.row, scope.$index)"
size="small" >{{ getRowEditButton(scope.$index) }}</el-button
@click="handleDelete(scope.row, scope.$index)">删除</el-button> >
<el-button
type="text"
size="small"
@click="handleDelete(scope.row, scope.$index)"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 表格结束 --> <!-- 表格结束 -->
</el-form> </el-form>
<button v-if="modelType != 'view'" <button
class="table-add-row-button" v-if="modelType != 'view'"
@click="handleAdd"> class="table-add-row-button"
@click="handleAdd"
>
<i class="el-icon-plus" /> <i class="el-icon-plus" />
<span>新增</span> <span>新增</span>
</button> </button>
@ -132,7 +183,7 @@
</template> </template>
<script> <script>
const ROW_DELETE_FLAG = 'deletedFlag' const ROW_DELETE_FLAG = "deletedFlag";
export default { export default {
components: {}, components: {},
props: { props: {
@ -142,326 +193,291 @@ export default {
type: [Object], type: [Object],
default: () => { default: () => {
return { return {
title: '', // title: "", //
labelWidth: '', labelWidth: "",
queryFormFields: [], // queryFormFields: [], //
buttons: { buttons: {
// //
query: {}, query: {},
edit: {}, edit: {},
delete: {}, delete: {},
add: {}, add: {}
}, },
columns: [], // columns: [] //
} };
}, }
}, },
relateData: { relateData: {
// //
type: [Object], type: [Object],
default: () => { default: () => {
return {} return {};
}, }
}, },
value: { value: {
type: [Array], type: [Array],
default: () => { default: () => {
return [] return [];
}, }
}, },
valueNew: { valueNew: {
type: [Array], type: [Array],
default: () => { default: () => {
return [] return [];
}, }
} }
}, },
data () { data() {
return { return {
checkRecords: [], // checkRecords: [], //
form: { form: {
records: [], // records: [], //
total: 0, // total: 0 //
}, },
saveButtonStatus: [], // inShow inEditing inAdding saveButtonStatus: [], // inShow inEditing inAdding
rowIdList: [] rowIdList: []
} };
}, },
computed: { computed: {
// //
primaryKeyFieldName () { primaryKeyFieldName() {
var primaryKey = this.option.columns.find((item) => item['primaryKey'] == true) let primaryKey = this.option.columns.find(
item => item["primaryKey"] == true
);
if (primaryKey != null) { if (primaryKey != null) {
return primaryKey['field'] return primaryKey["field"];
} else { } else {
return null return null;
console.warn('在columns中查找primaryKey=true失败会导致查询详情和删除失败') console.warn(
"在columns中查找primaryKey=true失败会导致查询详情和删除失败"
);
} }
}, },
// //
joinColumn () { joinColumn() {
var columnName = this.option.joinColumn let columnName = this.option.joinColumn;
if (this.isBlank(columnName)) { if (this.isBlank(columnName)) {
console.warn('在columns中查找关联字段失败会导致查询详情和删除失败孙子关联表忽略该错误') console.warn(
columnName = '' "在columns中查找关联字段失败会导致查询详情和删除失败孙子关联表忽略该错误"
);
columnName = "";
} }
return columnName return columnName;
}, },
// //
formRecordsUndelete () { formRecordsUndelete() {
if (this.form.records == null) { if (this.form.records == null) {
return [] return [];
} }
return this.form.records.filter((item) => item[ROW_DELETE_FLAG] == null || item[ROW_DELETE_FLAG] == false) return this.form.records.filter(
}, item => item[ROW_DELETE_FLAG] == null || item[ROW_DELETE_FLAG] == false
);
}
}, },
watch: {}, watch: {},
created () { created() {
// relateData joinColumn // relateData joinColumn
if (this.isNotBlank(this.joinColumn)) { if (this.isNotBlank(this.joinColumn)) {
this.$watch( this.$watch(
function () { function() {
return this.relateData[this.joinColumn] return this.relateData[this.joinColumn];
}, },
function (newVal, oldVal) { function(newVal, oldVal) {
// //
if (this.isNotBlank(newVal)) { if (this.isNotBlank(newVal)) {
this.handleQueryPageList(newVal) this.handleQueryPageList(newVal);
} else { } else {
// ()this.relateData = {} // ()this.relateData = {}
this.checkRecords = [] this.checkRecords = [];
this.form.records = [] this.form.records = [];
this.form.total = 0 this.form.total = 0;
this.saveButtonStatus = [] this.saveButtonStatus = [];
} }
} }
) );
} }
}, },
mounted () { mounted() {
// //
if (this.isNotBlank(this.relateData) && this.isNotBlank(this.relateData[this.joinColumn])) { if (
this.handleQueryPageList() this.isNotBlank(this.relateData) &&
this.isNotBlank(this.relateData[this.joinColumn])
) {
this.handleQueryPageList();
} }
}, },
methods: { methods: {
// true/false/ 'hideOnAdd hideOnView hideOnEdit' // true/false/ 'hideOnAdd hideOnView hideOnEdit'
fieldIsHide (tableHide) { fieldIsHide(tableHide) {
if (typeof tableHide == 'boolean') { if (typeof tableHide == "boolean") {
return tableHide return tableHide;
} }
if (typeof tableHide == 'string') { if (typeof tableHide == "string") {
if (this.modelType == 'add') { if (this.modelType == "add") {
return tableHide.indexOf('hideOnAdd') >= 0 return tableHide.indexOf("hideOnAdd") >= 0;
} }
if (this.modelType == 'view') { if (this.modelType == "view") {
return tableHide.indexOf('hideOnView') >= 0 return tableHide.indexOf("hideOnView") >= 0;
} }
if (this.modelType == 'edit') { if (this.modelType == "edit") {
return tableHide.indexOf('hideOnEdit') >= 0 return tableHide.indexOf("hideOnEdit") >= 0;
} }
} }
return false return false;
}, },
// //
getRowEditButton (index) { getRowEditButton(index) {
if (this.saveButtonStatus[index] == 'inEditing') { if (this.saveButtonStatus[index] == "inEditing") {
return 'btn_savetemp' return "btn_savetemp";
} else if (this.saveButtonStatus[index] == 'inAdding') { } else if (this.saveButtonStatus[index] == "inAdding") {
return 'btn_savetemp' return "btn_savetemp";
} else if (this.saveButtonStatus[index] == 'inShow') { } else if (this.saveButtonStatus[index] == "inShow") {
return 'btn_edit' return "btn_edit";
} else { } else {
return 'not_permission' return "not_permission";
} }
}, },
// //
tableRowClassAdapter ({ row, rowIndex }) { tableRowClassAdapter({ row, rowIndex }) {
row.index = rowIndex row.index = rowIndex;
}, },
// //
async handleQueryPageList (joinColumnValue) { async handleQueryPageList(joinColumnValue) {
if (this.isBlank(joinColumnValue)) { if (this.isBlank(joinColumnValue)) {
joinColumnValue = this.relateData[this.joinColumn] joinColumnValue = this.relateData[this.joinColumn];
} }
var params = {} let params = {};
params[this.joinColumn] = joinColumnValue params[this.joinColumn] = joinColumnValue;
this.queryPageList(params) this.queryPageList(params);
}, },
// //
async queryPageList (params) { async queryPageList(params) {
// //
if (this.isNotBlank(this.option.buttons.query.order)) { if (this.isNotBlank(this.option.buttons.query.order)) {
params['sort'] = this.option.buttons.query.sort params["sort"] = this.option.buttons.query.sort;
params['order'] = this.option.buttons.query.order params["order"] = this.option.buttons.query.order;
} }
const { data, code } = await this.option.buttons.query.api(params) const { data, code } = await this.option.buttons.query.api(params);
if (code != '200') return if (code != "200") return;
this.form.records = data.records this.form.records = data.records;
this.form.total = data.total this.form.total = data.total;
this.$emit('input', this.form.records) this.$emit("input", this.form.records);
for (var i = 0; i < this.form.total; i++) { for (let i = 0; i < this.form.total; i++) {
this.saveButtonStatus.push('inShow') this.saveButtonStatus.push("inShow");
} }
}, },
// //
handleSelectionChange (val) { handleSelectionChange(val) {
this.checkRecords = val this.checkRecords = val;
}, },
// //
handleTableRowClick (row, column, event) { handleTableRowClick(row, column, event) {
// console.log(row)
// console.log(column)
// optiontableRowClick // optiontableRowClick
if (typeof this.option.tableRowClick == 'function') { if (typeof this.option.tableRowClick == "function") {
this.option.tableRowClick(this.form.records, row, row.index, this.relateData) this.option.tableRowClick(
this.form.records,
row,
row.index,
this.relateData
);
} }
}, },
// //
tableRowChange (rowIndex, fieldName, fieldVal, fieldExtend) { tableRowChange(rowIndex, fieldName, fieldVal, fieldExtend) {
// //
this.$emit('input', this.form.records) this.$emit("input", this.form.records);
// optiontableRowChange // optiontableRowChange
if (typeof this.option.tableChange == 'function') { if (typeof this.option.tableChange == "function") {
this.option.tableChange(this.form.records, rowIndex, fieldName, fieldVal, fieldExtend, this.relateData) this.option.tableChange(
this.form.records,
rowIndex,
fieldName,
fieldVal,
fieldExtend,
this.relateData
);
} }
}, },
// //
handleAdd () { handleAdd() {
this.saveButtonStatus.push('inAdding') this.saveButtonStatus.push("inAdding");
this.form.records.push({}) this.form.records.push({});
}, },
// Change, // Change,
handleUpdata () { handleUpdata() {
this.saveButtonStatus = [] this.saveButtonStatus = [];
this.form.records = [] this.form.records = [];
}, },
// //
handleAddOrUpdate (row, index) { handleAddOrUpdate(row, index) {
// //
if (this.saveButtonStatus[index] == 'inEditing' || this.saveButtonStatus[index] == 'inAdding') { if (
this.handleSaveTemp(row, index) this.saveButtonStatus[index] == "inEditing" ||
this.saveButtonStatus[index] == "inAdding"
) {
this.handleSaveTemp(row, index);
} else { } else {
this.$set(this.saveButtonStatus, index, 'inEditing') this.$set(this.saveButtonStatus, index, "inEditing");
} }
}, },
// //
validate (callback) { validate(callback) {
this.$refs['form'].validate(async (valid, obj) => { this.$refs["form"].validate(async (valid, obj) => {
if (callback != null) { if (callback != null) {
callback(valid) callback(valid);
} }
}) });
}, },
// //
async handleSaveTemp (row, index) { async handleSaveTemp(row, index) {
this.$refs['form'].validate((valid) => { this.$refs["form"].validate(valid => {
if (valid) { if (valid) {
if (this.isBlank(row[this.primaryKeyFieldName])) { if (this.isBlank(row[this.primaryKeyFieldName])) {
// //
if (typeof this.option.beforeInsert == 'function') { if (typeof this.option.beforeInsert == "function") {
this.option.beforeInsert(this.relateData, row) this.option.beforeInsert(this.relateData, row);
} }
} else { } else {
// //
if (typeof this.option.beforeUpdate == 'function') { if (typeof this.option.beforeUpdate == "function") {
this.option.beforeUpdate(this.relateData, row) this.option.beforeUpdate(this.relateData, row);
} }
} }
// //
this.$set(this.saveButtonStatus, index, 'inShow') this.$set(this.saveButtonStatus, index, "inShow");
// //
this.$emit('input', this.form.records) this.$emit("input", this.form.records);
} }
}) });
/*
this.$refs['form'].validate((valid) => {
if (valid) {
//
if (this.isBlank(row[this.primaryKeyFieldName])) {
//
if (typeof this.option.beforeInsert == 'function') {
this.option.beforeInsert(this.relateData, row)
}
//
this.option.buttons.add.api(row).then((response) => {
if (response.code == 200) {
this.$set(this.saveButtonStatus, index, 'inShow')
//
this.handleQueryPageList()
}
})
} else {
//
if (typeof this.option.beforeUpdate == 'function') {
this.option.beforeUpdate(this.relateData, row)
}
//
this.option.buttons.edit.api(row).then((response) => {
if (response.code == 200) {
this.$set(this.saveButtonStatus, index, 'inShow')
//
this.handleQueryPageList()
}
})
}
} else {
console.log('valid fail')
return false
}
})
*/
}, },
// //
handleDelete (row, index) { handleDelete(row, index) {
this.saveButtonStatus.splice(index, 1) // this.saveButtonStatus.splice(index, 1); //
// //
if (this.saveButtonStatus[index] == 'inAdding') { if (this.saveButtonStatus[index] == "inAdding") {
this.form.records.splice(index, 1) this.form.records.splice(index, 1);
this.saveButtonStatus.splice(index, 1) this.saveButtonStatus.splice(index, 1);
this.$emit('input', this.form.records) this.$emit("input", this.form.records);
return return;
} }
// if (this.isBlank(row) || this.isBlank(row[this.primaryKeyFieldName])) { // if (this.isBlank(row) || this.isBlank(row[this.primaryKeyFieldName])) {
// return // return
// } // }
// //
// index // index
// var realIndex = this.form.records.findIndex((item) => item[this.primaryKeyFieldName] == row[this.primaryKeyFieldName]) let realIndex = this.form.records.findIndex(
// row[ROW_DELETE_FLAG] = true item => item[this.primaryKeyFieldName] == row[this.primaryKeyFieldName]
// this.$set(this.form.records, realIndex, row) );
// this.$emit('input', this.form.records) row[ROW_DELETE_FLAG] = true;
this.form.records.splice(index, 1) this.$set(this.form.records, realIndex, row);
this.rowIdList.push(row.id) this.$emit("input", this.form.records);
this.$emit('input', this.form.records) }
this.$emit('update:valueNew', this.rowIdList) }
/* };
之前是直接调用接口删除后面统一改成在主表接口中增加更新删除
//
var primaryKey = row[this.primaryKeyFieldName]
this.$confirm(this.$lang('promptMessage_deleteTip'), this.$lang('promptMessage_deleteTipTitle'), {
type: 'warning',
confirmButtonClass: 'delete_sure',
cancelButtonClass: 'el-button--danger is-plain',
})
.then(() => {
this.option.buttons.delete.api(primaryKey).then((res) => {
// {code: "200", message: "", data: true}
this.checkRecords = []
this.handleQueryPageList()
})
})
.catch((e) => {
e
})
*/
},
},
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

@ -1,13 +1,7 @@
<!--
* @Author: lide1202@hotmail.com
* @Date: 2021-3-13 11:04:24
* @Last Modified by: lide1202@hotmail.com
* @Last Modified time: 2021-3-13 11:04:24
!-->
<template> <template>
<el-dialog <el-dialog
:width="dialogWidth" :width="dialogWidth"
:class="dialogFullScreen?'full-screen':'notfull-screen'" :class="dialogFullScreen ? 'full-screen' : 'notfull-screen'"
:close-on-click-modal="false" :close-on-click-modal="false"
center center
:visible.sync="showDialog" :visible.sync="showDialog"
@ -15,7 +9,7 @@
@close="handleCloseDialog('close')" @close="handleCloseDialog('close')"
> >
<template v-slot:title> <template v-slot:title>
{{ option.title + '--' + modelType }} {{ option.title + "--" + modelType }}
<button <button
type="button" type="button"
aria-label="Close" aria-label="Close"
@ -67,49 +61,55 @@
<!--自定义的卡片插槽--> <!--自定义的卡片插槽-->
<slot name="customCard" /> <slot name="customCard" />
<div <div slot="footer" style="text-align: center">
slot="footer" <slot v-if="modelType == 'edit'" name="editBtn" :rowData="rowData" />
style="text-align: center" <el-button type="danger" plain @click="handleCloseDialog('close')"
> >关闭</el-button
<slot >
v-if="modelType =='edit'"
name="editBtn"
:rowData="rowData"
/>
<el-button
type="danger"
plain
@click="handleCloseDialog('close')"
>关闭</el-button>
<el-button <el-button
v-if="modelType!='view'" v-if="modelType != 'view'"
type="primary" type="primary"
plain plain
@click="handleValidateAndSave" @click="handleValidateAndSave"
>保存</el-button> >保存</el-button
>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import EditForm from './edit-form' import EditForm from "./edit-form";
import EditTable from './edit-table' import EditTable from "./edit-table";
export default { export default {
name: 'EditDialog', name: "EditDialog",
components: { EditForm, EditTable }, components: { EditForm, EditTable },
props: { props: {
visible: { visible: {
type: [Boolean], type: [Boolean],
default: () => { default: () => {
return false return false;
}, }
}, },
rowData: { rowData: {
// //
type: [Object], type: [Object],
default: () => { default: () => {
return {} return {};
}, }
},
//
handleDetailData: {
type: Function,
default: data => {
return data;
}
},
//
submitDetailData: {
type: Function,
default: (data, tpe) => {
return data;
}
}, },
modelType: String, // add view edit modelType: String, // add view edit
option: { option: {
@ -117,20 +117,20 @@ export default {
type: Object, type: Object,
default: () => { default: () => {
return { return {
title: '', // title: "", //
labelWidth: '', // label labelWidth: "", // label
queryFormFields: [], // queryFormFields: [], //
buttons: { buttons: {
// //
query: {}, query: {},
edit: {}, edit: {},
delete: {}, delete: {},
add: {}, add: {}
}, },
columns: [], // columns: [] //
} };
}, }
}, }
}, },
data() { data() {
return { return {
@ -141,232 +141,250 @@ export default {
// //
saveForm: {}, saveForm: {},
// //
countForValidJoinForm: 0, countForValidJoinForm: 0
} };
}, },
computed: { computed: {
// //
dialogWidth() { dialogWidth() {
if (this.cardRowColNum == 2) { if (this.cardRowColNum == 2) {
return '60%' return "60%";
} }
if (this.cardRowColNum == 3) { if (this.cardRowColNum == 3) {
return '70%' return "70%";
} }
if (this.cardRowColNum == 4) { if (this.cardRowColNum == 4) {
return '80%' return "80%";
} }
return '60%' return "60%";
}, },
// //
joinEntitys() { joinEntitys() {
if (this.isBlank(this.option.joinEntitys)) { if (this.isBlank(this.option.joinEntitys)) {
return [] return [];
} else { } else {
return this.option.joinEntitys return this.option.joinEntitys;
// hide != true
// var entitys = this.option.joinEntitys.filter((item) => item['hide'] == null || item['hide'] == false)
// return entitys
} }
}, },
// //
countJoinEntityOneToOne() { countJoinEntityOneToOne() {
var entitys = this.joinEntitys.filter((item) => item['joinType'] == 'OneToOne') let entitys = this.joinEntitys.filter(
item => item["joinType"] == "OneToOne"
);
if (entitys == null) { if (entitys == null) {
return 0 return 0;
} }
return entitys.length return entitys.length;
}, }
}, },
watch: { watch: {
// dialog // dialog
visible(newValue, oldValue) { visible(newValue, oldValue) {
this.showDialog = newValue this.showDialog = newValue;
// //
this.initDefaultSaveForm() this.initDefaultSaveForm();
}, },
rowData(newValue, oldValue) { rowData(newValue, oldValue) {
if (newValue != null) { if (newValue != null) {
this.queryByPrimarykey(newValue) this.queryByPrimarykey(newValue);
} }
}, }
}, },
mounted() { mounted() {
// //
this.initDefaultSaveForm() this.initDefaultSaveForm();
}, },
methods: { methods: {
// crudsaveForm // crudsaveForm
getSaveForm() { getSaveForm() {
return this.saveForm return this.saveForm;
}, },
setSaveForm(saveForm) { setSaveForm(saveForm) {
this.saveForm = saveForm this.saveForm = saveForm;
}, },
initDefaultSaveForm() { initDefaultSaveForm() {
// saveForm // saveForm
var defaultSaveForm = {} let defaultSaveForm = {};
this.option.columns.forEach((item) => { this.option.columns.forEach(item => {
var key = item.editField let key = item.editField;
if (this.isBlank(key)) { if (this.isBlank(key)) {
key = item.field key = item.field;
} }
var val = item.defaultValue let val = item.defaultValue;
if (this.isNotBlank(val)) { if (this.isNotBlank(val)) {
defaultSaveForm[key] = val defaultSaveForm[key] = val;
} }
}) });
// //
this.saveForm = this.deepClone(defaultSaveForm) this.saveForm = this.deepClone(defaultSaveForm);
console.log('编辑框默认值:' + JSON.stringify(this.saveForm)) console.log("编辑框默认值:" + JSON.stringify(this.saveForm));
}, },
handleCloseDialog(val) { handleCloseDialog(val) {
// //
this.initDefaultSaveForm() this.initDefaultSaveForm();
this.showDialog = false, // this.showDialog = false; //
this.dialogFullScreen = false, // this.dialogFullScreen = false; //
this.cardRowColNum = 2, // this.cardRowColNum = 2; //
this.countForValidJoinForm = 0, // this.countForValidJoinForm = 0; //
this.$emit('closeEvent', val) this.$emit("closeEvent", val);
},
handleTopCloseDialog() {
//
this.initDefaultSaveForm();
this.showDialog = false; //
this.dialogFullScreen = false; //
this.cardRowColNum = 2; //
this.countForValidJoinForm = 0; //
}, },
// //
handleSetRowColNum(num) { handleSetRowColNum(num) {
this.cardRowColNum = num this.cardRowColNum = num;
}, },
// //
getComponentByJoinType(type, item) { getComponentByJoinType(type, item) {
if (type == 'OneToOne') { if (type == "OneToOne") {
return 'EditForm' return "EditForm";
} else if (type == 'OneToMany') { } else if (type == "OneToMany") {
return 'EditTable' return "EditTable";
} else { } else {
return '' return "";
} }
}, },
async queryByPrimarykey(rowData) { async queryByPrimarykey(rowData) {
const { data, code } = await this.option.buttons.queryByPrimarykey.api(rowData) const { data, code } = await this.option.buttons.queryByPrimarykey.api(
if (code != '200') return rowData
this.showDialog = true );
this.saveForm = data if (code != "200") return;
this.showDialog = true;
this.saveForm = this.handleDetailData(data);
}, },
// //
handleValidateAndSave() { handleValidateAndSave() {
this.countForValidJoinForm = 0 this.countForValidJoinForm = 0;
// //
this.$refs.mainForm.validate((mainValid) => { this.$refs.mainForm.validate(mainValid => {
if (mainValid == false) { if (mainValid == false) {
console.warn('主表单校验失败') console.warn("主表单校验失败");
return return;
} }
console.log('主表单校验完成') console.log("主表单校验完成");
if (this.joinEntitys == null || this.joinEntitys.length == 0) { if (this.joinEntitys == null || this.joinEntitys.length == 0) {
// //
this.handleSave() this.handleSave();
return return;
} }
for (var i = 0; i < this.joinEntitys.length; i++) { for (let i = 0; i < this.joinEntitys.length; i++) {
console.log(`开始校验子表单-${i} 校验`) console.log(`开始校验子表单-${i} 校验`);
var item = this.joinEntitys[i] let item = this.joinEntitys[i];
if (this.$refs['joinForm' + i] == null || item.hide == true || this.saveForm[item.fieldNameInMainEntityOnSave] == null || this.saveForm[item.fieldNameInMainEntityOnSave].length == 0) { console.log(item);
console.log('子表单没有数据,直接跳过') if (
this.countForValidJoinForm++ this.$refs["joinForm" + i] == null ||
console.log('已经校验的子表单:' + this.countForValidJoinForm + ' 共:' + this.joinEntitys.length) item.hide == true ||
this.saveForm[item.fieldNameInMainEntityOnSave] == null ||
this.saveForm[item.fieldNameInMainEntityOnSave].length == 0
) {
console.warn("子表单校验失败");
} else {
const childrenChecked = this.checkedChildrenValidate(
this.saveForm[item.fieldNameInMainEntityOnSave],
item.columns
);
if (!childrenChecked) {
return;
}
// console.log('')
this.countForValidJoinForm++;
console.log(
"已经校验的子表单:" +
this.countForValidJoinForm +
" 共:" +
this.joinEntitys.length
);
// //
if (this.countForValidJoinForm == this.joinEntitys.length) { if (this.countForValidJoinForm == this.joinEntitys.length) {
console.log('子表单校验完成,提交主表单') console.log("子表单校验完成,提交主表单");
this.handleSave() this.handleSave();
} }
continue continue;
} }
var joinForm = this.$refs['joinForm' + i] let joinForm = this.$refs["joinForm" + i];
if (toString.call(joinForm) == '[object Array]') { if (toString.call(joinForm) == "[object Array]") {
joinForm = joinForm[0] joinForm = joinForm[0];
} }
joinForm.validate((joinValid) => { joinForm.validate(joinValid => {
if (joinValid) { if (joinValid) {
this.countForValidJoinForm++ this.countForValidJoinForm++;
console.log('已经校验的子表单:' + this.countForValidJoinForm + ' 共:' + this.joinEntitys.length) console.log(
"已经校验的子表单:" +
this.countForValidJoinForm +
" 共:" +
this.joinEntitys.length
);
// //
if (this.countForValidJoinForm == this.joinEntitys.length) { if (this.countForValidJoinForm == this.joinEntitys.length) {
console.log('子表单校验完成,提交主表单') console.log("子表单校验完成,提交主表单");
this.handleSave() this.handleSave();
} }
} else { } else {
console.warn(`子表单${i}校验失败:`) console.warn(`子表单${i}校验失败:`);
} }
}) });
} }
}) });
}, },
async handleSave() { async handleSave() {
const params = this.submitDetailData(this.saveForm, this.modelType);
// //
if (this.modelType == 'add') { if (this.modelType == "add") {
const { code, message } = await this.option.buttons.add.api(this.saveForm) const { code, message } = await this.option.buttons.add.api(params);
if (code == '200') { if (code == "200") {
// //
this.handleCloseDialog() this.handleCloseDialog();
// //
this.$emit('closeEvent') // this.$emit('closeEvent')
return return;
} else { } else {
this.countForValidJoinForm = 0, // // ;(this.countForValidJoinForm = 0), //
console.log(`提交表单调用新增接口失败:${message}`) console.log(`提交表单调用新增接口失败:${message}`);
} }
} }
// //
if (this.modelType == 'edit') { if (this.modelType == "edit") {
// console.log(this.$slots.customCard[0].context.$refs.cardInEditData.updateData.settingValue) const { code, message } = await this.option.buttons.edit.api(params);
const { code, message } = await this.option.buttons.edit.api(this.saveForm) if (code == "200") {
if (code == '200') {
// //
this.handleCloseDialog() this.handleCloseDialog();
// //
this.$emit('closeEvent') // this.$emit('closeEvent')
return return;
} else { } else {
this.countForValidJoinForm = 0, // // ;(this.countForValidJoinForm = 0), //
console.log(`提交表单调用更新接口失败:${message}`) console.log(`提交表单调用更新接口失败:${message}`);
} }
} }
/* },
// //
this.$refs.mainForm.handleSave(() => { checkedChildrenValidate(list, confingList) {
// const configFileds = confingList.map(item => item.field);
if (this.countJoinEntityOneToOne == 0) { for (let i = 0; i < list.length; i++) {
// const item = list[i];
this.handleCloseDialog() for (let key = 0; key < configFileds.length; key++) {
// if (
this.$emit('closeEvent') item.hasOwnProperty(configFileds[key]) &&
return !item[configFileds[key]]
} ) {
// return false;
for (var i = 0; i < this.joinEntitys.length; i++) {
if (this.joinEntitys[i].joinType == 'OneToOne') {
this.$refs['joinForm' + i].handleSave(() => {
this.countForSavedOneToOneJoinEntity++
if (this.countForSavedOneToOneJoinEntity == this.countJoinEntityOneToOne) {
//
this.handleCloseDialog()
//
this.$emit('closeEvent')
}
})
} }
} }
})*/ }
}, return true;
}, }
} }
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
// /deep/.el-dialog__body {
// background-color: rgb(240, 242, 245);
// padding: 5px;
// max-height: 60vh;
// overflow: auto;
// height: calc(100vh - 100px);
// }
.notfull-screen { .notfull-screen {
/deep/.el-dialog__body { /deep/.el-dialog__body {
background-color: rgb(240, 242, 245); background-color: rgb(240, 242, 245);

@ -0,0 +1,151 @@
<!--
:v-model=""
:format="'yyyy-MM-dd HH:mm:ss'" 绑定值的格式,一般是参数传到后台的数据格式
:defaultValue="['00:00:00','23:59:59']" 选中日期后的默认具体时刻 数据格式为数组 ['00:00:00', '23:59:59']
@change=""
-->
<template>
<div>
<el-date-picker
v-model="selectedRangeValue"
style="width: 100%"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:value-format="format"
unlink-panels
:picker-options="pickerOptions"
:default-time="defaultValue"
@change="valueChanged"
/>
</div>
</template>
<script>
import miment from "miment";
export default {
props: {
format: {
type: String,
default: "yyyy-MM-dd HH:mm:ss"
},
defaultValue: {
type: Array,
default: () => {
return [];
}
},
value: {
type: String,
default: ""
}
},
data() {
return {
selectedRangeValue: [],
pickerOptions: {
shortcuts: [
{
text: "今天",
onClick(picker) {
const end = new Date();
const start = new Date(
new Date(new Date().getTime()).setHours(0, 0, 0, 0)
);
picker.$emit("pick", [start, end]);
}
},
{
text: "昨天",
onClick(picker) {
const start = new Date(
new Date(new Date().getTime() - 24 * 60 * 60 * 1000).setHours(
0,
0,
0,
0
)
);
const end = new Date(
new Date(new Date().getTime() - 24 * 60 * 60 * 1000).setHours(
23,
59,
59,
999
)
);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(
miment()
.add(-1, "ww")
.stamp()
);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(
miment()
.add(-1, "MM")
.stamp()
);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(
miment()
.add(-3, "MM")
.stamp()
);
picker.$emit("pick", [start, end]);
}
}
],
onPick: ({ maxDate, minDate }) => {
this.minDate = minDate;
this.maxDate = maxDate;
}
}
};
},
watch: {
value(val) {
this.parseDefaultVal(val);
}
},
created() {},
methods: {
// el-date-rangegaea'start,end'
parseDefaultVal(val) {
if (val != null) {
this.selectedRangeValue = val.split(",");
} else {
this.selectedRangeValue = [];
}
},
valueChanged(val) {
if (val != null) {
let rangeVal = val.toString();
this.$emit("change", rangeVal);
this.$emit("input", rangeVal);
}
}
}
};
</script>

@ -0,0 +1,209 @@
<template>
<el-dialog
:width="dialogWidth"
:class="dialogFullScreen ? 'full-screen' : 'notfull-screen'"
center
:fullscreen="dialogFullScreen"
:visible.sync="dialogConfig.dialogVisible"
:before-close="handleDialogClose"
append-to-body
modal-append-to-body
>
<template v-slot:title>
{{ getDialogTitle(dialogConfig.dialogType) }}
<button
v-if="dialogConfig.isFullScreen"
type="button"
aria-label="Close"
class="el-dialog__headerbtn"
style="right: 50px"
@click="dialogFullScreen = !dialogFullScreen"
>
<i class="el-dialog__close el-icon el-icon-full-screen" />
</button>
</template>
<div class="card-body">
<div class="anji-card">
<div v-if="dialogConfig.isSetColRow" class="card-head">
<div class="main-card-header-button">
<el-button type="text" @click="handleSetRowColNum(4)"
>||||</el-button
>
<el-button type="text" @click="handleSetRowColNum(3)"
>|||</el-button
>
<el-button type="text" @click="handleSetRowColNum(2)">||</el-button>
</div>
</div>
<slot name="dialogCont" />
<slot />
</div>
</div>
<div slot="footer" class="anji-button">
<el-button
v-if="isBtnClose"
type="danger"
plain
@click="handleDialogClose"
>{{ dialogConfig.isBtnClose.text || "关闭" }}</el-button
>
<el-button
v-if="isBtnSave"
type="primary"
plain
@click="handleDialogSave"
>{{ dialogConfig.isBtnSave.text || "保存" }}</el-button
>
<slot name="dialogBtn" />
</div>
</el-dialog>
</template>
<script>
export default {
props: {
//
dialogConfig: {
required: true,
type: Object,
default: () => {
return {
dialogVisible: false,
dialogType: "add",
dialogWidth: "60%",
isFullScreen: true,
isSetColRow: true,
isBtnClose: {
value: true,
text: "关闭"
},
isBtnSave: {
value: true,
text: "保存"
},
column: 2,
setColumnFn: () => {}
};
}
}
},
data() {
return {
dialogFullScreen: false //
};
},
computed: {
dialogWidth() {
if (this.dialogConfig.dialogWidth) {
return this.dialogConfig.dialogWidth;
} else {
if (this.dialogConfig.column == 2) {
return "60%";
}
if (this.dialogConfig.column == 3) {
return "70%";
}
if (this.dialogConfig.column == 4) {
return "80%";
}
}
return "60%";
},
isBtnClose() {
return this.dialogConfig.isBtnClose || this.dialogConfig.isBtnClose.value;
},
isBtnSave() {
return this.dialogConfig.isBtnSave || this.dialogConfig.isBtnSave.value;
}
},
methods: {
getDialogTitle(type) {
let title = "新增";
switch (type) {
case "add":
title = "新增";
break;
case "edit":
title = "编辑";
break;
case "view":
title = "查看";
break;
default:
title = type;
break;
}
return title;
},
handleSetRowColNum(val) {
const cardRowColSpan = 24 / val;
this.dialogConfig.setColumnFn(cardRowColSpan);
},
handleDialogClose() {
this.$emit("handleClose");
},
handleDialogSave() {
this.$emit("handleDialogSave");
}
}
};
</script>
<style scoped lang="scss">
.notfull-screen {
/deep/.el-dialog__body {
background-color: rgb(240, 242, 245);
padding: 5px;
max-height: 60vh;
overflow: auto;
}
}
.full-screen {
/deep/.el-dialog__body {
background-color: rgb(240, 242, 245);
padding: 5px;
height: calc(100vh - 110px);
overflow: auto;
}
}
.anji-card {
margin-bottom: 5px;
box-sizing: border-box;
padding: 0 20px;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
font-letiant: tabular-nums;
line-height: 1.5;
list-style: none;
font-feature-settings: "tnum";
position: relative;
background: #fff;
border-radius: 2px;
transition: all 0.3s;
}
.drawerContainer {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.drawerMain {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 0 20px;
}
.footer {
border-top: 1px solid #eff0f3;
height: 66px;
display: flex;
justify-content: center;
align-items: center;
}
}
.addForm {
text-align: center;
}
.activeColor /deep/.el-form-item__label {
color: #5887fb;
}
</style>

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

Loading…
Cancel
Save