!68 update0.9.7

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

@ -189,7 +189,8 @@ sql文件的目录在report-core --> src --> main --> resources -- > db.migra
- openJdk
- Jdk 11
- Mysql 8.08.0.23/26版本没有问题8.0.21版本存在问题)
**[常见问题](https://ajreport.beliefteam.cn/report-doc/guide/question.html)**
**[常见问题](https://ajreport.beliefteam.cn/report-doc/guide/question.html)**
## 商业授权

@ -0,0 +1,86 @@
'use strict'
// Template version: 1.2.6
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 9528, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: true,
errorOverlay: true,
notifyOnErrors: false,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-source-map',
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
/**
* You can set by youself according to actual condition
* You will need to set this if you plan to deploy your site under a sub path,
* for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/,
* then assetsPublicPath should be set to "/bar/".
* In most cases please use '/' !!!
*/
assetsPublicPath: '/report/',
/**
* Source Maps
*/
productionSourceMap: false,
// https://webpack.js.org/configuration/devtool/#production
devtool: 'source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report || false,
// `npm run build:prod --generate_report`
generateAnalyzerReport: process.env.npm_config_generate_report || false
}
}

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.anji-plus.otwb</groupId>
<artifactId>product-report-starter</artifactId>
<version>1.2.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<additionalparam>-Xdoclint:none</additionalparam>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.anji-plus</groupId>
<artifactId>spring-boot-gaea</artifactId>
<version>2.0.3.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.9</version>
</dependency>
</dependencies>
<!-- 上传到公司私服, mvn clean deploy -Dmaven.test.skip=true -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.7</version>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>nexus-releases</id>
<url>http://10.108.10.53:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<url>http://10.108.10.53:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>

@ -0,0 +1,34 @@
#!/bin/bash
#该脚本为私有化脚本打包成内含网页的product-report-starter放在内网私服
#判断node.js mvn是否存在
command -v npm >/dev/null 2>&1 || { echo >&2 "I require node.js v14.16.0+ but it's not installed. Aborting."; sleep 5; exit 1; }
command -v mvn >/dev/null 2>&1 || { echo >&2 "I require maven 3.5 + but it's not installed. Aborting."; sleep 5; exit 1; }
cd `dirname $0`
BuildDir=`pwd` #工程根目录
#重置pom和index.js
cat $BuildDir/build/index.js > $BuildDir/report-ui/config/index.js
cat $BuildDir/build/pom.xml > $BuildDir/report-core/pom.xml
echo "build web"
cd $BuildDir/report-ui
rm -rf dist
npm install >/dev/null 2>&1
npm run build:prod
echo "publish web to springboot src/main/resources/static"
rm -rf $BuildDir/report-core/src/main/resources/db/migration
rm -rf $BuildDir/report-core/src/main/resources/static
mkdir -p $BuildDir/report-core/src/main/resources/static
mv $BuildDir/report-ui/dist/* $BuildDir/report-core/src/main/resources/static/
echo "build springboot"
cd $BuildDir/report-core
mvn clean deploy -DskipTests
rm -rf $BuildDir/report-core/src/main/resources/static
git reset --hard

@ -1,6 +1,9 @@
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**
**微信群: <br>**
个人企业微信加微信进群备注AJ-Report或者Report <br>
如果不是为了进群,请直接说明来意,每天加群的都很多,企微也是我们自己的工作企微,会有很多消息会被刷下去,如果半天没有回复你,请发送多次 <br>
![weixin.png](../picture/weixin.jpg)
#### 开源不易劳烦各位star ☺

@ -205,4 +205,18 @@
### 数据格式
和饼图、南丁格尔玫瑰图数据保持一致。<br>
和饼图、南丁格尔玫瑰图数据保持一致。<br>
## 热力图
热力图是类似坐标轴一样的数据当前的热力图数据集需要3个字段值对应的字典是选择“X轴”“Y轴”“数值”不明白可以看静态数据<br>
![img21](../picture/charts/img_21.png) <br>
注意:图设置功能中的最大最小值将会对热力图中的数值产生反应,主要根据设定的颜色来反应,数值越靠近最大值,颜色将更深 <br>
![img22](../picture/charts/img_22.png) <br>
### 数据格式
![img23](../picture/charts/img_23.png) <br>
**如有问题,请提交 [Issue](https://gitee.com/anji-plus/report/issues) <br>**

@ -51,6 +51,7 @@ report-core --> src --> main --> resources --> bootstrap.yml <br>
**打包之前如果系统用的不止mysql数据源需要自己在pom文件中加入对应的数据库的驱动登陆系统之后数据源提示无驱动则选择通用JDBC数据源这里不做演示了** <br>
使用 maven package <br>
**注**不要使用maven install <br>
**注**:此方式不会打包 lib目录下的驱动详情可查看 **数据源 扩展** <br>
![img10](../picture/quickly/img_10.png) <br>
### linux启动jar包

@ -15,7 +15,9 @@ http://serverip:9095
## 编译环境
请在Linux上先准备好maven、node.js、jdk
请在Linux上先准备好maven、node.js、jdk <br>
如果在Win10上部署还需要下载一个 Git 软件,软件名就是 Git <br>
以下内容需要特别注意的地方会有对应提示。<br>
- [Apache Maven] 3.5 <br>
- [Node.js] v14.16.0 <br>
@ -34,6 +36,9 @@ git clone https://gitee.com/anji-plus/report.git <br>
![img_4.png](../picture/quickly/img_4.png) <br>
编译完成后是放在当前目录下的build文件夹中aj-report-xxxx.zip <br>
**注:** 如果Win10部署的话如图用git执行sh build.sh就行了。Linux就直接去report目录下执行sh build.sh就行。 <br>
**特别注意:** 如果是Win10编译那么几个启动脚本的格式则是win的格式放linux上执行会报错的反之放linux编译在win10启动也会报错需要转格式。 <br>
## 修改mysql连接
解压aj-report-xxxx.zip找到bootstrap.yml <br>
@ -56,11 +61,12 @@ linux启动 <br>
aj-report-XXX --> bin --> start.sh <br>
sh bin/start.sh <br>
注意啊如果你在linux打包然后在win上执行要转化start.bat文件的格式反之也是一样。
win10启动<br>
aj-report-XXX --> bin --> start.bat <br>
双击start.bat启动 <br>
## 日志位置
看到控制台提示“The AJ-Report started!”说明report正在启动可以看看日志以确定程序启动到哪里了。<br>
日志的位置是report-xxx/logs/aj-report.log <br>
## 访问

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

@ -151,6 +151,13 @@
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.9</version>
</dependency>
</dependencies>
<developers>

@ -131,6 +131,7 @@ public interface ResponseCode {
String SET_CODE_ISEXIST = "4008";
String SOURCE_CODE_ISEXIST = "4009";
String CLASS_NOT_FOUND = "4010";
String EXECUTE_GROOVY_ERROR = "4011";
String REPORT_SHARE_LINK_INVALID = "report.share.link.invalid";

@ -11,6 +11,11 @@ public interface BusinessConstant {
String RIGTH_BIG_BOAST = "}";
String LEFT_MIDDLE_BOAST = "[";
String RIGHT_MIDDLE_BOAST = "]";
String SLASH = "/";
String USER_GUEST = "guest";
String USER_ADMIN = "admin";
/**
*

@ -0,0 +1,33 @@
package com.anjiplus.template.gaea.business.enums;
/**
* Created by raodeming on 2022/5/8.
*/
public enum ReportTypeEnum {
/**report_screen*/
report_screen("report_screen", "大屏报表"),
/**report_excel*/
report_excel("report_excel", "excel报表"),
;
private String codeValue;
private String codeDesc;
ReportTypeEnum() {
}
private ReportTypeEnum(String codeValue, String codeDesc) {
this.codeValue = codeValue;
this.codeDesc = codeDesc;
}
public String getCodeValue() {
return this.codeValue;
}
public String getCodeDesc() {
return this.codeDesc;
}
}

@ -1,6 +1,5 @@
package com.anjiplus.template.gaea.business.filter;
import com.alibaba.fastjson.JSONObject;
import com.anji.plus.gaea.bean.ResponseBean;
import com.anji.plus.gaea.cache.CacheHelper;
@ -14,10 +13,8 @@ import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
@ -25,9 +22,9 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.anji.plus.gaea.constant.GaeaConstant.URL_REPLACEMENT;
@ -40,8 +37,9 @@ import static com.anji.plus.gaea.constant.GaeaConstant.URL_REPLACEMENT;
@Order(Integer.MIN_VALUE + 99)
public class TokenFilter implements Filter {
private static final Pattern PATTERN = Pattern.compile(".*().*");
private static final String USER_GUEST = "guest";
private static final String SLASH = "/";
@Value("${server.servlet.context-path:/}")
private String SLASH = "/";
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Autowired
@ -49,12 +47,13 @@ public class TokenFilter implements Filter {
@Autowired
private JwtBean jwtBean;
/** 跳过token验证和权限验证的url清单*/
@Value("#{'${customer.skip-authenticate-urls}'.split(',')}")
/**
* tokenurl
*/
@Value("#{'${customer.skip-authenticate-urls:}'.split(',')}")
private List<String> skipAuthenticateUrls;
private Pattern skipAuthenticatePattern;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 生成匹配正则跳过token验证和权限验证的url
@ -68,14 +67,26 @@ public class TokenFilter implements Filter {
HttpServletResponse response = (HttpServletResponse) servletResponse;
String uri = request.getRequestURI();
// TODO 暂时先不校验 直接放行
/*if (true) {
filterChain.doFilter(request, response);
return;
}*/
//OPTIONS直接放行
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
filterChain.doFilter(request, response);
return;
}
if (SLASH.equals(uri)) {
response.sendRedirect("/index.html");
// swagger相关的直接放行
if (uri.contains("swagger-ui") || uri.contains("swagger-resources")) {
filterChain.doFilter(request, response);
return;
}
if (SLASH.equals(uri) || SLASH.concat(BusinessConstant.SLASH).equals(uri)) {
response.sendRedirect(SLASH + "/index.html");
return;
}
@ -119,59 +130,23 @@ public class TokenFilter implements Filter {
error(response);
return;
}
if (!cacheHelper.exist(userKey)) {
error(response);
return;
}
String gaeaUserJsonStr = cacheHelper.stringGet(userKey);
//判断接口权限
//请求路径
String requestUrl = request.getRequestURI();
String methodValue = request.getMethod();
//请求方法+#+请求路径
String urlKey = methodValue + GaeaConstant.URL_SPLIT + requestUrl;
String gaeaUserJsonStr = cacheHelper.stringGet(userKey);
GaeaUserDto gaeaUserDto = JSONObject.parseObject(gaeaUserJsonStr, GaeaUserDto.class);
List<String> authorities = gaeaUserDto.getAuthorities();
Map<String, String> applicationNameAllAuthorities = cacheHelper.hashGet(BusinessConstant.GAEA_SECURITY_AUTHORITIES);
AtomicBoolean authFlag = new AtomicBoolean(false);
//查询当前请求是否在对应的权限里。即:先精确匹配(保证当前路由是需要精确匹配还是模糊匹配,防止精确匹配的被模糊匹配)
// 比如:/user/info和/user/**同时存在,/user/info,被/user/**匹配掉
if (applicationNameAllAuthorities.containsKey(urlKey)) {
String permissionCode = applicationNameAllAuthorities.get(urlKey);
if (authorities.contains(permissionCode)) {
authFlag.set(true);
}
} else {
List<String> collect = applicationNameAllAuthorities.keySet().stream()
.filter(key -> StringUtils.isNotBlank(key) && key.contains(URL_REPLACEMENT))
.filter(key -> antPathMatcher.match(key, urlKey)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(collect)) {
authFlag.set(true);
}else {
collect.forEach(key -> {
String permissionCode = applicationNameAllAuthorities.getOrDefault(key, "");
if (authorities.contains(permissionCode)) {
authFlag.set(true);
}
});
// 判断用户是否有该url的权限
if (!BusinessConstant.USER_ADMIN.equals(loginName)) {
AtomicBoolean authorizeFlag = authorize(request, gaeaUserJsonStr);
if (!authorizeFlag.get()) {
authError(response);//无权限
return;
}
}
if (!authFlag.get()) {
//无权限
authError(response);
return;
}
// 延长有效期
cacheHelper.stringSetExpire(tokenKey, token, 3600);
cacheHelper.stringSetExpire(userKey, gaeaUserJsonStr, 3600);
//执行
filterChain.doFilter(request, response);
}
@ -206,14 +181,58 @@ public class TokenFilter implements Filter {
return Pattern.compile(patternString.toString());
}
/**
* @return
*/
private AtomicBoolean authorize(HttpServletRequest request, String gaeaUserJsonStr){
//判断接口权限
//请求路径
String requestUrl = request.getRequestURI();
if (!BusinessConstant.SLASH.equals(SLASH)) {
requestUrl = requestUrl.substring(SLASH.length());
}
String methodValue = request.getMethod();
//请求方法+#+请求路径
String path = methodValue + GaeaConstant.URL_SPLIT + requestUrl;
GaeaUserDto gaeaUserDto = JSONObject.parseObject(gaeaUserJsonStr, GaeaUserDto.class);
List<String> userAuthorities = gaeaUserDto.getAuthorities();
Map<String, String> authoritiesAllMap = cacheHelper.hashGet(BusinessConstant.GAEA_SECURITY_AUTHORITIES);
AtomicBoolean authFlag = new AtomicBoolean(false);
// 接口GET#/gaeaDictItem/pageList
if(authoritiesAllMap.containsKey(path)){
String permissionCode = authoritiesAllMap.get(path);
boolean flag = userAuthorities.contains(permissionCode);
authFlag.set(flag);
return authFlag;
}
// 接口GET#/accessUser/roleTree/**
Optional<String> optionalMatchKey = authoritiesAllMap.keySet().stream()
.filter(key -> StringUtils.isNotBlank(key) && key.contains(URL_REPLACEMENT))
.filter(key -> antPathMatcher.match(key, path)).findFirst();
if(optionalMatchKey.isPresent() == false){
authFlag.set(true);
return authFlag;
}
String authoritieKey = optionalMatchKey.get();
String needPermission = authoritiesAllMap.get(authoritieKey);
boolean flag = userAuthorities.contains(needPermission);
authFlag.set(flag);
return authFlag;
}
private void error(HttpServletResponse response) throws IOException {
ResponseBean responseBean = ResponseBean.builder().code("50014").message("The Token has expired").build();
ResponseBean responseBean = ResponseBean.builder().code("50008").message("The Token has expired").build();
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().print(JSONObject.toJSONString(responseBean));
}
private void authError(HttpServletResponse response) throws IOException {
ResponseBean responseBean = ResponseBean.builder().code("User.no.authority").message("没有权限").build();
ResponseBean responseBean = ResponseBean.builder().code("User.no.authority").message("no auth").build();
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().print(JSONObject.toJSONString(responseBean));
}

@ -0,0 +1,14 @@
package com.anjiplus.template.gaea.business.modules.datasettransform.service;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
/**
* @author: Raod
* @since: 2022-02-23
*/
public interface IGroovyHandler {
List<JSONObject> transform(List<JSONObject> data);
}

@ -0,0 +1,65 @@
package com.anjiplus.template.gaea.business.modules.datasettransform.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
import com.anjiplus.template.gaea.business.code.ResponseCode;
import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto;
import com.anjiplus.template.gaea.business.modules.datasettransform.service.IGroovyHandler;
import com.anjiplus.template.gaea.business.modules.datasettransform.service.TransformStrategy;
import groovy.lang.GroovyClassLoader;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.List;
/**
* Created by raodeming on 2021/3/23.
*/
@Component
@Slf4j
public class GroovyTransformServiceImpl implements TransformStrategy {
private GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
/**
*
*
* @return
*/
@Override
public String type() {
return "javaBean";
}
/***
*
* @param def
* @param data
* @return
*/
@Override
public List<JSONObject> transform(DataSetTransformDto def, List<JSONObject> data) {
String transformScript = def.getTransformScript();
Class<?> clazz = groovyClassLoader.parseClass(transformScript);
if (clazz != null) {
try {
Object instance = clazz.newInstance();
if (instance!=null) {
if (instance instanceof IGroovyHandler) {
IGroovyHandler handler = (IGroovyHandler) instance;
return handler.transform(data);
} else {
System.err.println("转换失败!");
}
}
} catch (Exception e) {
log.info("执行javaBean异常", e);
throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_GROOVY_ERROR, e.getMessage());
}
}
return data;
}
}

@ -58,6 +58,7 @@ public class JsTransformServiceImpl implements TransformStrategy {
}
} catch (Exception ex) {
log.info("执行js异常", ex);
throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_JS_ERROR, ex.getMessage());
}
return null;

@ -26,18 +26,21 @@ public class JdbcServiceImpl implements JdbcService {
/**
* map
*/
static Map<Long, DruidDataSource> map = new ConcurrentHashMap<>();
private Map<Long, DruidDataSource> map = new ConcurrentHashMap<>();
private Object lock = new Object();
public DruidDataSource getJdbcConnectionPool(DataSourceDto dataSource) {
if (map.containsKey(dataSource.getId())) {
return map.get(dataSource.getId());
} else {
try {
if (!map.containsKey(dataSource.getId())) {
DruidDataSource pool = druidProperties.dataSource(dataSource.getJdbcUrl(),
dataSource.getUsername(), dataSource.getPassword(), dataSource.getDriverName());
map.put(dataSource.getId(), pool);
log.info("创建连接池成功:{}", dataSource.getJdbcUrl());
synchronized (lock) {
if (!map.containsKey(dataSource.getId())) {
DruidDataSource pool = druidProperties.dataSource(dataSource.getJdbcUrl(),
dataSource.getUsername(), dataSource.getPassword(), dataSource.getDriverName());
map.put(dataSource.getId(), pool);
log.info("创建连接池成功:{}", dataSource.getJdbcUrl());
}
}
return map.get(dataSource.getId());
} finally {

@ -11,10 +11,7 @@ import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
import com.anjiplus.template.gaea.business.modules.report.service.ReportService;
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.web.bind.annotation.*;
/**
* TODO
@ -46,11 +43,11 @@ public class ReportController extends GaeaBaseController<ReportParam, Report, Re
return new ReportDto();
}
@DeleteMapping("/delReport")
@Permission(code = "delete", name = "删除")
@GaeaAuditLog(pageTitle = "删除")
public ResponseBean delReport(@RequestBody ReportDto reportDto) {
reportService.delReport(reportDto);
@GetMapping("/copy")
@Permission(code = "copy", name = "复制")
@GaeaAuditLog(pageTitle = "复制")
public ResponseBean copy(@RequestParam("reportId") Long reportId) {
reportService.copy(reportId);
return ResponseBean.builder().build();
}
}

@ -12,11 +12,16 @@ import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
*/
public interface ReportService extends GaeaBaseService<ReportParam, Report> {
void delReport(ReportDto reportDto);
/**
* +1
* @param reportCode
*/
void downloadStatistics(String reportCode);
/**
*
* @param reportId
*/
void copy(Long reportId);
}

@ -3,12 +3,26 @@ package com.anjiplus.template.gaea.business.modules.report.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.utils.GaeaBeanUtils;
import com.anjiplus.template.gaea.business.enums.ReportTypeEnum;
import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard;
import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService;
import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget;
import com.anjiplus.template.gaea.business.modules.dashboardwidget.service.ReportDashboardWidgetService;
import com.anjiplus.template.gaea.business.modules.report.controller.dto.ReportDto;
import com.anjiplus.template.gaea.business.modules.report.dao.ReportMapper;
import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report;
import com.anjiplus.template.gaea.business.modules.report.service.ReportService;
import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel;
import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Collections;
import java.util.List;
/**
*
@ -20,6 +34,12 @@ public class ReportServiceImpl implements ReportService {
@Autowired
private ReportMapper reportMapper;
@Autowired
private ReportDashboardService reportDashboardService;
@Autowired
private ReportDashboardWidgetService reportDashboardWidgetService;
@Autowired
private ReportExcelService reportExcelService;
@Override
public GaeaBaseMapper<Report> getMapper() {
@ -28,10 +48,41 @@ public class ReportServiceImpl implements ReportService {
@Override
public void delReport(ReportDto reportDto) {
deleteById(reportDto.getId());
//删除gaea_report_excel、gaea_report_dashboard、gaea_report_dashboard_widget
//...
public void processBatchBeforeOperation(List<Report> entities, BaseOperationEnum operationEnum) throws BusinessException {
ReportService.super.processBatchAfterOperation(entities, operationEnum);
switch (operationEnum) {
case DELETE_BATCH:
entities.forEach(report -> {
Long id = report.getId();
Report delReport = selectOne(id);
if (null == delReport) {
return;
}
String reportCode = delReport.getReportCode();
String reportType = delReport.getReportType();
switch (ReportTypeEnum.valueOf(reportType)) {
case report_screen:
LambdaQueryWrapper<ReportDashboard> reportDashboardLambdaQueryWrapper = Wrappers.lambdaQuery();
reportDashboardLambdaQueryWrapper.eq(ReportDashboard::getReportCode, reportCode);
reportDashboardService.delete(reportDashboardLambdaQueryWrapper);
LambdaQueryWrapper<ReportDashboardWidget> reportDashboardWidgetLambdaQueryWrapper = Wrappers.lambdaQuery();
reportDashboardWidgetLambdaQueryWrapper.eq(ReportDashboardWidget::getReportCode, reportCode);
reportDashboardWidgetService.delete(reportDashboardWidgetLambdaQueryWrapper);
break;
case report_excel:
LambdaQueryWrapper<ReportExcel> reportExcelLambdaQueryWrapper = Wrappers.lambdaQuery();
reportExcelLambdaQueryWrapper.eq(ReportExcel::getReportCode, reportCode);
reportExcelService.delete(reportExcelLambdaQueryWrapper);
break;
default:
}
});
break;
default:
}
}
/**
@ -55,6 +106,64 @@ public class ReportServiceImpl implements ReportService {
}
@Override
public void copy(Long reportId) {
Report report = selectOne(reportId);
String reportCode = report.getReportCode();
Report copyReport = copyReport(report);
//复制主表数据
insert(copyReport);
String copyReportCode = copyReport.getReportCode();
String reportType = report.getReportType();
switch (ReportTypeEnum.valueOf(reportType)) {
case report_screen:
//查询看板
ReportDashboard reportDashboard = reportDashboardService.selectOne("report_code", reportCode);
if (null != reportDashboard) {
reportDashboard.setId(null);
reportDashboard.setReportCode(copyReportCode);
reportDashboardService.insert(reportDashboard);
}
//查询组件
List<ReportDashboardWidget> reportDashboardWidgetList = reportDashboardWidgetService.list("report_code", reportCode);
if (!CollectionUtils.isEmpty(reportDashboardWidgetList)) {
String finalCopyReportCode = copyReportCode;
reportDashboardWidgetList.forEach(reportDashboardWidget -> {
reportDashboardWidget.setId(null);
reportDashboardWidget.setReportCode(finalCopyReportCode);
});
reportDashboardWidgetService.insertBatch(reportDashboardWidgetList);
}
break;
case report_excel:
ReportExcel reportExcel = reportExcelService.selectOne("report_code", reportCode);
if (null != reportExcel) {
reportExcel.setId(null);
reportExcel.setReportCode(copyReportCode);
reportExcelService.insert(reportExcel);
}
break;
default:
}
}
private Report copyReport(Report report){
//复制主表数据
Report copyReport = new Report();
GaeaBeanUtils.copyAndFormatter(report, copyReport);
copyReport.setId(null);
String copyReportCode = copyReport.getReportCode().concat("_").concat(String.valueOf(System.currentTimeMillis()));
if (copyReportCode.length() >= 100) {
copyReportCode = copyReportCode.substring(0, 100);
}
copyReport.setReportCode(copyReportCode);
copyReport.setReportName(copyReport.getReportName().concat("_copy"));
return copyReport;
}
@Override
public void processBeforeOperation(Report entity, BaseOperationEnum operationEnum) throws BusinessException {

@ -8,6 +8,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Enumeration;
@ -116,9 +117,11 @@ public class FileUtil {
*/
public static String readFile(File file) {
BufferedReader reader = null;
InputStreamReader isr = null;
StringBuilder sbf = new StringBuilder();
try {
reader = new BufferedReader(new FileReader(file));
isr = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
reader = new BufferedReader(isr);
String tempStr;
while ((tempStr = reader.readLine()) != null) {
sbf.append(tempStr);
@ -129,6 +132,13 @@ public class FileUtil {
log.error("读文件失败", e);
throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
} finally {
if (null != isr) {
try {
isr.close();
} catch (IOException e) {
throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
}
}
if (reader != null) {
try {
reader.close();

@ -66,9 +66,10 @@ logging:
customer:
# 开发测试用本地文件,如果是生产,请考虑使用对象存储
file:
#上传对应本地全路径,路径必须是真实存在的
#上传对应本地全路径,目录必须是真实存在的,注意 Win是 \ 且有盘符linux是 / 无盘符
dist-path: /app/disk/upload/
white-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi
#dist-path: D:\Download
white-list: .png|.jpg|.jpeg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi
excelSuffix: .xlsx|.xls|.csv
#上传对应下载的下载链接路径 http://serverip:9095/file/download
downloadPath: http://10.108.26.197:9095/file/download

@ -0,0 +1 @@
UPDATE `aj_report`.`gaea_dict_item` SET `dict_code` = 'TRANSFORM_TYPE', `item_name` = 'java脚本', `item_value` = 'javaBean', `item_extend` = NULL, `enabled` = 1, `locale` = 'zh', `remark` = NULL, `sort` = 2, `create_by` = 'admin', `create_time` = '2021-03-23 10:54:08', `update_by` = 'admin', `update_time` = '2021-03-23 10:54:08', `version` = 1 WHERE `id` = 151;

@ -0,0 +1,5 @@
-- 补充admin对于execl表格权限
INSERT INTO `aj_report`.`access_role_authority`(`role_code`,`target`,`action`) SELECT "root","excelManage","insert" FROM DUAL WHERE NOT EXISTS(SELECT `role_code`,`target`,`action` FROM `aj_report`.`access_role_authority` WHERE `role_code`="root" AND `target`="excelManage" AND `action`="insert");
INSERT INTO `aj_report`.`access_role_authority`(`role_code`,`target`,`action`) SELECT "root","excelManage","update" FROM DUAL WHERE NOT EXISTS(SELECT `role_code`,`target`,`action` FROM `aj_report`.`access_role_authority` WHERE `role_code`="root" AND `target`="excelManage" AND `action`="update");

@ -0,0 +1,7 @@
-- 新增坐标轴字典
INSERT INTO `aj_report`.`gaea_dict`(`dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('XY坐标属性', 'COORD_PROPERTIES', 'XY坐标属性', 'admin', NOW(), 'admin', NOW(), 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('COORD_PROPERTIES', '数据', 'series', NULL, 1, 'zh', NULL, NULL, 'admin', NOW(), 'admin', NOW(), 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('COORD_PROPERTIES', 'X轴', 'xAxis', NULL, 1, 'zh', NULL, NULL, 'admin', NOW(), 'admin', NOW(), 1);
INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('COORD_PROPERTIES', 'Y轴', 'yAxis', NULL, 1, 'zh', NULL, NULL, 'admin', NOW(), 'admin', NOW(), 1);

@ -0,0 +1,16 @@
-- 角色权限调整
-- access_authority
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('access', 'authorityManage', '权限管理', 'detail', '权限明细', 101, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('access', 'roleManage', '角色管理', 'detail', '角色明细', 105, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2021-07-17 20:41:46', 2);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('access', 'userManage', '用户管理', 'detail', '用户明细', 110, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('report', 'datasourceManage', '数据源管理', 'detail', '数据源明细', 200, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('report', 'resultsetManage', '数据集管理', 'detail', '数据集明细', 204, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('report', 'reportManage', '报表管理', 'detail', '报表明细', 221, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('report', 'bigScreenManage', '大屏报表', 'detail', '大屏明细', 231, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('report', 'excelManage', '表格报表', 'detail', 'excel明细', 234, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('system', 'fileManage', '文件管理', 'detail', '文件明细', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('system', 'dictManage', '数据字典', 'detail', '数据字典明细', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('system', 'dictItemManage', '数据字典项', 'detail', '数据字典项明细', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
REPLACE INTO `aj_report`.`access_authority`(`parent_target`, `target`, `target_name`, `action`, `action_name`, `sort`, `enable_flag`, `delete_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('report', 'bigScreenManage', '大屏报表', 'copy', '复制大屏', 236, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1);
UPDATE `aj_report`.`access_authority` SET `parent_target` = 'report', `target` = 'bigScreenManage', `target_name` = '大屏报表', `action` = 'view', `action_name` = '查看大屏', `sort` = 232, `enable_flag` = 1, `delete_flag` = 0, `create_by` = 'admin', `create_time` = '2019-07-23 15:59:40', `update_by` = 'admin', `update_time` = '2019-07-23 15:59:40', `version` = 1 WHERE `parent_target` = 'report' AND `target` = 'bigScreenManage' AND `action` = 'view';

@ -47,5 +47,6 @@ 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
4011=execute javaBean error
report.share.link.invalid=report share link invalid

@ -48,6 +48,7 @@ Component.load.check.error={0}\u7EC4\u4EF6\u672A\u52A0\u8F7D
4008=\u6570\u636E\u96C6\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D
4009=\u6570\u636E\u6E90\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D
4010=\u9A71\u52A8\u5305\u4E0D\u5B58\u5728
4011=\u6267\u884CjavaBean\u5931\u8D25
6001={0}
7001=\u89E3\u6790\u5931\u8D25

@ -0,0 +1,18 @@
package com;
import com.alibaba.fastjson.JSONObject;
import com.anjiplus.template.gaea.business.modules.datasettransform.service.IGroovyHandler;
import java.util.List;
/**
* ideareport-core/src/test/java/com/DemoGroovyHandler.java
*/
public class DemoGroovyHandler implements IGroovyHandler {
@Override
public List<JSONObject> transform(List<JSONObject> data) {
return data;
}
}

@ -0,0 +1,58 @@
package com;
import com.alibaba.fastjson.JSONObject;
import com.anjiplus.template.gaea.business.modules.datasettransform.service.IGroovyHandler;
import groovy.lang.GroovyClassLoader;
import java.util.List;
/**
* @author: Raod
* @since: 2022-02-23
*/
public class GroovyTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
// codeSource来自DemoGroovyHandler
String codeSource = "package com;\n" +
"\n" +
"import com.alibaba.fastjson.JSONObject;\n" +
"import com.anjiplus.template.gaea.business.modules.datasettransform.service.IGroovyHandler;\n" +
"\n" +
"import java.util.ArrayList;\n" +
"import java.util.List;\n" +
"\n" +
"/**\n" +
" * @author: Raod\n" +
" * @since: 2022-02-23\n" +
" */\n" +
"public class DemoGroovyHandler implements IGroovyHandler {\n" +
"\n" +
" @Override\n" +
" public List<JSONObject> transform(List<JSONObject> data) {\n" +
" List<JSONObject> result = new ArrayList<>();\n" +
" JSONObject jsonObject = new JSONObject();\n" +
" jsonObject.put(\"test\", \"demo\");\n" +
" result.add(jsonObject);\n" +
" return result;\n" +
" }\n" +
"}";
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Class<?> clazz = groovyClassLoader.parseClass(codeSource);
if (clazz != null) {
Object instance = clazz.newInstance();
if (instance!=null) {
if (instance instanceof IGroovyHandler) {
IGroovyHandler handler = (IGroovyHandler) instance;
List<JSONObject> transform = handler.transform(null);
System.out.println(JSONObject.toJSONString(transform));
} else {
System.err.println("转换失败!");
}
}
}
}
}

@ -71,7 +71,7 @@ export function initDictToLocalstorage(callback) {
}
// 保存数据字典到localStorage
setStorageItem('gaeaDict', res.data)
setStorageItem('AJReportDict', res.data)
if (callback != null) {
callback()
}

@ -39,4 +39,12 @@ export function reportDetail(data) {
})
}
export function reportCopy(data) {
return request({
url: '/report/copy',
method: 'get',
params: { reportId: data.id }
})
}
export default { reportList, reportAdd, reportDeleteBatch, reportUpdate, reportDetail }

@ -54,6 +54,24 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe683;</span>
<div class="name">热力图</div>
<div class="code-name">&amp;#xe683;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60d;</span>
<div class="name">恢复备份</div>
<div class="code-name">&amp;#xe60d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60e;</span>
<div class="name">撤销</div>
<div class="code-name">&amp;#xe60e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe7af;</span>
<div class="name">词云图</div>
@ -792,9 +810,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1643094287456') format('woff2'),
url('iconfont.woff?t=1643094287456') format('woff'),
url('iconfont.ttf?t=1643094287456') format('truetype');
src: url('iconfont.woff2?t=1650520683161') format('woff2'),
url('iconfont.woff?t=1650520683161') format('woff'),
url('iconfont.ttf?t=1650520683161') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -820,6 +838,33 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont iconrelitu"></span>
<div class="name">
热力图
</div>
<div class="code-name">.iconrelitu
</div>
</li>
<li class="dib">
<span class="icon iconfont iconhuifubeifen"></span>
<div class="name">
恢复备份
</div>
<div class="code-name">.iconhuifubeifen
</div>
</li>
<li class="dib">
<span class="icon iconfont iconundo"></span>
<div class="name">
撤销
</div>
<div class="code-name">.iconundo
</div>
</li>
<li class="dib">
<span class="icon iconfont iconciyuntu"></span>
<div class="name">
@ -1927,6 +1972,30 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconrelitu"></use>
</svg>
<div class="name">热力图</div>
<div class="code-name">#iconrelitu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconhuifubeifen"></use>
</svg>
<div class="name">恢复备份</div>
<div class="code-name">#iconhuifubeifen</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconundo"></use>
</svg>
<div class="name">撤销</div>
<div class="code-name">#iconundo</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#iconciyuntu"></use>

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 1513211 */
src: url('iconfont.woff2?t=1643094287456') format('woff2'),
url('iconfont.woff?t=1643094287456') format('woff'),
url('iconfont.ttf?t=1643094287456') format('truetype');
src: url('iconfont.woff2?t=1650520683161') format('woff2'),
url('iconfont.woff?t=1650520683161') format('woff'),
url('iconfont.ttf?t=1650520683161') format('truetype');
}
.iconfont {
@ -13,6 +13,18 @@
-moz-osx-font-smoothing: grayscale;
}
.iconrelitu:before {
content: "\e683";
}
.iconhuifubeifen:before {
content: "\e60d";
}
.iconundo:before {
content: "\e60e";
}
.iconciyuntu:before {
content: "\e7af";
}

File diff suppressed because one or more lines are too long

@ -5,6 +5,27 @@
"css_prefix_text": "icon",
"description": "",
"glyphs": [
{
"icon_id": "19004935",
"name": "热力图",
"font_class": "relitu",
"unicode": "e683",
"unicode_decimal": 59011
},
{
"icon_id": "15047024",
"name": "恢复备份",
"font_class": "huifubeifen",
"unicode": "e60d",
"unicode_decimal": 58893
},
{
"icon_id": "19657550",
"name": "撤销",
"font_class": "undo",
"unicode": "e60e",
"unicode_decimal": 58894
},
{
"icon_id": "23043843",
"name": "词云图",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

@ -77,3 +77,21 @@
.el-table td {
padding: 6px 0;
}
@keyframes turn {
0% {
-webkit-transform: rotate(0deg);
}
25% {
-webkit-transform: rotate(90deg);
}
50% {
-webkit-transform: rotate(180deg);
}
75% {
-webkit-transform: rotate(270deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}

@ -0,0 +1,237 @@
.layout {
width: 100%;
height: 100%;
background: #242a30;
color: #fff;
.layout-bar {
height: 40px;
line-height: 40px;
font-size: 12px;
padding: 0 10px;
display: flex;
flex-direction: row;
overflow: hidden;
.bar-item {
margin-right: 20px;
cursor: pointer;
.iconfont {
font-size: 12px;
margin-right: 4px;
}
.el-dropdown-link {
color: #fff;
cursor: pointer;
}
}
}
.layout-container {
width: 100%;
height: calc(100vh - 40px);
display: flex;
flex-direction: row;
justify-content: space-between;
overflow: hidden;
.layout-left {
width: 200px;
background: #242a30;
overflow-x: hidden;
overflow-y: auto;
.chart-type {
display: flex;
flex-direction: row;
overflow: hidden;
.type-left {
width: 100%;
height: calc(100vh - 80px);
text-align: center;
/deep/.el-tabs__header {
width: 30%;
margin-right: 0;
.el-tabs__nav-wrap {
&::after {
background: transparent;
}
.el-tabs__item {
text-align: center;
width: 100%;
color: #fff;
padding: 0;
}
}
}
/deep/.el-tabs__content {
width: 70%;
}
}
}
//
.tools-item {
display: flex;
position: relative;
width: 100%;
height: 48px;
align-items: center;
-webkit-box-align: center;
padding: 0 6px;
cursor: pointer;
font-size: 12px;
margin-bottom: 1px;
.tools-item-icon {
color: #409eff;
margin-right: 10px;
width: 53px;
height: 30px;
line-height: 30px;
text-align: center;
display: block;
border: 1px solid #3a4659;
background: #282a30;
}
.tools-item-text {
}
}
/deep/.el-tabs__content {
padding: 0;
}
}
.layout-middle {
// display: flex;
position: relative;
//width: calc(100% - 445px);
height: 100%;
background-color: rgb(36, 42, 48);
box-sizing: border-box;
-webkit-box-sizing: border-box;
border: 1px solid rgb(36, 42, 48);
align-items: center;
vertical-align: middle;
text-align: center;
.workbench-container {
position: relative;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
.vueRuler {
width: 100%;
padding: 18px 0px 0px 18px;
}
.workbench {
background-color: #1e1e1e;
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
margin: 0;
padding: 0;
}
.bg-grid {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: 30px 30px, 30px 30px;
background-image: linear-gradient(
hsla(0, 0%, 100%, 0.1) 1px,
transparent 0
),
linear-gradient(90deg, hsla(0, 0%, 100%, 0.1) 1px, transparent 0);
// z-index: 2;
}
}
}
.layout-right {
width: 300px;
}
/deep/ .el-tabs--border-card {
border: 0;
.el-tabs__header {
background: transparent;
.el-tabs__nav {
width: 100%;
.el-tabs__item {
background-color: #242f3b;
border: 0px;
font-size: 12px;
width: 50%;
.icon {
margin-right: 4px;
}
}
.el-tabs__item.is-active {
background-color: #31455d;
}
}
}
.el-tabs__content {
background-color: #242a30;
height: calc(100vh - 80px);
overflow-x: hidden;
overflow-y: auto;
.el-tab-pane {
color: #bfcbd9;
}
&::-webkit-scrollbar {
width: 5px;
height: 14px;
}
&::-webkit-scrollbar-track,
&::-webkit-scrollbar-thumb {
border-radius: 1px;
border: 0 solid transparent;
}
&::-webkit-scrollbar-track-piece {
/*修改滚动条的背景和圆角*/
background: #29405c;
-webkit-border-radius: 7px;
}
&::-webkit-scrollbar-track {
box-shadow: 1px 1px 5px rgba(116, 148, 170, 0.5) inset;
}
&::-webkit-scrollbar-thumb {
min-height: 20px;
background-clip: content-box;
box-shadow: 0 0 0 5px rgba(116, 148, 170, 0.5) inset;
}
&::-webkit-scrollbar-corner {
background: transparent;
}
/*修改垂直滚动条的样式*/
&::-webkit-scrollbar-thumb:vertical {
background-color: #00113a;
-webkit-border-radius: 7px;
}
/*修改水平滚动条的样式*/
&::-webkit-scrollbar-thumb:horizontal {
background-color: #00113a;
-webkit-border-radius: 7px;
}
}
}
}
}
/deep/.el-dropdown-menu__item {
max-width: none;
}

@ -127,7 +127,7 @@ export default {
},
queryData() {
axios({
url: process.env.VUE_APP_BASE_API + this.url,
url: process.env.BASE_API + this.url,
methods: "get",
headers: {
Authorization: getToken(),

@ -80,7 +80,7 @@ export default {
},
// localStorage gaeaDict
getOptionsFromLocalStorage() {
let dicts = JSON.parse(localStorage.getItem("gaeaDict"));
let dicts = JSON.parse(localStorage.getItem("AJReportDict"));
let options = [];
if (!dicts.hasOwnProperty(this.dictCode)) {
return [];

@ -148,36 +148,19 @@
<!-- 查询表单结束 -->
<!-- 批量操作 -->
<div style="padding-bottom: 8px">
<slot name="buttonLeftOnTable" :selection="checkRecords" />
<slot name="tableButtons" :selection="checkRecords" />
<el-button
v-if="
option.buttons.add.isShow == undefined
? true
: option.buttons.add.isShow
"
v-permission="option.buttons.add.permission"
class="button"
plain
icon="el-icon-plus"
@click="handleOpenEditView('add')"
>新增</el-button
v-for="(item, index) in option.tableButtons"
:key="index"
v-permission="item.permission"
class="tableButton"
:plain="item.plain"
:icon="item.icon"
:type="item.type"
:disabled="isDisabledButton(item, checkRecords)"
@click="item.click(checkRecords)"
>{{ handlegetLable(checkRecords, item.label) }}</el-button
>
<el-button
v-if="
option.buttons.delete.isShow == undefined
? true
: option.buttons.delete.isShow
"
v-permission="option.buttons.delete.permission"
class="button"
plain
:disabled="disableBatchDelete"
type="danger"
icon="el-icon-delete"
@click="handleDeleteBatch()"
>删除</el-button
>
<slot name="buttonRightOnTable" :selection="checkRecords" />
</div>
</div>
@ -282,59 +265,58 @@
align="center"
fixed="right"
label="操作"
:width="
option.buttons.customButton &&
option.buttons.customButton.operationWidth
? option.buttons.customButton.operationWidth
: 100
"
:width="option.buttons.rowButtonsWidth || 100"
>
<template slot-scope="scope">
<slot name="rowButton" :msg="scope.row" />
<el-button
v-if="
option.buttons.edit.isShow == undefined
? true
: option.buttons.edit.isShow
"
type="text"
size="small"
@click="handleOpenEditView('edit', scope.row)"
>编辑</el-button
>
<el-button
v-if="
hasCustomButtonInRowMore == false &&
option.buttons.delete.isShow == undefined
? true
: option.buttons.edit.isShow
"
type="text"
size="small"
@click="handleDeleteBatch(scope.row)"
>删除</el-button
>
<el-dropdown v-if="hasCustomButtonInRowMore" trigger="click">
<span class="el-dropdown-link"
>更多<i class="el-icon-caret-bottom el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item class="clearfix">
<slot name="rowButtonInMore" :msg="scope.row" />
<el-button
v-if="
option.buttons.delete.isShow == undefined
? true
: option.buttons.edit.isShow
"
type="text"
size="small"
@click="handleDeleteBatch(scope.row)"
>删除</el-button
>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div v-if="option.rowButtons.length <= 2">
<el-button
v-for="(item, index) in option.rowButtons"
:key="index"
v-permission="item.permission"
:disabled="isDisabledButton(item, scope.row)"
:type="item.type || 'text'"
size="small"
@click="item.click(scope.row)"
>{{ handlegetLable(scope.row, item.label) }}</el-button
>
</div>
<div v-else>
<el-button
v-permission="option.rowButtons[0].permission"
:type="option.rowButtons[0].type || 'text'"
:disabled="
isDisabledButton(option.rowButtons[0], scope.row)
"
@click="option.rowButtons[0].click(scope.row)"
>{{
handlegetLable(scope.row, option.rowButtons[0].label)
}}</el-button
>
<el-dropdown trigger="click">
<span class="el-dropdown-link">
更多
<i class="el-icon-caret-bottom el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item class="clearfix">
<el-button
v-for="(item, index) in option.rowButtons.filter(
(el, index) => index > 0
)"
:key="index"
v-permission="item.permission"
:type="item.type || 'text'"
:disabled="isDisabledButton(item, scope.row)"
size="small"
@click="item.click(scope.row)"
>{{
handlegetLable(scope.row, item.label)
}}</el-button
>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
</el-table-column>
</el-table>
@ -668,6 +650,21 @@ export default {
};
this.$emit("handleCustomValue", obj);
},
handlegetLable(item, label) {
if (typeof label == "function") {
return label(item);
} else {
return label;
}
},
// disabled
isDisabledButton(item, row) {
if (typeof item.isDisable === "function") {
return item.isDisable(row);
} else {
return !!item.disabled;
}
},
//
editDialogClosedEvent(value) {
//

@ -244,9 +244,9 @@ export default {
}
return result;
},
// localStorage gaeaDict
// localStorage AJReportDict
getOptionsFromLocalStorage() {
let dicts = JSON.parse(localStorage.getItem("gaeaDict"));
let dicts = JSON.parse(localStorage.getItem("AJReportDict"));
let options = [];
if (!dicts.hasOwnProperty(this.dictCode)) {
return [];

@ -6,39 +6,16 @@
:action="requestUrl"
list-type="picture-card"
:file-list="fileList"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:on-success="handleSuccess"
:show-file-list="true"
:before-upload="handleBeforeUpload"
:class="fileList && fileList.length >= limit ? 'hide_box' : ''"
>
<i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{ file }" class="imgBox">
<img
v-if="typeImgShow(file)"
class="el-upload-list__item-thumbnail"
:src="file.url"
alt=""
/>
<svg-icon
v-else-if="typePdfShow(file)"
icon-class="PDF"
class="iconFont"
/>
<svg-icon
v-else-if="typeExcelShow(file)"
icon-class="Excel"
class="iconFont"
/>
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span
v-if="typeImgShow(file)"
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
class="el-upload-list__item-delete"
@click="handleDownload(file)"
@ -51,9 +28,6 @@
</span>
</div>
</el-upload>
<el-dialog :visible.sync="dialogVisibleImageUpload" :modal="false">
<img width="100%" :src="imageUploadUrl" alt="" />
</el-dialog>
</div>
</template>
<script>
@ -79,22 +53,12 @@ export default {
}
},
value: {
type: Array,
default: () => {
return [];
}
},
uploadType: {
type: String,
default: () => {
return "img";
}
type: Array | String
}
},
data() {
return {
imageUploadUrl: "",
dialogVisibleImageUpload: false,
fileList: [],
modeString: ""
};
@ -102,9 +66,9 @@ export default {
computed: {
requestUrl() {
if (this.upLoadUrl != null && this.upLoadUrl.trim() != "") {
return process.env.VUE_APP_BASE_API + this.upLoadUrl;
return process.env.BASE_API + this.upLoadUrl;
} else {
return process.env.VUE_APP_BASE_API + "/meta/file/upload";
return process.env.BASE_API + "/file/upload";
}
},
headers() {
@ -114,60 +78,22 @@ export default {
}
},
watch: {
value: {
handler(val) {
this.echoUpload(val);
},
immediate: true
value(val) {
this.echoUpload(val);
}
},
mounted() {},
mounted() {
this.echoUpload(this.value);
},
methods: {
//
typeImgShow(file) {
if (!file.fileType) return;
const fileType = file.fileType.toLowerCase();
if (
fileType == "jpg" ||
fileType == "png" ||
fileType == "gif" ||
fileType == "icon"
) {
return true;
}
return false;
},
// pdf
typePdfShow(file) {
if (!file.fileType) return;
const fileType = file.fileType.toLowerCase();
if (fileType == "pdf") {
return true;
}
return false;
},
// excel
typeExcelShow(file) {
if (!file.fileType) return;
const fileType = file.fileType.toLowerCase();
if (fileType == "xlsx" || fileType == "xls" || fileType == "csv") {
return true;
}
return false;
},
handleRemove(file) {
const fileList = [];
this.fileList.forEach(el => {
if (el.fileId != file.fileId) {
fileList.push(el);
}
});
this.fileList = fileList;
this.fileList = [];
console.log(this.fileList);
console.log(this.limit);
this.change();
},
handlePictureCardPreview(file) {
this.imageUploadUrl = file.url;
this.dialogVisibleImageUpload = true;
handleExceed() {
this.$message.warning(`只能上传${this.limit}个文件`);
},
//
handleDownload(file) {
@ -175,7 +101,6 @@ export default {
},
//
handleSuccess(response, file, fileList) {
console.log(fileList);
if (response.code != 200) {
this.$message.error("上传失败");
return;
@ -185,11 +110,13 @@ export default {
fileId: file.response.data.fileId,
fileType: file.response.data.fileType
});
console.log(this.fileList);
this.change();
},
//
change() {
const fileList = this.fileList;
console.log(fileList);
this.$emit("input", fileList);
this.$emit("change", fileList);
},
@ -219,18 +146,13 @@ export default {
},
//
echoUpload(val) {
console.log(val);
if (val && val.length > 0) {
const fileList = [];
for (let i = 0; i < val.length; i++) {
const obj = {};
obj.url = val[i].urlPath || val[i].url;
obj.fileType = val[i].fileType;
obj.fileId = val[i].fileId;
fileList.push(obj);
}
fileList.forEach((el, index) => {
this.$set(this.fileList, index, el);
});
this.fileList = [
{
url: val
}
];
} else {
this.fileList = [];
}
@ -248,7 +170,7 @@ export default {
width: 60px;
height: 60px;
}
.hide_box .el-upload--picture-card {
.hide_box /deep/.el-upload--picture-card {
display: none;
}
.el-upload-list__item {

@ -66,6 +66,7 @@ export default {
},
selectChange(val) {
this.$emit("input", val);
this.$emit("change", val);
}
}
};

@ -272,6 +272,7 @@ export default {
return { top: top, left: left }
},
objToOne (obj) {
console.log(obj)
let tmpData = {}
for (let index in obj) {
if (typeof obj[index] == 'object' && !this.isArrayFn(obj[index])) {
@ -316,7 +317,7 @@ export default {
// 根据数据字典查询指定字典dict指定值code的返回整个dictItem{id, text, extend}
getDictItemByCode (dict, code) {
let dicts = getStorageItem('gaeaDict')
let dicts = getStorageItem('AJReportDict')
if (!dicts.hasOwnProperty(dict)) {
return null
}
@ -354,7 +355,7 @@ export default {
return dictItem['extend']
},
getSettingByName(settingName) {
let gaeaSetting = JSON.parse(localStorage.getItem('gaeaDict'))
let gaeaSetting = JSON.parse(localStorage.getItem('AJReportDict'))
if (gaeaSetting[settingName] != null) {
return gaeaSetting[settingName]
} else {

@ -109,6 +109,7 @@ export default {
// widget-text 文本框
// widge-table 表格(数据不要转)
// widget-stackchart 堆叠图
// widget-heatmap 热力图
const chartType = params.chartType
if (
chartType == "widget-barchart" ||
@ -121,10 +122,12 @@ export default {
chartType == "widget-funnel"
) {
return this.piechartFn(params.chartProperties, data);
} else if (chartType == "widget-text") {
} else if (chartType == "widget-text") {
return this.widgettext(params.chartProperties, data)
} else if (chartType == "widget-stackchart") {
return this.stackChartFn(params.chartProperties, data)
} else if (chartType == "widget-coord") {
return this.coordChartFn(params.chartProperties, data)
} else {
return data
}
@ -175,9 +178,9 @@ export default {
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)
const data = new Array(xAxisList.length).fill(0)
dataGroup[item].forEach(res => {
data[xAxisList.indexOf(res[xAxisField])]= res[key]
data[xAxisList.indexOf(res[xAxisField])] = res[key]
})
series.push({
name: yAxisList[item],
@ -223,6 +226,27 @@ export default {
}
return ananysicData;
},
// 坐标系数据解析
coordChartFn(chartProperties, data) {
const ananysicData = {};
let series = [];
//全部字段字典值
const types = Object.values(chartProperties)
//x轴字段、y轴字段、数值字段名
const xAxisField = Object.keys(chartProperties)[types.indexOf('xAxis')]
const yAxisField = Object.keys(chartProperties)[types.indexOf('yAxis')]
const dataField = Object.keys(chartProperties)[types.indexOf('series')]
//x轴数值去重y轴去重
const xAxisList = this.setUnique(data.map(item => item[xAxisField]))
const yAxisList = this.setUnique(data.map(item => item[yAxisField]))
ananysicData["xAxis"] = xAxisList;
ananysicData["yAxis"] = yAxisList;
for (const i in data) {
series[i] = [data[i][xAxisField], data[i][yAxisField], data[i][dataField]];
}
ananysicData["series"] = series;
return ananysicData;
},
setUnique(arr) {
let newArr = [];
arr.forEach(item => {

@ -260,6 +260,20 @@ export const constantRouterMap = [
requireAuth: true
}
},
// 重写大屏
{
path: '/screenDesigner',
component: () => import('@/views/screenDesigner/index'),
name: 'screenDesigner',
},
{
path: '/screen/preview',
component: () => import('@/views/screenDesigner/preview'),
hidden: true,
meta: {
requireAuth: true
}
},
{
path: '/404',
component: () => import('@/views/404'),

@ -1,8 +1,8 @@
import { getStorageItem, setStorageItem, delStorageItem } from '@/utils/storage'
const TokenKey = 'token'
const ShareTokenKey = 'shareToken'
const AccessUserKey = 'gaeaUser'
const TokenKey = 'AJReportToken'
const ShareTokenKey = 'AJReportShareToken'
const AccessUserKey = 'AJReportUser'
export function getToken() {
return getStorageItem(TokenKey)

@ -0,0 +1,102 @@
/**
撤销重做功能
* @Author: eyas66
* @Mail: 33955341@qq.com
* @Date: 2021-12-13 10:09:23
* @Last Modified by: eyas66
* @Last Modified time: 2021-12-13 10:09:23
*/
export class Revoke {
// 历史记录
recordList = [];
// 撤销记录,用于重做
redoList = [];
// 当前记录用currentRecord变量暂时存储当用户修改时再存放到recordList
currentRecord = null;
// 上次插入数据时间
time = 0;
/**
* @description: 插入历史记录
* @param {object}record
* @return {boolean}
*/
push(record) {
const nowTime = Date.now();
// 防止添加重复的时间当添加间隔小于100ms时则替换当前记录并取消执行添加
if (this.time + 100 > nowTime) {
this.currentRecord = JSON.stringify(record);
return false;
}
this.time = nowTime;
// 判断之前是否已经存在currentRecord记录有则存储到recordList
if (this.currentRecord) {
this.recordList.push(this.currentRecord);
//(清空记录)增加记录后则应该清空重做记录
//splice() 方法向/从数组添加/删除项目,并返回删除的项目。
this.redoList.splice(0, this.redoList.length);
}
// 将json转成字符串存储
this.currentRecord = JSON.stringify(record);
// 最多存储2000条记录超过2000条记录则删除之前的记录
if (this.length > 2000) {
//unshift() 方法将新项添加到数组的开头,并返回新的长度。
this.recordList.unshift();
}
return true;
}
/**
* @description: 撤销操作
* @param {*}
* @return {object}
*/
undo() {
// 没有记录时,返回false
// 新建的recordList里面不知为什么会存在一条记录未找到原因所以就判断长度为1时就不能撤销了。
if (this.recordList.length === 1 ) {
return false;
}
//pop() 方法用于删除并返回数组的最后一个元素。
const record = this.recordList.pop();
// 将当前记录添加到重做记录里面
if (this.currentRecord) {
this.redoList.push(this.currentRecord);
}
// 丢弃当前记录,防止重复添加
this.currentRecord = null;
//返回撤销的记录
return JSON.parse(record);
}
/**
* @description: 重做操作
* @param {*}
* @return {*}
*/
redo() {
// 没有重做记录时,返回false
if (this.redoList.length === 0) {
return false;
}
//pop() 方法用于删除并返回数组的最后一个元素。
const record = this.redoList.pop();
// 添加到重做记录里面
if (this.currentRecord) {
this.recordList.push(this.currentRecord);
}
// 丢弃当前记录,防止重复添加
this.currentRecord = null;
return JSON.parse(record);
}
}

@ -4,7 +4,7 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 12:20:56
* @LastEditTime: 2022-03-09 09:22:40
-->
<template>
<anji-crud ref="listPage" :option="crudOption" />
@ -67,6 +67,46 @@ export default {
field: "actionName"
}
],
//
tableButtons: [
{
label: "新增",
type: "", // primarysuccessinfowarningdanger
permission: "authorityManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.$refs.listPage.handleOpenEditView("add");
}
},
{
label: "删除",
type: "danger",
permission: "authorityManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "authorityManage:update",
click: row => {
return this.$refs.listPage.handleOpenEditView("edit", row);
}
},
{
label: "删除",
permission: "authorityManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
query: {
@ -89,9 +129,7 @@ export default {
api: accessAuthorityUpdate,
permission: "authorityManage:update"
},
customButton: {
operationWidth: "150px"
}
rowButtonsWidth: 150 // row
},
//
columns: [

@ -4,19 +4,10 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 12:20:46
* @LastEditTime: 2022-03-09 09:40:01
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
<template slot="rowButtonInMore" slot-scope="props">
<el-button
type="text"
@click="handleOpenDialogSetAuthorityForRole(props)"
v-permission="'roleManage:grantAuthority'"
>分配权限</el-button
>
</template>
<!--自定义的卡片插槽将在编辑详情页面出现在底部新卡片-->
<template v-slot:pageSection>
<RoleAuthority
:role-code="roleCode"
@ -52,6 +43,51 @@ export default {
title: "角色管理",
//
labelWidth: "160px",
//
tableButtons: [
{
label: "新增",
type: "", // primarysuccessinfowarningdanger
permission: "roleManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.$refs.listPage.handleOpenEditView("add");
}
},
{
label: "删除",
type: "danger",
permission: "roleManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "roleManage:update",
click: row => {
return this.$refs.listPage.handleOpenEditView("edit", row);
}
},
{
label: "分配权限",
permission: "roleManage:grantAuthority",
click: this.handleOpenDialogSetAuthorityForRole
},
{
label: "删除",
permission: "roleManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
queryFormFields: [
{
@ -95,9 +131,7 @@ export default {
api: accessRoleUpdate,
permission: "roleManage:update"
},
customButton: {
operationWidth: "160px"
}
rowButtonsWidth: 140 // row
},
//
columns: [
@ -200,7 +234,7 @@ export default {
},
methods: {
handleOpenDialogSetAuthorityForRole(props) {
this.roleCode = props.msg.roleCode;
this.roleCode = props.roleCode;
this.dialogVisibleSetAuthorityForRole = true;
}
}

@ -4,18 +4,10 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 12:20:35
* @LastEditTime: 2022-03-09 09:40:56
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
<template slot="rowButtonInMore" slot-scope="props">
<el-button
type="text"
@click="handleOpenDialogSetRoleForUser(props)"
v-permission="'userManage:grantRole'"
>分配角色</el-button
>
</template>
<template v-slot:pageSection>
<UserRole
:login-name="loginName"
@ -77,6 +69,51 @@ export default {
field: "phone"
}
],
//
tableButtons: [
{
label: "新增",
type: "roleManage:insert", // primarysuccessinfowarningdanger
permission: "userManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.$refs.listPage.handleOpenEditView("add");
}
},
{
label: "删除",
type: "danger",
permission: "userManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "userManage:update",
click: row => {
return this.$refs.listPage.handleOpenEditView("edit", row);
}
},
{
label: "分配权限",
permission: "userManage:grantRole",
click: this.handleOpenDialogSetRoleForUser
},
{
label: "删除",
permission: "userManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
query: {
@ -99,9 +136,7 @@ export default {
api: accessUserUpdate,
permission: "userManage:update"
},
customButton: {
operationWidth: "150px"
}
rowButtonsWidth: 150 // row
},
//
columns: [
@ -261,7 +296,7 @@ export default {
},
methods: {
handleOpenDialogSetRoleForUser(props) {
this.loginName = props.msg.loginName;
this.loginName = props.loginName;
this.dialogVisibleSetRoleForUser = true;
}
}

@ -47,7 +47,7 @@ export default {
if (type === "image") {
this.upload(file);
} else {
this.$message.warn("只能上图片格式");
this.$message.warn("只能上图片格式");
}
},
upload(imgUrl) {

@ -16,10 +16,12 @@
<!-- 左侧组件栏-->
<el-tab-pane label="工具栏">
<!-- <el-divider content-position="center">html</el-divider>-->
<draggable
<li
v-for="widget in widgetTools"
:key="widget.code"
@end="evt => widgetOnDragged(evt, widget.code)"
draggable="true"
@dragstart="dragStart(widget.code)"
@dragend="dragEnd()"
>
<div class="tools-item">
<span class="tools-item-icon">
@ -27,7 +29,7 @@
</span>
<span class="tools-item-text">{{ widget.label }}</span>
</div>
</draggable>
</li>
</el-tab-pane>
<!-- 左侧图层-->
<el-tab-pane label="图层">
@ -88,6 +90,29 @@
<i class="iconfont iconyulan" @click="viewScreen"></i>
</el-tooltip>
</span>
<span class="btn">
<el-tooltip
class="item"
effect="dark"
content="撤销"
placement="bottom"
>
<i class="iconfont iconundo"></i>
</el-tooltip>
</span>
<span class="btn">
<el-tooltip
class="item"
effect="dark"
content="恢复"
placement="bottom"
>
<i class="iconfont iconhuifubeifen"></i>
</el-tooltip>
</span>
<span class="btn" v-permission="'bigScreenManage:export'">
<el-tooltip
class="item"
@ -174,7 +199,7 @@
'background-origin': 'initial',
'background-clip': 'initial'
}"
@click.self="setOptionsOnClickScreen"
@click.self="setOptionsOnClickScreen" @drop="widgetOnDragged($event)" @dragover="dragOver($event)"
>
<div v-if="grade" class="bg-grid"></div>
<widget
@ -263,6 +288,7 @@ import draggable from "vuedraggable";
import VueRulerTool from "vue-ruler-tool"; //
import contentMenu from "./components/contentMenu";
import { getToken } from "@/utils/auth";
import { Revoke } from "@/utils/revoke"; // 2022-02-22
export default {
name: "Login",
@ -290,6 +316,7 @@ export default {
bigscreenWidth: 1920, //
bigscreenHeight: 1080,
revoke: null, // 2022-02-22
// gaea_report_dashboard
dashboard: {
@ -305,6 +332,7 @@ export default {
},
//
screenCode: "",
dragWidgetCode:'', //code
//
widgets: [
{
@ -395,10 +423,18 @@ export default {
widgets: {
handler(val) {
this.handlerLayerWidget(val);
//
this.$nextTick(() => {
this.revoke.push(this.widgets);
});
},
deep: true
}
},
created() {
/* 以下是记录历史的 */
this.revoke = new Revoke();
},
mounted() {
//
this.initEchartData();
@ -408,6 +444,30 @@ export default {
});
},
methods: {
/**
* @description: 恢复
* @param {*}
* @return {*}
*/
handleUndo() {
const record = this.revoke.undo();
if (!record) {
return false;
}
this.widgets = record;
},
/**
* @description: 重做
* @param {*}
* @return {*}
*/
handleRedo() {
const record = this.revoke.redo();
if (!record) {
return false;
}
this.widgets = record;
},
handlerLayerWidget(val) {
const layerWidgetArr = [];
for (let i = 0; i < val.length; i++) {
@ -603,14 +663,24 @@ export default {
getPXUnderScale(px) {
return this.bigscreenScaleInWorkbench * px;
},
dragStart( widgetCode) {
this.dragWidgetCode =widgetCode;
},
dragEnd() {
this.dragWidgetCode=''
},
dragOver(evt){
evt.preventDefault()
evt.stopPropagation()
evt.dataTransfer.dropEffect = 'copy'
},
//
widgetOnDragged(evt, widgetCode) {
let widgetType = widgetCode;
widgetOnDragged(evt) {
let widgetType = this.dragWidgetCode;
//
let eventX = evt.originalEvent.clientX; // x
let eventY = evt.originalEvent.clientY; // y
let eventX = evt.clientX; // x
let eventY = evt.clientY; // y
let workbenchPosition = this.getDomTopLeftById("workbench");
let widgetTopInWorkbench = eventY - workbenchPosition.top;
@ -639,6 +709,13 @@ export default {
};
//
const widgetJsonValue = this.handleDefaultValue(widgetJson);
//20220222
widgetJsonValue.value.position.left =
x - widgetJsonValue.value.position.width / 2;
widgetJsonValue.value.position.top =
y - widgetJsonValue.value.position.height / 2;
//
this.widgets.push(this.deepClone(widgetJsonValue));
//

@ -170,88 +170,6 @@ export const widgetBarchart = {
},
],
},
{
name: '图例操作',
list: [
{
type: 'el-switch',
label: '图例显示',
name: 'isShowLegend',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: '图例名称',
name: 'legendName',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '字体颜色',
name: 'lengedColor',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '字体字号',
name: 'lengedFontSize',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-input-number',
label: '图例宽度',
name: 'lengedWidth',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-select',
label: '横向位置',
name: 'lateralPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-select',
label: '纵向位置',
name: 'longitudinalPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'top', name: '顶部'},
{code: 'bottom', name: '底部'},
],
value: 'top'
},
{
type: 'el-select',
label: '布局前置',
name: 'layoutFront',
required: false,
placeholder: '',
selectOptions: [
{code: 'vertical', name: '竖排'},
{code: 'horizontal', name: '横排'},
],
value: 'horizontal'
},
],
},
{
name: 'X轴设置',
list: [
@ -519,9 +437,10 @@ export const widgetBarchart = {
{
type: 'el-input-number',
label: '字体字号',
name: 'tipFontSize',
name: 'tipsFontSize',
required: false,
placeholder: '',
value: 16
},
{
type: 'vue-color',

@ -162,88 +162,6 @@ export const widgetGradientBarchart = {
},
],
},
{
name: '图例操作',
list: [
{
type: 'el-switch',
label: '图例显示',
name: 'isShowLegend',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: '图例名称',
name: 'legendName',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '字体颜色',
name: 'lengedColor',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '字体字号',
name: 'lengedFontSize',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-input-number',
label: '图例宽度',
name: 'lengedWidth',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-select',
label: '横向位置',
name: 'lateralPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-select',
label: '纵向位置',
name: 'longitudinalPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'top', name: '顶部'},
{code: 'bottom', name: '底部'},
],
value: 'top'
},
{
type: 'el-select',
label: '布局前置',
name: 'layoutFront',
required: false,
placeholder: '',
selectOptions: [
{code: 'vertical', name: '竖排'},
{code: 'horizontal', name: '横排'},
],
value: 'horizontal'
},
],
},
{
name: 'X轴设置',
list: [

@ -0,0 +1,688 @@
/*
* @Descripttion: 热力图
* @version:
* @Author: whw
* @Date: 2021-11-3
* @LastEditors: whw
* @LastEditTime: 2021-11-3
*/
export const widgetHeatmap = {
code: 'widget-heatmap',
type: 'chart',
label: '热力图',
icon: 'iconrelitu',
options: {
// 配置
setup: [
{
type: 'el-input-text',
label: '图层名称',
name: 'layerName',
required: false,
placeholder: '',
value: '热力图',
},
{
type: 'vue-color',
label: '背景颜色',
name: 'background',
required: false,
placeholder: '',
value: ''
},
[
{
name: '标题设置',
list: [
{
type: 'el-switch',
label: '标题',
name: 'isNoTitle',
required: false,
placeholder: '',
value: true
},
{
type: 'el-input-text',
label: '标题',
name: 'titleText',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '字体颜色',
name: 'textColor',
required: false,
placeholder: '',
value: '#fff'
},
{
type: 'el-select',
label: '字体粗细',
name: 'textFontWeight',
required: false,
placeholder: '',
selectOptions: [
{code: 'normal', name: '正常'},
{code: 'bold', name: '粗体'},
{code: 'bolder', name: '特粗体'},
{code: 'lighter', name: '细体'}
],
value: 'normal'
},
{
type: 'el-input-number',
label: '字体大小',
name: 'textFontSize',
required: false,
placeholder: '',
value: 16
},
{
type: 'el-select',
label: '字体位置',
name: 'textAlign',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-input-text',
label: '副标题',
name: 'subText',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '字体颜色',
name: 'subTextColor',
required: false,
placeholder: '',
value: ''
},
{
type: 'el-select',
label: '字体粗细',
name: 'subTextFontWeight',
required: false,
placeholder: '',
selectOptions: [
{code: 'normal', name: '正常'},
{code: 'bold', name: '粗体'},
{code: 'bolder', name: '特粗体'},
{code: 'lighter', name: '细体'}
],
value: 'normal'
},
{
type: 'el-input-number',
label: '字体大小',
name: 'subTextFontSize',
required: false,
placeholder: '',
value: 16
},
],
},
{
name: 'X轴设置',
list: [
{
type: 'el-switch',
label: '显示',
name: 'hideX',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: 'X轴别名',
name: 'xName',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '别名颜色',
name: 'xNameColor',
required: false,
placeholder: '',
value: '#fff'
},
{
type: 'el-input-number',
label: '别名字号',
name: 'xNameFontSize',
required: false,
placeholder: '',
value: 14
},
{
type: 'el-switch',
label: '轴反转',
name: 'reversalX',
required: false,
placeholder: '',
value: false
},
{
type: 'el-slider',
label: '文字角度',
name: 'textAngleX',
required: false,
placeholder: '',
value: 0
},
{
type: 'el-input-number',
label: '文字间隔',
name: 'textInterval',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '文字颜色',
name: 'Xcolor',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '文字字号',
name: 'fontSizeX',
required: false,
placeholder: '',
value: 14,
},
{
type: 'vue-color',
label: '轴颜色',
name: 'lineColorX',
required: false,
placeholder: '',
value: '#fff',
},
],
},
{
name: 'Y轴设置',
list: [
{
type: 'el-switch',
label: '显示',
name: 'isShowY',
require: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: 'Y轴别名',
name: 'textNameY',
require: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '别名颜色',
name: 'NameColorY',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '别名字号',
name: 'NameFontSizeY',
required: false,
placeholder: '',
value: 14,
},
{
type: 'el-switch',
label: '轴反转',
name: 'reversalY',
required: false,
placeholder: '',
value: false
},
{
type: 'el-slider',
label: '文字角度',
name: 'textAngleY',
required: false,
placeholder: '',
value: 0
},
{
type: 'vue-color',
label: '文字颜色',
name: 'colorY',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '文字字号',
name: 'fontSizeY',
required: false,
placeholder: '',
value: 14,
},
{
type: 'vue-color',
label: '轴颜色',
name: 'lineColorY',
required: false,
placeholder: '',
value: '#fff',
},
],
},
{
name: '数值设定',
list: [
{
type: 'el-switch',
label: '显示',
name: 'isShow',
required: false,
placeholder: '',
value: true
},
{
type: 'el-input-number',
label: '字体字号',
name: 'fontSize',
required: false,
placeholder: '',
value: 14
},
{
type: 'vue-color',
label: '字体颜色',
name: 'subTextColor',
required: false,
placeholder: '',
value: '#fff'
},
{
type: 'el-select',
label: '字体粗细',
name: 'fontWeight',
required: false,
placeholder: '',
selectOptions: [
{code: 'normal', name: '正常'},
{code: 'bold', name: '粗体'},
{code: 'bolder', name: '特粗体'},
{code: 'lighter', name: '细体'}
],
value: 'normal'
},
],
},
{
name: '提示语设置',
list: [
{
type: 'el-input-number',
label: '字体字号',
name: 'tipsFontSize',
required: false,
placeholder: '',
value: 16
},
{
type: 'vue-color',
label: '字体颜色',
name: 'tipsLineColor',
required: false,
placeholder: '',
},
],
},
{
name: '坐标轴边距设置',
list: [
{
type: 'el-slider',
label: '左边距(像素)',
name: 'marginLeft',
required: false,
placeholder: '',
value: 10,
}, {
type: 'el-slider',
label: '顶边距(像素)',
name: 'marginTop',
required: false,
placeholder: '',
value: 50,
}, {
type: 'el-slider',
label: '右边距(像素)',
name: 'marginRight',
required: false,
placeholder: '',
value: 40,
}, {
type: 'el-slider',
label: '底边距(像素)',
name: 'marginBottom',
required: false,
placeholder: '',
value: 10,
},
],
},
{
name: '图设置',
list: [
{
type: 'el-switch',
label: '图例',
name: 'isShowLegend',
required: false,
placeholder: '',
value: false,
},
{
type: 'el-input-number',
label: '最小值',
name: 'dataMin',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '最大值',
name: 'dataMax',
required: false,
placeholder: '',
value: 5000,
},
{
type: 'vue-color',
label: '数值颜色',
name: 'lengedColor',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '图例大小',
name: 'lengedFontSize',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-input-number',
label: '图例宽度',
name: 'lengedWidth',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-select',
label: '横向位置',
name: 'lateralPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-select',
label: '纵向位置',
name: 'longitudinalPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'top', name: '顶部'},
{code: 'bottom', name: '底部'},
],
value: 'top'
},
{
type: 'el-select',
label: '布局前置',
name: 'layoutFront',
required: false,
placeholder: '',
selectOptions: [
{code: 'vertical', name: '竖排'},
{code: 'horizontal', name: '横排'},
],
value: 'horizontal'
},
],
},
{
name: '自定义配色',
list: [
{
type: 'customColor',
label: '',
name: 'lengedColorList',
required: false,
value: [{color: '#abd9e9'}, {color: '#74add1'}, {color: '#4575b4'}, {color: '#313695'}],
},
],
},
],
],
// 数据
data: [
{
type: 'el-radio-group',
label: '数据类型',
name: 'dataType',
require: false,
placeholder: '',
selectValue: true,
selectOptions: [
{
code: 'staticData',
name: '静态数据',
},
{
code: 'dynamicData',
name: '动态数据',
},
],
value: 'staticData',
},
{
type: 'el-input-number',
label: '刷新时间(毫秒)',
name: 'refreshTime',
relactiveDom: 'dataType',
relactiveDomValue: 'dynamicData',
value: 5000
},
{
type: 'el-button',
label: '静态数据',
name: 'staticData',
required: false,
placeholder: '',
relactiveDom: 'dataType',
relactiveDomValue: 'staticData',
value: [
{"axis": "0", "yaxis": "0", "num": 3320},
{"axis": "0", "yaxis": "1", "num": 1561},
{"axis": "0", "yaxis": "2", "num": 3194},
{"axis": "0", "yaxis": "3", "num": 2899},
{"axis": "0", "yaxis": "4", "num": 2363},
{"axis": "0", "yaxis": "5", "num": 3945},
{"axis": "0", "yaxis": "6", "num": 2051},
{"axis": "0", "yaxis": "7", "num": 3657},
{"axis": "0", "yaxis": "8", "num": 3304},
{"axis": "0", "yaxis": "9", "num": 2990},
{"axis": "1", "yaxis": "9", "num": 2663},
{"axis": "1", "yaxis": "0", "num": 378},
{"axis": "1", "yaxis": "1", "num": 4076},
{"axis": "1", "yaxis": "2", "num": 3178},
{"axis": "1", "yaxis": "3", "num": 1501},
{"axis": "1", "yaxis": "4", "num": 1660},
{"axis": "1", "yaxis": "5", "num": 726},
{"axis": "1", "yaxis": "6", "num": 4148},
{"axis": "1", "yaxis": "7", "num": 720},
{"axis": "1", "yaxis": "8", "num": 430},
{"axis": "2", "yaxis": "9", "num": 2983},
{"axis": "2", "yaxis": "0", "num": 1917},
{"axis": "2", "yaxis": "1", "num": 1188},
{"axis": "2", "yaxis": "2", "num": 3581},
{"axis": "2", "yaxis": "3", "num": 1781},
{"axis": "2", "yaxis": "4", "num": 4725},
{"axis": "2", "yaxis": "5", "num": 4077},
{"axis": "2", "yaxis": "6", "num": 299},
{"axis": "2", "yaxis": "7", "num": 4828},
{"axis": "2", "yaxis": "8", "num": 1778},
{"axis": "3", "yaxis": "9", "num": 3171},
{"axis": "3", "yaxis": "0", "num": 2944},
{"axis": "3", "yaxis": "1", "num": 763},
{"axis": "3", "yaxis": "2", "num": 1678},
{"axis": "3", "yaxis": "3", "num": 1765},
{"axis": "3", "yaxis": "4", "num": 2949},
{"axis": "3", "yaxis": "5", "num": 966},
{"axis": "3", "yaxis": "6", "num": 4622},
{"axis": "3", "yaxis": "7", "num": 2818},
{"axis": "3", "yaxis": "8", "num": 3913},
{"axis": "4", "yaxis": "9", "num": 4382},
{"axis": "4", "yaxis": "0", "num": 1670},
{"axis": "4", "yaxis": "1", "num": 4532},
{"axis": "4", "yaxis": "2", "num": 2116},
{"axis": "4", "yaxis": "3", "num": 2383},
{"axis": "4", "yaxis": "4", "num": 510},
{"axis": "4", "yaxis": "5", "num": 33},
{"axis": "4", "yaxis": "6", "num": 4974},
{"axis": "4", "yaxis": "7", "num": 3627},
{"axis": "4", "yaxis": "8", "num": 2737},
{"axis": "5", "yaxis": "9", "num": 656},
{"axis": "5", "yaxis": "0", "num": 3689},
{"axis": "5", "yaxis": "1", "num": 713},
{"axis": "5", "yaxis": "2", "num": 3551},
{"axis": "5", "yaxis": "3", "num": 3159},
{"axis": "5", "yaxis": "4", "num": 4150},
{"axis": "5", "yaxis": "5", "num": 1416},
{"axis": "5", "yaxis": "6", "num": 3021},
{"axis": "5", "yaxis": "7", "num": 1778},
{"axis": "5", "yaxis": "8", "num": 863},
{"axis": "6", "yaxis": "9", "num": 772},
{"axis": "6", "yaxis": "0", "num": 1675},
{"axis": "6", "yaxis": "1", "num": 1323},
{"axis": "6", "yaxis": "2", "num": 2023},
{"axis": "6", "yaxis": "3", "num": 43},
{"axis": "6", "yaxis": "4", "num": 4964},
{"axis": "6", "yaxis": "5", "num": 4781},
{"axis": "6", "yaxis": "6", "num": 2608},
{"axis": "6", "yaxis": "7", "num": 2278},
{"axis": "6", "yaxis": "8", "num": 3285},
{"axis": "7", "yaxis": "9", "num": 1977},
{"axis": "7", "yaxis": "0", "num": 882},
{"axis": "7", "yaxis": "1", "num": 2434},
{"axis": "7", "yaxis": "2", "num": 4694},
{"axis": "7", "yaxis": "3", "num": 3022},
{"axis": "7", "yaxis": "4", "num": 1798},
{"axis": "7", "yaxis": "5", "num": 2503},
{"axis": "7", "yaxis": "6", "num": 693},
{"axis": "7", "yaxis": "7", "num": 275},
{"axis": "7", "yaxis": "8", "num": 3774},
{"axis": "8", "yaxis": "9", "num": 1386},
{"axis": "8", "yaxis": "0", "num": 1212},
{"axis": "8", "yaxis": "1", "num": 1982},
{"axis": "8", "yaxis": "2", "num": 1509},
{"axis": "8", "yaxis": "3", "num": 94},
{"axis": "8", "yaxis": "4", "num": 2082},
{"axis": "8", "yaxis": "5", "num": 3930},
{"axis": "8", "yaxis": "6", "num": 4528},
{"axis": "8", "yaxis": "7", "num": 1861},
{"axis": "8", "yaxis": "8", "num": 4582},
{"axis": "9", "yaxis": "9", "num": 3038},
{"axis": "9", "yaxis": "0", "num": 4038},
{"axis": "9", "yaxis": "1", "num": 357},
{"axis": "9", "yaxis": "2", "num": 306},
{"axis": "9", "yaxis": "3", "num": 479},
{"axis": "9", "yaxis": "4", "num": 823},
{"axis": "9", "yaxis": "5", "num": 3442},
{"axis": "9", "yaxis": "6", "num": 904},
{"axis": "9", "yaxis": "7", "num": 399},
{"axis": "9", "yaxis": "8", "num": 4869},
]
},
{
type: 'dycustComponents',
label: '',
name: 'dynamicData',
required: false,
placeholder: '',
relactiveDom: 'dataType',
chartType: 'widget-coord',
relactiveDomValue: 'dynamicData',
dictKey: 'COORD_PROPERTIES',
value: '',
},
],
// 坐标
position: [
{
type: 'el-input-number',
label: '左边距',
name: 'left',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '上边距',
name: 'top',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '宽度',
name: 'width',
required: false,
placeholder: '该容器在1920px大屏中的宽度',
value: 700,
},
{
type: 'el-input-number',
label: '高度',
name: 'height',
required: false,
placeholder: '该容器在1080px大屏中的高度',
value: 300,
},
],
}
}

@ -1,6 +1,6 @@
/*
* @Descripttion: 图片json
* @version:
* @version:
* @Author: qianlishi
* @Date: 2021-08-29 07:07:23
* @LastEditors: qianlishi
@ -30,6 +30,14 @@ export const widgetImage = {
placeholder: '',
value: false,
},
{
type: 'el-slider',
label: '旋转速度',
name: 'rotationSpeed',
required: false,
placeholder: '',
value: 70
},
{
type: 'el-slider',
label: '透明度',

@ -186,88 +186,6 @@ export const widgetLinechart = {
},
],
},
{
name: '图例操作',
list: [
{
type: 'el-switch',
label: '图例显示',
name: 'isShowLegend',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: '图例名称',
name: 'legendName',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '字体颜色',
name: 'lengedColor',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '字体字号',
name: 'lengedFontSize',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-input-number',
label: '图例宽度',
name: 'lengedWidth',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-select',
label: '横向位置',
name: 'lateralPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-select',
label: '纵向位置',
name: 'longitudinalPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'top', name: '顶部'},
{code: 'bottom', name: '底部'},
],
value: 'top'
},
{
type: 'el-select',
label: '布局前置',
name: 'layoutFront',
required: false,
placeholder: '',
selectOptions: [
{code: 'vertical', name: '竖排'},
{code: 'horizontal', name: '横排'},
],
value: 'horizontal'
},
],
},
{
name: 'X轴设置',
list: [
@ -525,12 +443,12 @@ export const widgetLinechart = {
name: '提示语设置',
list: [
{
type: 'el-input-text',
type: 'el-input-number',
label: '字体大小',
name: 'fontSize',
name: 'tipsFontSize',
required: false,
placeholder: '',
value: ''
value: 16
},
{
type: 'vue-color',

@ -4,7 +4,7 @@
* @Author: qianlishi
* @Date: 2021-08-29 06:43:07
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 10:22:37
* @LastEditTime: 2022-03-11 10:35:35
*/
import { widgetTool } from "./main"
const screenConfig = {
@ -81,5 +81,5 @@ const getToolByCode = function (code) {
})
return item
}
console.log(widgetTools)
export {widgetTools, getToolByCode}

@ -35,6 +35,7 @@ import {widgetLineCompare} from "./configure/widget-line-compare"
import {widgetDecoratePie} from "./configure/widget-decorate-pie";
import {widgetMoreBarLine} from "./configure/widget-more-bar-line";
import {widgetWordCloud} from "./configure/widget-word-cloud";
import {widgetHeatmap} from "./configure/widget-heatmap";
export const widgetTool = [
// type=html类型的组件
@ -65,5 +66,6 @@ export const widgetTool = [
widgetLineCompare,
widgetDecoratePie,
widgetMoreBarLine,
widgetWordCloud
widgetWordCloud,
widgetHeatmap
]

@ -572,7 +572,7 @@ export default {
xAxisList = this.setUnique(xAxisList);
yAxisList = this.setUnique(yAxisList);
for (const i in yAxisList) {
const data = new Array(yAxisList.length).fill(0);
const data = new Array(xAxisList.length).fill(0);
for (const j in xAxisList) {
for (const k in val) {
if (val[k].name == yAxisList[i]) {

@ -314,7 +314,7 @@ export default {
xAxisList = this.setUnique(xAxisList);
yAxisList = this.setUnique(yAxisList);
for (const i in yAxisList) {
const data = new Array(yAxisList.length).fill(0);
const data = new Array(xAxisList.length).fill(0);
for (const j in xAxisList) {
for (const k in val) {
if (val[k].name == yAxisList[i]) {

@ -98,7 +98,6 @@ export default {
this.setOptionsTop();
this.setOptionsTooltip();
this.setOptionsMargin();
this.setOptionsLegend();
this.setOptionsColor();
this.setOptionsData();
},
@ -236,7 +235,7 @@ export default {
show: true,
textStyle: {
color: optionsSetup.lineColor,
fontSize: optionsSetup.tipFontSize
fontSize: optionsSetup.tipsFontSize
}
};
this.options.tooltip = tooltip;
@ -253,42 +252,6 @@ export default {
};
this.options.grid = grid;
},
// legend
setOptionsLegend() {
const optionsSetup = this.optionsSetup;
const legend = this.options.legend;
legend.show = optionsSetup.isShowLegend;
legend.left = optionsSetup.lateralPosition;
legend.right = optionsSetup.lateralPosition;
legend.top = optionsSetup.longitudinalPosition;
legend.bottom =
optionsSetup.longitudinalPosition;
legend.orient = optionsSetup.layoutFront;
legend.textStyle = {
color: optionsSetup.lengedColor,
fontSize: optionsSetup.fontSize
};
legend.itemWidth = optionsSetup.lengedWidth;
},
//
setOptionsLegendName(name){
const optionsSetup = this.optionsSetup;
const series = this.options.series;
const legendName = optionsSetup.legendName;
//
if (null == legendName || legendName == '') {
for (let i = 0; i < name.length; i++) {
series[i].name = name[i];
}
this.options.legend['data'] = name;
}else {
const arr = legendName.split('|');
for (let i = 0; i < arr.length; i++) {
series[i].name = arr[i];
}
this.options.legend['data'] = arr
}
},
//
setOptionsColor() {
const optionsSetup = this.optionsSetup;
@ -350,10 +313,6 @@ export default {
if (series[0].type == "bar") {
series[0].data = data;
}
const legendName = [];
legendName.push('销售量')
this.options.legend['data'] = legendName;
this.setOptionsLegendName(legendName);
},
//
dynamicDataFn(val, refreshTime, optionsSetup) {
@ -388,16 +347,12 @@ export default {
}
// series
const series = this.options.series;
const legendName = [];
for (const i in series) {
if (series[i].type == "bar") {
series[i].name = val.series[i].name;
series[i].data = val.series[i].data;
}
legendName.push(val.series[i].name);
}
this.options.legend['data'] = legendName;
this.setOptionsLegendName(legendName);
}
}
};

@ -167,7 +167,6 @@ export default {
this.setOptionsX();
this.setOptionsY();
this.setOptionsTop();
this.setOptionsLegend();
this.setOptionsMargin();
this.setOptionsColor();
this.setOptionsData();
@ -302,7 +301,7 @@ export default {
show: true,
textStyle: {
color: optionsSetup.lineColor,
fontSize: optionsSetup.fontSize
fontSize: optionsSetup.tipsFontSize
}
};
this.options.tooltip = tooltip;
@ -319,42 +318,6 @@ export default {
};
this.options.grid = grid;
},
// legend
setOptionsLegend() {
const optionsSetup = this.optionsSetup;
const legend = this.options.legend;
legend.show = optionsSetup.isShowLegend;
legend.left = optionsSetup.lateralPosition;
legend.right = optionsSetup.lateralPosition;
legend.top = optionsSetup.longitudinalPosition;
legend.bottom =
optionsSetup.longitudinalPosition;
legend.orient = optionsSetup.layoutFront;
legend.textStyle = {
color: optionsSetup.lengedColor,
fontSize: optionsSetup.fontSize
};
legend.itemWidth = optionsSetup.lengedWidth;
},
//
setOptionsLegendName(name){
const optionsSetup = this.optionsSetup;
const series = this.options.series;
const legendName = optionsSetup.legendName;
//
if (null == legendName || legendName == '') {
for (let i = 0; i < name.length; i++) {
series[i].name = name[i];
}
this.options.legend['data'] = name;
}else {
const arr = legendName.split('|');
for (let i = 0; i < arr.length; i++) {
series[i].name = arr[i];
}
this.options.legend['data'] = arr
}
},
//
setOptionsColor() {
const optionsSetup = this.optionsSetup;
@ -436,10 +399,6 @@ export default {
if (series[0].type == "bar") {
series[0].data = data;
}
const legendName = [];
legendName.push('销售量')
this.options.legend['data'] = legendName;
this.setOptionsLegendName(legendName);
},
//
dynamicDataFn(val, refreshTime, optionsSetup) {
@ -475,16 +434,12 @@ export default {
// series
const series = this.options.series;
const legendName = [];
for (const i in series) {
if (series[i].type == "bar") {
series[i].name = val.series[i].name;
series[i].data = val.series[i].data;
}
legendName.push(val.series[i].name);
}
this.options.legend['data'] = legendName;
this.setOptionsLegendName(legendName);
}
}
};

@ -0,0 +1,367 @@
<template>
<div :style="styleObj">
<v-chart :options="options" autoresize/>
</div>
</template>
<script>
export default {
name: "widgetHeatmap",
components: {},
props: {
value: Object,
ispreview: Boolean,
},
data() {
return {
options: {
title: {
text: "",
left: "center",
textStyle: {
color: "#fff",
},
},
tooltip: {
position: "top",
show: true,
textStyle: {},
},
grid: {
height: "90%",
width: "90%",
top: 10,
left: 20,
},
xAxis: {
name: "",
type: "category",
axisLabel: {
show: true,
color: "#0f0",
},
data: [],
splitArea: {
show: false,
},
nameTextStyle: {
color: "",
fontSize: 14,
},
},
yAxis: {
name: "",
type: "category",
axisLabel: {
show: true,
color: "#0f0",
},
data: [],
splitArea: {
show: false,
},
nameTextStyle: {
color: "",
fontSize: 14,
},
},
visualMap: {
show: true,
min: 0,
max: 5000,
calculable: true,
orient: "horizontal",
left: "center",
bottom: 0,
inRange: {
color: [],
},
textStyle: {
fontSize: 14,
color: "#fff",
},
},
series: [
{
name: "",
type: "heatmap",
data: [],
label: {
show: false,
fontSize: 16,
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
},
],
},
optionsStyle: {}, //
optionsData: {}, //
optionsCollapse: {}, //
optionsSetup: {},
};
},
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.collapse;
this.optionsSetup = val.setup;
this.editorOptions();
},
deep: true,
},
},
created() {
this.optionsStyle = this.value.position;
this.optionsData = this.value.data;
this.optionsCollapse = this.value.collapse;
this.optionsSetup = this.value.setup;
this.editorOptions();
},
methods: {
// options
editorOptions() {
this.setOptionsTitle();
this.setOptionsX();
this.setOptionsY();
this.setOptionsSeries();
this.setOptionsMargin();
this.setOptionsVisualMap();
this.setOptionsData();
},
//
setOptionsTitle() {
const optionsSetup = this.optionsSetup;
const title = {
text: optionsSetup.titleText,
show: optionsSetup.isNoTitle,
left: optionsSetup.textAlign,
textStyle: {
color: optionsSetup.textColor,
fontSize: optionsSetup.textFontSize,
fontWeight: optionsSetup.textFontWeight
},
subtext: optionsSetup.subText,
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
},
//
inverse: optionsSetup.reversalX,
axisLabel: {
show: true,
//
interval: optionsSetup.textInterval,
//
rotate: optionsSetup.textAngleX,
textStyle: {
//
color: optionsSetup.Xcolor,
fontSize: optionsSetup.fontSizeX
}
},
axisLine: {
show: true,
lineStyle: {
color: optionsSetup.lineColorX
}
},
splitArea: {
show: false,
},
};
this.options.xAxis = xAxis;
},
// Y
setOptionsY() {
const optionsSetup = this.optionsSetup;
const yAxis = {
type: "category",
//
show: optionsSetup.isShowY,
//
name: optionsSetup.textNameY,
nameTextStyle: {
color: optionsSetup.NameColorY,
fontSize: optionsSetup.NameFontSizeY
},
// y
inverse: optionsSetup.reversalY,
axisLabel: {
show: true,
//
rotate: optionsSetup.textAngleY,
textStyle: {
//
color: optionsSetup.colorY,
fontSize: optionsSetup.fontSizeY
}
},
axisLine: {
show: true,
lineStyle: {
color: optionsSetup.lineColorY
}
},
splitArea: {
show: false,
},
};
this.options.yAxis = yAxis;
},
//
setOptionsSeries() {
const optionsSetup = this.optionsSetup;
const lable = {
show: optionsSetup.isShow,
textStyle: {
fontSize: optionsSetup.fontSize,
color: optionsSetup.subTextColor,
fontWeight: optionsSetup.fontWeight
}
}
this.options.series[0].label = lable;
},
//
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;
},
// tooltip
setOptionsTooltip() {
const optionsSetup = this.optionsSetup;
const tooltip = {
trigger: "item",
position: "top",
show: true,
textStyle: {
color: optionsSetup.lineColor,
fontSize: optionsSetup.tipsLineColor
}
};
this.options.tooltip = tooltip;
},
//
setOptionsVisualMap() {
const optionsSetup = this.optionsSetup;
const visualMap = this.options.visualMap;
visualMap.show = optionsSetup.isShowLegend;
visualMap.min = optionsSetup.dataMin;
visualMap.max = optionsSetup.dataMax;
visualMap.textStyle = {
fontSize : optionsSetup.lengedFontSize,
color : optionsSetup.lengedColor
};
visualMap.inRange.color = optionsSetup.lengedColorList.map((x) => {
return x.color;
});
visualMap.left = optionsSetup.lateralPosition;
visualMap.top = optionsSetup.longitudinalPosition;
visualMap.bottom = optionsSetup.longitudinalPosition;
visualMap.orient = optionsSetup.layoutFront;
visualMap.itemWidth = optionsSetup.lengedWidth;
},
setOptionsData() {
const optionsData = this.optionsData; // or
optionsData.dataType == "staticData"
? this.staticDataFn(optionsData.staticData)
: this.dynamicDataFn(optionsData.dynamicData, optionsData.refreshTime);
},
//
setUnique(arr) {
let newArr = [];
arr.forEach(item => {
return newArr.includes(item) ? '' : newArr.push(item);
});
return newArr;
},
staticDataFn(val) {
const data = [];
let xAxisList = [];
let yAxisList = [];
for (const i in val) {
xAxisList[i] = val[i].axis;
yAxisList[i] = val[i].yaxis;
data[i] = [val[i].axis,val[i].yaxis,val[i].num]
}
xAxisList = this.setUnique(xAxisList);
yAxisList = this.setUnique(yAxisList);
this.options.xAxis.data = xAxisList;
this.options.yAxis.data = yAxisList;
this.options.series[0].data = data;
},
dynamicDataFn(val, refreshTime) {
if (!val) return;
if (this.ispreview) {
this.getEchartData(val);
this.flagInter = setInterval(() => {
this.getEchartData(val);
}, refreshTime);
} else {
this.getEchartData(val);
}
},
getEchartData(val) {
const data = this.queryEchartsData(val);
data.then((res) => {
this.renderingFn(res);
});
},
renderingFn(val) {
this.options.xAxis.data = val.xAxis;
this.options.yAxis.data = val.yAxis;
this.options.series[0].data = val.series;
},
},
};
</script>
<style scoped lang="scss">
.echarts {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>

@ -618,7 +618,7 @@ export default {
xAxisList = this.setUnique(xAxisList);
yAxisList = this.setUnique(yAxisList);
for (const i in yAxisList) {
const data = new Array(yAxisList.length).fill(0);
const data = new Array(xAxisList.length).fill(0);
for (const j in xAxisList) {
for (const k in val) {
if (val[k].name == yAxisList[i]) {

@ -332,7 +332,7 @@ export default {
xAxisList = this.setUnique(xAxisList);
yAxisList = this.setUnique(yAxisList);
for (const i in yAxisList) {
const data = new Array(yAxisList.length).fill(0);
const data = new Array(xAxisList.length).fill(0);
for (const j in xAxisList) {
for (const k in val) {
if (val[k].name == yAxisList[i]) {

@ -105,7 +105,6 @@ export default {
this.setOptionsTooltip();
this.setOptionsData();
this.setOptionsMargin();
this.setOptionsLegend();
this.setOptionsColor();
},
//
@ -244,7 +243,7 @@ export default {
show: true,
textStyle: {
color: optionsSetup.lineColor,
fontSize: optionsSetup.fontSize
fontSize: optionsSetup.tipsFontSize
}
};
this.options.tooltip = tooltip;
@ -261,42 +260,6 @@ export default {
};
this.options.grid = grid;
},
// legend
setOptionsLegend() {
const optionsSetup = this.optionsSetup;
const legend = this.options.legend;
legend.show = optionsSetup.isShowLegend;
legend.left = optionsSetup.lateralPosition;
legend.right = optionsSetup.lateralPosition;
legend.top = optionsSetup.longitudinalPosition;
legend.bottom =
optionsSetup.longitudinalPosition;
legend.orient = optionsSetup.layoutFront;
legend.textStyle = {
color: optionsSetup.lengedColor,
fontSize: optionsSetup.fontSize
};
legend.itemWidth = optionsSetup.lengedWidth;
},
//
setOptionsLegendName(name){
const optionsSetup = this.optionsSetup;
const series = this.options.series;
const legendName = optionsSetup.legendName;
//
if (null == legendName || legendName == '') {
for (let i = 0; i < name.length; i++) {
series[i].name = name[i];
}
this.options.legend['data'] = name;
}else {
const arr = legendName.split('|');
for (let i = 0; i < arr.length; i++) {
series[i].name = arr[i];
}
this.options.legend['data'] = arr
}
},
//
setOptionsColor() {
const optionsSetup = this.optionsSetup;
@ -332,10 +295,6 @@ export default {
series[i].data = data;
}
}
const legendName = [];
legendName.push('销售量')
this.options.legend['data'] = legendName;
this.setOptionsLegendName(legendName);
},
dynamicDataFn(val, refreshTime) {
if (!val) return;
@ -359,15 +318,11 @@ export default {
this.options.xAxis.data = val.xAxis;
// series
const series = this.options.series;
const legendName = [];
for (const i in series) {
if (series[i].type == "line") {
series[i].data = val.series[i].data;
}
legendName.push(val.series[i].name);
}
this.options.legend['data'] = legendName;
this.setOptionsLegendName(legendName);
}
}
};

@ -38,6 +38,7 @@ import widgetLineCompareChart from "./line/widgetLineCompareChart";
import widgetDecoratePieChart from "./decorate/widgetDecoratePieChart";
import widgetMoreBarLineChart from "./bar/widgetMoreBarLineChart";
import widgetWordCloud from "./wordcloud/widgetWordCloud";
import widgetHeatmap from "./heatmap/widgetHeatmap";
export default {
name: "WidgetTemp",
@ -68,7 +69,8 @@ export default {
widgetLineCompareChart,
widgetDecoratePieChart,
widgetMoreBarLineChart,
widgetWordCloud
widgetWordCloud,
widgetHeatmap
},
model: {
prop: "value",

@ -17,7 +17,7 @@
@focus="handleFocus"
@blur="handleBlur"
>
<component :is="type" :value="value"/>
<component :is="type" :value="value" />
</avue-draggable>
</template>
@ -49,6 +49,7 @@ import widgetLineCompareChart from "./line/widgetLineCompareChart";
import widgetDecoratePieChart from "./decorate/widgetDecoratePieChart";
import widgetMoreBarLineChart from "./bar/widgetMoreBarLineChart";
import widgetWordCloud from "./wordcloud/widgetWordCloud";
import widgetHeatmap from "./heatmap/widgetHeatmap";
export default {
name: "Widget",
@ -79,7 +80,8 @@ export default {
widgetLineCompareChart,
widgetDecoratePieChart,
widgetMoreBarLineChart,
widgetWordCloud
widgetWordCloud,
widgetHeatmap
},
model: {
prop: "value",
@ -95,8 +97,7 @@ export default {
bigscreen: Object,
value: {
type: [Object],
default: () => {
}
default: () => {}
},
step: Number
},
@ -126,13 +127,11 @@ export default {
return this.value.position.zIndex || 1;
}
},
mounted() {
},
mounted() {},
methods: {
handleFocus({index, left, top, width, height}) {
},
handleBlur({index, left, top, width, height}) {
this.$emit("onActivated", {index, left, top, width, height});
handleFocus({ index, left, top, width, height }) {},
handleBlur({ index, left, top, width, height }) {
this.$emit("onActivated", { index, left, top, width, height });
this.$refs.draggable.setActive(true);
}
}

@ -41,7 +41,8 @@ export default {
return {
imageAdress: this.transStyle.imageAdress,
"border-radius": this.transStyle.borderRadius + "px",
opacity: this.transStyle.transparency / 100
opacity: this.transStyle.transparency / 100,
animation: this.transStyle.startRotate? "turn "+(101-this.transStyle.rotationSpeed)/10+"s linear infinite":"none"
};
}
},
@ -74,21 +75,5 @@ export default {
.startImg {
animation: turn 1s linear infinite;
}
@keyframes turn {
0% {
-webkit-transform: rotate(0deg);
}
25% {
-webkit-transform: rotate(90deg);
}
50% {
-webkit-transform: rotate(180deg);
}
75% {
-webkit-transform: rotate(270deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
</style>

@ -4,28 +4,10 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-24 14:00:47
* @LastEditTime: 2022-03-09 09:43:31
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
<template v-slot:buttonLeftOnTable>
<el-button
type="primary"
icon="el-icon-plus"
@click="operateDatasource('add')"
v-permission="'datasourceManage:insert'"
>新增</el-button
>
</template>
<template slot="rowButton" slot-scope="props">
<el-button
type="text"
@click="operateDatasource('edit', props)"
v-permission="'datasourceManage:update'"
>编辑</el-button
>
</template>
<template v-slot:pageSection>
<EditDataSource
ref="EditDataSource"
@ -60,6 +42,46 @@ export default {
title: "数据源",
//
labelWidth: "120px",
//
tableButtons: [
{
label: "新增",
type: "", // primarysuccessinfowarningdanger
permission: "datasourceManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.operateDatasource("add");
}
},
{
label: "删除",
type: "danger",
permission: "datasourceManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "datasourceManage:update",
click: row => {
return this.operateDatasource("edit", row);
}
},
{
label: "删除",
permission: "datasourceManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
queryFormFields: [
{
@ -83,9 +105,7 @@ export default {
],
//
buttons: {
customButton: {
operationWidth: 150
},
rowButtonsWidth: 150, // row
query: {
api: reportDataSourceList,
permission: "datasourceManage:query",
@ -218,7 +238,7 @@ export default {
operateDatasource(type, prop) {
this.dialogVisibleSetDataSource = true;
if (prop) {
this.dataSource = prop.msg;
this.dataSource = prop;
} else {
this.dataSource = {};
}

@ -64,6 +64,46 @@ export default {
field: "locale"
}
],
//
tableButtons: [
{
label: "新增",
type: "", // primarysuccessinfowarningdanger
permission: "dictItemManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.$refs.listPage.handleOpenEditView("add");
}
},
{
label: "删除",
type: "danger",
permission: "dictItemManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "dictItemManage:update",
click: row => {
return this.$refs.listPage.handleOpenEditView("edit", row);
}
},
{
label: "删除",
permission: "dictItemManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
query: {
@ -86,9 +126,7 @@ export default {
api: dictItemEdit,
permission: "dictItemManage:update"
},
customButton: {
operationWidth: "150px"
}
rowButtonsWidth: 150 // row
},
//
columns: [

@ -4,7 +4,7 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 13:46:33
* @LastEditTime: 2022-03-09 10:02:26
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
@ -75,6 +75,64 @@ export default {
that.$store.commit("user/SET_PROJECT", queryForm["project"]);
}
},
//
tableButtons: [
{
label: "刷新字典项",
type: "primary", // primarysuccessinfowarningdanger
permission: "dictManage:fresh", //
icon: "el-icon-edit",
plain: true,
click: this.dictRefresh
},
{
label: "新增",
type: "", // primarysuccessinfowarningdanger
permission: "dictManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.$refs.listPage.handleOpenEditView("add");
}
},
{
label: "删除",
type: "danger",
permission: "dictManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "dictManage:update",
click: row => {
return this.$refs.listPage.handleOpenEditView("edit", row);
}
},
{
label: "编辑字典项",
permission: "dictItemManage:query",
click: this.editItem
},
{
label: "刷新字典项",
permission: "dictManage:fresh",
click: this.itemRefresh
},
{
label: "删除",
permission: "dictManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
query: {
@ -97,10 +155,7 @@ export default {
api: dictEdit,
permission: "dictManage:update"
},
//
customButton: {
operationWidth: 160 // row
}
rowButtonsWidth: 150 // row
},
//
columns: [
@ -200,7 +255,7 @@ export default {
},
//
async itemRefresh(val) {
const selectedList = val.msg;
const selectedList = val;
let dictCodes = [];
if (selectedList.length > 0) {
dictCodes = selectedList.map(item => item.dictCode);
@ -214,7 +269,7 @@ export default {
this.$router.push({
path: "/system/dictItem",
query: {
dictCode: val.msg.dictCode,
dictCode: val.dictCode,
project: this.$store.state.user.project
}
});

@ -4,11 +4,11 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 13:47:02
* @LastEditTime: 2022-03-09 09:57:17
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
<template v-slot:buttonLeftOnTable>
<template v-slot:tableButtons>
<el-upload
class="el-upload"
ref="upload"
@ -61,6 +61,37 @@ export default {
field: "filePath"
}
],
//
tableButtons: [
{
label: "删除",
type: "danger",
permission: "fileManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "复制url",
click: this.copyUrlPath
},
{
label: "下载",
click: this.customButtom
},
{
label: "删除",
permission: "fileManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
query: {
@ -87,10 +118,7 @@ export default {
permission: "fileManage:update",
isShow: false
},
//
customButton: {
operationWidth: 160 // row
}
rowButtonsWidth: 150 // row
},
//
columns: [
@ -233,10 +261,10 @@ export default {
window.open(row.urlPath);
},
customButtom(val) {
this.downloadFile(val.msg);
this.downloadFile(val);
},
copyUrlPath(val) {
this.copyToClip(val.msg.urlPath);
this.copyToClip(val.urlPath);
this.$message({
message: "已将url路径复制至剪切板",
type: "success"

@ -3,7 +3,7 @@
<div class="admin-title" @click="goBigScreen">
<div class="con">
<img src="../../../../../static/logo-dp.png" width="50" />
<span class="version">V0.9.6.1</span>
<span class="version">V0.9.7</span>
</div>
</div>
<el-menu

@ -13,7 +13,7 @@
<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" />
<img src="@/assets/images/login.jpg" alt="image" class="login_img" />
<el-form
ref="loginForm"
:model="loginForm"

@ -4,31 +4,10 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-13 12:20:46
* @LastEditTime: 2022-05-15 10:44:58
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
<template slot="rowButtonInMore" slot-scope="props">
<el-button
type="text"
@click="preview(props.msg)"
v-permission="'bigScreenManage:view'"
>预览</el-button
>
<el-button
type="text"
@click="design(props.msg)"
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"
@ -45,10 +24,12 @@ import {
reportAdd,
reportDeleteBatch,
reportUpdate,
reportDetail
reportDetail,
reportCopy
} from "@/api/reportmanage";
import Share from "./components/share";
import { validateEngOrNum } from "@/utils/validate";
import { verificationSet } from "@/api/report";
export default {
name: "Report",
components: {
@ -92,6 +73,66 @@ export default {
field: "reportAuthor"
}
],
//
tableButtons: [
{
label: "新增",
type: "", // primarysuccessinfowarningdanger
permission: "reportManage:insert", //
icon: "el-icon-plus",
plain: true,
click: () => {
return this.$refs.listPage.handleOpenEditView("add");
}
},
{
label: "删除",
type: "danger",
permission: "reportManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "reportManage:update",
click: row => {
return this.$refs.listPage.handleOpenEditView("edit", row);
}
},
{
label: "预览",
permission: "bigScreenManage:view",
click: this.preview
},
{
label: "设计",
permission: "bigScreenManage:design",
click: this.design
},
{
label: "分享",
permission: "bigScreenManage:share",
click: this.shareReport
},
{
label: "复制",
permission: "bigScreenManage:copy",
click: this.copyReport
},
{
label: "删除",
permission: "reportManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
query: {
@ -116,9 +157,7 @@ export default {
api: reportUpdate,
permission: "reportManage:update"
},
customButton: {
operationWidth: "150px"
}
rowButtonsWidth: 150 // row
},
//
columns: [
@ -257,7 +296,16 @@ export default {
// fieldName input name
// fieldVal input
// fieldExtend select
formChange: (formData, fieldName, fieldVal, fieldExtend) => {}
formChange: (formData, fieldName, fieldVal, fieldExtend) => {
console.log(formData);
if (fieldName == "reportImage") {
if (fieldVal.length > 0) {
formData["reportImage"] = fieldVal && fieldVal[0].url;
} else {
formData["reportImage"] = "";
}
}
}
}
};
},
@ -307,6 +355,15 @@ export default {
this.reportCodeForShareDialog = val.reportCode;
this.reportNameForShareDialog = val.reportName;
this.visibleForShareDialog = true;
},
//
async copyReport(val) {
const { code } = await reportCopy(val);
if (code != "200") {
return;
}
this.$message.success("复制成功");
this.$refs.listPage.handleQueryForm("query");
}
}
};

@ -219,6 +219,7 @@
v-model="item.transformType"
:updata-dict="item.transformType"
:dict-key="'TRANSFORM_TYPE'"
@change="changeForm"
/>
<el-button
type="text"
@ -229,7 +230,8 @@
<el-button
v-if="
item.transformType == 'js' ||
item.transformType == 'dict'
item.transformType == 'dict' ||
item.transformType == 'javaBean'
"
type="text"
class="editor"
@ -251,10 +253,16 @@
min-height="400px"
append-to-body
>
<div v-if="isItemFilterType.transformType == 'js'">
<div
v-if="
isItemFilterType.transformType == 'js' ||
isItemFilterType.transformType == 'javaBean'
"
>
<div class="codemirror">
<!-- // -->
<monaco-editor
v-if="jsScriptVisible"
v-model.trim="transformScript"
language="javascript"
style="height: 500px"
@ -482,6 +490,7 @@ export default {
dialogFormVisibleTitle: "",
dialogPermissionVisible: false,
dialogSwitchVisible: false,
jsScriptVisible: false,
permissionTextarea: "",
isItemFilterType: "", // id
itemFilterList: [
@ -533,7 +542,7 @@ export default {
],
isRowData: {},
tableData2: [],
dialogTitle: "js脚本填写",
dialogTitle: "脚本填写",
isShowPagination: false,
updataDisabled: false,
dialogCaseResult: false,
@ -662,6 +671,12 @@ export default {
this.isShowPagination = false;
}
},
changeForm(val) {
if (!val) {
this.dialogSwitchVisible = false;
this.jsScriptVisible = false
}
},
//
closeDialog() {
this.$emit("handleClose");
@ -743,6 +758,7 @@ export default {
console.log(item);
this.isItemFilterType = item;
this.dialogSwitchVisible = true;
this.jsScriptVisible = true
if (item.transformType == "js") {
this.itemFilterScriptId = item.itemFilterSort;
const fnCont = `function dataTransform(data){\n\t//自定义脚本内容\n\treturn data;\n}`;
@ -750,25 +766,29 @@ export default {
? item.transformScript
: fnCont;
} else if (item.transformType == "dict") {
// this.dialogTitle = ''
// this.itemFilterScriptId = item.itemFilterSort
// const { code, data } = await getDictList('TRANSFORM_TYPE')
// if (code != '200') return
// const extend = data.find(function (y) {
// if (y.id == item.transformType) {
// return y
// }
// })
// const extendArry = []
// const extendObj = JSON.parse(extend.extend)
// for (const i in extendObj) {
// const children = []
// for (const y in extendObj[i]) {
// children.push({ name: y, value: extendObj[i][y] })
// }
// extendArry.push({ name: i, children: children })
// }
// this.tableData2 = extendArry
} else if (item.transformType == "javaBean") {
this.itemFilterScriptId = item.itemFilterSort;
const fnCont = `package com;
import com.alibaba.fastjson.JSONObject;
import com.anjiplus.template.gaea.business.modules.datasettransform.service.IGroovyHandler;
import java.util.List;
/**
* 建议在idea写好复制整个类到此处位置report-core/src/test/java/com/DemoGroovyHandler.java
*/
public class DemoGroovyHandler implements IGroovyHandler {
@Override
public List<JSONObject> transform(List<JSONObject> data) {
return data;
}
}`;
this.transformScript = item.transformScript
? item.transformScript
: fnCont;
}
},
// js

@ -4,11 +4,11 @@
* @Author: qianlishi
* @Date: 2021-12-11 14:48:27
* @LastEditors: qianlishi
* @LastEditTime: 2021-12-24 14:01:19
* @LastEditTime: 2022-04-14 18:48:24
-->
<template>
<anji-crud ref="listPage" :option="crudOption">
<template v-slot:buttonLeftOnTable>
<template v-slot:tableButtons>
<el-dropdown placement="bottom" @command="operateDataset">
<el-button type="primary" icon="el-icon-plus">
新增
@ -21,23 +21,6 @@
</el-dropdown>
</template>
<template slot="rowButton" slot-scope="props">
<el-button
type="text"
@click="operateDataset('edit', props)"
v-permission="'resultsetManage:update'"
>编辑
</el-button>
</template>
<template slot="rowButtonInMore" slot-scope="props">
<el-button
type="text"
@click="dataView(props)"
v-permission="'resultsetManage:query'"
>数据预览
</el-button>
</template>
<template v-slot:pageSection>
<EditDataSet
ref="EditDataSet"
@ -113,11 +96,44 @@ export default {
field: "setType"
}
],
//
tableButtons: [
{
label: "删除",
type: "danger",
permission: "resultsetManage:delete",
icon: "el-icon-delete",
plain: false,
click: () => {
return this.$refs.listPage.handleDeleteBatch();
}
}
],
//
rowButtons: [
{
label: "编辑",
permission: "resultsetManage:update",
click: row => {
return this.operateDataset("edit", row);
}
},
{
label: "数据预览",
permission: "resultsetManage:query",
click: this.dataView
},
{
label: "删除",
permission: "resultsetManage:delete",
click: row => {
return this.$refs.listPage.handleDeleteBatch(row);
}
}
],
//
buttons: {
customButton: {
operationWidth: 180
},
rowButtonsWidth: 180, // row
query: {
api: reportDataSetList,
permission: "resultsetManage:query",
@ -275,9 +291,9 @@ export default {
methods: {
operateDataset(type, prop) {
this.dialogVisibleSetDataSet = true;
if (prop && prop.msg) {
this.dataSet = prop.msg;
type = prop.msg.setType;
if (prop && prop.setType) {
this.dataSet = prop;
type = prop.setType;
} else {
this.dataSet = {};
}
@ -289,8 +305,8 @@ export default {
dataView(prop) {
this.dialogCaseResult = true;
this.$refs.DataView.dataViewPreview(
prop.msg.setName,
JSON.parse(prop.msg.caseResult)
prop.setName,
JSON.parse(prop.caseResult)
);
}
}

@ -0,0 +1,71 @@
<template>
<el-input
clearable
v-model="colorValue"
placeholder="请输入颜色"
size="mini"
@change="changeColor"
>
<template slot="append">
<el-color-picker
v-model="colorValue"
:predefine="predefineColors"
show-alpha
size="mini"
@change="changeColor"
/>
</template>
</el-input>
</template>
<script>
export default {
name: "ColorPicker",
model: {
prop: "value",
event: "input"
},
props: {
value: {
type: [String],
default: ""
}
},
data() {
return {
predefineColors: [
"#ff4500",
"#ff8c00",
"#ffd700",
"#90ee90",
"#00ced1",
"#1e90ff",
"#c71585"
],
colorValue: ""
};
},
watch: {
value(val) {
this.colorValue = val || "";
}
},
mounted() {
this.colorValue = this.value;
},
methods: {
changeColor(val) {
this.colorValue = val || "";
this.$emit("input", this.colorValue);
this.$emit("change", this.colorValue);
}
}
};
</script>
<style lang="scss" scoped>
/deep/.el-color-picker--mini,
/deep/.el-color-picker--mini .el-color-picker__trigger {
width: 23px;
height: 23px;
}
</style>

@ -0,0 +1,106 @@
<template>
<div v-show="visible" class="contentmenu" :style="styleObj">
<div class="contentmenu__item" @click="deleteLayer">
<i class="iconfont iconguanbi"></i> 删除图层
</div>
<div class="contentmenu__item" @click="copyLayer">
<i class="iconfont iconfuzhi1"></i> 复制图层
</div>
<div class="contentmenu__item" @click="istopLayer">
<i class="iconfont iconjinlingyingcaiwangtubiao01"></i> 置顶图层
</div>
<div class="contentmenu__item" @click="setlowLayer">
<i class="iconfont iconleft-copy"></i> 置底图层
</div>
<div class="contentmenu__item" @click="moveupLayer">
<i class="iconfont iconjinlingyingcaiwangtubiao01"></i> 上移一层
</div>
<div class="contentmenu__item" @click="movedownLayer">
<i class="iconfont iconleft-copy"></i> 下移一层
</div>
</div>
</template>
<script>
export default {
props: {
styleObj: Object,
visible: Boolean
},
data() {
return {};
},
watch: {
visible(value) {
if (value) {
document.body.addEventListener("click", this.closeMenu);
} else {
document.body.removeEventListener("click", this.closeMenu);
}
}
},
methods: {
closeMenu() {
this.$emit("update:visible", false);
},
deleteLayer() {
this.$confirm("是否删除所选图层?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$emit("deletelayer");
this.$message({
type: "success",
message: "删除成功!"
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
},
copyLayer() {
this.$emit("copylayer");
},
istopLayer() {
this.$emit("istopLayer");
},
setlowLayer() {
this.$emit("setlowLayer");
},
moveupLayer() {
this.$emit("moveupLayer");
},
movedownLayer() {
this.$emit("movedownLayer");
}
}
};
</script>
<style lang="scss" scoped>
.contentmenu {
width: 160px;
position: fixed;
z-index: 99999;
list-style: none;
-webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
padding: 0;
background: #27343e;
color: #bcc9d4;
.contentmenu__item {
z-index: 10000;
list-style: none;
padding: 8px 12px;
cursor: pointer;
position: relative;
font-size: 12px;
}
.iconfont {
font-size: 12px;
}
}
</style>

@ -0,0 +1,191 @@
<template>
<div>
<el-button
type="primary"
size="mini"
icon="el-icon-plus"
plain
@click="handleAddClick"
>新增</el-button
>
<el-table :data="formData" style="width: 100%">
<el-table-column prop="color" label="颜色" align="center">
<template slot-scope="scope">
<span class="color-box" :style="{ background: scope.row.color }" />
</template>
</el-table-column>
<el-table-column label="位置" align="center">
<template slot-scope="scope">
<span
class="editor"
@click="handleEditorClick(scope.$index, scope.row)"
>
<i class="el-icon-edit" /> 编辑
</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<span
class="editor"
@click="handleDeleteClick(scope.$index, scope.row)"
>
<i class="el-icon-delete" /> 删除
</span>
</template>
</el-table-column>
</el-table>
<el-dialog
title="新增"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose"
>
<el-form>
<el-form-item label="颜色">
<el-input
v-model="colorValue"
style="width: 200px"
placeholder="请输入颜色"
size="mini"
>
<template slot="append">
<el-color-picker
v-model="colorValue"
:predefine="predefineColors"
size="mini"
/>
</template>
</el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="mini" @click="dialogVisible = false"> </el-button>
<el-button size="mini" type="primary" @click="handleSaveClick"
> </el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "CustomColorComponents",
model: {
prop: "formData",
event: "input"
},
props: {
formData: Array
},
data() {
return {
predefineColors: [
"#ff4500",
"#ff8c00",
"#ffd700",
"#90ee90",
"#00ced1",
"#1e90ff",
"#c71585"
],
colorValue: "",
dialogVisible: false,
flag: true, // true false
indexEditor: -1 //
};
},
mounted() {},
methods: {
//
handleClose() {
this.dialogVisible = false;
this.colorValue = "";
},
//
handleAddClick() {
this.colorValue = "";
this.flag = true;
this.dialogVisible = true;
},
//
handleSaveClick() {
if (this.flag) {
//
const obj = {
color: this.colorValue
};
this.formData.push(obj);
this.dialogVisible = false;
} else {
//
this.formData[this.indexEditor].color = this.colorValue;
this.dialogVisible = false;
}
this.$emit("input", this.formData);
this.$emit("change", this.formData);
},
//
handleEditorClick(index, row) {
this.flag = false;
this.colorValue = row.color;
this.dialogVisible = true;
this.indexEditor = index;
},
//
handleDeleteClick(index) {
this.formData.splice(index, 1);
this.$emit("input", this.formData);
this.$emit("change", this.formData);
}
}
};
</script>
<style lang="scss" scoped>
.color-box {
.title {
display: flex;
flex-direction: row;
}
}
/deep/.el-table,
/deep/.el-table__expanded-cell,
/deep/.el-table th,
/deep/.el-table tr {
background-color: transparent !important;
color: #859094 !important;
}
/deep/.el-table td,
/deep/.el-table th.is-leaf {
border-bottom: none;
line-height: 26px;
}
/deep/.el-table tbody tr:hover > td {
background-color: #263445 !important;
}
/deep/.el-table::before {
height: 0;
}
/deep/.el-color-picker--mini,
/deep/.el-color-picker--mini .el-color-picker__trigger {
width: 23px;
height: 23px;
}
/deep/.el-dialog {
background: #1b1e25;
.el-dialog__title {
color: #fff;
}
}
.color-box {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 5px;
}
.editor {
color: #409eff;
cursor: pointer;
}
</style>

@ -0,0 +1,101 @@
<template>
<div>
<el-input
clearable
v-model.trim="uploadImgUrl"
size="mini"
@change="changeInput"
>
<template slot="append">
<i class="iconfont iconfolder-o"></i>
<input type="file" class="file" ref="files" @change="getImages" />
</template>
</el-input>
</div>
</template>
<script>
import axios from "axios";
import { getToken } from "@/utils/auth";
export default {
model: {
prop: "value",
event: "input"
},
props: {
value: {
type: "",
default: ""
}
},
data() {
return {
requestUrl: process.env.BASE_API + "/file/upload",
headers: {
Authorization: getToken()
},
fileList: [],
uploadImgUrl: ""
};
},
created() {
this.uploadImgUrl = this.value;
},
methods: {
getImages(el) {
let file = el.target.files[0];
let type = file.type.split("/")[0];
if (type === "image") {
this.upload(file);
} else {
this.$message.warn("只能上传图片格式");
}
},
upload(imgUrl) {
let that = this;
console.log(that.headers);
let formdata = new FormData();
formdata.append("file", imgUrl);
axios
.post(this.requestUrl, formdata, {
headers: that.headers
})
.then(response => {
let res = response.data;
if (res.code == "200") {
that.uploadImgUrl = res.data.urlPath;
that.$emit("input", that.uploadImgUrl);
that.$emit("change", that.uploadImgUrl);
}
});
},
changeInput(e) {
if (e) {
this.uploadImgUrl = e;
} else {
this.$refs.files.value = "";
this.uploadImgUrl = "";
}
this.$emit("input", this.uploadImgUrl);
this.$emit("change", this.uploadImgUrl);
}
}
};
</script>
<style lang="scss" scoped>
.file {
position: absolute;
width: 100%;
padding: 100%;
right: 0;
top: 0;
opacity: 0;
}
/deep/.el-input-group__append,
/deep/.el-input-group__prepend {
padding: 0 10px !important;
overflow: hidden;
}
.iconfont {
font-size: 12px;
}
</style>

@ -0,0 +1,178 @@
<template>
<div>
<el-button
type="primary"
size="small"
icon="el-icon-plus"
plain
@click="handleAddClick"
>新增</el-button
>
<el-table :data="formData" style="width: 100%">
<el-table-column prop="name" label="名称" width="60" />
<el-table-column prop="key" label="key值" width="70" />
<el-table-column prop="width" label="宽度" width="50" />
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<div class="button-group">
<el-button
@click="handleEditorClick(scope.$index, scope.row)"
type="text"
size="small"
>编辑</el-button
>
<el-button
type="text"
size="small"
@click="handleDeleteClick(scope.$index, scope.row)"
>删除</el-button
>
</div>
</template>
</el-table-column>
</el-table>
<el-dialog
title="新增"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose"
>
<el-form :model="rowFormData" label-width="50px">
<el-form-item label="名称:">
<el-input
v-model.trim="rowFormData['name']"
placeholder="请输入名称"
size="mini"
>
</el-input>
</el-form-item>
<el-form-item label="key值:">
<el-input
v-model.trim="rowFormData['key']"
placeholder="请输入key值"
size="mini"
>
</el-input>
</el-form-item>
<el-form-item label="宽度:">
<el-input
v-model.trim="rowFormData['width']"
placeholder="请输入宽度"
size="mini"
>
</el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="mini" @click="dialogVisible = false"> </el-button>
<el-button size="mini" type="primary" @click="handleSaveClick"
> </el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
model: {
prop: "formData",
event: "input"
},
props: {
formData: Array
},
data() {
return {
dialogVisible: false,
rowFormData: {
name: "",
key: "",
width: ""
},
flag: true, // true false
indexEditor: -1, //
tableData: []
};
},
methods: {
//
handleAddClick() {
this.rowFormData = {};
this.flag = true;
this.dialogVisible = true;
},
//
handleEditorClick(index, row) {
this.flag = false;
this.rowFormData = this.deepClone(row);
this.indexEditor = index;
this.dialogVisible = true;
},
//
handleClose() {
this.dialogVisible = false;
},
//
handleSaveClick() {
if (this.flag) {
//
this.formData.push(this.rowFormData);
this.dialogVisible = false;
} else {
//
this.formData[this.indexEditor] = this.rowFormData;
this.$set(this.formData, this.indexEditor, this.rowFormData);
this.dialogVisible = false;
}
this.$emit("input", this.formData);
this.$emit("change", this.formData);
},
//
handleDeleteClick(index) {
this.formData.splice(index, 1);
this.$emit("input", this.formData);
this.$emit("change", this.formData);
}
}
};
</script>
<style lang="scss" scoped>
/deep/::-webkit-scrollbar-track-piece {
background-color: transparent;
}
/deep/ .el-table__body-wrapper::-webkit-scrollbar {
width: 0; //
height: 8px; //
}
//
/deep/ .el-table__body-wrapper::-webkit-scrollbar-thumb {
border-radius: 5px;
background-color: rgba(144, 146, 152, 0.3);
}
/deep/.el-table,
/deep/.el-table__expanded-cell,
/deep/.el-table th,
/deep/.el-table tr {
background-color: transparent !important;
color: #859094 !important;
font-size: 12px !important;
}
/deep/.el-table td,
/deep/.el-table th.is-leaf {
border-bottom: none;
line-height: 26px;
}
/deep/.el-table tbody tr:hover {
background-color: #263445 !important;
}
/deep/.el-table tbody tr:hover > td {
background-color: #263445 !important;
}
/deep/.el-table::before {
height: 0;
}
.button-group .el-button {
padding: 0;
}
</style>

@ -0,0 +1,161 @@
<template>
<div>
<el-form label-width="100px" label-position="left">
<el-form-item label="数据集">
<el-select
size="mini"
v-model="dataSetValue"
filterable
placeholder="请选择"
@change="selectDataSet"
>
<el-option
v-for="item in dataSet"
:key="item.code"
:label="item.setName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-for="(item, index) in userNameList"
:key="index"
:label="item.paramName"
>
<el-input v-model.trim="item.sampleItem" size="mini" />
</el-form-item>
<el-form-item v-for="item in setParamList" :key="item" :label="item">
<Dictionary
v-model="params[item]"
:dict-key="getDictKey()"
@input="selectParams($event, item)"
/>
</el-form-item>
<el-button
style="width: 100%"
type="primary"
plain
size="mini"
@click="saveDataBtn"
>刷新</el-button
>
</el-form>
</div>
</template>
<script>
import { queryAllDataSet, detailBysetId } from "@/api/bigscreen";
import Dictionary from "@/components/Dictionary/index";
export default {
name: "DynamicComponents",
components: {
Dictionary
},
model: {
prop: "formData",
event: "input"
},
props: {
chartType: String,
dictKey: String,
formData: Object
},
data() {
return {
dataSetValue: "",
dataSet: [], //
userNameList: [], //
setParamList: [], //
params: {},
chartProperties: {}
};
},
watch: {
formData: {
handler(val) {
this.echoDataSet(val);
},
deep: true
}
},
computed: {
setCode() {
let code = "";
this.dataSet.forEach(el => {
if (el.id == this.dataSetValue) {
code = el.setCode;
}
});
return code;
}
},
mounted() {
this.loadDataSet();
this.echoDataSet(this.formData);
},
methods: {
async loadDataSet() {
const { code, data } = await queryAllDataSet();
this.dataSet = data;
if (code != "200") return;
},
async selectDataSet() {
const { code, data } = await detailBysetId(this.dataSetValue);
this.userNameList = data.dataSetParamDtoList;
this.setParamList = data.setParamList;
if (code != "200") return;
},
async saveDataBtn() {
const contextData = {};
for (let i = 0; i < this.userNameList.length; i++) {
contextData[this.userNameList[i].paramName] = this.userNameList[
i
].sampleItem;
}
const params = {
chartType: this.chartType,
setCode: this.setCode,
chartProperties: this.chartProperties,
contextData
};
this.$emit("input", params);
this.$emit("change", params);
},
selectParams(val, key) {
this.chartProperties[key] = val;
},
getDictKey() {
return this.dictKey == null ? "CHART_PROPERTIES" : this.dictKey;
},
//
async echoDataSet(val) {
if (!val) return;
const setCode = val.setCode;
await this.loadDataSet();
this.dataSetValue = this.dataSet.filter(
el => setCode == el.setCode
)[0].id;
await this.selectDataSet();
this.echoDynamicData(val);
},
echoDynamicData(val) {
const chartProperties = this.deepClone(val.chartProperties);
this.chartProperties = chartProperties;
if (this.userNameList.length > 0) {
}
if (this.setParamList.length > 0) {
for (let i = 0; i < this.setParamList.length; i++) {
const item = this.setParamList[i];
if (chartProperties.hasOwnProperty(item)) {
this.params[item] = chartProperties[item];
}
}
}
}
}
};
</script>
<style lang="sass" scoped></style>

@ -0,0 +1,442 @@
<template>
<div class="collapse-input-style">
<el-form label-width="100px" label-position="left">
<template v-for="(item, index) in options">
<div v-if="isShowForm(item, '[object Object]')" :key="index">
<el-form-item
v-if="
inputShow[item.name] &&
item.type != 'dycustComponents' &&
item.type != 'dynamic-add-table'
"
:label="item.label"
:prop="item.name"
:required="item.required"
>
<el-input-number
v-if="item.type == 'el-input-number'"
size="mini"
style="width:100%"
v-model.trim="formData[item.name]"
controls-position="right"
@change="changed($event, item.name)"
/>
<el-input
v-if="item.type == 'el-input-text'"
v-model.trim="formData[item.name]"
type="text"
size="mini"
placeholder="请输入内容"
clearable
@change="changed($event, item.name)"
/>
<el-input
v-if="item.type == 'el-input-textarea'"
v-model.trim="formData[item.name]"
type="textarea"
size="mini"
rows="2"
placeholder="请输入内容"
@change="changed($event, item.name)"
/>
<el-switch
v-if="item.type == 'el-switch'"
v-model="formData[item.name]"
size="mini"
placeholder="请输入内容"
@change="changed($event, item.name)"
/>
<ColorPicker
v-if="item.type == 'vue-color'"
v-model="formData[item.name]"
@change="val => changed(val, item.name)"
/>
<customUpload
v-if="item.type == 'custom-upload'"
v-model="formData[item.name]"
@change="changed($event, item.name)"
/>
<el-radio-group
v-if="item.type == 'el-radio-group'"
v-model="formData[item.name]"
@change="val => changed(val, item.name)"
>
<el-radio
v-for="itemChild in item.selectOptions"
:key="itemChild.code"
:label="itemChild.code"
>{{ itemChild.name }}</el-radio
>
</el-radio-group>
<el-select
v-if="item.type == 'el-select'"
size="mini"
v-model="formData[item.name]"
clearable
placeholder="请选择"
@change="val => changed(val, item.name)"
>
<el-option
v-for="itemChild in item.selectOptions"
:key="itemChild.code"
:label="itemChild.name"
:value="itemChild.code"
/>
</el-select>
<el-slider
v-if="item.type == 'el-slider'"
v-model="formData[item.name]"
@change="val => changed(val, item.name)"
/>
<el-button
v-if="item.type == 'el-button'"
type="primary"
size="mini"
plain
@click="addStaticData"
>编辑</el-button
>
<!-- 弹窗 -->
<el-dialog
title="代码编辑"
:visible.sync="dialogVisibleStaticData"
width="50%"
:before-close="handleClose"
>
<vue-json-editor
v-model="formData[item.name]"
:show-btns="false"
:mode="'code'"
lang="zh"
class="my-editor"
/>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisibleStaticData = false"
> </el-button
>
<el-button type="primary" @click="saveData"> </el-button>
</span>
</el-dialog>
</el-form-item>
<dynamicComponents
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
v-if="item.type == 'dynamic-add-table' && inputShow[item.name]"
v-model="formData[item.name]"
:chart-type="item.chartType"
@change="changed($event, item.name)"
/>
</div>
<div v-else-if="isShowForm(item, '[object Array]')" :key="'a-' + index">
<el-collapse accordion>
<el-collapse-item
v-for="(itemChild, indexChild) in item"
:key="indexChild"
:title="itemChild.name"
:name="indexChild"
>
<template v-for="(itemChildList, idx) in itemChild.list">
<el-form-item
:key="idx"
:label="itemChildList.label"
:prop="itemChildList.name"
:required="itemChildList.required"
>
<el-input-number
v-if="itemChildList.type == 'el-input-number'"
size="mini"
style="width:100%"
v-model="formData[itemChildList.name]"
controls-position="right"
:placeholder="itemChildList.placeholder"
@change="changed($event, itemChildList.name)"
/>
<el-input
v-if="itemChildList.type == 'el-input-text'"
v-model.trim="formData[itemChildList.name]"
type="text"
size="mini"
placeholder="请输入内容"
clearable
@change="changed($event, itemChildList.name)"
/>
<el-input
v-if="itemChildList.type == 'el-input-textarea'"
v-model.trim="formData[itemChildList.name]"
size="mini"
type="textarea"
rows="2"
placeholder="请输入内容"
@change="changed($event, itemChildList.name)"
/>
<el-switch
v-if="itemChildList.type == 'el-switch'"
v-model="formData[itemChildList.name]"
placeholder="请输入内容"
size="mini"
@change="changed($event, itemChildList.name)"
/>
<ColorPicker
v-if="itemChildList.type == 'vue-color'"
v-model="formData[itemChildList.name]"
@change="val => changed(val, itemChildList.name)"
/>
<el-upload
v-if="itemChildList.type == 'el-upload-picture'"
size="mini"
action="https://jsonplaceholder.typicode.com/posts/"
list-type="picture-card"
/>
<el-radio-group
v-if="itemChildList.type == 'el-radio-group'"
v-model="formData[itemChildList.name]"
@change="val => changed(val, itemChildList.name)"
>
<el-radio
v-for="it in itemChildList.selectOptions"
:key="it.code"
:label="it.code"
>{{ it.name }}</el-radio
>
</el-radio-group>
<el-select
v-if="itemChildList.type == 'el-select'"
size="mini"
v-model="formData[itemChildList.name]"
clearable
placeholder="请选择"
@change="val => changed(val, itemChildList.name)"
>
<el-option
v-for="it in itemChildList.selectOptions"
:key="it.code"
:label="it.name"
:value="it.code"
/>
</el-select>
<el-slider
v-if="itemChildList.type == 'el-slider'"
v-model="formData[itemChildList.name]"
@change="val => changed(val, itemChildList.name)"
/>
</el-form-item>
<customColorComponents
v-if="itemChildList.type == 'customColor'"
:key="'b-' + idx"
v-model="formData[itemChildList.name]"
@change="changed($event, itemChildList.name)"
/>
</template>
</el-collapse-item>
</el-collapse>
</div>
</template>
</el-form>
</div>
</template>
<script>
import ColorPicker from "./colorPicker.vue";
import vueJsonEditor from "vue-json-editor";
import "codemirror/lib/codemirror.css"; //
import "codemirror/theme/cobalt.css"; // options
// language
import "codemirror/mode/vue/vue.js";
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/sql/sql.js";
import "codemirror/mode/shell/shell.js";
import dynamicComponents from "./dynamicComponents.vue";
import customColorComponents from "./customColorComponents";
import dynamicAddTable from "./dynamicAddTable.vue";
import customUpload from "./customUpload.vue";
export default {
name: "DynamicForm",
components: {
ColorPicker,
vueJsonEditor,
dynamicComponents,
customColorComponents,
dynamicAddTable,
customUpload
},
model: {
prop: "value",
event: "input"
},
props: {
options: Array,
value: {
type: [Object],
default: () => {}
}
},
data() {
return {
formData: {},
inputShow: {}, //
dialogVisibleStaticData: false,
validationRules: "",
optionsJavascript: {
mode: "text/javascript",
tabSize: 2, //
lineNumbers: true, //
line: true,
styleActiveLine: true, //
hintOptions: {
completeSingle: true //
}
}
};
},
watch: {
value(newValue, oldValue) {
this.formData = newValue || {};
},
options(val) {
this.setDefaultValue();
this.isShowData();
}
},
created() {
this.isShowData();
this.setDefaultValue();
},
mounted() {},
methods: {
onJsonChange(val) {
console.log(val);
},
onJsonSave(val) {
console.log(val);
},
//
changed(val, key) {
if (val.extend) {
this.$set(this.formData, key, val.value);
} else {
this.$set(this.formData, key, val);
}
this.$emit("onChanged", this.formData);
// key
for (let i = 0; i < this.options.length; i++) {
let item = this.options[i];
if (item.relactiveDom == key) {
this.inputShow[item.name] = val == item.relactiveDomValue;
this.inputShow = Object.assign({}, this.inputShow);
}
}
},
saveData() {
this.$emit("onChanged", this.formData);
this.dialogVisibleStaticData = false;
},
//
addStaticData() {
this.dialogVisibleStaticData = true;
},
handleClose() {
this.dialogVisibleStaticData = false;
},
//
isShowData() {
let currentData = {};
const data = [];
for (let i = 0; i < this.options.length; i++) {
// inputShow
this.inputShow[this.options[i].name] = true;
if (this.options[i].selectValue) {
currentData = this.options[i];
} else {
data.push(this.options[i]);
}
}
data.forEach(el => {
if (el.relactiveDomValue != currentData.value) {
this.inputShow[el.name] = false;
}
});
},
//
setDefaultValue() {
if (this.options && this.options.length > 0) {
for (let i = 0; i < this.options.length; i++) {
const obj = this.options[i];
if (Object.prototype.toString.call(obj) == "[object Object]") {
this.formData[this.options[i].name] = this.deepClone(
this.options[i].value
);
} else if (Object.prototype.toString.call(obj) == "[object Array]") {
for (let j = 0; j < obj.length; j++) {
const list = obj[j].list;
list.forEach(el => {
this.formData[el.name] = el.value;
});
}
}
}
this.formData = Object.assign({}, this.formData);
}
},
//
isShowForm(val, type) {
return Object.prototype.toString.call(val) == type;
}
}
};
</script>
<style scoped lang="scss">
/deep/ .el-form-item {
margin-bottom: 5px;
}
/deep/ .el-form-item__label {
font-size: 12px;
color: #fff;
}
.code-mirror {
width: 100%;
height: 100% !important;
}
.el-collapse {
border-top: none;
border-bottom: none;
}
/deep/.el-collapse-item__header {
height: 40px;
line-height: 40px;
background: transparent;
color: #bcc9d4;
font-weight: 300;
font-size: 12px;
border-color: #282e3a;
}
/deep/.el-collapse-item__wrap {
background: transparent;
border: none;
}
/deep/.el-collapse-item__content {
padding-bottom: 0;
}
</style>

@ -0,0 +1,90 @@
<!--
* @Descripttion:
* @version:
* @Author: qianlishi
* @Date: 2022-04-28 12:20:28
* @LastEditors: qianlishi
* @LastEditTime: 2022-04-28 12:31:14
-->
<template>
<div>
<component :is="type" :value="value" :ispreview="true"/>
</div>
</template>
<script>
import widgetHref from "../widget/texts/widgetHref.vue";
import WidgetIframe from "../widget/texts/widgetIframe.vue";
import widgetImage from "../widget/texts/widgetImage.vue";
import WidgetMarquee from "../widget/texts/widgetMarquee.vue";
import widgetSlider from "../widget/texts/widgetSlider.vue";
import widgetTable from "../widget/texts/widgetTable.vue";
import widgetText from "../widget/texts/widgetText.vue";
import widgetTime from "../widget/texts/widgetTime.vue";
import widgetVideo from "../widget/texts/widgetVideo.vue";
import widgetBarchart from "../widget/barCharts/widgetBarchart.vue";
import widgetGradientColorBarchart from "../widget/barCharts/widgetGradientColorBarchart.vue";
import widgetLinechart from "../widget/lineCharts/widgetLinechart.vue";
import widgetBarlinechart from "../widget/barlineCharts/widgetBarlinechart";
import WidgetPiechart from "../widget/pieCharts/widgetPiechart.vue";
import WidgetFunnel from "../widget/funnelCharts/widgetFunnel.vue";
import WidgetGauge from "../widget/percentCharts/widgetGauge.vue";
import WidgetPieNightingaleRoseArea from "../widget/pieCharts/widgetPieNightingaleRose";
import widgetMap from "../widget/mapCharts/widgetMap.vue";
import widgetPiePercentageChart from "../widget/percentCharts/widgetPiePercentageChart";
import widgetAirBubbleMap from "../widget/mapCharts/widgetAirBubbleMap";
import widgetBarStackChart from "../widget/barCharts/widgetBarStackChart";
import widgetLineStackChart from "../widget/lineCharts/widgetLineStackChart";
import widgetBarCompareChart from "../widget/barCharts/widgetBarCompareChart";
import widgetLineCompareChart from "../widget/lineCharts/widgetLineCompareChart";
import widgetDecoratePieChart from "../widget/decorateCharts/widgetDecoratePieChart";
import widgetMoreBarLineChart from "../widget/barlineCharts/widgetMoreBarLineChart";
import widgetWordCloud from "../widget/wordcloudCharts/widgetWordCloud";
import widgetHeatmap from "../widget/heatmap/widgetHeatmap";
export default {
name: "WidgetTemp",
components: {
widgetHref,
WidgetIframe,
widgetImage,
WidgetMarquee,
widgetSlider,
widgetTable,
widgetText,
widgetTime,
widgetVideo,
widgetBarchart,
widgetGradientColorBarchart,
widgetLinechart,
widgetBarlinechart,
WidgetPiechart,
WidgetFunnel,
WidgetGauge,
WidgetPieNightingaleRoseArea,
widgetMap,
widgetPiePercentageChart,
widgetAirBubbleMap,
widgetBarStackChart,
widgetLineStackChart,
widgetBarCompareChart,
widgetLineCompareChart,
widgetDecoratePieChart,
widgetMoreBarLineChart,
widgetWordCloud,
widgetHeatmap
},
model: {
prop: "value",
event: "input"
},
props: {
type: String,
value: {
type: [Object],
default: () => {
}
}
}
};
</script>

@ -0,0 +1,659 @@
/*
* @Descripttion: 柱状对比图 json
* @version:
* @Author: qianlishi
* @Date: 2021-08-29 07:39:35
* @LastEditors: qianlishi
* @LastEditTime: 2021-09-28 14:09:58
*/
export const widgetBarCompare = {
code: 'widgetBarCompareChart',
type: 'barChart',
tabName: '柱状图',
label: '柱状对比图',
icon: 'iconduibitupu',
options: {
// 配置
setup: [
{
type: 'el-input-text',
label: '图层名称',
name: 'layerName',
required: false,
placeholder: '',
value: '柱状对比图',
},
{
type: 'vue-color',
label: '背景颜色',
name: 'background',
required: false,
placeholder: '',
value: ''
},
[
{
name: '柱体设置',
list: [
{
type: 'el-slider',
label: '最大宽度',
name: 'maxWidth',
required: false,
placeholder: '',
value: 15,
},
{
type: 'el-slider',
label: '圆角',
name: 'radius',
require: false,
placeholder: '',
value: 5,
},
],
},
{
name: '标题设置',
list: [
{
type: 'el-switch',
label: '标题',
name: 'isNoTitle',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: '标题',
name: 'titleText',
required: false,
placeholder: '',
value: '',
},
{
type: 'vue-color',
label: '字体颜色',
name: 'textColor',
required: false,
placeholder: '',
value: '#FFD700'
},
{
type: 'el-select',
label: '字体粗细',
name: 'textFontWeight',
required: false,
placeholder: '',
selectOptions: [
{code: 'normal', name: '正常'},
{code: 'bold', name: '粗体'},
{code: 'bolder', name: '特粗体'},
{code: 'lighter', name: '细体'}
],
value: 'normal'
},
{
type: 'el-input-number',
label: '字体大小',
name: 'textFontSize',
required: false,
placeholder: '',
value: 20
},
{
type: 'el-select',
label: '字体位置',
name: 'textAlign',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
],
},
{
name: '图例操作',
list: [
{
type: 'el-switch',
label: '图例显示',
name: 'isShowLegend',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-text',
label: '图例名称',
name: 'legendName',
required: false,
placeholder: '多值以' | '隔开',
value: ''
},
{
type: 'vue-color',
label: '字体颜色',
name: 'lengedColor',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '字体字号',
name: 'lengedFontSize',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-input-number',
label: '图例宽度',
name: 'lengedWidth',
required: false,
placeholder: '',
value: 12,
},
{
type: 'el-select',
label: '横向位置',
name: 'lateralPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-select',
label: '纵向位置',
name: 'longitudinalPosition',
required: false,
placeholder: '',
selectOptions: [
{code: 'top', name: '顶部'},
{code: 'bottom', name: '底部'},
],
value: 'top'
},
{
type: 'el-select',
label: '布局前置',
name: 'layoutFront',
required: false,
placeholder: '',
selectOptions: [
{code: 'vertical', name: '竖排'},
{code: 'horizontal', name: '横排'},
],
value: 'horizontal'
},
],
},
{
name: '左X轴设置',
list: [
{
type: 'el-switch',
label: '显示',
name: 'hideXLeft',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-number',
label: '数值间隔',
name: 'splitNumberLeft',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '数值颜色',
name: 'XcolorLeft',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '数值字号',
name: 'fontSizeXLeft',
required: false,
placeholder: '',
value: 14,
},
{
type: 'el-switch',
label: '刻度线',
name: 'tickLineLeft',
require: false,
placeholder: '',
value: false,
},
{
type: 'el-switch',
label: 'X轴线',
name: 'xLineLeft',
require: false,
placeholder: '',
value: false,
},
{
type: 'vue-color',
label: '轴颜色',
name: 'lineColorXLeft',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-switch',
label: '竖分割线',
name: 'SplitLineLeft',
require: false,
placeholder: '',
value: false,
},
{
type: 'vue-color',
label: '分割线颜色',
name: 'SplitLineColorLeft',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '分割线宽度',
name: 'SplitLinefontSizeLeft',
required: false,
placeholder: '',
value: 1,
},
{
type: 'el-switch',
label: '边框线',
name: 'frameLineLeft',
require: false,
placeholder: '',
value: false,
},
],
},
{
name: '右X轴设置',
list: [
{
type: 'el-switch',
label: '显示',
name: 'hideXRight',
required: false,
placeholder: '',
value: true,
},
{
type: 'el-input-number',
label: '数值间隔',
name: 'splitNumberRight',
required: false,
placeholder: '',
value: ''
},
{
type: 'vue-color',
label: '数值颜色',
name: 'XcolorRight',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '数值字号',
name: 'fontSizeXRight',
required: false,
placeholder: '',
value: 14,
},
{
type: 'el-switch',
label: '刻度线',
name: 'tickLineRight',
require: false,
placeholder: '',
value: false,
},
{
type: 'el-switch',
label: 'X轴线',
name: 'xLineRight',
require: false,
placeholder: '',
value: false,
},
{
type: 'vue-color',
label: '轴颜色',
name: 'lineColorXRight',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-switch',
label: '竖分割线',
name: 'SplitLineRight',
require: false,
placeholder: '',
value: false,
},
{
type: 'vue-color',
label: '分割线颜色',
name: 'SplitLineColorRight',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '分割线宽度',
name: 'SplitLinefontSizeRight',
required: false,
placeholder: '',
value: 1,
},
{
type: 'el-switch',
label: '边框线',
name: 'frameLineRight',
require: false,
placeholder: '',
value: false,
},
],
},
{
name: 'Y轴设置',
list: [
{
type: 'el-switch',
label: '显示',
name: 'hideY',
required: false,
placeholder: '',
value: true,
},
{
type: 'vue-color',
label: '数值颜色',
name: 'colorY',
required: false,
placeholder: '',
value: '#fff',
},
{
type: 'el-input-number',
label: '数值字号',
name: 'fontSizeY',
required: false,
placeholder: '',
value: 14,
},
{
type: 'el-select',
label: '数值对齐',
name: 'textAlign',
required: false,
placeholder: '',
selectOptions: [
{code: 'center', name: '居中'},
{code: 'left', name: '左对齐'},
{code: 'right', name: '右对齐'},
],
value: 'center'
},
{
type: 'el-switch',
label: '刻度线',
name: 'tickLineY',
require: false,
placeholder: '',
value: false,
},
{
type: 'el-switch',
label: 'Y轴线',
name: 'lineY',
require: false,
placeholder: '',
value: false,
},
{
type: 'vue-color',
label: '轴颜色',
name: 'lineColorY',
required: false,
placeholder: '',
value: '#fff',
},
],
},
{
name: '数值设定',
list: [
{
type: 'el-switch',
label: '显示',
name: 'isShow',
required: false,
placeholder: '',
value: true
},
{
type: 'el-input-number',
label: '字体大小',
name: 'fontSize',
required: false,
placeholder: '',
value: 14
},
{
type: 'vue-color',
label: '字体颜色',
name: 'subTextColor',
required: false,
placeholder: '',
value: '#fff'
},
{
type: 'el-select',
label: '字体粗细',
name: 'fontWeight',
required: false,
placeholder: '',
selectOptions: [
{code: 'normal', name: '正常'},
{code: 'bold', name: '粗体'},
{code: 'bolder', name: '特粗体'},
{code: 'lighter', name: '细体'}
],
value: 'normal'
},
],
},
{
name: '提示语设置',
list: [
{
type: 'el-input-number',
label: '字体大小',
name: 'tipsFontSize',
required: false,
placeholder: '',
value: 16
},
{
type: 'vue-color',
label: '字体颜色',
name: 'lineColor',
required: false,
placeholder: '',
},
],
},
{
name: '坐标轴边距设置',
list: [
{
type: 'el-slider',
label: '左右边距(像素)',
name: 'marginLeftRight',
required: false,
placeholder: '',
value: 10,
},
{
type: 'el-slider',
label: '顶边距(像素)',
name: 'marginTop',
required: false,
placeholder: '',
value: 40,
},
{
type: 'el-slider',
label: '底边距(像素)',
name: 'marginBottom',
required: false,
placeholder: '',
value: 10,
},
],
},
{
name: '自定义配色',
list: [
{
type: 'customColor',
label: '',
name: 'customColor',
required: false,
value: [{color: '#36c5e7'}, {color: '#e68b55'}],
},
],
},
],
],
// 数据
data: [
{
type: 'el-radio-group',
label: '数据类型',
name: 'dataType',
require: false,
placeholder: '',
selectValue: true,
selectOptions: [
{
code: 'staticData',
name: '静态数据',
},
{
code: 'dynamicData',
name: '动态数据',
},
],
value: 'staticData',
},
{
type: 'el-input-number',
label: '刷新时间(毫秒)',
name: 'refreshTime',
relactiveDom: 'dataType',
relactiveDomValue: 'dynamicData',
value: 5000
},
{
type: 'el-button',
label: '静态数据',
name: 'staticData',
required: false,
placeholder: '',
relactiveDom: 'dataType',
relactiveDomValue: 'staticData',
value: [
{"axis": "07-25", "name": "success", "data": "2"},
{"axis": "07-25", "name": "fail", "data": "10"},
{"axis": "07-26", "name": "success", "data": "5"},
{"axis": "07-26", "name": "fail", "data": "20"},
{"axis": "07-27", "name": "success", "data": "15"},
{"axis": "07-27", "name": "fail", "data": "30"},
{"axis": "07-28", "name": "success", "data": "10"},
{"axis": "07-28", "name": "fail", "data": "12"},
{"axis": "07-29", "name": "success", "data": "9"},
{"axis": "07-29", "name": "fail", "data": "16"},
],
},
{
type: 'dycustComponents',
label: '',
name: 'dynamicData',
required: false,
placeholder: '',
relactiveDom: 'dataType',
relactiveDomValue: 'dynamicData',
chartType: 'widget-stackchart',
dictKey: 'STACK_PROPERTIES',
value: '',
},
],
// 坐标
position: [
{
type: 'el-input-number',
label: '左边距',
name: 'left',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '上边距',
name: 'top',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '宽度',
name: 'width',
required: false,
placeholder: '该容器在1920px大屏中的宽度',
value: 500,
},
{
type: 'el-input-number',
label: '高度',
name: 'height',
required: false,
placeholder: '该容器在1080px大屏中的高度',
value: 250,
},
],
}
}

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

Loading…
Cancel
Save