Merge pull request !3 from Raod/dev
V0.9.2
Raod 3 years ago committed by Gitee
commit b31bd6fe6c

@ -110,14 +110,18 @@ bin/start.bat Windows修改第4行的JAVA_HOME后双击启动
启动后访问
http://serverip:9095
```
源码编译部署和发行版部署可参考在线文档 <br>
https://report.anji-plus.com/report-doc/guide/quicklyDevelop.html
## 谁在使用
希望你们的logo出现在此[请点此Issue进行登记](https://gitee.com/anji-plus/report/issues/I3ZXT4) <br>
希望你们的logo出现在此[请点此Issue进行登记](https://gitee.com/anji-plus/report/issues/I3ZXT4) ,我们将优先进行技术支持 <br>
<a href='http://www.anji-plus.com/'> <img src="https://report.anji-plus.com/file/download/d287d4d3-d30b-4850-9bac-a6c991409251" width = "130" height = "50" align=left/> </a>
<a href='https://www.yunstech.cn/'><img src="https://www.yunstech.cn/images/logo.png" 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='https://www.gykjweb.com/'><img src="https://report.anji-plus.com/file/download/d13b03f5-0c20-4878-9a79-f3c76b44bfd9" width = "130" height = "130" /> </a>
## 近期计划
@ -128,6 +132,15 @@ http://serverip:9095
- 基础图表增加
- 现有图表功能修复/增加
## 版本问题
已知以下版本存在兼容性问题
- Node.js V16
- Jdk 11
- Mysql 8.0
- Windows 11
AJ-Report 使用Druid版本为1.2.6如果你觉得你配置都是正常但是数据源测试不过请尝试降低Druid版本
## 技术支持
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**

@ -35,40 +35,57 @@
**存在问题,还在开发中**<br>
### 柱状图
目前**柱状图-渐变色**图形右侧功能区还在开发调整中 <br>
柱状图数据集对应字典值需要选择一个“X轴”、“柱状”只需要2个字段 <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 柱状堆叠图
开发中 <br>
动态的数据集对应字典值需要选择一个“X轴”、“Y轴”、“柱状”也就是说需要3个字段不明白可以看看静态数据 <br>
![img.17](../picture/dashboard/img_17.png)
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 折线图
### 折线堆叠图
动态的数据集对应字典值需要选择一个“X轴”、“Y轴”、“折线”也就是说需要3个字段不明白可以看看静态数据 <br>
![img.17](../picture/dashboard/img_17.png)
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 折线图
折线图数据集对应字典值需要选择一个“X轴”、“折线”只需要2个字段 <br>
![img_8.png](../picture/dashboard/img_8.png)
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 柱线图
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
柱线图数据集对应字典值需要选择一个“X轴”、“柱状”、“折线”需要3个字段 <br>
![img9](../picture/dashboard/img_9.png)
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 饼图
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
饼图的数据集选择的时候只能选择饼图对应的字典即“Name”、“Value”不明白可以参考静态数据 <br>
![img10](../picture/dashboard/img_10.png) <br>
![img11](../picture/dashboard/img_11.png) <br>
![img12](../picture/dashboard/img_12.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 漏斗图
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
和饼图一样 <br>
![img13](../picture/dashboard/img_13.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 仪表盘
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
数据集只能有一个字段,且字典选择“文本数字” <br>
![img14](../picture/dashboard/img_14.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 中国地图
**注**:气泡地图已支持动态数据,中国地图(迁徙图)暂不支持动态数据
气泡地图动态数据集和饼图一样对应字典值需要选择一个“Name”、“Value”且name的字段值要和echarts图表里面的值能对应上可参考静态数据 <br>
![img15](../picture/dashboard/img_15.png) <br>
### 百分百图
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
数据集只能有一个字段,且字典选择“文本数字” <br>
![img16](../picture/dashboard/img_16.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
### 热力图
**开发中** <br>

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

@ -132,4 +132,6 @@ public interface ResponseCode {
String SOURCE_CODE_ISEXIST = "4009";
String CLASS_NOT_FOUND = "4010";
String REPORT_SHARE_LINK_INVALID = "report.share.link.invalid";
}

@ -0,0 +1,47 @@
package com.anjiplus.template.gaea.business.enums;
public enum DeleteFlagEnum {
DELETED(1,"已删除"),
UNDELETED(0,"未删除"),
;
private int codeValue;
private String codeDesc;
private DeleteFlagEnum(int codeValue, String codeDesc) {
this.codeValue = codeValue;
this.codeDesc = codeDesc;
}
public int getCodeValue(){ return this.codeValue;}
public String getCodeDesc(){ return this.codeDesc;}
//根据codeValue获取枚举
public static DeleteFlagEnum parseFromCodeValue(int codeValue){
for (DeleteFlagEnum e : DeleteFlagEnum.values()){
if(e.codeValue == codeValue){ return e;}
}
return null;
}
//根据codeValue获取描述
public static String getCodeDescByCodeValue(int codeValue){
DeleteFlagEnum enumItem = parseFromCodeValue(codeValue);
return enumItem == null ? "" : enumItem.getCodeDesc();
}
//验证codeValue是否有效
public static boolean validateCodeValue(int codeValue){ return parseFromCodeValue(codeValue)!=null;}
//列出所有值字符串
public static String getString(){
StringBuffer buffer = new StringBuffer();
for (DeleteFlagEnum e : DeleteFlagEnum.values()){
buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", ");
}
buffer.deleteCharAt(buffer.lastIndexOf(","));
return buffer.toString().trim();
}
}

@ -0,0 +1,47 @@
package com.anjiplus.template.gaea.business.enums;
public enum EnableFlagEnum {
ENABLE(1,"启用"),
DISABLE(0,"禁用"),
;
private int codeValue;
private String codeDesc;
private EnableFlagEnum(int codeValue, String codeDesc) {
this.codeValue = codeValue;
this.codeDesc = codeDesc;
}
public int getCodeValue(){ return this.codeValue;}
public String getCodeDesc(){ return this.codeDesc;}
//根据codeValue获取枚举
public static EnableFlagEnum parseFromCodeValue(int codeValue){
for (EnableFlagEnum e : EnableFlagEnum.values()){
if(e.codeValue == codeValue){ return e;}
}
return null;
}
//根据codeValue获取描述
public static String getCodeDescByCodeBalue(int codeValue){
EnableFlagEnum enumItem = parseFromCodeValue(codeValue);
return enumItem == null ? "" : enumItem.getCodeDesc();
}
//验证codeValue是否有效
public static boolean validateCodeValue(int codeValue){ return parseFromCodeValue(codeValue)!=null;}
//列出所有值字符串
public static String getString(){
StringBuffer buffer = new StringBuffer();
for (EnableFlagEnum e : EnableFlagEnum.values()){
buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", ");
}
buffer.deleteCharAt(buffer.lastIndexOf(","));
return buffer.toString().trim();
}
}

@ -6,6 +6,7 @@ import com.anji.plus.gaea.bean.ResponseBean;
import com.anji.plus.gaea.cache.CacheHelper;
import com.anji.plus.gaea.utils.JwtBean;
import com.anjiplus.template.gaea.business.constant.BusinessConstant;
import com.anjiplus.template.gaea.business.util.JwtUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -68,6 +69,24 @@ public class TokenFilter implements Filter {
return;
}
//针对大屏分享,优先处理
String shareToken = request.getHeader("Share-Token");
if (StringUtils.isNotBlank(shareToken)) {
//两个接口需要处理
// /reportDashboard/getData
// /reportDashboard/{reportCode}
String reportCode = JwtUtil.getReportCode(shareToken);
if (!uri.endsWith("/getData") && !uri.contains(reportCode)) {
ResponseBean responseBean = ResponseBean.builder().code("50014")
.message("分享链接已过期").build();
response.getWriter().print(JSONObject.toJSONString(responseBean));
return;
}
filterChain.doFilter(request, response);
return;
}
//获取token
String token = request.getHeader("Authorization");
if (StringUtils.isBlank(token)) {

@ -13,7 +13,7 @@ import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.Repo
import com.anjiplus.template.gaea.business.modules.dashboard.dao.ReportDashboardMapper;
import com.anjiplus.template.gaea.business.modules.dashboard.service.ChartStrategy;
import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService;
import com.anjiplus.template.gaea.business.modules.dashboard.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.ReportDashboardWidgetValueDto;
import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard;

@ -54,9 +54,7 @@ public class JsTransformServiceImpl implements TransformStrategy {
engine.eval(js);
if(engine instanceof Invocable){
Invocable invocable = (Invocable) engine;
Object exec = invocable.invokeFunction("dataTransform", data);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.convertValue(exec, List.class);
return (List<JSONObject>) invocable.invokeFunction("dataTransform", data);
}
} catch (Exception ex) {

@ -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.dao.entity.Report;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* TODO
@ -28,6 +28,9 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/report")
public class ReportController extends GaeaBaseController<ReportParam, Report, ReportDto> {
@Autowired
private ReportShareService reportShareService;
@Autowired
private ReportService reportService;
@ -47,15 +50,17 @@ public class ReportController extends GaeaBaseController<ReportParam, Report, Re
}
@DeleteMapping("/delReport")
@Permission(
code = "delete",
name = "删除"
)
@GaeaAuditLog(
pageTitle = "删除"
)
@Permission(code = "delete", name = "删除")
@GaeaAuditLog(pageTitle = "删除")
public ResponseBean delReport(@RequestBody ReportDto reportDto) {
reportService.delReport(reportDto);
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();
}
}

@ -0,0 +1,69 @@
package com.anjiplus.template.gaea.business.modules.reportshare.controller;
import com.anji.plus.gaea.annotation.AccessKey;
import com.anji.plus.gaea.annotation.Permission;
import com.anji.plus.gaea.bean.ResponseBean;
import com.anji.plus.gaea.curd.controller.GaeaBaseController;
import com.anji.plus.gaea.curd.service.GaeaBaseService;
import com.anji.plus.gaea.utils.GaeaBeanUtils;
import com.anji.plus.gaea.utils.GaeaUtils;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.param.ReportShareParam;
import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare;
import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author Raod
* @desc controller
* @date 2021-08-18 13:37:26.663
**/
@RestController
@Api(tags = "报表分享管理")
@RequestMapping("/reportShare")
@Permission(code = "reportShareManage", name = "报表分享管理")
public class ReportShareController extends GaeaBaseController<ReportShareParam, ReportShare, ReportShareDto> {
@Autowired
private ReportShareService reportShareService;
@Override
public GaeaBaseService<ReportShareParam, ReportShare> getService() {
return reportShareService;
}
@Override
public ReportShare getEntity() {
return new ReportShare();
}
@Override
public ReportShareDto getDTO() {
return new ReportShareDto();
}
@GetMapping({"/{id}"})
@AccessKey
@Override
@Permission(code = "detail", name = "明细")
public ResponseBean detail(@PathVariable("id") Long id) {
this.logger.info("{}根据ID查询服务开始id为{}", this.getClass().getSimpleName(), id);
ReportShare result = reportShareService.getDetail(id);
ReportShareDto dto = this.getDTO();
GaeaBeanUtils.copyAndFormatter(result, dto);
ResponseBean responseBean = this.responseSuccessWithData(this.resultDtoHandle(dto));
this.logger.info("{}根据ID查询结束结果{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean));
return responseBean;
}
@GetMapping({"/detailByCode"})
@Permission(code = "detail", name = "明细")
public ResponseBean detailByCode(@RequestParam("shareCode") String shareCode) {
return ResponseBean.builder().data(reportShareService.detailByCode(shareCode)).build();
}
}

@ -0,0 +1,56 @@
package com.anjiplus.template.gaea.business.modules.reportshare.controller.dto;
import java.io.Serializable;
import com.anji.plus.gaea.curd.dto.GaeaBaseDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
*
* @description dto
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
@Data
public class ReportShareDto extends GaeaBaseDTO implements Serializable {
/** 分享编码系统生成默认UUID */
@ApiModelProperty(value = "分享编码系统生成默认UUID")
private String shareCode;
/** 分享有效期类型DIC_NAME=SHARE_VAILD */
@ApiModelProperty(value = "分享有效期类型DIC_NAME=SHARE_VAILD")
@NotNull(message = "6002")
private Integer shareValidType;
/** 分享有效期 */
@ApiModelProperty(value = "分享有效期")
private Date shareValidTime;
/** 分享token */
@ApiModelProperty(value = "分享token")
private String shareToken;
/** 分享url */
@ApiModelProperty(value = "分享url")
@NotEmpty(message = "6002")
private String shareUrl;
/** 报表编码 */
@ApiModelProperty(value = "报表编码")
@NotEmpty(message = "6002")
private String reportCode;
/** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */
@ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG")
private Integer enableFlag;
/** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */
@ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG")
private Integer deleteFlag;
}

@ -0,0 +1,16 @@
/**/
package com.anjiplus.template.gaea.business.modules.reportshare.controller.param;
import com.anji.plus.gaea.curd.params.PageParam;
import lombok.Data;
import java.io.Serializable;
/**
* @desc ReportShare
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
@Data
public class ReportShareParam extends PageParam implements Serializable{
}

@ -0,0 +1,15 @@
package com.anjiplus.template.gaea.business.modules.reportshare.dao;
import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare;
import org.apache.ibatis.annotations.Mapper;
/**
* ReportShare Mapper
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
@Mapper
public interface ReportShareMapper extends GaeaBaseMapper<ReportShare> {
}

@ -0,0 +1,43 @@
package com.anjiplus.template.gaea.business.modules.reportshare.dao.entity;
import lombok.Data;
import io.swagger.annotations.ApiModelProperty;
import com.anji.plus.gaea.curd.entity.GaeaBaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import javax.validation.constraints.*;
import java.util.Date;
/**
* @description entity
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
@TableName(value="gaea_report_share")
@Data
public class ReportShare extends GaeaBaseEntity {
/** 分享编码系统生成默认UUID */
private String shareCode;
/** 分享有效期类型DIC_NAME=SHARE_VAILD */
private Integer shareValidType;
/** 分享有效期 */
private Date shareValidTime;
/** 分享token */
private String shareToken;
/** 分享url */
private String shareUrl;
/** 报表编码 */
private String reportCode;
/** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */
private Integer enableFlag;
/** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */
private Integer deleteFlag;
}

@ -0,0 +1,27 @@
package com.anjiplus.template.gaea.business.modules.reportshare.service;
import com.anji.plus.gaea.curd.service.GaeaBaseService;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.param.ReportShareParam;
import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare;
/**
* @desc ReportShare
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
public interface ReportShareService extends GaeaBaseService<ReportShareParam, ReportShare> {
/***
*
*
* @param id
* @return
*/
ReportShare getDetail(Long id);
ReportShareDto insertShare(ReportShareDto dto);
ReportShare detailByCode(String shareCode);
}

@ -0,0 +1,107 @@
package com.anjiplus.template.gaea.business.modules.reportshare.service.impl;
import com.anji.plus.gaea.constant.BaseOperationEnum;
import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
import com.anji.plus.gaea.exception.BusinessException;
import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
import com.anjiplus.template.gaea.business.code.ResponseCode;
import com.anjiplus.template.gaea.business.enums.EnableFlagEnum;
import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto;
import com.anjiplus.template.gaea.business.modules.reportshare.dao.ReportShareMapper;
import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare;
import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService;
import com.anjiplus.template.gaea.business.util.DateUtil;
import com.anjiplus.template.gaea.business.util.JwtUtil;
import com.anjiplus.template.gaea.business.util.UuidUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @desc ReportShare
* @author Raod
* @date 2021-08-18 13:37:26.663
**/
@Service
public class ReportShareServiceImpl implements ReportShareService {
/**
* aj
*/
private static final String SHARE_FLAG = "#/aj/";
private static final String SHARE_URL = "#";
@Autowired
private ReportShareMapper reportShareMapper;
@Override
public GaeaBaseMapper<ReportShare> getMapper() {
return reportShareMapper;
}
@Override
public ReportShare getDetail(Long id) {
ReportShare reportShare = this.selectOne(id);
return reportShare;
}
@Override
public ReportShareDto insertShare(ReportShareDto dto) {
ReportShareDto reportShareDto = new ReportShareDto();
ReportShare entity = new ReportShare();
BeanUtils.copyProperties(dto, entity);
insert(entity);
//将分享链接返回
reportShareDto.setShareUrl(entity.getShareUrl());
return reportShareDto;
}
@Override
public ReportShare detailByCode(String shareCode) {
LambdaQueryWrapper<ReportShare> wrapper = Wrappers.lambdaQuery();
wrapper.eq(ReportShare::getShareCode, shareCode);
wrapper.eq(ReportShare::getEnableFlag, EnableFlagEnum.ENABLE.getCodeValue());
ReportShare reportShare = selectOne(wrapper);
if (null == reportShare) {
throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID);
}
return reportShare;
}
@Override
public void processBeforeOperation(ReportShare entity, BaseOperationEnum operationEnum) throws BusinessException {
switch (operationEnum) {
case INSERT:
init(entity);
break;
default:
break;
}
}
/**
*
* @param entity
*/
private void init(ReportShare entity) {
//前端地址 window.location.href https://report.anji-plus.com/index.html#/report/bigscreen
//截取#之前的内容
//http://localhost:9528/#/bigscreen/viewer?reportCode=bigScreen2
//http://127.0.0.1:9095/reportDashboard/getData
String shareCode = UuidUtil.generateShortUuid();
entity.setShareCode(shareCode);
if (entity.getShareUrl().contains(SHARE_URL)) {
String prefix = entity.getShareUrl().substring(0, entity.getShareUrl().indexOf("#"));
entity.setShareUrl(prefix + SHARE_FLAG + shareCode);
} else {
entity.setShareUrl(entity.getShareUrl() + SHARE_FLAG + shareCode);
}
entity.setShareValidTime(DateUtil.getFutureDateTmdHms(entity.getShareValidType()));
entity.setShareToken(JwtUtil.createToken(entity.getReportCode(), shareCode, entity.getShareValidTime()));
}
}

@ -0,0 +1,152 @@
/*
*Copyright © 2018 anji-plus
*
*http://www.anji-plus.com
*All rights reserved.
*/
package com.anjiplus.template.gaea.business.util;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.util.Base64;
public class AESUtil {
//算法
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
private static final String AES_KEY = "AnjiPLUSAjReport";
/**
* key
*
* @return
*/
public static String getKey() {
return AES_KEY;
}
/**
* byte[]
*
* @param bytes byte[]
* @param radix Character.MIN_RADIXCharacter.MAX_RADIX10
* @return
*/
public static String binary(byte[] bytes, int radix) {
return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
}
/**
* base 64 encode
*
* @param bytes byte[]
* @return base 64 code
*/
public static String base64Encode(byte[] bytes) {
//return Base64.encodeBase64String(bytes);
return Base64.getEncoder().encodeToString(bytes);
}
/**
* base 64 decode
*
* @param base64Code base 64 code
* @return byte[]
* @throws Exception
*/
public static byte[] base64Decode(String base64Code) throws Exception {
Base64.Decoder decoder = Base64.getDecoder();
return StringUtils.isEmpty(base64Code) ? null : decoder.decode(base64Code);
}
/**
* AES
*
* @param content
* @param encryptKey
* @return byte[]
* @throws Exception
*/
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
/**
* AESbase 64 code
*
* @param content
* @param encryptKey
* @return base 64 code
* @throws Exception
*/
public static String aesEncrypt(String content, String encryptKey) throws Exception {
if (StringUtils.isBlank(encryptKey)) {
return content;
}
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
/**
* AES
*
* @param encryptBytes byte[]
* @param decryptKey
* @return String
* @throws Exception
*/
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
/**
* base 64 code AES
*
* @param encryptStr base 64 code
* @param decryptKey
* @return string
* @throws Exception
*/
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
if (StringUtils.isBlank(decryptKey)) {
return encryptStr;
}
return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
/**
*
*/
public static void main(String[] args) throws Exception {
String randomString = getKey();
String content = "report";
System.out.println("加密前:" + content);
System.out.println("加密密钥和解密密钥:" + randomString);
String encrypt = aesEncrypt(content, randomString);
System.out.println("加密后:" + encrypt);
String decrypt = aesDecrypt(encrypt, randomString);
System.out.println("解密后:" + decrypt);
}
}

@ -1,7 +1,8 @@
package com.anjiplus.template.gaea.business.modules.dashboard.util;
package com.anjiplus.template.gaea.business.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
@ -44,4 +45,25 @@ public class DateUtil {
return null;
}
}
/**
*
*
* @param day
* @return
*/
public static Date getFutureDateTmdHms(int day) {
if (day <= 0) {
//默认2099年
return parse("2099-01-01", defaultDatePattern);
}
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + day);
return calendar.getTime();
}
public static void main(String[] args) {
Date futureDateTmdHms = getFutureDateTmdHms(7);
System.out.println(futureDateTmdHms);
}
}

@ -0,0 +1,58 @@
package com.anjiplus.template.gaea.business.util;
import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
import com.anjiplus.template.gaea.business.code.ResponseCode;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.Map;
/**
* Created by raodeming on 2021/8/18.
*/
public class JwtUtil {
private static final String JWT_SECRET = "aj-report";
public static String createToken(String reportCode, String shareCode, Date expires) {
String token = JWT.create()
.withIssuedAt(new Date())
.withExpiresAt(expires)
.withClaim("reportCode", reportCode)
.withClaim("shareCode", shareCode)
.sign(Algorithm.HMAC256(JWT_SECRET));
return token;
}
public static Map<String, Claim> getClaim(String token) {
try {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET)).build();
DecodedJWT decodedJwt = jwtVerifier.verify(token);
return decodedJwt.getClaims();
} catch (Exception e) {
throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID, e.getMessage());
}
}
public static String getReportCode(String token) {
Claim claim = getClaim(token).get("reportCode");
if (null == claim) {
throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID);
}
return claim.asString();
}
public static String getShareCode(String token) {
Claim claim = getClaim(token).get("shareCode");
if (null == claim) {
throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID);
}
return claim.asString();
}
}

@ -0,0 +1,44 @@
package com.anjiplus.template.gaea.business.util;
import java.util.UUID;
/**
* Created by raodeming on 2021/8/19.
*/
public class UuidUtil {
public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z" };
/**
* 8id
* @return
*/
public static String generateShortUuid() {
StringBuilder builder = new StringBuilder();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
builder.append(chars[x % 0x3E]);
}
return builder.toString();
}
public static String generateUuid() {
return UUID.randomUUID().toString().replace("-", "");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(generateShortUuid());
}
}
}

@ -73,7 +73,7 @@ customer:
downloadPath: http://10.108.26.197:9095/file/download
# 跳过token验证和权限验证的url清单
skip-authenticate-urls: /gaeaDict/all, /login, /static, /file/download/, /index.html, /favicon.ico
skip-authenticate-urls: /gaeaDict/all, /login, /static, /file/download/, /index.html, /favicon.ico, /reportShare/detailByCode
user:
##新增用户默认密码
default:

@ -0,0 +1,86 @@
use
aj_report;
CREATE TABLE `gaea_report_share`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`share_code` varchar(50) DEFAULT NULL COMMENT '分享编码系统生成默认UUID',
`share_valid_type` int(2) DEFAULT NULL COMMENT '分享有效期类型DIC_NAME=SHARE_VAILD',
`share_valid_time` datetime DEFAULT NULL COMMENT '分享有效期',
`share_token` varchar(255) DEFAULT NULL COMMENT '分享token',
`share_url` varchar(100) DEFAULT NULL COMMENT '分享url',
`report_code` varchar(50) DEFAULT NULL COMMENT '报表编码',
`enable_flag` int(1) DEFAULT '1' COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG',
`delete_flag` int(1) DEFAULT '0' COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG',
`create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(255) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`version` int(8) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `UNIQUE_SHARE_CODE` (`share_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报表分享';
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '分享有效期', 'SHARE_VAILD', '报表分享', 'admin', '2021-08-18 13:29:19', 'admin', '2021-08-18 13:29:24', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '柱状图属性', 'BAR_PROPERTIES', '柱状图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '折线图属性', 'LINE_PROPERTIES', '折线图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '柱线图属性', 'BAR_LINE_PROPERTIES', '柱线图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '饼图属性', 'PIE_PROPERTIES', '饼图、漏斗图', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '单文本图属性', 'TEXT_PROPERTIES', '仪表盘、百分比、文本框、滚动文本', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '堆叠图属性', 'STACK_PROPERTIES', '堆叠图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict`(`id`, `dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , '地图属性', 'MAP_PROPERTIES', '地图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'SHARE_VAILD', '永久有效', '0', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-18 13:30:21', 'admin', '2021-08-18 13:30:21', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default, 'SHARE_VAILD', '1天', '1', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-18 13:30:39', 'admin', '2021-08-18 13:30:39', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default, 'SHARE_VAILD', '7天', '7', NULL, 1, 'zh', NULL, 3, 'admin', '2021-08-18 13:30:51', 'admin', '2021-08-18 13:30:56', 2);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default, 'SHARE_VAILD', '30天', '30', NULL, 1, 'zh', NULL, 4, 'admin', '2021-08-18 13:31:11', 'admin', '2021-08-18 13:31:11', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:19:35', 'admin', '2021-08-20 10:19:35', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:19:56', 'admin', '2021-08-20 10:19:56', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'LINE_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:27:39', 'admin', '2021-08-20 10:27:39', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'LINE_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:27:49', 'admin', '2021-08-20 10:27:49', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:31:51', 'admin', '2021-08-20 10:31:51', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', 'x轴时间轴-时', 'xAxis-hour', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:32:11', 'admin', '2021-08-20 10:32:11', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', 'x轴时间轴-天', 'xAxis-day', NULL, 1, 'zh', NULL, 3, 'admin', '2021-08-20 10:32:25', 'admin', '2021-08-20 10:32:25', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', 'x轴时间轴-月', 'xAxis-month', NULL, 1, 'zh', NULL, 4, 'admin', '2021-08-20 10:32:38', 'admin', '2021-08-20 10:32:38', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', '时间轴-年', 'xAxis-year', NULL, 1, 'zh', NULL, 5, 'admin', '2021-08-20 10:32:52', 'admin', '2021-08-20 10:32:52', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 6, 'admin', '2021-08-20 10:33:02', 'admin', '2021-08-20 10:33:02', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'BAR_LINE_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 7, 'admin', '2021-08-20 10:33:11', 'admin', '2021-08-20 10:33:11', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'PIE_PROPERTIES', '名称name', 'name', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:35:27', 'admin', '2021-08-20 10:35:27', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'PIE_PROPERTIES', '数值value', 'value', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:35:38', 'admin', '2021-08-20 10:35:38', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'TEXT_PROPERTIES', '文本数字', 'text', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:36:04', 'admin', '2021-08-20 10:36:04', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:31:51', 'admin', '2021-08-20 10:31:51', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', 'x轴时间轴-时', 'xAxis-hour', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:32:11', 'admin', '2021-08-20 10:32:11', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', 'x轴时间轴-天', 'xAxis-day', NULL, 1, 'zh', NULL, 3, 'admin', '2021-08-20 10:32:25', 'admin', '2021-08-20 10:32:25', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', 'x轴时间轴-月', 'xAxis-month', NULL, 1, 'zh', NULL, 4, 'admin', '2021-08-20 10:32:38', 'admin', '2021-08-20 10:32:38', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', '时间轴-年', 'xAxis-year', NULL, 1, 'zh', NULL, 5, 'admin', '2021-08-20 10:32:52', 'admin', '2021-08-20 10:32:52', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', 'y轴字段', 'yAxis', NULL, 1, 'zh', NULL, 6, 'admin', '2021-08-20 10:32:52', 'admin', '2021-08-20 10:32:52', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 7, 'admin', '2021-08-20 10:33:02', 'admin', '2021-08-20 10:33:02', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'STACK_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 8, 'admin', '2021-08-20 10:33:11', 'admin', '2021-08-20 10:33:11', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'MAP_PROPERTIES', '名称name', 'name', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:41:00', 'admin', '2021-08-20 10:41:00', 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (default , 'MAP_PROPERTIES', '数值value', 'value', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:41:11', 'admin', '2021-08-20 10:41:11', 1);
INSERT INTO `aj_report`.`gaea_report_data_set`(`set_code`, `set_name`, `set_desc`, `source_code`, `dyn_sentence`, `case_result`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('barstack_ajreport', '柱状堆叠数据', '', 'mysql_ajreport', 'select time,type,nums from aj_report_barstack', '[{\"time\":\"2021-07-27\",\"type\":\"A\",\"nums\":12},{\"time\":\"2021-07-27\",\"type\":\"B\",\"nums\":20},{\"time\":\"2021-07-27\",\"type\":\"C\",\"nums\":11},{\"time\":\"2021-07-26\",\"type\":\"A\",\"nums\":11},{\"time\":\"2021-07-26\",\"type\":\"B\",\"nums\":30},{\"time\":\"2021-07-25\",\"type\":\"B\",\"nums\":20},{\"time\":\"2021-07-25\",\"type\":\"C\",\"nums\":15}]', 1, 0, 'admin', '2021-07-27 19:50:52', 'admin', '2021-08-16 14:08:51', 7);
use
aj_report_init;
CREATE TABLE `aj_report_barstack`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` date DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`nums` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*堆叠图数据*/
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (1, '2021-07-27', 'A', 12);
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (2, '2021-07-27', 'B', 20);
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (3, '2021-07-27', 'C', 11);
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (4, '2021-07-26', 'A', 11);
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (5, '2021-07-26', 'B', 30);
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (6, '2021-07-25', 'B', 20);
INSERT INTO `aj_report_init`.`aj_report_barstack`(`id`, `time`, `type`, `nums`) VALUES (7, '2021-07-25', 'C', 15);

@ -0,0 +1,3 @@
UPDATE `aj_report`.`gaea_dict_item` SET `dict_code` = 'CHART_PROPERTIES', `item_name` = 'x轴字段', `item_value` = 'xAxis', `item_extend` = NULL, `enabled` = 1, `locale` = 'zh', `remark` = NULL, `sort` = 1, `create_by` = 'admin', `create_time` = now(), `update_by` = 'admin', `update_time` = now(), `version` = 1 WHERE `id` = 260;
INSERT INTO `aj_report`.`gaea_dict_item`(`id`, `dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES (288, 'CHART_PROPERTIES', 'y轴字段', 'yAxis', NULL, 1, 'zh', NULL, 11, 'admin', '2021-07-05 15:33:59', 'admin', '2021-07-05 15:33:59', 1);

@ -47,3 +47,5 @@ Component.load.check.error={0} Component not load
4008=The set code does not allow duplication
4009=The source code does not allow duplication
4010=Can't auto find match driver class
report.share.link.invalid=report share link invalid

@ -52,3 +52,4 @@ Component.load.check.error={0}\u7EC4\u4EF6\u672A\u52A0\u8F7D
7001=\u89E3\u6790\u5931\u8D25
report.share.link.invalid=\u5206\u4EAB\u94FE\u63A5\u5DF2\u5931\u6548

@ -0,0 +1,26 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.anjiplus.template.gaea.business.modules.reportshare.dao.ReportShareMapper">
<resultMap type="com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare" id="ReportShareMap">
<!--jdbcType="{column.columnType}"-->
<result property="id" column="id" />
<result property="shareCode" column="share_code" />
<result property="shareValidType" column="share_valid_type" />
<result property="shareValidTime" column="share_valid_time" />
<result property="shareUrl" column="share_url" />
<result property="reportCode" column="report_code" />
<result property="enableFlag" column="enable_flag" />
<result property="deleteFlag" column="delete_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="version" column="version" />
</resultMap>
<sql id="Base_Column_List">
id,share_code,share_valid_type,share_valid_time,share_url,report_code,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version
</sql>
</mapper>

@ -0,0 +1,48 @@
package com.anjiplus.template.gaea.business.modules.reportshare.service.impl;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Test;
import java.util.Date;
/**
* Created by raodeming on 2021/8/18.
*/
public class ReportShareServiceImplTest {
@Test
public void jwtTest() throws InterruptedException {
long l = System.currentTimeMillis();
String sign = JWT.create()
.withIssuedAt(new Date())
.withExpiresAt(new Date(l + 5000))
.withClaim("reportCode", "report")
.withClaim("shareCode", "1234567")
.sign(Algorithm.HMAC256("111"));
System.out.println(sign);
Thread.sleep(8000L);
DecodedJWT verify = JWT.require(Algorithm.HMAC256("111")).build().verify(sign);
Date expiresAt = verify.getExpiresAt();
String reportCode = verify.getClaim("reportCode").asString();
String shareCode = verify.getClaim("shareCode").asString();
System.out.println(expiresAt);
System.out.println(reportCode);
System.out.println(shareCode);
}
}

@ -1,4 +1,5 @@
import request from '@/utils/request'
import { getShareToken, getToken } from "@/utils/auth";
// 保存大屏设计
export function insertDashboard(data) {
@ -13,6 +14,7 @@ export function insertDashboard(data) {
export function detailDashboard(data) {
return request({
url: 'reportDashboard/' + data,
headers: { 'Share-Token': getShareToken(), 'Authorization': getToken() },
method: 'get',
})
}
@ -22,6 +24,7 @@ export function queryAllDataSet(data) {
return request({
url: 'dataSet/queryAllDataSet',
method: 'get',
})
}
@ -38,6 +41,7 @@ export function getData(data) {
return request({
url: 'reportDashboard/getData',
method: 'post',
headers: { 'Share-Token': getShareToken(), 'Authorization': getToken() },
data,
})
}

@ -0,0 +1,50 @@
import request from '@/utils/request'
export function reportShareList(params) {
return request({
url: 'reportShare/pageList',
method: 'GET',
params,
})
}
export function reportShareAdd(data) {
return request({
url: 'report/share',
method: 'post',
data
})
}
export function reportShareDeleteBatch(data) {
return request({
url: 'reportShare/delete/batch',
method: 'post',
data
})
}
export function reportShareUpdate(data) {
return request({
url: 'reportShare',
method: 'put', data,
})
}
export function reportShareDetail(data) {
return request({
url: 'reportShare/' + data.id,
method: 'get',
params: { accessKey: data.accessKey }
})
}
export function reportShareDetailByCode(data) {
return request({
url: 'reportShare/detailByCode',
method: 'get',
params: { shareCode: data }
})
}
export default { reportShareList, reportShareAdd, reportShareDeleteBatch, reportShareUpdate, reportShareDetail }

@ -54,6 +54,18 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe621;</span>
<div class="name">堆叠图</div>
<div class="code-name">&amp;#xe621;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe61f;</span>
<div class="name">堆叠图</div>
<div class="code-name">&amp;#xe61f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe645;</span>
<div class="name">文件</div>
@ -750,9 +762,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1628064452460') format('woff2'),
url('iconfont.woff?t=1628064452460') format('woff'),
url('iconfont.ttf?t=1628064452460') format('truetype');
src: url('iconfont.woff2?t=1629425895962') format('woff2'),
url('iconfont.woff?t=1629425895962') format('woff'),
url('iconfont.ttf?t=1629425895962') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -778,6 +790,24 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont iconbianzu23"></span>
<div class="name">
堆叠图
</div>
<div class="code-name">.iconbianzu23
</div>
</li>
<li class="dib">
<span class="icon iconfont iconduidietu"></span>
<div class="name">
堆叠图
</div>
<div class="code-name">.iconduidietu
</div>
</li>
<li class="dib">
<span class="icon iconfont iconfill_folder"></span>
<div class="name">
@ -1822,6 +1852,22 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconbianzu23"></use>
</svg>
<div class="name">堆叠图</div>
<div class="code-name">#iconbianzu23</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconduidietu"></use>
</svg>
<div class="name">堆叠图</div>
<div class="code-name">#iconduidietu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconfill_folder"></use>

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 1513211 */
src: url('iconfont.woff2?t=1628064452460') format('woff2'),
url('iconfont.woff?t=1628064452460') format('woff'),
url('iconfont.ttf?t=1628064452460') format('truetype');
src: url('iconfont.woff2?t=1629425895962') format('woff2'),
url('iconfont.woff?t=1629425895962') format('woff'),
url('iconfont.ttf?t=1629425895962') format('truetype');
}
.iconfont {
@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.iconbianzu23:before {
content: "\e621";
}
.iconduidietu:before {
content: "\e61f";
}
.iconfill_folder:before {
content: "\e645";
}

File diff suppressed because one or more lines are too long

@ -5,6 +5,20 @@
"css_prefix_text": "icon",
"description": "",
"glyphs": [
{
"icon_id": "18888301",
"name": "堆叠图",
"font_class": "bianzu23",
"unicode": "e621",
"unicode_decimal": 58913
},
{
"icon_id": "23457042",
"name": "堆叠图",
"font_class": "duidietu",
"unicode": "e61f",
"unicode_decimal": 58911
},
{
"icon_id": "5472881",
"name": "文件",

@ -109,6 +109,7 @@ export default {
// widget-gauge 仪表盘
// widget-text 文本框
// widge-table 表格(数据不要转)
// widget-stackchart 堆叠图
const chartType = params.chartType
if (
chartType == "widget-barchart" ||
@ -125,6 +126,8 @@ export default {
return this.gaugeFn(params.chartProperties, data);
} else if (chartType == "widget-text") {
return this.widgettext(params.chartProperties, data)
} else if (chartType == "widget-stackchart") {
return this.stackChartFn(params.chartProperties, data)
} else {
return data
}
@ -157,6 +160,39 @@ export default {
ananysicData["series"] = series;
return ananysicData;
},
//堆叠图
stackChartFn(chartProperties, data) {
const ananysicData = {};
const series = [];
//全部字段字典值
const types = Object.values(chartProperties)
//x轴字段、y轴字段名
const xAxisField = Object.keys(chartProperties)[types.indexOf('xAxis')]
const yAxisField = Object.keys(chartProperties)[types.indexOf('yAxis')]
//x轴数值去重y轴去重
const xAxisList = this.setUnique(data.map(item => item[xAxisField]))
const yAxisList = this.setUnique(data.map(item => item[yAxisField]))
const dataGroup = this.setGroupBy(data, yAxisField)
for (const key in chartProperties) {
if (chartProperties[key] !== 'yAxis' && !chartProperties[key].startsWith('xAxis')) {
Object.keys(dataGroup).forEach(item => {
const data = new Array(yAxisList.length).fill(0)
dataGroup[item].forEach(res => {
data[xAxisList.indexOf(res[xAxisField])]= res[key]
})
series.push({
name: yAxisList[item],
type: chartProperties[key],
data,
})
})
}
}
ananysicData["xAxis"] = xAxisList;
ananysicData["series"] = series;
return ananysicData;
},
// 饼图、漏斗图
piechartFn(chartProperties, data) {
const ananysicData = [];
@ -208,6 +244,24 @@ export default {
}
return ananysicData;
},
setUnique(arr) {
let newArr = [];
arr.forEach(item => {
return newArr.includes(item) ? '' : newArr.push(item);
});
return newArr;
},
setGroupBy(array, name) {
const groups = {}
array.forEach(function (o) {
const group = JSON.stringify(o[name])
groups[group] = groups[group] || []
groups[group].push(o)
})
return Object.keys(groups).map(function (group) {
return groups[group]
})
},
},
watch: {
'selectInput.keyname'(newVal, oldVal) {

@ -4,7 +4,7 @@ import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { getToken, getAccessUser } from "@/utils/auth";
export default router
var whiteList = ['/login']
var whiteList = ['/login', '/aj/**', '/bigscreen/viewer']
// 判断是否需要登录权限 以及是否登录
router.beforeEach((to, from, next) => {
@ -20,13 +20,19 @@ router.beforeEach((to, from, next) => {
next()
}
}else {
// 如果没有token
if ((token == null || token == '' || token ==undefined || gaeaUser == {}) && (to.meta != null && to.meta.requireAuth == true)) { // 在免登录白名单,直接进入
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
NProgress.done()
} else {
console.log(to.path)
if (whiteList.includes(to.path)) {
next()
}else {
// 如果没有token
if ((token == null || token == '' || token ==undefined || gaeaUser == {}) && (to.meta != null && to.meta.requireAuth == true)) {// 在免登录白名单,直接进入
next(`/login?redirect=${to.path}`); // 否则全部重定向到登录页
NProgress.done();
} else {
next();
}
}
}
})

@ -27,6 +27,7 @@ import Layout from '../views/layout/Layout'
**/
export const constantRouterMap = [
{ path: '/login', component: () => import('@/views/login'), hidden: true },
{ path: '/aj/**', component: () => import('@/views/report/aj'), hidden: true },
{
path: '/index', component: Layout, name: 'index', meta: { title: '首页', icon: 'iconhome2' },
children: [
@ -56,7 +57,7 @@ export const constantRouterMap = [
children: [
{ path: 'file', name: 'file', component: () => import('@/views/file-management/index'), meta: { title: '文件管理', icon: 'iconfill_folder', keepAlive: true, requireAuth: true, permission: 'fileManage'} },
{ path: 'dict', name: 'dict', component: () => import('@/views/dict/index'), meta: { title: '数据字典', icon: 'iconzidian', keepAlive: true, requireAuth: true, permission: 'dictManage'} },
{ path: 'dictItem', name: 'dictItem', component: () => import('@/views/dict/dict-item'), meta: { title: '字典项', icon: 'iconzidianxiang', keepAlive: true, requireAuth: true, permission: 'dictItemManage'} },
{ path: 'dictItem', name: 'dictItem', component: () => import('@/views/dict/dict-item'), hidden: true, meta: { title: '字典项', icon: 'iconzidianxiang', keepAlive: true, requireAuth: true, permission: 'dictItemManage'} },
]
},
{ path: '/bigscreen/viewer', component: () => import('@/views/report/bigscreen/viewer'), hidden: true, meta: { requireAuth: true }},

@ -1,5 +1,5 @@
import { login, logout } from '@/api/login'
import { setToken, delToken, setAccessUser, delAccessUser } from '@/utils/auth'
import {setToken, delToken, setAccessUser, delAccessUser, delShareToken} from '@/utils/auth'
const user = {
state: {
@ -51,6 +51,7 @@ const user = {
commit('SET_TOKEN', '')
commit('SET_ACCESSUSER', {})
delToken()
delShareToken()
delAccessUser()
resolve()
}).catch(error => {
@ -65,6 +66,7 @@ const user = {
commit('SET_TOKEN', '')
commit('SET_ACCESSUSER', {})
delToken()
delShareToken()
delAccessUser()
resolve()
})

@ -1,17 +1,27 @@
import { getStorageItem, setStorageItem, delStorageItem } from '@/utils/storage'
const TokenKey = 'token'
const ShareTokenKey = 'shareToken'
const AccessUserKey = 'gaeaUser'
export function getToken() {
return getStorageItem(TokenKey)
}
export function getShareToken() {
return getStorageItem(ShareTokenKey) == null ? '' : getStorageItem(ShareTokenKey);
}
export function setToken(token) {
return setStorageItem(TokenKey, token)
}
export function setShareToken(shareToken) {
return setStorageItem(ShareTokenKey, shareToken)
}
export function delToken() {
return delStorageItem(TokenKey)
}
export function delShareToken() {
return delStorageItem(ShareTokenKey)
}
export function getAccessUser() {
return getStorageItem(AccessUserKey)

@ -49,7 +49,7 @@ service.interceptors.response.use(
type: 'error',
duration: 5 * 1000
})
return Promise.reject('error')
return response.data
} else {
return response.data
}

@ -177,7 +177,8 @@ export default {
rules: [
{ required: true, message: "状态不能为空", trigger: "blur" }
],
disabled: false
disabled: false,
defaultValue: 1
},
{
label: "排序", //

@ -1,19 +1,22 @@
<template>
<anji-crud ref="listPage" :option="crudOption">
<template v-slot:buttonLeftOnTable>
<el-upload class="el-upload" :action="uploadUrl" :headers="headers" :on-success="handleUpload" :on-error="handleUpload" :show-file-list="false" :limit="1">
<el-upload class="el-upload" ref="upload" :action="uploadUrl" :headers="headers" :on-success="handleUpload"
:on-error="handleError" :show-file-list="false" :limit="1">
<el-button type="primary" icon="el-icon" v-permission="'fileManage:upload'"></el-button>
</el-upload>
</template>
<template slot="rowButton" slot-scope="props">
<el-button type="text" @click="copyUrlPath(props)">url</el-button>
<el-button type="text" @click="customButtom(props)"></el-button>
</template>
</anji-crud>
</template>
<script>
import { fileList, fileAdd, fileDel, fileUpdate, fileDetail } from '@/api/file'
import { getToken } from '@/utils/auth'
import {fileList, fileAdd, fileDel, fileUpdate, fileDetail} from '@/api/file'
import {getToken} from '@/utils/auth'
export default {
name: 'File',
components: {
@ -95,7 +98,7 @@ export default {
editField: 'fileId',
tableHide: true, //
inputType: 'input',
rules: [{ min: 1, max: 64, message: '不超过64个字符', trigger: 'blur' }],
rules: [{min: 1, max: 64, message: '不超过64个字符', trigger: 'blur'}],
disabled: false,
},
{
@ -104,7 +107,7 @@ export default {
field: 'fileType',
editField: 'fileType',
inputType: 'input',
rules: [{ min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur' }],
rules: [{min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur'}],
disabled: false,
},
{
@ -113,7 +116,7 @@ export default {
field: 'filePath',
editField: 'filePath',
inputType: 'input',
rules: [{ min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur' }],
rules: [{min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur'}],
disabled: false,
},
{
@ -122,7 +125,7 @@ export default {
field: 'urlPath',
editField: 'urlPath',
inputType: 'input',
rules: [{ min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur' }],
rules: [{min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur'}],
disabled: false,
},
{
@ -131,7 +134,7 @@ export default {
field: 'fileInstruction',
editField: 'fileInstruction',
inputType: 'input',
rules: [{ min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur' }],
rules: [{min: 1, max: 1024, message: '不超过1024个字符', trigger: 'blur'}],
disabled: false,
},
{
@ -162,21 +165,45 @@ export default {
},
},
created() {},
created() {
},
methods: {
//
handleUpload(response) {
handleUpload(response, file, fileList) {
console.log(this)
//
this.$refs.listPage.handleQueryForm()
//el-upload
this.$refs.upload.clearFiles()
},
handleError() {
this.$message({
message: '上传失败!',
type: 'error',
})
},
handleError() {},
async downloadFile(row) {
window.open(row.urlPath)
},
customButtom(val) {
this.downloadFile(val.msg)
},
copyUrlPath(val) {
this.copyToClip(val.msg.urlPath)
this.$message({
message: '已将url路径复制至剪切板',
type: 'success',
})
},
copyToClip(content, message) {
var aux = document.createElement("input");
aux.setAttribute("value", content);
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);
},
},
}
</script>

@ -8,20 +8,19 @@
<div class="login_container">
<!-- 顶部logo -->
<div class="login_title">
<img src="@/assets/images/home-logo.png"
alt="logo" />
<img src="@/assets/images/home-logo.png" alt="logo" />
</div>
<div class="login_contant">
<img src="@/assets/images/login.png"
alt="image"
class="login_img" />
<el-form ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login_form"
autocomplete="on"
label-position="left"
@keyup.enter.native="handleLogin">
<img src="@/assets/images/login.png" alt="image" class="login_img" />
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login_form"
autocomplete="on"
label-position="left"
@keyup.enter.native="handleLogin"
>
<div class="title_container">
<h3 class="title">
HELLO,
@ -37,41 +36,48 @@
<div>
<p>用户名</p>
<el-form-item prop="loginName">
<el-input ref="loginName"
v-model="loginForm.loginName"
placeholder="用户名"
name="loginName"
type="text"
tabindex="1"
autocomplete="on"
@focus="setTop('0')"
@change="getPsw" />
<el-input
ref="loginName"
v-model="loginForm.loginName"
placeholder="用户名"
name="loginName"
type="text"
tabindex="1"
autocomplete="on"
@focus="setTop('0')"
@change="getPsw"
/>
</el-form-item>
</div>
<div>
<p>密码</p>
<input name="password"
type="password"
autocomplete="off"
class="take" />
<el-tooltip v-model="capsTooltip"
content="Caps lock is On"
placement="right"
manual>
<input
name="password"
type="password"
autocomplete="off"
class="take"
/>
<el-tooltip
v-model="capsTooltip"
content="Caps lock is On"
placement="right"
manual
>
<el-form-item prop="password">
<el-input :key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="用户密码"
name="password"
tabindex="2"
autocomplete="on"
@blur="capsTooltip = false"
@focus="setTop('50')"
@keyup.native="checkCapslock" />
<span class="show_pwd"
@click="showPwd">
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="用户密码"
name="password"
tabindex="2"
autocomplete="on"
@blur="capsTooltip = false"
@focus="setTop('50')"
@keyup.native="checkCapslock"
/>
<span class="show_pwd" @click="showPwd">
<i class="el-icon-view" />
</span>
</el-form-item>
@ -80,180 +86,181 @@
</div>
<div class="control">
<div class="remember">
<input v-model="rememberPsw"
type="checkbox" />
<input v-model="rememberPsw" type="checkbox" />
<p>记住密码</p>
</div>
</div>
<el-button :loading="loading"
type="primary"
class="login_btn"
@click.native.prevent="handleLogin">登录</el-button>
<el-button
:loading="loading"
type="primary"
class="login_btn"
@click.native.prevent="handleLogin"
>登录</el-button
>
</el-form>
</div>
<!-- 验证码 -->
<Verify v-if="needCaptcha"
ref="verify"
:captcha-type="'blockPuzzle'"
:img-size="{ width: '400px', height: '200px' }"
@success="verifylogin" />
<Verify
v-if="needCaptcha"
ref="verify"
:captcha-type="'blockPuzzle'"
:img-size="{ width: '400px', height: '200px' }"
@success="verifylogin"
/>
</div>
</template>
<script>
import Verify from '@/components/verifition/Verify'
import cookies from 'js-cookie'
import { Decrypt, Encrypt } from '@/utils/index'
import { login } from '@/api/login'
import { transPsw } from '@/utils/encrypted'
import Verify from "@/components/verifition/Verify";
import cookies from "js-cookie";
import { Decrypt, Encrypt } from "@/utils/index";
import { login } from "@/api/login";
import { transPsw } from "@/utils/encrypted";
import { setToken, setAccessUser } from "@/utils/auth";
export default {
name: 'Login',
name: "Login",
components: {
Verify,
Verify
},
data () {
data() {
return {
activeTop: '-50%', //
activeTop: "-50%", //
rememberPsw: false, //
loginForm: {
loginName: '',
password: '',
verifyCode: '',
loginName: "",
password: "",
verifyCode: ""
}, //
loginRules: {
loginName: [{ required: true, message: '用户名必填', trigger: 'blur' }],
password: [
{ required: true, message: '用户密码必填', trigger: 'blur' },
],
loginName: [{ required: true, message: "用户名必填", trigger: "blur" }],
password: [{ required: true, message: "用户密码必填", trigger: "blur" }]
}, //
passwordType: 'password', //
passwordType: "password", //
capsTooltip: false, //
loading: false, // loding
redirect: undefined, //
otherQuery: {}, //
needCaptcha: false,
}
needCaptcha: false
};
},
watch: {
$route: {
// from
handler: function (route) {
const query = route.query
handler: function(route) {
const query = route.query;
if (query) {
this.redirect = query.redirect
this.otherQuery = this.getOtherQuery(query)
this.redirect = query.redirect;
this.otherQuery = this.getOtherQuery(query);
}
},
immediate: true,
},
immediate: true
}
},
mounted () {
mounted() {
//
if (this.loginForm.loginName === '') {
this.$refs.loginName.focus()
} else if (this.loginForm.password === '') {
this.$refs.password.focus()
if (this.loginForm.loginName === "") {
this.$refs.loginName.focus();
} else if (this.loginForm.password === "") {
this.$refs.password.focus();
}
},
methods: {
//
getPsw () {
const cookVal = cookies.get(`u_${this.loginForm.loginName}`)
this.loginForm.password = cookVal && Decrypt(cookVal)
getPsw() {
const cookVal = cookies.get(`u_${this.loginForm.loginName}`);
this.loginForm.password = cookVal && Decrypt(cookVal);
},
// top
setTop (val) {
this.activeTop = val
setTop(val) {
this.activeTop = val;
},
//
checkCapslock (e) {
const { key } = e
this.capsTooltip = key && key.length === 1 && key >= 'A' && key <= 'Z'
checkCapslock(e) {
const { key } = e;
this.capsTooltip = key && key.length === 1 && key >= "A" && key <= "Z";
},
//
showPwd () {
if (this.passwordType === 'password') {
this.passwordType = ''
showPwd() {
if (this.passwordType === "password") {
this.passwordType = "";
} else {
this.passwordType = 'password'
this.passwordType = "password";
}
this.$nextTick(() => {
this.$refs.password.focus()
})
this.$refs.password.focus();
});
},
//
useVerify () {
this.$refs.loginForm.validate((valid) => {
useVerify() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.$refs.verify.show()
this.$refs.verify.show();
} else {
return false
return false;
}
})
});
},
//
verifylogin (params) {
this.loginForm.verifyCode = params.captchaVerification
verifylogin(params) {
this.loginForm.verifyCode = params.captchaVerification;
if (this.loginForm.verifyCode) {
this.loginApi()
this.loginApi();
}
},
//
handleLogin () {
this.$refs.loginForm.validate((valid) => {
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.loading = true;
//
if (this.needCaptcha) {
this.useVerify()
return
this.useVerify();
return;
}
this.loginApi()
this.loginApi();
} else {
return false
return false;
}
})
});
},
async loginApi () {
async loginApi() {
let obj = {
loginName: this.loginForm.loginName,
password: transPsw(this.loginForm.password),
verifyCode: '',
}
const { code, data } = await login(obj)
console.log(data)
this.loading = false
if (code != '200') return
setToken(data.token)
setAccessUser(data)
verifyCode: ""
};
const { code, data } = await login(obj);
this.loading = false;
if (code != "200") return;
setToken(data.token);
setAccessUser(data);
// cookie,15
this.rememberPsw &&
cookies.set(
`u_${this.loginForm.loginName}`,
Encrypt(this.loginForm.password),
{ expires: 15 }
)
);
if (data && data.captcha) {
this.needCaptcha = true
this.needCaptcha = true;
} else {
this.needCaptcha = false
this.needCaptcha = false;
this.$router.push({
path: this.redirect || '/index',
query: this.otherQuery,
})
path: this.redirect || "/index",
query: this.otherQuery
});
}
},
getOtherQuery (query) {
getOtherQuery(query) {
return Object.keys(query).reduce((acc, cur) => {
if (cur !== 'redirect') {
acc[cur] = query[cur]
if (cur !== "redirect") {
acc[cur] = query[cur];
}
return acc
}, {})
},
},
}
return acc;
}, {});
}
}
};
</script>
<style lang="scss">

@ -0,0 +1,50 @@
<!--
* @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>
<div>
</div>
</template>
<script>
import { reportShareDetailByCode} from '@/api/reportShare'
import { setShareToken } from '@/utils/auth'
export default {
name: "Report",
components: {
},
data() {
return {
};
},
created() {
this.handleOpen()
},
methods: {
async handleOpen() {
const url = window.location.href
const shareCode = url.substring(url.lastIndexOf("/") + 1);
console.log(shareCode)
const {code, data} = await reportShareDetailByCode(shareCode)
if (code != '200') return
setShareToken(data.shareToken)
//shareToken
//
this.$router.push({
path: '/bigscreen/viewer',
query: {
reportCode: data.reportCode
},
})
},
}
};
</script>

@ -5,7 +5,7 @@
<el-select
size="mini"
v-model="dataSetValue"
clearable
filterable
placeholder="请选择"
@change="selectDataSet"
>
@ -27,7 +27,7 @@
<el-form-item v-for="item in setParamList" :key="item" :label="item">
<Dictionary
v-model="params"
:dict-key="'CHART_PROPERTIES'"
:dict-key="getDictKey()"
@input="selectParams($event, item)"
/>
</el-form-item>
@ -57,6 +57,7 @@ export default {
},
props: {
chartType: String,
dictKey: String,
props: ["formData"]
},
data() {
@ -66,7 +67,7 @@ export default {
userNameList: [], //
setParamList: [], //
params: {},
chartProperties: {}
chartProperties: {},
};
},
computed: {
@ -113,6 +114,9 @@ export default {
},
selectParams(val, key) {
this.chartProperties[key] = val;
},
getDictKey(){
return this.dictKey == null ? 'CHART_PROPERTIES' : this.dictKey
}
}
};

@ -137,6 +137,7 @@
v-if="item.type == 'dycustComponents' && inputShow[item.name]"
v-model="formData[item.name]"
:chart-type="item.chartType"
:dict-key='item.dictKey'
@change="changed($event, item.name)"
/>
<dynamic-add-table

@ -87,7 +87,7 @@
<i class="iconfont iconyulan" @click="viewScreen"></i>
</el-tooltip>
</span>
<span class="btn border-left">
<!-- <span class="btn border-left">
<ul class="nav">
<li>
<i class="el-icon-brush"></i><i class="el-icon-arrow-down"></i>
@ -116,7 +116,7 @@
</ul>
</li>
</ul>
</span>
</span> -->
</div>
<div
class="workbench-container"
@ -170,8 +170,6 @@
</div>
</vue-ruler-tool>
</div>
<!-- 如果是二次开发商业使用必须带上这个技术支持 -->
<div class="bottom-text">技术支持 安吉加加信息技术有限公司</div>
</div>
<div class="layout-right" :style="{ width: widthLeftForOptions + 'px' }">

File diff suppressed because it is too large Load Diff

@ -0,0 +1,411 @@
<template>
<div :style="styleObj">
<v-chart :options="options" autoresize/>
</div>
</template>
<script>
export default {
name: "WidgetBarStackchart",
components: {},
props: {
value: Object,
ispreview: Boolean
},
data() {
return {
options: {
grid: {},
legend: {
textStyle: {
color: "#fff"
}
},
xAxis: {
type: "category",
data: [],
axisLabel: {
show: true,
textStyle: {
color: "#fff"
}
}
},
yAxis: {
type: "value",
data: [],
axisLabel: {
show: true,
textStyle: {
color: "#fff"
}
}
},
series: [
{
data: [],
name: '',
type: "bar",
barGap: "0%",
itemStyle: {
barBorderRadius: null
}
}
]
},
optionsStyle: {}, //
optionsData: {}, //
optionsSetup: {},
flagInter: null
};
},
computed: {
styleObj() {
return {
position: this.ispreview ? "absolute" : "static",
width: this.optionsStyle.width + "px",
height: this.optionsStyle.height + "px",
left: this.optionsStyle.left + "px",
top: this.optionsStyle.top + "px",
background: this.optionsSetup.background
};
}
},
watch: {
value: {
handler(val) {
this.optionsStyle = val.position;
this.optionsData = val.data;
this.optionsCollapse = val.setup;
this.optionsSetup = val.setup;
this.editorOptions();
},
deep: true
}
},
mounted() {
this.optionsStyle = this.value.position;
this.optionsData = this.value.data;
this.optionsCollapse = this.value.setup;
this.optionsSetup = this.value.setup;
this.editorOptions();
},
methods: {
// options
editorOptions() {
this.setOptionsTitle();
this.setOptionsX();
this.setOptionsY();
this.setOptionsTooltip();
this.setOptionsMargin();
this.setOptionsLegend();
this.setOptionsData();
},
//
setOptionsTitle() {
const optionsSetup = this.optionsSetup;
const title = {};
title.text = optionsSetup.titleText;
title.show = optionsSetup.isNoTitle;
title.left = optionsSetup.textAlign;
title.textStyle = {
color: optionsSetup.textColor,
fontSize: optionsSetup.textFontSize,
fontWeight: optionsSetup.textFontWeight
};
title.subtext = optionsSetup.subText;
title.subtextStyle = {
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.subTextFontWeight,
fontSize: optionsSetup.subTextFontSize
};
this.options.title = title;
},
// X
setOptionsX() {
const optionsSetup = this.optionsSetup;
const xAxis = {
type: "category",
show: optionsSetup.hideX, //
name: optionsSetup.xName, //
nameTextStyle: {
color: optionsSetup.xNameColor,
fontSize: optionsSetup.xNameFontSize
},
nameRotate: optionsSetup.textAngleX, //
inverse: optionsSetup.reversalX, //
axisLabel: {
show: true,
interval: optionsSetup.textInterval, //
rotate: optionsSetup.textAngle, //
textStyle: {
color: optionsSetup.Xcolor, // x
fontSize: optionsSetup.fontSizeX
}
},
axisLine: {
show: true,
lineStyle: {
color: optionsSetup.lineColorX
}
},
splitLine: {
show: optionsSetup.isShowSplitLineX,
lineStyle: {
color: optionsSetup.splitLineColorX
}
}
};
this.options.xAxis = xAxis;
},
// Y
setOptionsY() {
const optionsSetup = this.optionsSetup;
const yAxis = {
type: "value",
show: optionsSetup.isShowY, //
name: optionsSetup.textNameY, //
nameTextStyle: {
color: optionsSetup.NameColorY,
fontSize: optionsSetup.NameFontSizeY
},
inverse: optionsSetup.reversalY, // y
axisLabel: {
show: true,
rotate: optionsSetup.textAngleY,//
textStyle: {
color: optionsSetup.colorY, // y
fontSize: optionsSetup.fontSizeY
}
},
axisLine: {
show: true,
lineStyle: {
color: optionsSetup.lineColorY
}
},
splitLine: {
show: optionsSetup.isShowSplitLineY,
lineStyle: {
color: optionsSetup.splitLineColorY
}
}
};
this.options.yAxis = yAxis;
},
// tooltip
setOptionsTooltip() {
const optionsSetup = this.optionsSetup;
const tooltip = {
trigger: "item",
show: true,
textStyle: {
color: optionsSetup.lineColor,
fontSize: optionsSetup.tipsFontSize
}
};
this.options.tooltip = tooltip;
},
//
setOptionsMargin() {
const optionsSetup = this.optionsSetup;
const grid = {
left: optionsSetup.marginLeft,
right: optionsSetup.marginRight,
bottom: optionsSetup.marginBottom,
top: optionsSetup.marginTop,
containLabel: true
};
this.options.grid = grid;
},
// legend
setOptionsLegend() {
const optionsSetup = this.optionsSetup;
const legend = this.options.legend;
legend.show = optionsSetup.isShowLegend;
legend.left = optionsSetup.lateralPosition;
legend.top = optionsSetup.longitudinalPosition == "top" ? 0 : "auto";
legend.bottom =
optionsSetup.longitudinalPosition == "bottom" ? 0 : "auto";
legend.orient = optionsSetup.layoutFront;
legend.textStyle = {
color: optionsSetup.lengedColor,
fontSize: optionsSetup.lengedFontSize
};
legend.itemWidth = optionsSetup.lengedWidth;
},
//
setOptionsData() {
const optionsSetup = this.optionsSetup;
const optionsData = this.optionsData; // or
optionsData.dataType == "staticData"
? this.staticDataFn(optionsData.staticData, optionsSetup)
: this.dynamicDataFn(
optionsData.dynamicData,
optionsData.refreshTime,
optionsSetup
);
},
//
setUnique(arr) {
let newArr = [];
arr.forEach(item => {
return newArr.includes(item) ? '' : newArr.push(item);
});
return newArr;
},
//
getStackStyle() {
const optionsSetup = this.optionsSetup;
let style = ""
if (optionsSetup.stackStyle == "upDown") {
style = "total"
}
return style
},
//
staticDataFn(val) {
const optionsSetup = this.optionsSetup;
//
const customColor = optionsSetup.customColor;
const arrColor = [];
for (let i = 0; i < customColor.length; i++) {
arrColor.push(customColor[i].color);
}
//
const series = [];
let xAxisList = []
let yAxisList = []
for (const i in val) {
xAxisList[i] = val[i].axis
yAxisList[i] = val[i].name
}
xAxisList = this.setUnique(xAxisList) // x 0725 0726 0727
yAxisList = this.setUnique(yAxisList) // y A B C
for (const i in yAxisList) {
const data = new Array(yAxisList.length).fill(0)
for (const j in xAxisList) {
for (const k in val) {
if (val[k].name == yAxisList[i]) { // a = a
if (val[k].axis == xAxisList[j]) { // 0725
data[j] = val[k].data
}
}
}
}
series.push({
name: yAxisList[i],
type: "bar",
data: data,
barGap: "0%",
stack: this.getStackStyle(),
barWidth: optionsSetup.maxWidth,
label: {
show: optionsSetup.isShow,
position: "top",
distance: 10,
fontSize: optionsSetup.fontSize,
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.fontWeight
},
//
itemStyle: {
normal: {
color: arrColor[i],
barBorderRadius: optionsSetup.radius,
}
}
})
}
this.options.series = series
if (optionsSetup.verticalShow) {
this.options.xAxis.data = [];
this.options.yAxis.data = xAxisList;
this.options.xAxis.type = "value";
this.options.yAxis.type = "category";
} else {
this.options.xAxis.data = xAxisList;
this.options.yAxis.data = [];
this.options.xAxis.type = "category";
this.options.yAxis.type = "value";
}
},
//
dynamicDataFn(val, refreshTime, optionsSetup) {
if (!val) return;
if (this.ispreview) {
this.getEchartData(val, optionsSetup);
this.flagInter = setInterval(() => {
this.getEchartData(val, optionsSetup);
}, refreshTime);
} else {
this.getEchartData(val, optionsSetup);
}
},
getEchartData(val, optionsSetup) {
const data = this.queryEchartsData(val);
data.then(res => {
this.renderingFn(optionsSetup, res);
});
},
renderingFn(optionsSetup, val) {
//
const customColor = optionsSetup.customColor;
const arrColor = [];
for (let i = 0; i < customColor.length; i++) {
arrColor.push(customColor[i].color);
}
// x
if (optionsSetup.verticalShow) {
this.options.xAxis.data = [];
this.options.yAxis.data = val.xAxis;
this.options.xAxis.type = "value";
this.options.yAxis.type = "category";
} else {
this.options.xAxis.data = val.xAxis;
this.options.yAxis.data = [];
this.options.xAxis.type = "category";
this.options.yAxis.type = "value";
}
const series = [];
for (const i in val.series) {
if (val.series[i].type == "bar") {
series.push({
name: val.series[i].name,
type: "bar",
data: val.series[i].data,
barGap: "0%",
stack: this.getStackStyle(),
barWidth: optionsSetup.maxWidth,
label: {
show: optionsSetup.isShow,
position: "top",
distance: 10,
fontSize: optionsSetup.fontSize,
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.fontWeight
},
//
itemStyle: {
normal: {
color: arrColor[i],
barBorderRadius: optionsSetup.radius,
}
}
})
}
}
this.options.series = series
}
}
};
</script>
<style scoped lang="scss">
.echarts {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>

@ -283,12 +283,11 @@ export default {
fontWeight: optionsCollapse.fontWeight
};
series[key].barWidth = optionsCollapse.maxWidth;
//series[key].barMinHeight = optionsCollapse.minHeight;
}
}
this.options.series = series;
},
// tooltip
// tooltip
setOptionsTooltip() {
const optionsCollapse = this.optionsSetup;
const tooltip = {

@ -0,0 +1,443 @@
<template>
<div :style="styleObj">
<v-chart :options="options" autoresize/>
</div>
</template>
<script>
export default {
name: "WidgetBarStackchart",
components: {},
props: {
value: Object,
ispreview: Boolean
},
data() {
return {
options: {
grid: {},
legend: {
textStyle: {
color: "#fff"
}
},
xAxis: {
type: "category",
data: [],
axisLabel: {
show: true,
textStyle: {
color: "#fff"
}
}
},
yAxis: {
type: "value",
data: [],
axisLabel: {
show: true,
textStyle: {
color: "#fff"
}
}
},
series: [
{
data: [],
name: '',
type: "line",
barGap: "0%",
itemStyle: {
barBorderRadius: null
}
}
]
},
optionsStyle: {}, //
optionsData: {}, //
optionsSetup: {},
flagInter: null
};
},
computed: {
styleObj() {
return {
position: this.ispreview ? "absolute" : "static",
width: this.optionsStyle.width + "px",
height: this.optionsStyle.height + "px",
left: this.optionsStyle.left + "px",
top: this.optionsStyle.top + "px",
background: this.optionsSetup.background
};
}
},
watch: {
value: {
handler(val) {
this.optionsStyle = val.position;
this.optionsData = val.data;
this.optionsCollapse = val.setup;
this.optionsSetup = val.setup;
this.editorOptions();
},
deep: true
}
},
mounted() {
this.optionsStyle = this.value.position;
this.optionsData = this.value.data;
this.optionsCollapse = this.value.setup;
this.optionsSetup = this.value.setup;
this.editorOptions();
},
methods: {
// options
editorOptions() {
this.setOptionsTitle();
this.setOptionsX();
this.setOptionsY();
this.setOptionsTooltip();
this.setOptionsMargin();
this.setOptionsLegend();
this.setOptionsData();
},
//
setOptionsTitle() {
const optionsSetup = this.optionsSetup;
const title = {};
title.text = optionsSetup.titleText;
title.show = optionsSetup.isNoTitle;
title.left = optionsSetup.textAlign;
title.textStyle = {
color: optionsSetup.textColor,
fontSize: optionsSetup.textFontSize,
fontWeight: optionsSetup.textFontWeight
};
title.subtext = optionsSetup.subText;
title.subtextStyle = {
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.subTextFontWeight,
fontSize: optionsSetup.subTextFontSize
};
this.options.title = title;
},
// X
setOptionsX() {
const optionsSetup = this.optionsSetup;
const xAxis = {
type: "category",
show: optionsSetup.hideX, //
name: optionsSetup.xName, //
nameTextStyle: {
color: optionsSetup.xNameColor,
fontSize: optionsSetup.xNameFontSize
},
nameRotate: optionsSetup.textAngleX, //
inverse: optionsSetup.reversalX, //
axisLabel: {
show: true,
interval: optionsSetup.textInterval, //
rotate: optionsSetup.textAngle, //
textStyle: {
color: optionsSetup.Xcolor, // x
fontSize: optionsSetup.fontSizeX
}
},
axisLine: {
show: true,
lineStyle: {
color: optionsSetup.lineColorX
}
},
splitLine: {
show: optionsSetup.isShowSplitLineX,
lineStyle: {
color: optionsSetup.splitLineColorX
}
}
};
this.options.xAxis = xAxis;
},
// Y
setOptionsY() {
const optionsSetup = this.optionsSetup;
const yAxis = {
type: "value",
show: optionsSetup.isShowY, //
name: optionsSetup.textNameY, //
nameTextStyle: {
color: optionsSetup.NameColorY,
fontSize: optionsSetup.NameFontSizeY
},
inverse: optionsSetup.reversalY, // y
axisLabel: {
show: true,
rotate: optionsSetup.textAngleY,//
textStyle: {
color: optionsSetup.colorY, // y
fontSize: optionsSetup.fontSizeY
}
},
axisLine: {
show: true,
lineStyle: {
color: optionsSetup.lineColorY
}
},
splitLine: {
show: optionsSetup.isShowSplitLineY,
lineStyle: {
color: optionsSetup.splitLineColorY
}
}
};
this.options.yAxis = yAxis;
},
//
getOptionArea() {
const optionsSetup = this.optionsSetup;
let areaStyle = [];
if (optionsSetup.area) {
areaStyle = {
opacity: optionsSetup.areaThickness / 100
}
} else {
areaStyle = {
opacity: 0
}
}
return areaStyle
},
// tooltip
setOptionsTooltip() {
const optionsSetup = this.optionsSetup;
const tooltip = {
trigger: "item",
show: true,
textStyle: {
color: optionsSetup.lineColor,
fontSize: optionsSetup.tipsFontSize
}
};
this.options.tooltip = tooltip;
},
//
setOptionsMargin() {
const optionsSetup = this.optionsSetup;
const grid = {
left: optionsSetup.marginLeft,
right: optionsSetup.marginRight,
bottom: optionsSetup.marginBottom,
top: optionsSetup.marginTop,
containLabel: true
};
this.options.grid = grid;
},
// legend
setOptionsLegend() {
const optionsSetup = this.optionsSetup;
const legend = this.options.legend;
legend.show = optionsSetup.isShowLegend;
legend.left = optionsSetup.lateralPosition;
legend.top = optionsSetup.longitudinalPosition == "top" ? 0 : "auto";
legend.bottom =
optionsSetup.longitudinalPosition == "bottom" ? 0 : "auto";
legend.orient = optionsSetup.layoutFront;
legend.textStyle = {
color: optionsSetup.lengedColor,
fontSize: optionsSetup.lengedFontSize
};
legend.itemWidth = optionsSetup.lengedWidth;
},
//
setOptionsColor() {
const optionsCollapse = this.optionsSetup;
const customColor = optionsCollapse.customColor;
if (!customColor) return;
const arrColor = [];
for (let i = 0; i < customColor.length; i++) {
arrColor.push(customColor[i].color);
}
this.options.color = arrColor;
this.options = Object.assign({}, this.options);
},
//
setOptionsData() {
const optionsSetup = this.optionsSetup;
const optionsData = this.optionsData; // or
optionsData.dataType == "staticData"
? this.staticDataFn(optionsData.staticData, optionsSetup)
: this.dynamicDataFn(
optionsData.dynamicData,
optionsData.refreshTime,
optionsSetup
);
},
//
setUnique(arr) {
let newArr = [];
arr.forEach(item => {
return newArr.includes(item) ? '' : newArr.push(item);
});
return newArr;
},
//
staticDataFn(val) {
const optionsSetup = this.optionsSetup;
//
const customColor = optionsSetup.customColor;
const arrColor = [];
for (let i = 0; i < customColor.length; i++) {
arrColor.push(customColor[i].color);
}
//
const series = [];
let xAxisList = []
let yAxisList = []
for (const i in val) {
xAxisList[i] = val[i].axis
yAxisList[i] = val[i].name
}
xAxisList = this.setUnique(xAxisList) // x 0725 0726 0727
yAxisList = this.setUnique(yAxisList) // y A B C
for (const i in yAxisList) {
const data = new Array(yAxisList.length).fill(0)
for (const j in xAxisList) {
for (const k in val) {
if (val[k].name == yAxisList[i]) { // a = a
if (val[k].axis == xAxisList[j]) { // 0725
data[j] = val[k].data
}
}
}
}
series.push({
name: yAxisList[i],
type: "line",
data: data,
width: optionsSetup.lineWidth,
symbol: 'circle',
showSymbol: optionsSetup.markPoint,
symbolSize: optionsSetup.pointSize,
symbolColor: arrColor[i],
smooth: optionsSetup.smoothCurve,
// 线
lineStyle: {
color: arrColor[i],
width: optionsSetup.lineWidth
},
//
itemStyle: {
color: arrColor[i],
},
areaStyle: this.getOptionArea(),
//
label: {
show: optionsSetup.isShow,
position: "top",
distance: 10,
fontSize: optionsSetup.fontSize,
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.fontWeight
},
})
}
this.options.series = series
if (optionsSetup.verticalShow) {
this.options.xAxis.data = [];
this.options.yAxis.data = xAxisList;
this.options.xAxis.type = "value";
this.options.yAxis.type = "category";
} else {
this.options.xAxis.data = xAxisList;
this.options.yAxis.data = [];
this.options.xAxis.type = "category";
this.options.yAxis.type = "value";
}
},
//
dynamicDataFn(val, refreshTime, optionsSetup) {
if (!val) return;
if (this.ispreview) {
this.getEchartData(val, optionsSetup);
this.flagInter = setInterval(() => {
this.getEchartData(val, optionsSetup);
}, refreshTime);
} else {
this.getEchartData(val, optionsSetup);
}
},
getEchartData(val, optionsSetup) {
const data = this.queryEchartsData(val);
data.then(res => {
this.renderingFn(optionsSetup, res);
});
},
renderingFn(optionsSetup, val) {
//
const customColor = optionsSetup.customColor;
const arrColor = [];
for (let i = 0; i < customColor.length; i++) {
arrColor.push(customColor[i].color);
}
// x
if (optionsSetup.verticalShow) {
this.options.xAxis.data = [];
this.options.yAxis.data = val.xAxis;
this.options.xAxis.type = "value";
this.options.yAxis.type = "category";
} else {
this.options.xAxis.data = val.xAxis;
this.options.yAxis.data = [];
this.options.xAxis.type = "category";
this.options.yAxis.type = "value";
}
const series = [];
for (const i in val.series) {
if (val.series[i].type == "line") {
series.push({
name: val.series[i].name,
type: "line",
data: val.series[i].data,
width: optionsSetup.lineWidth,
symbol: 'circle',
showSymbol: optionsSetup.markPoint,
symbolSize: optionsSetup.pointSize,
symbolColor: arrColor[i],
smooth: optionsSetup.smoothCurve,
// 线
lineStyle: {
color: arrColor[i],
width: optionsSetup.lineWidth
},
//
itemStyle: {
color: arrColor[i],
},
areaStyle: this.getOptionArea(),
//
label: {
show: optionsSetup.isShow,
position: "top",
distance: 10,
fontSize: optionsSetup.fontSize,
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.fontWeight
},
})
}
}
this.options.series = series
}
}
};
</script>
<style scoped lang="scss">
.echarts {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>

@ -31,6 +31,9 @@ import widgetTable from "./widgetTable.vue";
import widgetMap from "./widgetMap.vue";
import widgetPiePercentageChart from "./pie/widgetPiePercentageChart";
import widgetAirBubbleMap from "./map/widgetAirBubbleMap";
import widgetBarStackChart from "./bar/widgetBarStackChart";
import widgetLineStackChart from "./line/widgetLineStackChart";
export default {
name: "WidgetTemp",
components: {
@ -53,7 +56,9 @@ export default {
widgetTable,
widgetMap,
widgetPiePercentageChart,
widgetAirBubbleMap
widgetAirBubbleMap,
widgetBarStackChart,
widgetLineStackChart
},
model: {
prop: "value",

@ -41,6 +41,9 @@ import widgetTable from "./widgetTable.vue";
import widgetMap from "./widgetMap.vue";
import widgetPiePercentageChart from "./pie/widgetPiePercentageChart";
import widgetAirBubbleMap from "./map/widgetAirBubbleMap";
import widgetBarStackChart from "./bar/widgetBarStackChart";
import widgetLineStackChart from "./line/widgetLineStackChart";
export default {
name: "Widget",
components: {
@ -63,7 +66,9 @@ export default {
widgetTable,
widgetMap,
widgetPiePercentageChart,
widgetAirBubbleMap
widgetAirBubbleMap,
widgetBarStackChart,
widgetLineStackChart
},
model: {
prop: "value",

@ -99,6 +99,7 @@
<Share
:visib="visibleForShareDialog"
:reportCode="reportCodeForShareDialog"
:reportName="reportNameForShareDialog"
@handleClose="visibleForShareDialog = false"
/>
</div>
@ -127,7 +128,8 @@ export default {
},
//
visibleForShareDialog: false,
reportCodeForShareDialog: ""
reportCodeForShareDialog: "",
reportNameForShareDialog: ""
};
},
mounted() {},
@ -172,6 +174,7 @@ export default {
//
share(val) {
this.reportCodeForShareDialog = val.reportCode;
this.reportNameForShareDialog = val.reportName;
this.visibleForShareDialog = true;
},
openDesign(val) {

@ -14,8 +14,6 @@
:type="widget.type"
/>
</div>
<!-- 如果是二次开发商业使用必须带上这个技术支持 -->
<div class="bottom-text">技术支持 安吉加加信息技术有限公司</div>
</div>
</template>

@ -1,14 +1,45 @@
<template>
<el-dialog class="tree_dialog" title="报表分享" width="60%" :close-on-click-modal="false" center :visible.sync="visib" :before-close="closeDialog">
<el-dialog class="tree_dialog" :title="titleBuild()" width="60%" :close-on-click-modal="false" center :visible.sync="visib" :before-close="closeDialog">
<div v-if="shareLinkFlag1">
<el-form ref="userForm" :model="dialogForm" :rules="rules" size="small" label-width="100px">
<el-row :gutter="10">
<el-col :xs="24" :sm="20" :md="6" :lg="6" :xl="6">
<el-form-item label="有效期" prop="shareValidType">
<el-select v-model.trim="dialogForm.shareValidType" placeholder="请选择" clearable @change="selectChange">
<el-option v-for="item in shareValidTypeOptions" :key="item.id" :label="item.text" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-button type="primary" plain @click="createShare"></el-button>
</div>
<div v-else>
<el-row :gutter="10">
<el-col :xs="24" :sm="20" :md="20" :lg="20" :xl="16">
<el-input v-model="reportShareUrl" :disabled="true"/>
</el-col>
</el-row>
<el-row :gutter="10">
<el-button type="primary" plain @click="copyShare"></el-button>
</el-row>
</div>
<div slot="footer" style="text-align: center">
{{reportCode}}
<el-button type="primary" plain @click="saveReportShare"></el-button>
<!-- <el-button type="primary" plain @click="saveReportShare"></el-button>-->
<el-button type="danger" plain @click="closeDialog"></el-button>
</div>
</el-dialog>
</template>
<script>
import { reportShareAdd } from '@/api/reportShare'
import { getDictList } from '@/api/dict-data' //
import Dictionary from '@/components/Dictionary/index'
export default {
components: { Dictionary },
props: {
visib: {
required: true,
@ -22,20 +53,87 @@ export default {
return ''
},
},
reportName: {
required: true,
type: String,
default: () => {
return ''
},
},
},
data() {
return {
}
title: '报表分享',
reportShareUrl:'',
shareValidTypeOptions: [], //
dialogForm: {
shareValidType: 0,
reportCode: '',
shareUrl: '',
shareCode: '',
},
shareLinkFlag1: true,
rules: {
shareValidType: [
{required: true, message: '有效期必选', trigger: 'change'},
],
},
};
},
watch: {
visib(val) {
if (val) {
//
this.getSystem()
}
},
},
created() {},
methods: {
titleBuild(){
return '【' +this.reportName + '】' + '报表分享-' + this.reportCode
},
selectChange(val) {
this.dialogForm.shareValidType = val
},
//
async getSystem() {
this.shareLinkFlag1 = true
const { code, data } = await getDictList('SHARE_VAILD')
if (code != '200') return
this.shareValidTypeOptions = data
this.dialogForm.shareValidType = this.shareValidTypeOptions[0].id
},
async createShare() {
this.dialogForm.reportCode = this.reportCode
this.dialogForm.shareUrl = window.location.href
console.log(this.dialogForm)
const {code, data} = await reportShareAdd(this.dialogForm)
if (code != '200') return
console.log(data)
this.shareLinkFlag1 = false
this.$message({
message: '创建链接成功!',
type: 'success',
})
this.reportShareUrl = data.shareUrl
},
copyShare(){
this.copyToClip(this.reportShareUrl)
this.$message({
message: '复制链接成功!',
type: 'success',
})
},
copyToClip(content, message) {
var aux = document.createElement("input");
aux.setAttribute("value", content);
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);
},
async saveReportShare() {
var params = {

@ -19,6 +19,21 @@
v-permission="'bigScreenManage:design'"
>设计</el-button
>
<el-button
type="text"
@click="shareReport(props.msg)"
v-permission="'bigScreenManage:share'"
>分享</el-button
>
</template>
<template v-slot:pageSection>
<Share
:visib="visibleForShareDialog"
:reportCode="reportCodeForShareDialog"
:reportName="reportNameForShareDialog"
@handleClose="visibleForShareDialog = false"
/>
</template>
</anji-crud>
</template>
@ -30,13 +45,19 @@ import {
reportUpdate,
reportDetail
} from "@/api/reportmanage";
import Share from "@/views/report/report/components/share";
export default {
name: "Report",
components: {
anjiCrud: require("@/components/AnjiPlus/anji-crud/anji-crud").default
anjiCrud: require("@/components/AnjiPlus/anji-crud/anji-crud").default,
Share
},
data() {
return {
//
visibleForShareDialog: false,
reportCodeForShareDialog: "",
reportNameForShareDialog: "",
crudOption: {
// 使
title: "报表管理",
@ -233,6 +254,12 @@ export default {
}
});
window.open(routeUrl.href, "_blank");
},
//
shareReport(val){
this.reportCodeForShareDialog = val.reportCode;
this.reportNameForShareDialog = val.reportName;
this.visibleForShareDialog = true;
}
}
};

@ -161,11 +161,11 @@
</template>
</el-table-column>
</el-table>
<el-checkbox
v-model="isShowPagination"
@change="changePagination"
>加入分页参数
</el-checkbox>
<!-- <el-checkbox-->
<!-- v-model="isShowPagination"-->
<!-- @change="changePagination"-->
<!-- >加入分页参数-->
<!-- </el-checkbox>-->
</el-tab-pane>
<el-tab-pane label="数据转换" name="second">
<template>

Loading…
Cancel
Save