feat: initial iShare project code

This commit is contained in:
purovps
2026-02-16 23:20:59 +08:00
parent 8c83a6fd46
commit 6f270a972e
1910 changed files with 218015 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
FROM pig4cloud/java:8-jre
MAINTAINER wangiegie@gmail.com
ENV TZ=Asia/Shanghai
ENV JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom"
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN mkdir -p /pigx-jimu-platform
WORKDIR /pigx-jimu-platform
EXPOSE 5008
ADD ./target/pigx-jimu-platform.jar ./
CMD sleep 120;java $JAVA_OPTS -jar pigx-jimu-platform.jar

View File

@@ -0,0 +1,101 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-visual</artifactId>
<version>5.2.0</version>
</parent>
<artifactId>pigx-jimu-platform</artifactId>
<packaging>jar</packaging>
<description>积木报表系统</description>
<dependencies>
<!--注册中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--配置中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--sentinel-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-sentinel</artifactId>
</dependency>
<!--feign 调用-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-feign</artifactId>
</dependency>
<!--API 依赖-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>as-upms-api</artifactId>
</dependency>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot-starter</artifactId>
<version>${jimu.version}</version>
</dependency>
<!-- druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!--MYSQL 数据驱动-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- ojdbc8 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<!--PG-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.bi;
import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author lengleng
* @date 2022-04-06
* <p>
*/
@EnablePigxFeignClients
@EnableDiscoveryClient
@SpringBootApplication(scanBasePackages = { "org.jeecg.modules.jmreport", "com.pig4cloud.pigx.bi" },
exclude = MongoAutoConfiguration.class)
public class PigxJimuApplication {
public static void main(String[] args) {
SpringApplication.run(PigxJimuApplication.class, args);
}
}

View File

@@ -0,0 +1,63 @@
package com.pig4cloud.pigx.bi.config;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pigx.admin.api.feign.RemoteTokenService;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.core.util.RetOps;
import lombok.RequiredArgsConstructor;
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author lengleng
* @date 2022/4/6
*
* 积木安全控制
*/
@Component
@RequiredArgsConstructor
public class JimuReportTokenService implements JmReportTokenServiceI {
private final RemoteTokenService tokenService;
@Override
public String getUsername(String token) {
// 分割出 PIGX 的租户信息
List<String> splitList = StrUtil.split(token, CharUtil.UNDERLINE);
// @formatter:off
return RetOps.of(tokenService.queryToken(splitList.get(1), splitList.get(0) ,SecurityConstants.FROM_IN))
.getDataIf(RetOps.CODE_SUCCESS)
.map(o -> (String)o.get("principalName"))
.orElse(null);
// @formatter:off
}
@Override
public Map<String, Object> getUserInfo(String token) {
String username = this.getUsername(token);
Map<String, Object> map = new HashMap<>(4);
map.put("principalName", username);
map.put("access_token", token);
// 将所有信息存放至map 解析sql会根据map的键值解析,可自定义其他值
return map;
}
@Override
public Boolean verifyToken(String token) {
// 分割出 PIGX 的租户信息
List<String> splitList = StrUtil.split(token, CharUtil.UNDERLINE);
R<Map<String, Object>> result = tokenService.queryToken(splitList.get(1), splitList.get(0) , SecurityConstants.FROM_IN);
if (CommonConstants.SUCCESS.equals(result.getCode())) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,19 @@
server:
port: 5008
spring:
application:
name: @artifactId@
cloud:
nacos:
username: @nacos.username@
password: @nacos.password@
discovery:
server-addr: ${NACOS_HOST:pigx-register}:${NACOS_PORT:8848}
service: @artifactId@
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
config:
import:
- optional:nacos:application-@profiles.active@.yml
- optional:nacos:${spring.application.name}-@profiles.active@.yml

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
~
~ Redistributions of source code must retain the above copyright notice,
~ this list of conditions and the following disclaimer.
~ Redistributions in binary form must reproduce the above copyright
~ notice, this list of conditions and the following disclaimer in the
~ documentation and/or other materials provided with the distribution.
~ Neither the name of the pig4cloud.com developer nor the names of its
~ contributors may be used to endorse or promote products derived from
~ this software without specific prior written permission.
~ Author: lengleng (wangiegie@gmail.com)
-->
<!--
小技巧: 在根pom里面设置统一存放路径统一管理方便维护
<properties>
<log-path>/Users/lengleng</log-path>
</properties>
1. 其他模块加日志输出直接copy本文件放在resources 目录即可
2. 注意修改 <property name="${log-path}/log.path" value=""/> 的value模块
-->
<configuration debug="false" scan="false">
<property name="log.path" value="logs/${project.artifactId}"/>
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- Console log output -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Log file debug output -->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
</encoder>
</appender>
<!-- Log file error output -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<!--nacos 心跳 INFO 屏蔽-->
<logger name="com.alibaba.nacos" level="OFF">
<appender-ref ref="error"/>
</logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="debug"/>
<appender-ref ref="error"/>
</root>
</configuration>

View File

@@ -0,0 +1,43 @@
<#assign CACHE_VERSION = "v=1693888295.10">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>没有权限</title>
<script>
let base = "${base}";
</script>
<style>
.no-authority{
width: 100%;
height: 100%;
text-align: center;
justify-content: center;
position: absolute;
top: 50%;
}
.no-authority span{
font-size: 20px;
}
.img-position{
width: 100%;
height: 100%;
text-align: center;
justify-content: center;
position: absolute;
top: 17%;
margin: 0 auto;
}
</style>
<body style="overflow: hidden">
<div id="app" style="overflow: hidden">
<div class="img-position">
<img src="${base}/jmreport/desreport_/chartsImg/authority/no-authority.png"/>
</div>
<div class="no-authority">
<span>您没有权限访问该页面</span>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,14 @@
<!-- vue -->
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/cdn/vue/vue.min.js"></script>
<!-- iview -->
<link rel="stylesheet" type="text/css" href="${base}${customPrePath}/jmreport/desreport_/cdn/iview/iview.css">
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/cdn/iview/iview.min.js"></script>
<!-- axios -->
<script src="${base}${customPrePath}/jmreport/desreport_/cdn/axios/axios.min.js"></script>
<script src="${base}${customPrePath}/jmreport/desreport_/cdn/axios/qs.min.js"></script>
<!-- core -->
<script src="${base}${customPrePath}/jmreport/desreport_/js/core/request.js?${CACHE_VERSION}"></script>
<script src="${base}${customPrePath}/jmreport/desreport_/js/core/api.js?${CACHE_VERSION}"></script>
<!-- biz -->
<script src="${base}${customPrePath}/jmreport/desreport_/js/biz/manager.js?${CACHE_VERSION}"></script>

View File

@@ -0,0 +1,17 @@
<script>
(function() {
//https://blog.csdn.net/aizou6838/article/details/101664336
function async_load(){
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = "https://hm.baidu.com/hm.js?b756a4a8e1c58d613e27d1459c6d6076";
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
}
if (window.attachEvent)
window.attachEvent('onload', async_load);
else
window.addEventListener('load', async_load, false);
})();
</script>

View File

@@ -0,0 +1,835 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>积木报表设计器</title>
<!-- Import via CDN -->
<link rel="stylesheet" href="${base}${customPrePath}/jmreport/desreport_/corelib/jmsheet.css">
<script src="${base}${customPrePath}/jmreport/desreport_/corelib/jmsheet.js"></script>
<script src="${base}${customPrePath}/jmreport/desreport_/corelib/locale/zh-cn.js"></script>
<style>
body {
overflow-x: hidden;
overflow-y: hidden;
}
</style>
<body onload="load()">
<div id="jm-sheet-wrapper"></div>
<script>
function load() {
const options = {
showToolbar: true, //头部操作按钮
showGrid: true, //excel表格
showContextmenu: true, //右键操作按钮
rpBar: {
show: true,
style: {
//设置二级菜单栏样式
"padding-left": "23px",
}
},
view: {
height: () => document.documentElement.clientHeight,
width: () => document.documentElement.clientWidth,
},
row: {
len: 50,
height: 25,
minRowResizerHeight:1 //拖拽行最小高度
},
col: {
len: 26,
width: 100,
minWidth: 60,
height: 0,
minColResizerHeight:1//拖拽列最小高度
},
style: {
bgcolor: '#ffffff',
align: 'left',
valign: 'middle',
textwrap: false,
strike: false,
underline: false,
color: '#0a0a0a',
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
},
},
};
//x.spreadsheet.locale('zh-cn');
var xs = x.spreadsheet('#jm-sheet-wrapper', options).loadData(
{
"name": "sheet1",
"freeze": "A1",
"styles": [
{
"bgcolor": "#f4f5f8",
"textwrap": true,
"color": "#900b09",
"border": {
"top": [
"thin",
"#0366d6"
],
"bottom": [
"thin",
"#0366d6"
],
"right": [
"thin",
"#0366d6"
],
"left": [
"thin",
"#0366d6"
]
}
},
{
"format": "rmb"
},
{
"textwrap": true
},
{
"bgcolor": "#c45a10"
},
{
"valign": "middle"
},
{
"valign": "top"
},
{
"valign": "middle",
"bgcolor": "#71ae47"
},
{
"bgcolor": "#71ae47"
},
{
"valign": "middle",
"bgcolor": "#a7d08c"
},
{
"bgcolor": "#a7d08c"
},
{
"valign": "middle",
"bgcolor": "#a7d08c",
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
}
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
}
},
{
"bgcolor": "#ffffff"
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
},
"align": "center"
},
{
"align": "center"
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
},
"align": "center",
"font": {
"bold": true
}
},
{
"align": "center",
"font": {
"bold": true
}
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
},
"align": "center",
"font": {
"bold": true,
"size": 26
}
},
{
"align": "center",
"font": {
"bold": true,
"size": 26
}
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
},
"align": "center",
"font": {
"bold": true,
"size": 22
}
},
{
"align": "center",
"font": {
"bold": true,
"size": 22
}
},
{
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
}
},
{
"textwrap": true,
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
}
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"align": "center",
"font": {
"bold": true,
"size": 22
}
},
{
"align": "right"
},
{
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
},
"bgcolor": "#5b9cd6"
},
{
"border": {
"bottom": [
"thin",
"#000"
],
"top": [
"thin",
"#000"
],
"left": [
"thin",
"#000"
],
"right": [
"thin",
"#000"
]
},
"bgcolor": "#ffc001"
},
{
"valign": "middle",
"bgcolor": "#ffffff",
"align": "center",
"font": {
"bold": true,
"size": 18
}
},
{
"font": {
"size": 18
}
},
{
"font": {
"size": 22
}
}
],
"merges": [
"JAAAAAABJ6:JAAAAAABJ8",
"C2:H2"
],
"rows": {
"len": 200,
"1": {
"cells": {
"2": {
"text": "年度各月份佣金收入",
"style": 27,
"merge": [
0,
5
]
},
"3": {
"style": 28
},
"4": {
"style": 28
},
"5": {
"style": 28
},
"6": {
"style": 28
},
"7": {
"style": 28
},
"8": {
"style": 12
},
"9": {
"style": 12
}
},
"height": 45
},
"3": {
"cells": {
"2": {
"text": "查询年度:",
"style": 24
},
"3": {
"text": "2019"
},
"5": {
"text": "查询机构:",
"style": 24
},
"6": {
"text": "总公司"
},
"7": {
"text": "单位:元",
"style": 24
}
}
},
"5": {
"cells": {
"2": {
"text": "月份",
"style": 26
},
"3": {
"text": "佣金/主营业收入",
"style": 26
},
"4": {
"text": "累计",
"style": 26
},
"5": {
"text": "历史最低水平",
"style": 26
},
"6": {
"text": "历史平均水平",
"style": 26
},
"7": {
"text": "历史最高水平",
"style": 26
}
}
},
"6": {
"cells": {
"2": {
"style": 21,
"text": "1"
},
"3": {
"style": 22,
"text": "\t483834.66"
},
"4": {
"style": 21,
"text": "483834.66"
},
"5": {
"style": 21,
"text": "\t57569.771"
},
"6": {
"style": 21,
"text": "\t216797.62"
},
"7": {
"style": 21,
"text": "\t483834.66"
}
}
},
"7": {
"cells": {
"2": {
"style": 21,
"text": "2"
},
"3": {
"style": 22,
"text": "11666578.65"
},
"4": {
"style": 21,
"text": "12150413.31"
},
"5": {
"style": 21,
"text": "\t22140.00"
},
"6": {
"style": 21,
"text": "4985361.57"
},
"7": {
"style": 21,
"text": "\t11666578.65"
}
}
},
"8": {
"cells": {
"2": {
"style": 21,
"text": "3"
},
"3": {
"style": 21,
"text": "27080982.08"
},
"4": {
"style": 21,
"text": "\t17428381.401"
},
"5": {
"style": 21,
"text": "\t73106.2911"
},
"6": {
"style": 21,
"text": "16192642.30\t"
},
"7": {
"style": 21,
"text": "27080982.08"
}
}
},
"9": {
"cells": {
"2": {
"style": 21,
"text": "4"
},
"3": {
"style": 21,
"text": "0.001"
},
"4": {
"style": 21,
"text": "39231395.3911"
},
"5": {
"style": 21,
"text": "73106.2911"
},
"6": {
"style": 21,
"text": "8513415.34"
},
"7": {
"style": 21,
"text": "\t17428381.40"
}
}
},
"10": {
"cells": {
"2": {
"style": 21,
"text": "5"
},
"3": {
"style": 21,
"text": "0.00"
},
"4": {
"style": 21,
"text": ""
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"11": {
"cells": {
"2": {
"style": 21,
"text": "6"
},
"3": {
"style": 21,
"text": "0.00"
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"12": {
"cells": {
"2": {
"style": 21,
"text": "7"
},
"3": {
"style": 21,
"text": "0.00"
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"13": {
"cells": {
"2": {
"style": 21,
"text": "8"
},
"3": {
"style": 21,
"text": "0.00"
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"14": {
"cells": {
"2": {
"style": 21,
"text": "9"
},
"3": {
"style": 21,
"text": "0.00"
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"15": {
"cells": {
"2": {
"style": 21
},
"3": {
"style": 21
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"16": {
"cells": {
"2": {
"style": 21
},
"3": {
"style": 21
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
"17": {
"cells": {
"2": {
"style": 21
},
"3": {
"style": 21
},
"4": {
"style": 21
},
"5": {
"style": 21
},
"6": {
"style": 21
},
"7": {
"style": 21
}
}
},
},
"cols": {
"2": {
"width": 75
},
"3": {
"width": 108
},
"5": {
"width": 109
},
"6": {
"width": 108
},
"7": {
"width": 117
},
"len": 25
},
"validations": [],
"autofilter": {
"ref": "E13",
"filters": [],
"sort": null
}
}
).change((cdata) => {
// console.log(cdata);
// console.log(xs.validate());
var str = JSON.stringify(cdata)
console.log(str);
});
}
</script>
</html>

View File

@@ -0,0 +1,800 @@
<#assign CACHE_VERSION = "v=1693888295.10">
<!DOCTYPE html>
<html>
<head>
<script>
let base = "${base}";
let baseFull = "${base}"+"${customPrePath}";
/**
* 获取url参数
*/
function getRequestUrl() {
var url = location.search;
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("&");
for(var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]]=decodeURI(strs[i].split("=")[1]);
}
}
return theRequest;
}
let token = getRequestUrl().token;
if (token == "" || token == null){
token = window.localStorage.getItem('JmReport-Access-Token');
}
window.localStorage.setItem('JmReport-Access-Token',token);
//update-begin---author:wangshuai ---date:20220708 for[JMREP-2661]多租户权限集成------------
let tenantId = getRequestUrl().tenantId;
if("" == tenantId || null == tenantId){
tenantId = window.localStorage.getItem('JmReport-Tenant-Id');
}
window.localStorage.setItem('JmReport-Tenant-Id',tenantId);
//update-end---author:wangshuai ---date:20220708 for[JMREP-2661]多租户权限集成------------
</script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>在线设计</title>
<#include "./common/resource.ftl">
<link rel="stylesheet" href="${base}${customPrePath}/jmreport/desreport_/corelib/cust.css?${CACHE_VERSION}">
<link rel="shortcut icon" href="${base}${customPrePath}/jmreport/desreport_/corelib/logo.png?${CACHE_VERSION}" type="image/x-ico">
</head>
<body style="background: #ffffff">
<style>
.ivu-page,
.ivu-page-prev,
.ivu-page-next,
.ivu-select-selection,
.ivu-select-dropdown,
.ivu-page.mini .ivu-page-options-elevator input
{
background-color: #ffffff;
color: #515a6e;
}
.page{
display: flex;
justify-content: center;
-webkit-box-pack: center;
}
.ivu-page-item{
background-color: #ffffff;
border: 1px solid rgba(131, 125, 125, 0.5);
}
.ivu-page-item-active{
background-color: white;
border: 1px solid #409eff;
}
.ivu-page-item a{
margin: 0 6px;
text-decoration: none;
color: #515a6e;
}
.ivu-page-next a, .ivu-page-prev a {
font-size: 14px;
color: #515a6e;
}
.ivu-spin-fix{
background-color: rgba(131, 125, 125, 0.5);
}
</style>
<style>
.title{
font-size: 20px;
color: #000000;
text-align: center;
line-height: 60px;
font-weight: 500;
}
.ivu-layout-sider {
transition: all .2s ease-in-out;
position: relative;
background: #ffffff;
}
.ivu-layout {
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
-webkit-box-flex: 1;
flex: auto;
background: #ffffff;
}
.ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened .ivu-menu-submenu-title {
background: #ffffff;
}
.ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened {
background: #ffffff;
}
.ivu-upload-list{
display: none;
}
.ivu-table-tip table tbody tr td{
background-color: ffffff;
color: #000000;
}
.ivu-select-dropdown-list .ivu-select-item-focus{
background: none !important;
}
/*列表底部tooltip字体大小*/
.tooltip-footer-font-size .ivu-tooltip-inner{
font-size: 12px;
}
.tooltip-footer-font-size{
font-size: 12px;
}
</style>
<!--引入自定义组件-->
<#include "./template/list.ftl">
<div id="app" style="padding-left: 30px">
<div class="layout" style="margin-left: -30px;margin-top: -10px;">
<Layout>
<Sider breakpoint="md" collapsible :collapsed-width="78" v-model="isCollapsed">
<i-menu theme="primary" width="auto" :class="menuitemClasses" active-name="datainfo" :open-names="['sub']" @on-select="onMenuSelect">
<Submenu name="sub">
<template slot="title">
<Icon type="ios-apps"/></Icon>
报表管理
</template>
<Menu-Item name="datainfo">
<Icon type="md-list"/></Icon>
<span>数据报表</span>
</Menu-Item>
<Menu-Item name="printinfo">
<Icon type="md-print"></Icon>
<span>打印设计</span>
</Menu-Item>
</Submenu>
</i-menu>
<div slot="trigger"></div>
</Sider>
<Tabs value="name1" style="width: 100%" @on-click="tabsClick">
<tab-pane icon="md-desktop" label="报表设计" name="name1" class="jimu-tab">
<div style="display: flex;justify-content:space-between;margin-left:16px;margin-right: 38px;">
<div>
<i-input size="small" v-model="name" @keyup.enter.native="enterSearchClick" placeholder="搜索报表名称"></i-input>
</div>
<div class="page">
<Page :total="page.total"
show-total
show-elevator
:page-size="page.size"
show-sizer
@on-change="handleCurrentChange"
@on-page-size-change="handleSizeChange"
size="small">
</Page>
</div>
<div>
<i-select
transfer="true"
v-model="previewModel"
size="small"
style="width: 78px;text-align: center;">
<i-option value="view" style="font-size: 10px">视图</i-option>
<i-option value="list" style="font-size: 10px">列表</i-option>
</i-select>
</div>
</div>
<div style="display: flex;flex-wrap: wrap;" v-if="previewModel =='view'">
<div class="excel-view-item excel-list-add">
<a @click="createExcel">
<i class="ivu-icon ivu-icon-md-add" style="font-size:20px; padding-bottom: 5px;"></i>
<p style="letter-spacing: 2px;font-size: 14px;">新建报表</p>
</a>
</div>
<!-- 循环开始 &ndash;&gt;-->
<div
v-for="(item,index) in dataSource"
:key="index"
class="excel-view-item"
@mouseover="item.editable=true"
@mouseout="item.editable=false">
<!-- 缩略图 &ndash;&gt;-->
<div class="thumb">
<img :src="getThumbSrc(item)"/>
<div class="excel-edit-container" v-show="item.editable">
<a :href="getExcelEditUrl(item)" target="_blank">
设计
</a>
</div>
</div>
<!-- 底部 &ndash;&gt;-->
<div class="item-footer">
<Tooltip :content="item.name" placement="top-start" :transfer="true">
<template slot="content">
<span class="tooltip-footer-font-size">{{item.name}}</span>
</template>
<div class="item-name">
{{ item.name }}
</div>
</Tooltip>
<div>
<a class="opt-show" :href="getExcelViewUrl(item)" target="_blank">
<Tooltip content="预览模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-eye-outline" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-show" v-show="userMessage" @click="setTemplate(item,1)">
<Tooltip content="收藏模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-star-outline" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-show" @click="handleDelete(item)">
<Tooltip content="删除模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-trash" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-show" @click="handleCopy(item)">
<Tooltip content="复制模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-browsers" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-show" @click="handleShare(item.id)">
<Tooltip content="分享" placement="top">
<i class="ivu-icon ivu-icon-ios-share-alt" style="font-size: 16px"></i>
</Tooltip>
</a>
</div>
</div>
</div>
<!-- 循环结束 &ndash;&gt;-->
</div>
<div v-else style="padding: 10px 10px">
<i-button type="primary" @click="createExcel" size="small" style="margin-left: 6px;width:78px;font-size: 10px">
新建报表
</i-button>
<i-table size="small" style="margin-top: 10px" border :columns="listColumns" :data="dataSource">
<template slot-scope="{ row, index }" slot="action">
<a class="opt-list-show" :href="getExcelViewUrl(row)" target="_blank">
<Tooltip transfer="true" content="预览模板" placement="top">
<i class="ivu-icon ivu-icon-ios-eye-outline" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" :href="getExcelEditUrl(row)" target="_blank">
<Tooltip transfer="true" content="编辑" placement="top">
<i class="ivu-icon ivu-icon-md-create" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" v-show="userMessage" @click="setTemplate(row,1)">
<Tooltip transfer="true" content="收藏模板" placement="top">
<i class="ivu-icon ivu-icon-ios-star-outline" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" @click="handleDelete(row)">
<Tooltip transfer="true" content="删除模板" placement="top">
<i class="ivu-icon ivu-icon-ios-trash" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" @click="handleCopy(row)">
<Tooltip transfer="true" content="复制模板" placement="top">
<i class="ivu-icon ivu-icon-ios-browsers" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" @click="handleShare(row.id)">
<Tooltip transfer="true" content="分享" placement="top">
<i class="ivu-icon ivu-icon-ios-share-alt" style="font-size: 16px"></i>
</Tooltip>
</a>
</template>
</i-table>
</div>
</tab-pane>
<tab-pane icon="md-options" label="模板案例" name="name2" class="jimu-tab">
<div style="display: flex;justify-content:space-between;margin-left:16px;margin-right: 38px">
<div>
<i-input size="small" v-model="name" @keyup.enter.native="loadData" placeholder="搜索报表名称"></i-input>
</div>
<div class="page">
<Page :total="page.total"
show-total
show-elevator
:page-size="page.size"
show-sizer
@on-change="handleCurrentChange"
@on-page-size-change="handleSizeChange"
size="small">
</Page>
</div>
<div>
<i-select
transfer="true"
v-model="previewModel"
size="small"
style="width: 78px;text-align: center;">
<i-option value="view" style="font-size: 10px">视图</i-option>
<i-option value="list" style="font-size: 10px">列表</i-option>
</i-select>
</div>
</div>
<div style="display: flex;flex-wrap: wrap;" v-if="previewModel =='view'">
<!-- 循环开始 &ndash;&gt;-->
<div
v-for="(item,index) in dataSource"
:key="index"
class="excel-view-item"
@mouseover="item.editable=true"
@mouseout="item.editable=false">
<!-- 缩略图 &ndash;&gt;-->
<div class="thumb">
<img :src="getThumbSrc(item)"/>
<div class="excel-edit-container" v-show="item.editable">
<a v-show="userMessage" :href="getExcelEditUrl(item)" target="_blank">
设计
</a>
</div>
</div>
<!-- 底部 &ndash;&gt;-->
<div class="item-footer">
<Tooltip placement="top-start" transfer>
<template slot="content">
<span class="tooltip-footer-font-size">{{item.name}}</span>
</template>
<div class="item-name">
{{ item.name }}
</div>
</Tooltip>
<div style="margin-left: 14%;">
<a class="opt-show" :href="getExcelViewUrl(item)" target="_blank">
<Tooltip content="预览模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-eye-outline" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-show" v-show="userMessage" @click="setTemplate(item,0)">
<Tooltip content="取消收藏" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-star" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-show" @click="handleCopy(item)">
<Tooltip content="复制模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-browsers" style="font-size: 16px"></i>
</Tooltip>
</a>
</div>
<div v-show="userMessage" >
<Upload
:headers="uploadHeader"
:before-upload="handleUpload"
:data="{'id':item.id}"
:action="actionUrl"
:format="['jpg','jpeg','png']"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:on-success="handleSuccess">
<Tooltip content="上传封面" placement="top-end" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-md-image" style="font-size: 16px"></i>
</Tooltip>
</Upload>
</div>
</div>
</div>
<!-- 循环结束 &ndash;&gt;-->
</div>
<div v-else style="padding: 10px 10px">
<i-button type="primary" @click="createExcel" style="margin-left: 6px;width:78px;font-size: 10px" size="small">
新建报表
</i-button>
<i-table size="small" style="margin-top: 10px" border :columns="listColumns" :data="dataSource">
<template slot-scope="{ row, index }" slot="action">
<a class="opt-list-show" :href="getExcelEditUrl(row)" target="_blank">
<Tooltip transfer="true" content="编辑" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-md-create" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" :href="getExcelViewUrl(row)" target="_blank">
<Tooltip transfer="true" content="预览模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-eye-outline" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" v-show="userMessage" @click="setTemplate(row,0)">
<Tooltip transfer="true" content="取消收藏" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-star" style="font-size: 16px"></i>
</Tooltip>
</a>
<a class="opt-list-show" @click="handleCopy(row)">
<Tooltip transfer="true" content="复制模板" placement="top" class="tooltip-footer-font-size">
<i class="ivu-icon ivu-icon-ios-browsers" style="font-size: 16px"></i>
</Tooltip>
</a>
</template>
</i-table>
</div>
</tab-pane>
</Tabs>
</Layout>
</div>
<#--分享弹窗-->
<j-jurisdiction ref="jurisdiction"></j-jurisdiction>
<#-- <i-button @click="show">Click me!</i-button>
<Modal v-model="visible" title="Welcome">Welcome to ViewUI</Modal>-->
</div>
<script>
var BASE_URL="${base}"+"${customPrePath}";
var currentPage = new Vue({
el: '#app',
data: {
isCollapsed: false,
token:'',//token
name:'',
designerObj:{},
loading:true,
showEdit:false,
dataSource:[],
modalTitle:"",
page: { //分页参数
page: 1,
size: 10,
total: 0,
},
changecode : "",
changename : "",
menuitem : "datainfo",
tabpan : "name1",
userMessage: false,
file:null,
uploadHeader:{},
actionUrl:"",
previewModel:"view",//浏览方式
listColumns: [
<#--{-->
<#-- title: '背景图',-->
<#-- align: 'center',-->
<#-- key: 'thumb',-->
<#-- width: 150,-->
<#-- className: 'table-background',-->
<#-- render: (h, params) => {-->
<#-- let _img = ""-->
<#-- if(!params.row.thumb){-->
<#-- _img = "${base}"+"${customPrePath}"+"/jmreport/desreport_/corelib/jiade.jpg"-->
<#-- }else{-->
<#-- if(params.row.thumb.indexOf('http')==0){-->
<#-- _img = params.row.thumb-->
<#-- }else{-->
<#-- _img = "${base}"+"${customPrePath}"+"/jmreport/img/"+params.row.thumb-->
<#-- }-->
<#-- }-->
<#-- if(_img){-->
<#-- return h('img', {-->
<#-- attrs: {-->
<#-- src: _img,-->
<#-- style: 'width: 100px;height: 39px;vertical-align: middle;'-->
<#-- },-->
<#-- })-->
<#-- }else{-->
<#-- return h("span", '');-->
<#-- }-->
<#-- }-->
<#--},-->
{
title: '报表名称',
key: 'name',
align: 'left',
className: 'table-background'
},
{
title: '操作',
width: 240,
align: 'center',
slot: 'action',
className: 'table-background',
fixed:'right'
}
],//列表的列
},
computed: {
menuitemClasses: function () {
return [
'menu-item',
this.isCollapsed ? 'collapsed-menu' : ''
]
}
},
mounted:function(){
this.token = token;
//console.log("list_mount--------------",this.token);
this.uploadHeader = {"X-Access-Token":this.token};
this.actionUrl=BASE_URL+"/jmreport/putFile";
this.$nextTick(()=>{
this.dataSource=[];
this.userInfo();
});
},
methods: {
handleSizeChange(val){
this.page.size = val;
this.loadData();
},
handleCurrentChange (val) {
this.page.page = val;
this.loadData();
},
show: function () {
},
//查询用户信息并加载数据
userInfo: function(){
var that = this;
$http.get({
url:api.userInfo,
data:{
token:that.token
},
success:(result)=>{
if (result.message != null && result.message != ""){
if (result.message === "admin"){
that.userMessage = true;
}
}
that.$nextTick(()=>{
that.loadData();
});
},
error:(err)=>{
that.handleSpinHide();
}
},that)
},
//加载数据
loadData: function(name){
var that = this;
if (name != null && name != ""){
that.tabpan = name;
that.page={page: 1,size: 10,total: 0,};
}
var url = "";
that.dataSource=[];
if (that.tabpan == "name1"){
url = api.excelQuery
}else {
url = api.excelQueryByTemplate
}
$http.get({
url:url,
data:{
pageNo:that.page.page,
pageSize:that.page.size,
reportType:that.menuitem,
name:that.name,
token:that.token
},
success:(result)=>{
var ls = result.records;
that.page.total = result.total
if(ls && ls.length>0){
for(var i = 0;i<ls.length;i++){
//预览时设置报表打印宽度
let jsonStr = ls[i].jsonStr;
let width;
if(jsonStr){
jsonStr = JSON.parse(jsonStr);
width = jsonStr.printElWidth || jsonStr.dataRectWidth || 800;
ls[i].printWidth = width;
}
ls[i].editable=false;
}
that.$nextTick(()=>{
that.dataSource =JSON.parse(JSON.stringify(ls));
});
}
},
error:(err)=>{
that.handleSpinHide();
}
},that)
},
//新建报表
createExcel: function(){
var that = this;
$http.post({
url:api.saveReport,
data:{},
contentType:'json',
success:(result)=>{
//update-begin---author:wangshuai ---date:20220215 for[issues/I4SOSH]做完的积木报表预览生成的访问地址默认都加了token=null------------
let url = api.index+result.id+"?menuType="+this.menuitem;
window.open(this.splicingToken(url));
//update-end---author:wangshuai ---date:20220215 for[issues/I4SOSH]做完的积木报表预览生成的访问地址默认都加了token=null------------
}
},that)
},
//未使用
handleEditConfig: function(item){
window.location.href = api.index+item.id+"?token="+this.token;
},
/**
* 为路径拼接token
* @param url 需要拼接的路径
* @return 拼接后的token
*/
splicingToken(url){
if(this.token && "null" != this.token){
if(url.indexOf("?")!=-1){
url =url + "&token="+this.token;
}else{
url =url + "?token="+this.token;
}
}
return url;
},
//删除报表
handleDelete:function(item){
$http.confirm({
title:'删除报表',
content:'是否确认删除?',
url:api.deleteReport,
data:{
id:item.id,
token:this.token
},
success:(result)=>{
this.loadData();
}
},this);
},
//复制模版
handleCopy: function(item){
$http.confirm({
title:'复制报表',
content:'是否确认复制?',
url:api.reportCopy,
method:'get',
data:{
id:item.id,
token:this.token
},
success:(result)=>{
this.loadData();
}
},this);
},
handlerViewExcel: function(item){
//console.log(item)
},
getExcelEditUrl: function(item){
//update-begin---author:wangshuai ---date:20220215 for[issues/I4SOSH]做完的积木报表预览生成的访问地址默认都加了token=null------------
return this.splicingToken(api.index+item.id);
//update-end---author:wangshuai ---date:20220215 for[issues/I4SOSH]做完的积木报表预览生成的访问地址默认都加了token=null------------
},
getExcelViewUrl: function(item){
//update-begin---author:wangshuai ---date:20220215 for[issues/I4SOSH]做完的积木报表预览生成的访问地址默认都加了token=null------------
return this.splicingToken(api.view+item.id);
//update-end---author:wangshuai ---date:20220215 for[issues/I4SOSH]做完的积木报表预览生成的访问地址默认都加了token=null------------
},
getLabelText1:function (createElement) {
return createElement('div',
{
style:{color:'#fff'}
},
[
createElement('Icon',{props:{type:'ios-checkmark'}}),
'模板库'
]
)
},
onMenuSelect:function(name){
this.menuitem = name;
this.page={page: 1,size: 10,total: 0,};
this.dataSource=[];
this.name=""
this.loadData();
},
//报表设计和模板案例点击事件
tabsClick(name){
this.name=""
this.loadData(name)
},
//回车搜索事件
enterSearchClick(){
this.loadData()
},
//设置取消模版
setTemplate: function(item,arg){
var content = (arg == 1)?'是否确认设置为模板?':'是否确认取消模板?';
let title = (arg == 1)?'收藏报表':'取消收藏报表'
$http.confirm({
title:title,
content:content,
url:api.setTemplate,
method:'get',
data:{
id:item.id,
template:arg,
token:this.token
},
success:(result)=>{
this.loadData();
}
},this);
},
handleUpload (file) {
this.file = file;
return true;
},
handleFormatError (file) {
this.$Notice.warning({
title: '文件格式不正确',
desc: '文件 ' + file.name + ' 格式不正确,请上传 jpg 或 png 格式的图片。'
});
},
handleMaxSize (file) {
this.$Notice.warning({
title: '超出文件大小限制',
desc: '文件 ' + file.name + ' 太大,不能超过 2M。'
});
},
handleSuccess (res) {
if (res != null){
this.$Message.success(res.message);
this.dataSource.forEach((item,index,array)=>{
if (item.id === res.result.id){
item.thumb = res.result.thumb;
}
})
}
},
handleSpinHide(){
/* setTimeout(() => {
this.$Spin.hide();
}, 3000);*/
},
//分享按钮点击事件
handleShare(id){
$http.get({
url:api.queryJurisdiction,
data:{reportId:id},
success:(result)=>{
if(result){
if(result.status=='0'){
let protocol = window.location.protocol;
let host = window.location.host;
//update-begin---author:wangshuai ---date:20221118 for[issues/1383]yml中设置了项目前缀分享链接地址有误------------
let url = protocol+"//"+host+BASE_URL;
//update-end---author:wangshuai ---date:20221118 for[issues/1383]yml中设置了项目前缀分享链接地址有误------------
result.previewUrl = url+result.previewUrl;
this.$refs.jurisdiction.jurisdictionData = result;
this.$refs.jurisdiction.shareUrlModal = true
}else{
//update-begin---author:wangshuai ---date:20220315 for[issues/I4WWKE]分享链接的预览密码能否忽略------------
//兼容老数据没有是否显示密码的情况下;
//previewLockStatus 密码锁状态(0不存在密码锁1存在密码锁);原来取消分享后的默认应该是1
if(!result.previewLockStatus){
result.previewLockStatus = "1"
}
//update-end---author:wangshuai ---date:20220315 for[issues/I4WWKE]分享链接的预览密码能否忽略------------
this.$refs.jurisdiction.jurisdictionData = result;
this.$refs.jurisdiction.shareModal = true
}
}else{
this.$refs.jurisdiction.jurisdictionData.reportId=id
this.$refs.jurisdiction.shareModal = true
}
}
})
},
// 获取缩略图的预览地址
getThumbSrc(item){
if(!item.thumb){
return "${base}"+"${customPrePath}"+"/jmreport/desreport_/corelib/jiade.jpg"
}else{
if(item.thumb.indexOf('http')==0){
return item.thumb
}else{
return "${base}"+"${customPrePath}"+JM_VIEW_IMG_URL+"/"+item.thumb
}
}
}
}
})
</script>
<#include "./common/tj.ftl">
</body>
</html>

View File

@@ -0,0 +1,172 @@
<template>
<Modal
v-model="deleteParamModel"
@on-ok="deleteParamTable"
title="确认删除">
<p><Icon type="ios-alert" color="#f90" size="20px"></Icon>是否删除选中数据?</p>
</Modal>
<Modal
v-model="deleteFieldModel"
@on-ok="deleteFieldTable"
title="确认删除">
<p><Icon type="ios-alert" color="#f90" size="16px"></Icon>是否删除选中配置?</p>
</Modal>
<Modal :loading="false" v-model="visible" title="报表信息" :width="500">
<div style="padding-right: 30px">
<i-form ref="designerObj" :model="designerObj" :label-width="90" :rules="designerObjRules">
<#--<form-item label="编码">
<i-input v-model="designerObj.code" disabled></i-input>
</form-item>-->
<form-item label="名称" prop="name">
<i-input v-model="designerObj.name" placeholder="请输入名称" @on-change="changeName"></i-input>
</form-item>
<form-item label="类型" prop="type">
<i-select :model.sync="designerObj.type" v-model="designerObj.type" style="width:100%" @on-change="selectmenuList">
<i-option v-for="item in menuList" :value="item.value">{{ item.label }}</i-option>
</i-select>
</form-item>
</i-form>
</div>
<div slot="footer">
<i-button @click="closePopup('designerObj')">取消</i-button>
<i-button :loading="saveReportLoading" type="primary" @click="saveReport('designerObj')">确定</i-button>
</div>
</Modal>
<Modal :loading="loading" v-model="addEchart" title="数据编辑" :width="50" @on-ok="addEchartData">
<div>
<i-form>
<form-item>
<i-input type="textarea" :autosize="{minRows: 15,maxRows: 15}" v-model="apiStaticDataList" ></i-input>
</form-item>
</i-form>
</div>
</Modal>
<Modal :loading="loading" v-model="chartModule" :width="1000" @on-ok="okAddChart" @on-cancel="selectedChartType=''">
<p slot="header">
<span>添加图表
<Tooltip :transfer="true" content="图表文档" placement="top">
<a class="jimu-table-tip help-color" href="https://help.jeecg.com/jimureport/chart.html" target="_blank"><Icon size="14" type="ios-help-circle-outline" style="margin-top: 2px"/></a>
</Tooltip>
</span>
</p>
<Tabs value="bar" class="chart-modal-content" >
<tab-pane :label="obj.label" :name="obj.name" v-for="(obj,index) of chartTypeList" :index="index+1">
<Row justify="center">
<i-col span="5" offset="1" v-for="(item,index) of obj.typeList" :class="item.allowed ? '':'no-allowed'" style="margin-top: 20px">
<div style="border: solid 1px #dcdee2;width: 180px;height: 130px;" :class="selectedChartId == item.id ? 'chart-selected':''" @click="setSelectCharType(item)" >
<img :src="'${base}'+'${customPrePath}'+item.imgUrl" style="width:95%;height:95%;margin: 0 5px;">
<span style="float: left;width:180px;margin-top: 8px;text-align:center;;font-size: 12px">{{item.name}}</span>
</div>
</i-col>
</Row>
</tab-pane>
</Tabs>
</Modal>
<Modal :loading="loading" v-model="seriesModal" title="系列类型信息" :width="30" @on-ok="addSeriesType" @on-cancel="seriesObj={}">
<div style="padding-right: 50px">
<i-form :model="seriesObj" label-colon :label-width="90">
<form-item label="系列">
<i-select v-model="seriesObj.name" style="width:100%" @on-change="selectmenuList" placeholder="请选择">
<i-option v-for="(item, index) in customColorNameList" :index="index" :value="item">{{ item }}</i-option>
</i-select>
</form-item>
<form-item label="图表类型" v-if="selectedChartType !== 'bar.stack' && selectedChartId!='bar.negative'">
<i-select v-model="seriesObj.type" placeholder="请选择图表类型">
<i-option value="bar">柱形图</i-option>
<i-option value="line">折线图</i-option>
</i-select>
</form-item>
<form-item label="系列堆叠值" v-if="selectedChartType === 'bar.stack'|| selectedChartId==='bar.negative'">
<i-input v-model="seriesObj.stack" placeholder="请自定义系列堆叠值,相同值的会堆叠在一起"></i-input>
</form-item>
</i-form>
</div>
</Modal>
<#--自定义表达式弹窗-->
<Modal :draggable="funDraggable" :loading="loading" :fullscreen="functionScreen" v-model="customExpressionShow" :width="1000" :autosize="true" @on-ok="expressionSave" @on-cancel="expressionCancel" class="expression">
<p slot="header">
<span>添加表达式
<Tooltip :transfer="true" content="表达式文档" placement="top">
<a class="jimu-table-tip help-color" href="https://help.jeecg.com/jimureport/function.html" target="_blank"><Icon size="14" type="ios-help-circle-outline" style="margin-top: 2px"/></a>
</Tooltip>
<Tooltip style="cursor: pointer;float: right;margin-right: 30px;" v-if="functionScreen" :transfer="true" content="缩小" placement="top">
<Icon type="ios-contract" @click="functionScreenClick"/>
</Tooltip>
<Tooltip style="cursor: pointer;float: right;margin-right: 30px;" v-else :transfer="true" content="放大" placement="top">
<Icon type="ios-expand" @click="functionScreenClick"/>
</Tooltip>
</span>
</p>
<i-form label-colon :label-width="90">
<Row justify="left">
<i-col>
<span class="fontColor">请在下面的文本框中输入公式,不需要输入开头的等号:</span>
</i-col>
</Row>
<Row justify="center" style="margin-top: 10px">
<i-col>
<i-input type="textarea" v-model="expression" placeholder="请输入表达式" :class="functionScreen==false?'expressionInput':'expressionHeight'"></i-input>
</i-col>
</Row>
<Row justify="center" style="margin-top: 10px">
<i-col span="6" class="functionDiv">
<div :class="leftFunctionIndex == item.id?'leftFunctionSelect':'leftFunction'" v-for="(item,index) in functionType" @click="leftFunctionClick(item.id)">
<span class="fontColor">{{item.name}}</span>
</div>
</i-col>
<i-col span="1">
</i-col>
<i-col span="13">
<div class="childrenDiv">
<div v-if="commonFunction" v-for="(item,index) in newFunctionList" @click="rightFunctionClick(item,index)" :class="rightFunctionIndex == index?'rightFunctionSelect':'activeItem'">
<span class="fontColor">{{item}}</span>
</div>
</div>
</i-col>
<i-col span="5">
<j-function-interpretation :text="interpretation"></j-function-interpretation>
</i-col>
</Row>
</i-form>
</Modal>
<#-- 增强弹框 -->
<Modal draggable :loading="loading" v-model="enhanceModalVisible" title="增强配置" :width="1000" :class="'jmreport-enhance'"
@on-ok="saveEnhanceConfig" @on-cancel="cancleEnhanceModal">
<Collapse value="1">
<Panel name="1">
CSS
<div slot="content">
<i-input :rows="10" type="textarea" v-model="enhanceCssStr" placeholder="请输入值CSS片段" ></i-input>
</div>
</Panel>
<Panel name="2">
JS
<div slot="content">
<i-input :rows="10" type="textarea" v-model="enhanceJsStr" placeholder="请输入值JS片段" ></i-input>
</div>
</Panel>
</Collapse>
</Modal>
<#--输入框值放大-->
<Modal draggable :loading="loading" v-model="enlargeInputModal" title="输入值" :width="1000" @on-ok="enlargeInputOk"
@on-cancel="enlargeInputCancel" class="expression">
<i-form label-colon :label-width="90">
<form-item prop="valueCoordinate" label="单元格">
<i-input readonly v-model="valueCoordinate"></i-input>
</form-item>
<form-item prop="valueExpression" label="值">
<i-input type="textarea" v-model="valueExpression" placeholder="请输入值" class="expressionInput"></i-input>
</form-item>
</i-form>
</Modal>
</template>

View File

@@ -0,0 +1,33 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打印页面</title>
</head>
<body>
<input type="text" id='printInput' placeholder="请输入打印地址" style="width: 650px;">
<button onclick="printFn()">打印</button>
<iframe id='report' frameborder="0" width="100%" height="100%"></iframe>
<script>
function getRequestUrl() {
var url = location.search;
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("&");
for(var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]]=decodeURI(strs[i].split("=")[1]);
}
}
return theRequest;
}
function printFn(){
const printText = document.getElementById('printInput').value;
if(!printText) alert('请输入打印地址');
document.getElementById('report').src=printText;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,131 @@
<script type="text/x-template" id="background-setting-template">
<Submenu name="background" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>背景设置</span>
<Tooltip placement="top" content="背景图片会覆盖背景颜色" :transfer="true">
<Icon size="16" style="margin-left: 10px;" type="ios-help-circle-outline"/>
</Tooltip>
</template>
<div class="blockDiv" style="padding-bottom: 20px">
<Row class="ivurow">
<p>启用背景&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 117px;" v-model="chartBackground.enabled" @on-change="chartBackgroundChange"/>
</Row>
<Row class="ivurow">
<p>背景颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="iSelect" v-model="chartBackground.color" size="small" @on-change="chartBackgroundChange">
<span slot="append">
<color-picker class="colorPicker" v-model="chartBackground.color" :editable="false" alpha :transfer="true" size="small" @on-change="chartBackgroundChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow">
<p>背景图片&nbsp;&nbsp;</p>
<div style="height: 0">
<Upload
:headers = "uploadHeaders"
:show-upload-list="false"
:default-file-list="chartBackgroundImg"
:on-success="uploadSuccess"
:on-exceeded-size="(e)=>handleMaxSize(e,10)"
:format="['jpg','jpeg','png']"
:max-size="10240"
:action=" actionUrlPre + '/jmreport/upload' "
style="display: inline-block;width:58px;">
<i-button v-if="chartBackground.image" style="margin-left:106px" type="primary" size="small">修改</i-button>
<i-button v-else style="margin-left:106px" type="primary" size="small">上传</i-button>
</Upload>
</div>
</Row>
<Row class="ivurow">
<div style="width: 196px" class="pictorial-icon-upload" v-if="chartBackground.image">
<img style="max-width: 196px;max-height: 50px" :src="getChartBackgroundImg()"/>
<div class="cover">
<Icon type="ios-trash-outline" @click="removeChartBackground"/>
</div>
</div>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-background-setting', {
template: '#background-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
chartBackgroundImg: [{'name': 'chartBackgroundImg', 'url': ''}],
actionUrlPre: baseFull,
chartBackground: {
color:''
},
uploadHeaders:{}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.chartBackground = Object.assign(this.chartBackground, this.settings)
}
this.uploadHeaders = vm.uploadHeaders
},
//获取图片预览图
getChartBackgroundImg(){
let path = this.chartBackground['image']
if(path){
if(path.indexOf('http')<0){
path = baseFull+path
}
}
return path
},
//图片上传文件大小
handleMaxSize(file, size){
// console.log("file===>", file)
// console.log("size===>", size)
this.$Notice.warning({
title: '超出文件大小限制',
desc: '文件 ' + file.name + ' 太大,请上传' + size + 'M以内图片',
duration: 6
});
},
uploadSuccess(res){
this.$emit('upload-success',res,this.chartBackground, (image)=>{
this.chartBackground['image'] = image
this.$forceUpdate(()=>{
this.getChartBackgroundImg();
})
})
},
removeChartBackground(){
this.chartBackground['image'] = ''
this.$forceUpdate(()=>{
this.getChartBackgroundImg();
})
this.$emit('remove',this.chartBackground)
},
chartBackgroundChange(){
this.$emit('change', this.chartBackground)
}
}
})
</script>

View File

@@ -0,0 +1,75 @@
<script type="text/x-template" id="bar-series-template">
<Submenu name="6" style="border-bottom: inset 1px;" class="rightFontSize dataSourceForm">
<template slot="title">
<span>类型设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow" v-for="(item,index) in seriesData">
<Tooltip :content="item.name" placement="top">
<p class="text-width">
{{item.name}}&nbsp;&nbsp;
</p>
</Tooltip>
<i-select size="small" class="iSelect" v-model="item.type" @on-change="onSeriesChange">
<i-option class="rightFontSize" value="bar">bar</i-option>
<i-option class="rightFontSize" value="line">line</i-option>
</i-select>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-bar-series-setting', {
template: '#bar-series-template',
props: {
chartOptions: {
type: Object,
default: () => {
}
},
dataSettings: {
type: [Object, String],
default: () => {
}
}
},
data() {
return {
seriesData: {}
}
},
watch: {
chartOptions: {
deep: true,
immediate: true,
handler: function () {
this.initData()
}
}
},
methods: {
initData: function () {
if (this.chartOptions && this.chartOptions.series) {
this.seriesData = this.chartOptions.series;
}
},
onSeriesChange(value) {
this.chartOptions.series = this.seriesData
let id = this.dataSettings.id;
xs.updateChart(id, this.chartOptions);
}
}
})
</script>
<style scoped>
.text-width {
width: 50px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
position: relative;
top: 6px;
}
</style>

View File

@@ -0,0 +1,87 @@
<script type="text/x-template" id="bar-setting-template">
<div >
<Submenu name="2" style="border-bottom: inset 1px;">
<template slot="title">
<span class="rightFontSize">柱体设置</span>
</template>
<div class="blockDiv">
<Row class="ivurow">
<p>宽度&nbsp;&nbsp;</p>
<slider v-model="barOptions.barWidth" @on-change="onBarChange" style="margin-top: -9px;width: 140px;margin-left: 26px;"></slider>
</Row>
<Row class="ivurow">
<p>圆角&nbsp;&nbsp;</p>
<slider v-model="barOptions.itemStyle_barBorderRadius" @on-change="onBarChange" style="margin-top: -9px;width: 134px;margin-left: 31px;"></slider>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">最小高度&nbsp;&nbsp;</p>
<slider v-model="barOptions.barMinHeight" @on-change="onBarChange" style="margin-top: -9px;width: 134px;margin-left: 8px;"></slider>
</Row>
<Row v-if="isMultiChart === false && typeof barOptions.itemStyle_color!== 'undefined' " class="ivurow">
<p>柱体颜色&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" v-model="barOptions.itemStyle_color" size="small" @on-change="onBarChange">
<span slot="append">
<color-picker class="colorPicker" v-model="barOptions.itemStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onBarChange"/>
</span>
</i-input>
</Row>
<Row v-if="isMultiChart === false && typeof barOptions.backgroundStyle_color!== 'undefined' " class="ivurow">
<p>柱体背景&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" v-model="barOptions.backgroundStyle_color" size="small" @on-change="onBarChange">
<span slot="append">
<color-picker class="colorPicker" v-model="barOptions.backgroundStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onBarChange"/>
</span>
</i-input>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-bar-setting', {
template: '#bar-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
},
isMultiChart:{
type: Boolean,
default: false
}
},
data(){
return {
barOptions: {
barWidth: 50,
itemStyle_barBorderRadius: 0,
itemStyle_color: '#c43632',
barMinHeight: 2,
textStyle_color: 'black',
textStyle_fontWeight: 'bolder'
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.barOptions = Object.assign(this.barOptions, this.settings)
}
},
onBarChange (){
this.$emit('change',this.barOptions)
}
}
})
</script>

View File

@@ -0,0 +1,208 @@
<style>
.jm-form-barcode .ivu-form-item-label{
padding-bottom: 2px !important;
}
.jm-form-horizontal .ivu-form-item-content{
margin-left: 100px;
}
.jm-form-horizontal .ivu-form-item-label{
text-align: left;
width: 100px;
float: left;
padding: 10px 12px 10px 0;
}
.jm-form-barcode .ivu-switch:after{
height: 16px;
}
.jm-form-barcode .ivu-switch{
height: 20px;
line-height: 20px;
}
.little-input textarea{
height: inherit !important;
}
.jm-form-barcode .ivu-color-picker .ivu-select-dropdown {
left: -142px !important;
}
.jm-setting-container{
overflow-y: auto;
padding-right: 5px;
overflow-x:hidden;
padding-bottom: 50px;
}
.pb120{
padding-bottom: 120px;
}
.jm-setting-container::-webkit-scrollbar {
width: 6px;
}
.jm-setting-container::-webkit-scrollbar-thumb {
background-color: #d9d9d9;
}
</style>
<#--JsBarcode("#imgcode", "123", {
format: "CODE39",//选择要使用的条形码类型
width:3,//设置条之间的宽度
height:100,//高度
displayValue:true,//是否在条形码下方显示文字
text:"456",//覆盖显示的文本
fontOptions:"bold italic",//使文字加粗体或变斜体
font:"fantasy",//设置文本的字体
textAlign:"left",//设置文本的水平对齐方式
textPosition:"top",//设置文本的垂直位置
textMargin:5,//设置条形码和文本之间的间距
fontSize:15,//设置文本的大小
background:"#eee",//设置条形码的背景
lineColor:"#2196f3",//设置条和文本的颜色。
margin:15//设置条形码周围的空白边距-->
<script type="text/x-template" id="barcode-setting-template">
<div :style="{height: settingsDivHeight+'px'}" class="jm-setting-container pb120" style="padding-top: 10px;padding-left: 7px">
<i-form class="jm-form-barcode dataSourceForm rightFontSize" >
<form-item label="条形码内容">
<i-input v-model="barcodeContent" id="barcodeContent" type="textarea" :rows="2" @on-blur="onBarcodeChange"></i-input>
</form-item>
<form-item label="条间距">
<i-input v-model="width" placeholder="请输入条间距" :min="1" type="number" @on-change="onBarcodeChange"></i-input>
</form-item>
<form-item label="高度">
<i-input v-model="height" placeholder="请输入高度" :min="1" type="number" @on-change="onBarcodeChange"></i-input>
</form-item>
<form-item label="条颜色" class="colorHeight">
<i-input v-model="lineColor" size="small" style="width: 111px;" @on-change="onBarcodeChange">
<span slot="append">
<color-picker class="colorPicker colorHeight" v-model="lineColor" :editable="false" alpha :transfer="true" size="small" @on-change="onBarcodeChange"/>
</span>
</i-input>
</form-item>
<form-item label="背景色" class="colorHeight">
<i-input v-model="background" size="small" style="width: 111px;" @on-change="onBarcodeChange">
<span slot="append">
<color-picker class="colorPicker" v-model="background" :editable="false" alpha :transfer="true" size="small" @on-change="onBarcodeChange"/>
</span>
</i-input>
</form-item>
<form-item label="是否显示文字" class="jm-form-horizontal">
<div>
<i-switch v-model="displayValue" @on-change="onBarcodeChange"/>
</div>
</form-item>
<template v-if="displayValue">
<form-item label="覆盖文字">
<i-input v-model="text" placeholder="请输入覆盖文字" @on-blur="onBarcodeChange"></i-input>
</form-item>
<form-item label="文字位置">
<i-select v-model="textPosition" placeholder="请选择文字位置" @on-change="onBarcodeChange">
<i-option value="bottom">底部</i-option>
<i-option value="top">上方</i-option>
</i-select>
</form-item>
<form-item label="文字水平对齐">
<i-select v-model="textAlign" placeholder="请选择水平对齐方式" @on-change="onBarcodeChange">
<i-option value="center">居中</i-option>
<i-option value="left">左对齐</i-option>
<i-option value="right">右对齐</i-option>
</i-select>
</form-item>
<form-item label="文字大小">
<i-input v-model="fontSize" placeholder="请输入文字大小" :min="1" type="number" @on-change="onBarcodeChange"></i-input>
</form-item>
<form-item label="文字样式">
<i-select v-model="fontOptions" placeholder="请选择文字样式" @on-change="onBarcodeChange">
<i-option value="bold">加粗</i-option>
<i-option value="italic">斜体</i-option>
<i-option value="bold italic">加粗&斜体</i-option>
</i-select>
</form-item>
</template>
</i-form>
</div>
</script>
<script>
Vue.component('j-barcode-setting', {
template: '#barcode-setting-template',
props: {
settings: {
type: Object,
required: true,
default:()=>{}
}
},
data(){
return {
barcodeContent: '',
background: '#fff',
lineColor: '#000',
width:'',
height:'',
displayValue: false,
text: '',
textPosition: 'bottom',
textAlign: 'center',
fontSize: '',
fontOptions:'',
settingsDivHeight: ''
}
},
created(){
this.settingsDivHeight = window.innerHeight - 100
},
watch:{
settings:{
deep: true,
immediate: true,
handler: function(){
this.resetForm()
}
}
},
methods:{
validateBarcode:(value) => {
if(!value){
return false;
}
if(value.indexOf('$')>=0 || value.indexOf('#')>=0){
return true
}
let reg = /^[a-zA-Z0-9]+$/
let reg2 = /^.{4,18}$/
// 长度为4到18个字符
if (value !== '' && !reg.test(value)) {
Vue.prototype.$Message.error('条码内容只允许字母、数字')
return false;
}
return true;
},
resetForm: function () {
if(this.settings){
Object.keys(this.settings).map(k=>{
this[k] = this.settings[k]
})
}
},
onBarcodeChange(){
if(this.validateBarcode(this.barcodeContent)){
let obj = {}
Object.keys(this.settings).map(k=>{
obj[k] = this[k]
})
//清除颜色后恢复默认
obj.background=this.background?obj.background:'#ffffff'
obj.lineColor=this.lineColor?obj.lineColor:'#000000'
this.$emit('change', obj)
}
}
}
})
</script>

View File

@@ -0,0 +1,404 @@
<style>
.jimu-table-tip{
font-weight: bold;
display: inline-block;
margin-left: 5px;
}
</style>
<script type="text/x-template" id="cell-linkage-template">
<Modal
width="600px"
title="图表联动"
v-model="chartLinkageShow"
:closable = "true"
:mask-closable="false">
<div slot="footer">
<i-button @click="chartLinkageCancel">取消</i-button>
<i-button type="primary" @click="chartLinkageOk">确定</i-button>
</div>
<i-form :label-width="100">
<form-item label="链接名称">
<i-input placeholder="请填写链接名称" v-model="linkName"></i-input>
</form-item>
<form-item label="链接图表">
<i-select v-model="linkChartId" filterable @on-change="chartLinkageChange">
<i-option v-for="(item, index) in existChartList" :key="index" placeholder="请选择链接图表" :value="item.id">{{ item.name }}</i-option>
</i-select>
</form-item>
<form-item label="条件">
<i-input placeholder="请填写条件" v-model="requirement"></i-input>
</form-item>
<span>参数设置</span>
<div style="margin-top: 10px">
<i-button type="primary" @click="addClParam">新增</i-button>
<i-button @click="removeClParam" v-if="selectedClParams.length>0">删除</i-button>
<i-table
style="margin-top: 10px"
ref="paramTable"
stripe
@on-selection-change="handleClParamSelected"
:columns="clParamColumns"
:data="clParamData">
</i-table>
</div>
</i-form>
</Modal>
</script>
<script>
/**
* 处理 字段
* @param list
*/
function handleLinkageFields(list) {
let { x, y, z } = this.currentChart
let arr = []
arr.push(x)
arr.push(y)
arr.push(z)
let dictInfo = {}
for(let item of list){
if(item.dictCode && arr.indexOf(item.fieldName)>=0){
dictInfo[item.fieldName] = item.dictCode
}
}
this.dictInfo = dictInfo
}
/**
* 处理参数
* @param list
*/
function handleLinkageParams(list) {
let ls = []
let index = 0
for(let item of list){
ls.push({
paramName: item.paramName,
paramValue: '',
index: ++index
})
}
this.clParamData = ls
}
function handleLinkageOldParam(){
const { selectedChart, oldConfig } = this
if(selectedChart.id == oldConfig.linkChartId){
this.clParamData = [...oldConfig.params]
}
}
Vue.component('j-cell-linkage', {
template: '#cell-linkage-template',
props: {
settings: {
type: Object,
required: true,
default:()=>{}
}
},
data(){
return {
chartLinkageShow: false,
linkId: '',
reportId: '',
linkType: '2',
linkName: '',
linkChartId: '',
requirement:'',
currentChart:'',
selectedChart: '',
existChartList: [],
dictInfo: '',
clParamData:[],
selectedClParams: [],
clParamColumns:[
{
type: 'selection',
width: 35,
align: 'center'
},{
title: '映射参数',
key: 'paramName',
render: (h, params) => {
return h('i-input', {
props: {
"size":"small",
type: 'text',
value: this.clParamData[params.index].paramName,
placeholder: `请输入参数名`
},
on: {
'on-blur': (event) => {
this.clParamData[params.index].paramName = event.target.value;
}
},
})
}
},{
title: '原始参数',
key: 'paramValue',
renderHeader: (h, params) => {
const sub = ()=>{
let arr = []
let it1 = h('span',params.column.title)
let it2 = h('Tooltip', {
props:{
placement: 'top',
transfer: true
}
}, [
h('span',{class:'jimu-table-tip'}, '?'),
h('div',{slot:'content', style:{'white-space':'normal'}}, [
h('p','1.支持下拉框选择数据集字段'),
h('p','3.支持表达式=A1表示A1单元格的值'),
h('p','2.支持表达式=A表示当前点击行所在的A列单元格的值')
])
])
arr.push(it1)
arr.push(it2)
return arr
}
return h('div', {}, sub())
},
render: (h, params) => {
let paramSelectOptions = this.getChartParamSelectOptions()
return h('j-select-input', {
props: {
options: paramSelectOptions,
size:'small',
transfer: true,
value: this.clParamData[params.index].paramValue,
clearable: true,
},
on: {
'on-change': (value) => {
this.clParamData[params.index].paramValue = value;
}
},
},
paramSelectOptions.map(item => {
return h('i-option', {
props: {
value: item.value
}
}, item.title)
})
);
}
}
]
}
},
created(){
this.settingsDivHeight = window.innerHeight - 100
},
watch:{
settings:{
deep: true,
immediate: true,
handler: function(){
// this.resetForm()
}
}
},
methods:{
// 清空
clearChartLinkage(){
this.linkId = ''
this.reportId = ''
this.linkName = ''
this.linkChartId = ''
this.requirement = ''
// 当前单元格数据集对应的 字段集合
this.fieldList = []
this.currentDbCode = ''
this.fieldName = ''
// 联动下拉框选中的图表
this.selectedChart = ''
// 字典信息
this.dictInfo = ''
// 联动下拉框的集合数据xs.get获取
this.existChartList = []
// 图表联动参数数据
this.clParamData = []
// 选中的参数index集合 删除用到
this.selectedClParams = []
// 编辑页面回显数据 参数记录
this.oldConfig = {}
},
addChartLinkage(existChartList, fieldList, dbCode, fieldName){
this.clearChartLinkage()
this.reportId = excel_config_id
this.linkType = '2'
if(existChartList && existChartList.length>0){
this.existChartList = [...existChartList]
}
this.fieldList = fieldList
this.currentDbCode = dbCode
this.fieldName = fieldName
this.chartLinkageShow = true
},
editChartLinkage(existChartList, fieldList, dbCode, fieldName, row){
// 需要给row赋值
/* apiMethod: null
apiUrl: null
ejectType: null
id: "552823131696795648"
linkChartId: "b9Nqn1FauH9p5C1I"
linkName: "121212"
linkType: "2"
parameter: "[{\"paramName\":\"sex\",\"paramValue\":\"sex\",\"index\":1}]"
reportId: "552378751072604160"*/
this.clearChartLinkage()
if(existChartList && existChartList.length>0){
this.existChartList = [...existChartList]
}
this.fieldList = fieldList
this.currentDbCode = dbCode
this.fieldName = fieldName
this.linkId = row.id
this.linkChartId = row.linkChartId
this.linkName = row.linkName
this.linkType = row.linkType
this.reportId = row.reportId
this.requirement = row.requirement
if(row.parameter){
let arr = JSON.parse(row.parameter)
this.clParamData = [...arr]
this.oldConfig = {
linkChartId: row.linkChartId,
params: [...arr]
}
}
this.chartLinkageShow = true
},
// 确定事件
chartLinkageOk(){
let arr = [...this.clParamData]
for(let item of arr){
item.dbCode = this.currentDbCode
item.fieldName = this.fieldName
}
let obj = {
reportId: this.reportId,
linkName: this.linkName,
linkChartId: this.linkChartId,
linkType: '2',
parameter: JSON.stringify(arr)
}
if(this.linkId){
obj['id'] = this.linkId
}
obj['requirement'] = this.requirement
$http.post({
url:api.linkSaveAndEdit,
contentType:'json',
data:JSON.stringify(obj),
success:(linkId)=>{
// 返回保存的联动表的ID
this.chartLinkageShow = false
this.$emit('ok',linkId)
}
});
},
chartLinkageCancel(){
this.chartLinkageShow = false
},
// 图表下拉框改变事件
chartLinkageChange(value){
for(let i=0;i<this.existChartList.length;i++){
if(value === this.existChartList[i]['id']){
this.selectedChart = this.existChartList[i]
}
}
this.getLinkageChartInfo();
},
// 图表下拉框改变 请求后台获取当前图标的字段 和 联动图标的参数信息
getLinkageChartInfo(){
let param = {
reportId: this.reportId,
linkageDbCode: this.selectedChart.db,
dbCode: this.currentChart.db
}
$http.get(
{
url: api.getLinkageChartInfo,
data: param,
success: (result) => {
// console.log(112,result)
// 设置被联动图表的参数接收
handleLinkageParams.call(this, result.paramList)
// 设置当前图表的字段字典信息
handleLinkageFields.call(this, result.fieldList)
// 编辑页面 如果切换下拉选项 再切回来 需要将初始数据显示出来
handleLinkageOldParam.call(this)
}
});
},
/**
* 获取报表参数下拉选项
* @param data
* @returns {*[]|[{title: string, value: *}, {title: string, value: *}]}
*/
getChartParamSelectOptions() {
let arr = []
for(let item of this.fieldList){
arr.push({
title: item.fieldText, value: item.title
})
}
/*arr.push({
title: '自定义', value: '-1'
})*/
return arr;
},
// 新增参数
addClParam(){
let arr = this.clParamData
arr.push({
index: arr.length+1,
paramName: '',
paramValue: ''
})
this.clParamData = [...arr]
},
// 参数移除事件
removeClParam(){
let indexArray = this.selectedClParams
// 先过滤
let arr = this.clParamData.filter(k=>{
return indexArray.indexOf(k.index)<0
})
// 重排序
for(let i=0;i<arr.length;i++){
arr[i]['index'] = i+1
}
// 赋值
this.clParamData = [...arr]
},
// 参数选中改变事件
handleClParamSelected(selections){
// console.log('selections', selections)
let arr = []
selections.map(k=>{
arr.push(k.index)
})
this.selectedClParams = arr
}
}
})
</script>

View File

@@ -0,0 +1,60 @@
<script type="text/x-template" id="central-point-setting-template">
<div >
<Submenu name="5" style="border-bottom: inset 1px; " class="rightFontSize">
<template slot="title">
<span>中心点设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>x轴&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="centralPoint.center[0]" @on-change="onMarginChange" style="margin-left: 5px;width: 164px" :value="centralPoint.center[0]"></i-input>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">y轴&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="centralPoint.center[1]" @on-change="onMarginChange" style="margin-left: 5px;width: 164px" :value="centralPoint.center[1]"></i-input>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-central-point-setting', {
template: '#central-point-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
},
},
data(){
return {
centralPoint: {
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
// console.log("我进来了")
this.initData()
}
}
},
methods: {
initData: function (){
// console.log(this.centralPoint,"我进来了")
if (this.settings){
this.centralPoint = Object.assign(this.centralPoint, this.settings)
}
},
onMarginChange (){
this.$emit('change',this.centralPoint)
}
}
})
</script>

View File

@@ -0,0 +1,375 @@
<script type="text/x-template" id="chart-linkage-template">
<Modal
width="600px"
title="图表联动"
v-model="chartLinkageShow"
:closable = "true"
:mask-closable="false">
<div slot="footer">
<i-button @click="chartLinkageCancel">取消</i-button>
<i-button type="primary" @click="chartLinkageOk">确定</i-button>
</div>
<i-form :label-width="100">
<form-item label="链接名称">
<i-input placeholder="请填写链接名称" v-model="linkName"></i-input>
</form-item>
<form-item label="链接图表">
<i-select v-model="linkChartId" filterable @on-change="chartLinkageChange">
<i-option v-for="(item, index) in existChartList" :key="index" placeholder="请选择链接图表" :value="item.id">{{ item.name }}</i-option>
</i-select>
</form-item>
<form-item label="条件">
<i-input placeholder="请填写条件" v-model="requirement"></i-input>
</form-item>
<span>参数设置</span>
<div style="margin-top: 10px">
<i-button type="primary" @click="addClParam">新增</i-button>
<i-button @click="removeClParam" v-if="selectedClParams.length>0">删除</i-button>
<i-table
style="margin-top: 10px"
ref="paramTable"
@on-selection-change="handleClParamSelected"
stripe
:columns="clParamColumns"
:data="clParamData">
</i-table>
</div>
</i-form>
</Modal>
</script>
<script>
/**
* 处理 字段
* @param list
*/
function handleLinkageFields(list) {
let { x, y, z } = this.currentChart
let arr = []
arr.push(x)
arr.push(y)
arr.push(z)
let dictInfo = {}
for(let item of list){
if(item.dictCode && arr.indexOf(item.fieldName)>=0){
dictInfo[item.fieldName] = item.dictCode
}
}
this.dictInfo = dictInfo
}
/**
* 处理参数
* @param list
*/
function handleLinkageParams(list) {
let ls = []
let index = 0
for(let item of list){
ls.push({
paramName: item.paramName,
paramValue: '',
index: ++index
})
}
this.clParamData = ls
}
function handleLinkageOldParam(){
const { selectedChart, oldConfig } = this
if(selectedChart.id == oldConfig.linkChartId){
this.clParamData = [...oldConfig.params]
}
}
Vue.component('j-chart-linkage', {
template: '#chart-linkage-template',
props: {
settings: {
type: Object,
required: true,
default:()=>{}
}
},
data(){
return {
chartLinkageShow: false,
linkId: '',
reportId: '',
linkType: '2',
linkName: '',
linkChartId: '',
requirement:'',
currentChart:'',
selectedChart: '',
existChartList: [],
dictInfo: '',
clParamData:[],
selectedClParams: [],
clParamColumns:[
{
type: 'selection',
width: 35,
align: 'center'
},{
title: '映射参数',
key: 'paramName',
render: (h, params) => {
return h('i-input', {
props: {
"size":"small",
type: 'text',
value: this.clParamData[params.index].paramName,
placeholder: `请输入参数名`
},
on: {
'on-blur': (event) => {
this.clParamData[params.index].paramName = event.target.value;
}
},
})
}
},{
title: '原始参数',
key: 'paramValue',
render: (h, params) => {
let paramSelectOptions = this.getChartParamSelectOptions()
return h('i-select', {
props: {
size:'small',
transfer: true,
value: this.clParamData[params.index].paramValue,
clearable: true,
},
on: {
'on-change': (value) => {
this.clParamData[params.index].paramValue = value;
}
},
},
paramSelectOptions.map(item => {
return h('i-option', {
props: {
value: item.value
}
}, item.title)
})
);
}
}
]
}
},
created(){
this.settingsDivHeight = window.innerHeight - 100
},
watch:{
settings:{
deep: true,
immediate: true,
handler: function(){
// this.resetForm()
}
}
},
methods:{
// 清空
clearChartLinkage(){
this.linkId = ''
this.reportId = ''
this.linkName = ''
this.requirement = ''
this.linkChartId = ''
// 当前图表
this.currentChart = ''
// 联动下拉框选中的图表
this.selectedChart = ''
// 字典信息
this.dictInfo = ''
// 联动下拉框的集合数据xs.get获取
this.existChartList = []
// 图表联动参数数据
this.clParamData = []
// 选中的参数index集合 删除用到
this.selectedClParams = []
// 编辑页面回显数据 参数记录
this.oldConfig = {}
},
addChartLinkage(existChartList, currentChartId){
this.clearChartLinkage()
this.reportId = excel_config_id
this.linkType = '2'
this.initChartList(existChartList, currentChartId)
this.chartLinkageShow = true
},
editChartLinkage(existChartList, currentChartId, row){
// 需要给row赋值
/* apiMethod: null
apiUrl: null
ejectType: null
id: "552823131696795648"
linkChartId: "b9Nqn1FauH9p5C1I"
linkName: "121212"
linkType: "2"
parameter: "[{\"paramName\":\"sex\",\"paramValue\":\"sex\",\"index\":1}]"
reportId: "552378751072604160"*/
this.clearChartLinkage()
this.linkId = row.id
this.linkChartId = row.linkChartId
this.linkName = row.linkName
this.requirement = row.requirement
this.linkType = row.linkType
this.reportId = row.reportId
if(row.parameter){
let arr = JSON.parse(row.parameter)
this.clParamData = [...arr]
this.oldConfig = {
linkChartId: row.linkChartId,
params: [...arr]
}
}
this.initChartList(existChartList, currentChartId)
this.chartLinkageShow = true
},
initChartList(existChartList, currentChartId){
if(existChartList && existChartList.length>0){
let arr1 = existChartList.filter(item=>{
return item.id!=currentChartId
});
let arr2 = existChartList.filter(item=>{
return item.id==currentChartId
});
this.existChartList = [...arr1]
this.currentChart = arr2[0]
}
},
// 确定事件
chartLinkageOk(){
let obj = {
reportId: this.reportId,
linkName: this.linkName,
requirement: this.requirement,
linkChartId: this.linkChartId,
linkType: '2',
parameter: JSON.stringify(this.clParamData)
}
if(this.linkId){
obj['id'] = this.linkId
}
$http.post({
url:api.linkSaveAndEdit,
contentType:'json',
data:JSON.stringify(obj),
success:(linkId)=>{
// 返回保存的联动表的ID
this.chartLinkageShow = false
this.$emit('ok',linkId)
}
});
},
chartLinkageCancel(){
this.chartLinkageShow = false
},
// 图表下拉框改变事件
chartLinkageChange(value){
for(let i=0;i<this.existChartList.length;i++){
if(value === this.existChartList[i]['id']){
this.selectedChart = this.existChartList[i]
}
}
this.getLinkageChartInfo();
},
// 图表下拉框改变 请求后台获取当前图标的字段 和 联动图标的参数信息
getLinkageChartInfo(){
let param = {
reportId: this.reportId,
linkageDbCode: this.selectedChart.db,
dbCode: this.currentChart.db
}
$http.get(
{
url: api.getLinkageChartInfo,
data: param,
success: (result) => {
// console.log(112,result)
// 设置被联动图表的参数接收
handleLinkageParams.call(this, result.paramList)
// 设置当前图表的字段字典信息
handleLinkageFields.call(this, result.fieldList)
// 编辑页面 如果切换下拉选项 再切回来 需要将初始数据显示出来
handleLinkageOldParam.call(this)
}
});
},
/**
* 获取报表参数下拉选项
* @param data
* @returns {*[]|[{title: string, value: *}, {title: string, value: *}]}
*/
getChartParamSelectOptions() {
let data = this.currentChart
if(!data){
console.log("未选择联动图表!")
return []
}
if(!data.x || !data.y){
console.log("图表未正确配置数据源!")
return []
}
let arr = [{
title: '图表分类属性', value: 'name',
},{
title: '图表值属性', value: 'value'
}]
if(data.z){
arr.push({
title: '图表系列属性', value: 'seriesName'
})
}
return arr;
},
// 新增参数
addClParam(){
let arr = this.clParamData
arr.push({
index: arr.length+1,
paramName: '',
paramValue: ''
})
this.clParamData = [...arr]
},
// 参数移除事件
removeClParam(){
let indexArray = this.selectedClParams
// 先过滤
let arr = this.clParamData.filter(k=>{
return indexArray.indexOf(k.index)<0
})
// 重排序
for(let i=0;i<arr.length;i++){
arr[i]['index'] = i+1
}
// 赋值
this.clParamData = [...arr]
},
// 参数选中改变事件
handleClParamSelected(selections){
//console.log('selections', selections)
let arr = []
selections.map(k=>{
arr.push(k.index)
})
this.selectedClParams = arr
}
}
})
</script>

View File

@@ -0,0 +1,693 @@
<script type="text/x-template" id="data-dictionary">
<div class="dictClass">
<Modal
:loading="loading"
width="100%"
v-model="dictShow"
:title="moduleTitle"
fullscreen=true
:closable="true"
:mask-closable="false">
<div slot="footer">
<i-button @click="close">关闭</i-button>
</div>
<#--查询-->
<div style="margin-top: 10px;display: flex;width: 100%">
<i-form style="width: 100%" ref="queryParam" :model="queryParam" :label-width="80">
<row>
<i-col span="4">
<form-item label="字典名称" prop="dictName">
<i-input v-model="queryParam.dictName" placeholder="请填写字典名称"></i-input>
</form-item>
</i-col>
<i-col span="4">
<form-item label="字典编号" prop="dictCode">
<i-input v-model="queryParam.dictCode" placeholder="请填写字典编号"></i-input>
</form-item>
</i-col>
<i-col span="4" style="margin-left: 20px">
<i-button type="primary" @click="loadData(1)">查询</i-button>
<i-button @click="resetParam">清空</i-button>
</i-col>
</row>
</i-form>
</div>
<#--begin字典-->
<div style="margin-top: 10px">
<i-button type="primary" @click="dictClick">添加</i-button>
<i-button icon="ios-loading" type="primary" @click="dictReflesh">刷新缓存</i-button>
<i-button v-if="dictDeleteShow==true" type="error" @click="dictDeleteBatch">删除</i-button>
</div>
<div style="margin-top: 10px">
<i-table @on-selection-change="dictTableSelect" border stripe :columns="dictData.columns" :data="dictData.data"
style="margin-top: 1%;">
<template slot-scope="{ row, index }" slot="action">
<i-button type="primary" size="small" @click="editDict(row)">编辑</i-button>
<i-button type="primary" size="small" @click="dictConfig(row.id)">字典配置</i-button>
<Poptip
confirm
placement="left"
title="确定要删除吗?"
:transfer="true"
@on-ok="dictRemove(row)">
<i-button type="error" size="small" >删除</i-button>
</Poptip>
</template>
</i-table>
<div class="page">
<Page
:total="dictData.page.total"
show-total
show-elevator
@on-change="handleCurrentChange"
@on-page-size-change="handleSizeChange">
</Page>
</div>
</div>
<#--字典编辑和新增 begin-->
<Modal
width="36%"
v-model="createDictShow"
:title="dictTitle"
:mask-closable="false"
:closable="false"
>
<div slot="footer">
<i-button @click="cancelReset('dictModel')">取消</i-button>
<i-button :loading="createDictLoading" type="primary" @click="createDictOk('dictModel')">确定</i-button>
</div>
<i-form ref="dictModel" :model="dictModel" :rules="dictModelRule" :label-width="100" class="dict">
<form-item label="字典名称:" prop="dictName">
<i-input v-model="dictModel.dictName" placeholder="请填写字典名称"/>
</form-item>
<form-item label="字典编码:" prop="dictCode">
<i-input v-model="dictModel.dictCode" placeholder="请填写字典编码"/>
</form-item>
<form-item label="描述:" prop="description">
<i-input v-model="dictModel.description"/>
</form-item>
</i-form>
</Modal>
<#--字典编辑和新增 end-->
<#--回收站 begin-->
<Modal
width="50%"
v-model="recycleBinShow"
title="回收站"
:mask-closable="false"
:closable="false"
>
<div slot="footer">
<i-button @click="recycleBinReset">关闭</i-button>
</div>
<div style="margin-top: 10px">
<i-table border stripe :columns="recycleBin.columns" :data="recycleBin.data"
style="margin-top: 1%;">
<template slot-scope="{ row, index }" slot="action">
<i-button type="primary" size="small" style="cursor: pointer" @click="recycleBinRetrieve(row.id)">取回</i-button>
<Poptip
confirm
placement="left"
title="确定要彻底删除吗"
content="删除之后不可取回"
:transfer="true"
@on-ok="recycleBinDelete(row.id)">
<i-button type="error" size="small">彻底删除</i-button>
</Poptip>
</template>
</i-table>
</div>
</Modal>
<#--回收站 end-->
<#--end字典-->
<#--字典配置页面 begin-->
<Drawer :transfer="true" class="dictDrawer" width="500" title="字典列表" v-model="itemDrawer">
<div style="margin-top: 10px">
<i-button type="primary" @click="dictItemClick">添加</i-button>
</div>
<div style="margin-top: 10px">
<i-table border stripe
:columns="dictItemList.columns"
:data="dictItemList.data"
:rowClassName="getRowClassname"
style="margin-top: 1%;">
<template slot-scope="{ row, index }" slot="action">
<i-button type="primary" size="small" @click="editItemDict(row)">编辑</i-button>
<Poptip
confirm
placement="left"
title="确定要删除吗?"
:transfer="true"
@on-ok="dictItemRemove(row)">
<i-button type="error" size="small">删除</i-button>
</Poptip>
</template>
</i-table>
<div class="page">
<Page
:total="dictItemList.page.total"
show-total
show-elevator
@on-change="handleItemCurrentChange"
@on-page-size-change="handleItemSizeChange">
</Page>
</div>
</div>
</Drawer>
<#--字典详细新增和编辑 begin-->
<Modal
width="50%"
v-model="createDictItemShow"
:title="dictItemTitle"
class-name="dictItem"
:closable="false"
:mask-closable="false"
>
<div slot="footer">
<i-button @click="cancelItemReset('dictItemModel')">取消</i-button>
<i-button :loading="createDictItemLoading" type="primary" @click="createItemDictOk('dictItemModel')">确定
</i-button>
</div>
<i-form ref="dictItemModel" :model="dictItemModel" :rules="dictItemModelRule" :label-width="100" class="dict">
<form-item label="名称:" prop="itemText">
<i-input v-model="dictItemModel.itemText" placeholder="请填写名称"/>
</form-item>
<form-item label="数据值:" prop="itemValue">
<i-input v-model="dictItemModel.itemValue" placeholder="请填写数据值"/>
</form-item>
<form-item label="描述:" prop="description">
<i-input v-model="dictItemModel.description"/>
</form-item>
<form-item label="排序值:" prop="sortOrder">
<input-number :step="1" v-model="dictItemModel.sortOrder" :min="1"/>
</form-item>
<form-item label="是否启用:" prop="status">
<i-switch v-model="dictItemModel.status" :true-value="1" :false-value="0"/>
</form-item>
</i-form>
</Modal>
<#--字典详细新增和编辑 end-->
<#--字典配置页面 end-->
</Modal>
</div>
</div>
</script>
<script>
Vue.component('j-data-dictionary', {
template: '#data-dictionary',
data() {
return {
moduleTitle: "数据字典",
loading: false,
dictShow: false,
dictData: {
data: [],
columns: [
{
type: 'selection',
width: 60,
align: 'center'
},
{
title: '字典名称',
key: 'dictName',
align: 'center'
},
{
title: '字典编号',
key: 'dictCode',
align: 'center'
},
{
title: '描述',
key: 'description',
align: 'center'
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center',
slot: 'action'
},
],//字典集合
page: { //分页参数
page: 1,
size: 10,
total: 0,
},
},
dictItemList: {
data: [],
columns: [
{
title: '名称',
key: 'itemText',
align: 'center'
},
{
title: '数据值',
key: 'itemValue',
align: 'center'
},
{
title: '操作',
key: 'action',
width: 150,
align: 'center',
slot: 'action'
},
],//字典集合
page: { //分页参数
page: 1,
size: 10,
total: 0,
},
},//字典详细集合
recycleBin: {
data: [],
columns: [
{
type: 'selection',
width: 60,
align: 'center'
},
{
title: '字典名称',
key: 'dictName',
align: 'center'
},
{
title: '字典编号',
key: 'dictCode',
align: 'center'
},
{
title: '描述',
key: 'description',
align: 'center'
},
{
title: '操作',
key: 'action',
width: 150,
align: 'center',
slot: 'action'
},
],
},//回收站
createDictShow: false,
dictTitle: "添加字典",
dictItemTitle: "新增",
dictModel: {
id: "",
dictName: "",
dictCode: "",
description: ""
}, //新增字典集合
dictItemModel: {
id: "",
itemText: "",
itemValue: "",
description: "",
sortOrder: 1,
status: 1,
},
dictItemModelRule: {
itemText: [
{required: true, message: '请输入名称', trigger: 'blur'}
],
itemValue: [
{required: true, message: '请输入数据值', trigger: 'blur'}
],
},
dictModelRule: {
dictName: [
{required: true, message: '请输入字典名称', trigger: 'blur'}
],
dictCode: [
{required: true, message: '请输入字典编码', trigger: 'blur'}
],
},//字典验证
createDictLoading: false,
//批量删除按钮是否显示
dictDeleteShow: false,
//批量删除选中的数据
dictSelectData: [],
//抽屉显示事件
itemDrawer: false,
dictId: "", //字典id
createDictItemShow: false, //字典详细是否显示
createDictItemLoading: false,
recycleBinShow:false, //回收站显示
queryParam:{} //查询条件
}
},
created() {
this.loadData()
},
watch: {
dictShow: {
deep: true,
immediate: true,
handler: function (val){
if(!val){
this.itemDrawer=false
this.createDictShow=false
this.createDictItemShow=false
}
}
},
},
methods: {
loadData(arg) {
//加载数据列表
let that = this;
let data = {}
//update-begin---author:wangshuai ---date:20220720 for[VUEN-1657]积木报表的字典查询,不好使输入 sex 或者性别都查不到数据------------
if(arg){
data.pageNo = arg
}else{
data.pageNo = that.dictData.page.page
}
//update-end---author:wangshuai ---date:20220720 for[VUEN-1657]积木报表的字典查询,不好使输入 sex 或者性别都查不到数据--------------
data.pageSize = that.dictData.page.size
if(this.queryParam.dictCode){
data.dictCode=this.queryParam.dictCode
}
if(this.queryParam.dictName){
data.dictName=this.queryParam.dictName
}
$http.get({
url: api.dictList,
data: data,
success: (res) => {
that.dictData.data = res.records;
that.dictData.page.size = res.size;
that.dictData.page.total = res.total;
}
});
},
resetParam(){
this.queryParam={}
//update-begin---author:wangshuai ---date:20220720 for[VUEN-1657]积木报表的字典查询,不好使输入 sex 或者性别都查不到数据------------
this.loadData(1)
//update-end---author:wangshuai ---date:20220720 for[VUEN-1657]积木报表的字典查询,不好使输入 sex 或者性别都查不到数据------------
},
loadItemData() {
//加载数据列表
let that = this;
$http.get({
url: api.dictItemList,
data: {
pageNo: that.dictItemList.page.page,
pageSize: that.dictItemList.page.size,
dictId: this.dictId
},
success: (res) => {
that.dictItemList.data = res.records;
that.dictItemList.page.size = res.size;
that.dictItemList.page.total = res.total;
}
});
},
handleSizeChange(val) {
this.dictData.page.size = val;
this.loadData();
},
handleCurrentChange(val) {
this.dictData.page.page = val;
this.loadData();
},
//字典新增
dictClick() {
this.moduleTitle = "添加字典"
this.createDictShow = true
},
//字典添加和修改确定操作
createDictOk(name) {
let that = this
this.$refs[name].validate((valid) => {
if (valid) {
this.createDictLoading = true
let url = ""
if (that.dictModel.id) {
url = api.dictEdit
} else {
url = api.dictAdd
}
$http.post({
url: url,
contentType: 'json',
data: JSON.stringify(that.dictModel),
success: (res) => {
this.createDictShow = false
that.dictModel = {};
this.loadData()
},
finally: () => {
this.createDictLoading = false
}
})
}
})
},
createItemDictOk(name) {
let that = this
this.$refs[name].validate((valid) => {
if (valid) {
this.createDictItemLoading = true
let url = ""
if (that.dictItemModel.id) {
url = api.dictItemEdit
} else {
url = api.dictItemAdd
}
that.dictItemModel.dictId = this.dictId
if (!that.dictItemModel.sortOrder) {
that.dictItemModel.sortOrder = 1
}
if (that.dictItemModel.status ==undefined) {
that.dictItemModel.status = 1
}
//console.log(that.dictItemModel);
$http.post({
url: url,
contentType: 'json',
data: JSON.stringify(that.dictItemModel),
success: (res) => {
this.createDictItemShow = false
that.dictItemModel = {};
this.loadItemData()
},
finally: () => {
this.createDictItemLoading = false
}
})
}
})
},
//表单验证情况清空
cancelReset(name) {
this.$refs[name].resetFields();
this.createDictShow = false
this.dictModel = {};
this.loadData()
},
cancelItemReset(name) {
this.$refs[name].resetFields();
this.createDictItemShow = false
this.dictItemModel = {};
this.loadItemData()
},
//字典编辑
editDict(row) {
this.moduleTitle = "修改字典"
this.dictModel = row
this.createDictShow = true
},
//字典删除
dictRemove(row) {
let id = row.id;
$http.del({
url: api.dictDelete,
data: {"id": id},
success: (res) => {
this.loadData()
}
})
},
//字典详情删除
dictItemRemove(row) {
let id = row.id;
$http.del({
url: api.dictItemDelete,
data: {"id": id},
success: (res) => {
this.loadItemData()
}
})
},
//复选框选中事件
dictTableSelect(selection) {
if (selection.length > 0) {
this.dictDeleteShow = true
this.dictSelectData = selection
} else {
this.dictDeleteShow = false
}
},
//批量删除点击事件
dictDeleteBatch() {
let dictSelectData = this.dictSelectData
let ids = ""
for (const dictSelectDatum of dictSelectData) {
let id = dictSelectDatum.id;
ids = ids + id + ","
}
if (ids.length > 1) {
ids = ids.substr(0, ids.lastIndexOf(","))
}
this.$Modal.confirm({
title: "批量删除",
content: "确定要删除吗",
closable: true,
onOk: (res) => {
$http.del({
url: api.dictDeleteBatch,
data: {"ids": ids},
success: (res) => {
this.loadData()
}
})
},
});
},
//字典配置选项
dictConfig(id) {
this.itemDrawer = true
this.dictId = id
this.loadItemData()
},
handleItemSizeChange(val) {
this.dictItemList.page.size = val;
this.loadItemData()
},
handleItemCurrentChange(val) {
this.dictItemList.page.page = val;
this.loadItemData()
},
//字典详细添加
dictItemClick() {
this.dictItemModel = {}
this.dictItemTitle = "新增"
this.dictItemModel.status = 1
this.createDictItemShow = true
},
//字典详情编辑
editItemDict(row) {
//console.log(row)
this.dictItemTitle = "修改"
this.dictItemModel = row
this.createDictItemShow = true
},
close() {
this.dictShow = false
this.resetParam()
},
getRowClassname(row) {
if (row.status == 0) {
return "data-rule-invalid"
}
},
//刷新缓存
dictReflesh() {
let that = this
$http.get({
url: api.refleshCache,
success: (res) => {
that.$Message.success(res);
}
})
},
//回收站点击按钮事件
recycleBinClick(){
this.recycleBinShow = true
this.loadRecycleBin();
},
//回收站关闭事件
recycleBinReset(){
this.recycleBinShow = false
},
//加载回收站数据
loadRecycleBin(){
$http.get({
url:api.deleteList,
success: (res) => {
this.recycleBin.data = res
}
})
},
//回收站字典取回
recycleBinRetrieve(id){
$http.post({
url: api.back,
contentType: 'json',
data: {"id": id},
success: (res) => {
this.loadRecycleBin()
this.loadData()
}
})
},
//回收站字典彻底删除
recycleBinDelete(id){
$http.del({
url:api.thoroughDelete,
data: {"id": id},
success: (res) => {
this.loadRecycleBin()
}
})
}
}
})
</script>
<style>
.dict .ivu-form-item {
margin-bottom: 24px !important;
}
.ivu-drawer-mask {
z-index: 2000 !important;
}
.ivu-drawer-wrap {
z-index: 2000 !important;
}
.dictItem {
z-index: 2025 !important;
}
.ivu-poptip-popper {
z-index: 9999 !important;
}
.data-rule-invalid {
background: #f4f4f4;
color: #bababa;
}
.ivu-table-stripe .ivu-table-body tr:nth-child(2n) td {
background-color: #ffffff;
}
.ivu-btn-small {
font-size: 12px;
}
</style>

View File

@@ -0,0 +1,87 @@
<script type="text/x-template" id="funnel-setting-template">
<Submenu name="6" style="border-bottom: inset 1px;" class="rightFontSize dataSourceForm">
<template slot="title">
<span>漏斗设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>图形间距&nbsp;&nbsp;</p>
<slider v-model="funnelOptions.gap" @on-change="onFunnelChange" style="margin-top: -9px;width: 139px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>数据排序&nbsp;&nbsp;</p>
<i-select size="small" class="iSelect" v-model="funnelOptions.sort" @on-change="onFunnelChange">
<i-option class="rightFontSize" value="ascending">升序</i-option>
<i-option class="rightFontSize" value="descending">降序</i-option>
<i-option class="rightFontSize" value="none">无序</i-option>
</i-select>
</Row>
<Row class="ivurow">
<p>宽度(%)&nbsp;&nbsp;&nbsp;</p>
<slider :tip-format="util.percentFormat" :value="util.getNumberFromPercent(funnelOptions.width)" @on-change="(value)=>onPercentChange(value, 'funnelOptions.width','onFunnelChange')" style="margin-top: -9px;width: 139px;margin-left: 5px;"></slider>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-funnel-setting', {
template: '#funnel-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
},
isMultiChart: {
type: Boolean,
default: false
}
},
data(){
return {
funnelOptions: {
gap:2,
sort: "descending",
width: "80%"
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.funnelOptions = Object.assign(this.funnelOptions, this.settings)
}
},
//slider 百分数改变事件
onPercentChange(value, key, eventName,suffix=''){
let arr = key.split('.')
if(arr.length>1){
let temp = this
for(let i=0;i<arr.length-1;i++){
temp = temp[arr[i]]
}
temp[arr[arr.length-1]] = value+'%'+suffix
}else{
this[key] = value+'%'+suffix
}
//this[eventName]();
this.$emit('change', this.funnelOptions)
},
onFunnelChange(){
this.$emit('change', this.funnelOptions)
}
}
})
</script>

View File

@@ -0,0 +1,145 @@
<script type="text/x-template" id="gauge-setting-template">
<div>
<Submenu name="20" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>仪表盘数据设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>标题显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 115px;" v-model="gaugeOption.title_show" @on-change="onGaugeChange"/>
</Row>
<Row class="ivurow">
<p>标题字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="gaugeOption.title_textStyle_fontSize" @on-blur="onGaugeChange" style="width: 119px;"></i-input>
</Row>
<Row class="ivurow" v-if="typeof gaugeOption.title_textStyle_color !== 'undefined'">
<p>标题颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="gaugeOption.title_textStyle_color" size="small" style="width:143px;" @on-change="onGaugeChange">
<span slot="append">
<color-picker class="colorPicker" v-model="gaugeOption.title_textStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onGaugeChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow">
<p>指针显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 116px;" v-model="gaugeOption.pointer_show" @on-change="onGaugeChange"/>
</Row>
<Row class="ivurow" v-if="typeof gaugeOption.itemStyle_color !== 'undefined'">
<p>指针颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="gaugeOption.itemStyle_color" size="small" style="width:143px;" @on-change="onGaugeChange">
<span slot="append">
<color-picker class="colorPicker" v-model="gaugeOption.itemStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onGaugeChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow">
<p>指针字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="gaugeOption.detail_textStyle_fontSize" @on-blur="onGaugeChange" style="width: 119px;"></i-input>
</Row>
<Row class="ivurow" v-if="typeof gaugeOption.detail_textStyle_color !== 'undefined'">
<p>指针字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="gaugeOption.detail_textStyle_color" size="small" style="width: 119px;" @on-change="onGaugeChange">
<span slot="append">
<color-picker class="colorPicker" v-model="gaugeOption.detail_textStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onGaugeChange"/>
</span>
</i-input>
</Col>
</Row>
</div>
</Submenu>
<Submenu name="21" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>仪表盘刻度设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>刻度值显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 104px;" v-model="gaugeOption.axisLabel_show" @on-change="onGaugeChange"/>
</Row>
<Row class="ivurow">
<p>刻度值字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="gaugeOption.axisLabel_textStyle_fontSize" @on-blur="onGaugeChange" style="width: 108px"></i-input>
</Row>
<Row class="ivurow">
<p>仪表盘半径(%)&nbsp;&nbsp;</p>
<slider :tip-format="util.percentFormat" :value="util.getNumberFromPercent(gaugeOption.radius)" @on-change="(value)=>onPercentChange(value, 'gaugeOption.radius','onGaugeChange')" style="margin-top: -9px;width: 109px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>轴线宽度&nbsp;&nbsp;</p>
<slider max="50" step="5" v-model="gaugeOption.axisLine_lineStyle_width" @on-change="onGaugeChange" style="margin-top: -9px;width: 139px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>分割线长度&nbsp;&nbsp;</p>
<slider max="50" step="2" v-model="gaugeOption.splitLine_length" @on-change="onGaugeChange" style="margin-top: -9px;width: 128px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>刻度线长度&nbsp;&nbsp;</p>
<slider max="50" step="2" v-model="gaugeOption.axisTick_length" @on-change="onGaugeChange" style="margin-top: -9px;width: 128px;margin-left: 5px;"></slider>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-gauge-setting', {
template: '#gauge-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
gaugeOption: {
title_textStyle_color:'',
detail_textStyle_color:'',
itemStyle_color:''
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.gaugeOption = Object.assign(this.gaugeOption, this.settings)
}
},
//slider 百分数改变事件
onPercentChange(value, key, eventName,suffix=''){
let arr = key.split('.')
if(arr.length>1){
let temp = this
for(let i=0;i<arr.length-1;i++){
temp = temp[arr[i]]
}
temp[arr[arr.length-1]] = value+'%'+suffix
}else{
this[key] = value+'%'+suffix
}
//this[eventName]();
this.$emit('change', this.gaugeOption)
},
onGaugeChange(){
this.$emit('change', this.gaugeOption)
}
}
})
</script>

View File

@@ -0,0 +1,66 @@
<script type="text/x-template" id="grid-setting-template">
<div>
<Submenu name="18" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>坐标轴边距</span>
</template>
<div class="blockDiv">
<Row class="ivurow">
<p>左边距&nbsp;&nbsp;</p>
<slider v-model="gridOptions.left" @on-change="onGridChange" style="margin-top: -9px;width: 145px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>顶边距&nbsp;&nbsp;</p>
<slider v-model="gridOptions.top" @on-change="onGridChange" style="margin-top: -9px;width: 145px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>右边距&nbsp;&nbsp;</p>
<slider v-model="gridOptions.right" @on-change="onGridChange" style="margin-top: -9px;width: 145px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">底边距&nbsp;&nbsp;</p>
<slider v-model="gridOptions.bottom" @on-change="onGridChange" style="margin-top: -9px;width: 145px;margin-left: 5px;"></slider>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-grid-setting', {
template: '#grid-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
gridOptions: {
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.gridOptions = Object.assign(this.gridOptions, this.settings)
}
},
onGridChange (){
this.$emit('change','grid',this.gridOptions)
}
}
})
</script>

View File

@@ -0,0 +1,567 @@
<style>
.jimu-table-tip{
font-weight: bold;
display: inline-block;
margin-left: 5px;
}
</style>
<script type="text/x-template" id="hyperlinks-setting-template">
<Modal
:title="title"
v-model="hyperlinksShow"
width="600px"
:closable = "false"
:mask-closable="false"
>
<div slot="footer">
<i-button @click="hyperlinksCancel('linkData')">取消</i-button>
<i-button type="primary" @click="hyperlinksOk('linkData')">确定
</i-button>
</div>
<i-form ref="linkData" :model="linkData" :label-width="100" :rules="linkDataRule">
<form-item label="链接名称" prop="linkName">
<i-input placeholder="请填写链接名称" v-model="linkData.linkName"></i-input>
</form-item>
<form-item label="链接报表" prop="reportId" v-if="linkData.linkType==='0'">
<i-select clearable v-model="linkData.reportId" filterable @on-change="networkClick">
<i-option v-for="item in reportData" placeholder="请选择链接报表" :value="item.id" :key="item.id">{{ item.name }}</i-option>
</i-select>
</form-item>
<form-item label="链接图表" prop="charId" v-if="linkData.linkType==='2'">
<i-select v-model="linkData.charId" filterable @on-change="charsClick">
<i-option v-for="item in chartData" placeholder="请选择链接图表" :value="item.id" :key="item.id">{{ item.name }}</i-option>
</i-select>
</form-item>
<form-item label="网络连接" prop="apiUrl" v-if="linkData.linkType=='1'">
<i-input placeholder="请填写网络连接" v-model="linkData.apiUrl"></i-input>
</form-item>
<form-item label="弹出方式" prop="ejectType" v-if="linkData.linkType=='0' || linkData.linkType=='1'">
<i-select clearable :transfer="true" v-model="linkData.ejectType">
<i-option value="0">新窗口</i-option>
<i-option value="1">当前窗口</i-option>
</i-select>
</form-item>
<form-item label="条件" prop="requirement">
<i-input placeholder="请填写条件" v-model="linkData.requirement"></i-input>
</form-item>
<span>参数设置</span>
<div style="margin-top: 10px">
<i-button type="primary" @click="addParamTable">新增</i-button>
<i-button type="primary" @click="removeParamTable" v-if="selectParamTables.length>0">删除</i-button>
<i-table
style="margin-top: 10px"
ref="paramTable"
@on-select="selectParam"
@on-select-all="selectParamAll"
@on-select-all-cancel="cancelParamAll"
@on-select-cancel="cancelParam"
stripe
:columns="hyperlinksData.columns"
:data="hyperlinksData.data"
:height="paramTableHeight">
</i-table>
</div>
</i-form>
</Modal>
</script>
<script>
Vue.component('j-hyperlinks-setting', {
template: '#hyperlinks-setting-template',
props: {
excel: {
type: String,
required: true,
default:""
}
},
data(){
return {
title:"",
hyperlinksShow:false,
fieldList:[],
hyperlinksData:{
columns: [
{
type: 'selection',
width: 35,
align: 'center'
},
{
title: '映射参数',
key: 'paramName',
align: 'center',
render: (h, params) => {
return this.renderInput(h, params, 'paramName','hyperlinksData')
}
},
{
title: '原始参数',
key: 'paramValue',
renderHeader: (h, params) => {
//update-begin--Author:wangshuai Date:20211213 for判断是够选中图表----
let selectChart = this.ifSelectChart();
//update-end--Author:wangshuai Date:20211213 for判断是够选中图表----
const sub = ()=>{
let arr = []
let it1 = h('span',params.column.title)
let it2 = h('Tooltip', {
props:{
placement: 'top',
transfer: true
}
}, [
h('span',{class:'jimu-table-tip'}, '?'),
h('div',{slot:'content', style:{'white-space':'normal'}}, [
h('p','1.支持下拉框选择数据集字段'),
h('p','2.支持表达式=A1表示A1单元格的值'),
h('p','3.支持表达式=A表示当前点击行所在的A列单元格的值')
])
])
arr.push(it1)
//update-begin--Author:wangshuai Date:20211213 for【JMREP-2470】如果当前点击的不是图表那么就显示问号提示----
if(!selectChart){
arr.push(it2)
}
//update-end--Author:wangshuai Date:20211213 for【JMREP-2470】如果当前点击的不是图表那么就显示问号提示----
return arr
}
return h('div', {}, sub())
},
render: (h, params) => {
let paramSelectOptions = this.getChartParamSelectOptions()
//update-begin--Author:wangshuai--Date:20211012--for:图表钻取的时候不显示自定义表达式
let assembly = this.randerSelectInput(params,paramSelectOptions);
let props = assembly.get("props")
let select = assembly.get("select")
assembly.clear()
return h(select, {
props: props,
//update-end--Author:wangshuai--Date:20211012--for:图表钻取的时候不显示自定义表达式
on: {
'on-change': (value) => {
this.hyperlinksData.data[params.index].paramValue = value;
}
},
},
paramSelectOptions.map(item => {
return h('i-option', {
props: {
value: item.value
}
}, item.title)
})
);
}
},
],
data:[],
},
selectParamTables:[],
paramTableHeight: 0,
linkData:{
id:"",
reportId:"",//积木设计器id
parameter:"",//参数JSON串
ejectType:"",//弹出方式0 当前页面 1 新窗口)
linkName:"",
apiMethod:"",
linkType:"",
apiUrl:"",
charId:"",
requirement:"",
},
reportData:[],//积木报表下拉框的数据
linkDataRule: {
reportId: [
{ required: true, message: '请选择链接目标', trigger: 'change' }
],
ejectType: [
{ required: true, message: '请选择弹出方式', trigger: 'change' },
],
linkName: [
{ required: true, message: '请填写链接名称', trigger: 'change' },
],
charId: [
{ required: true, message: '请选择链接图表', trigger: 'change' },
],
apiUrl: [
{ required: true, message: '请填写网络连接', trigger: 'change' },
{ validator: this.validateHttpExist, trigger: 'change' }
],
},
chartData:[],// 图表下拉框数据
paramData:[], //参数数据用于父页面传递参数便于监听
currentDbCode:"",
fieldName:"",
currentChart:"" //存放当前点击图表的数据
}
},
watch: {
'paramData': function(val) {
//先清空数据
this.hyperlinksData.data=[];
for (const valElement of val) {
if(valElement.paramName != 'charId'){
//为参数table添加数据
this.hyperlinksData.data.push(valElement)
}
}
}
},
created(){
},
methods:{
addParamTable(){
let indexArr = this.hyperlinksData.data.map(item=>item.tableIndex);
if(indexArr.length==0){
indexArr=[0];
}
this.selectParamTables = [];
this.hyperlinksData.data=[...this.hyperlinksData.data,{
'paramName':"",
'paramValue':"",
'paramCell':"",
'tableIndex':Math.max(...indexArr)+1
}];
},
removeParamTable(){
// this.deleteParamModel = true;
let tableIndexArr = this.selectParamTables.map(item=>item.tableIndex);
this.hyperlinksData.data = this.hyperlinksData.data.filter(item=>!tableIndexArr.includes(item.tableIndex));
this.selectParamTables = [];
},
selectParamAll(){
this.selectParamTables = this.hyperlinksData.data.map(item=>
{
return {"tableIndex":item.tableIndex,"id":item.id}
});
},
cancelParamAll(){
this.selectParamTables = [];
},
selectParam(selection,row){
this.selectParamTables=[...this.selectParamTables,{"tableIndex":row.tableIndex,"id":row.id}];
},
cancelParam(selection,row){
this.selectParamTables = this.selectParamTables.filter(item=>item.tableIndex!=row.tableIndex);
},
getReportByUser(fieldList,dbCode,fieldName,existChartList,chartId){
this.linkData.reportId = ""
this.linkData.ejectType = ""
this.fieldList = fieldList
this.currentDbCode = dbCode
this.fieldName = fieldName
$http.get({
url: api.getReportByUser,
data:{reportId:excel_config_id},
success:(result)=>{
this.reportData = result
}
})
if(vm.chartsflag){
this.initChartList(existChartList,chartId)
}
},
//初始化图表
initChartList(existChartList, currentChartId){
if(existChartList && existChartList.length>0){
let arr2 = existChartList.filter(item=>{
return item.id==currentChartId
});
if(arr2.length>0){
this.currentChart = arr2[0]
this.currentDbCode = arr2[0].db
}
}
},
getReportChars(){
let param={}
param.reportId = excel_config_id;
if(vm.chartsflag){
param.charId = vm.dataSettings.id
}
$http.get({
url: api.getReportChars,
data:param,
success:(result)=>{
this.chartData=[]
this.chartData = result
}
})
let parameter = this.linkData.parameter;
if(parameter){
let parse = JSON.parse(parameter);
let parameters = [];
for (let i = 0; i < parse.length; i++) {
let paramName = parse[i].paramName;
if(paramName =="charId"){
this.linkData.charId = parse[i].paramValue
}else{
let params={}
params.paramName= parse[i].paramName;
params.paramValue= parse[i].paramValue;
params.paramCell= parse[i].paramCell;
parameters.push(params)
}
}
this.linkData.parameter = parameters;
this.hyperlinksData.data = parameters;
}
},
//网络报表点击事件
networkClick(value){
let id = api.checkParam(value);
$http.get({
url: id,
success:(result)=>{
let linksData = [];
let i=0;
for (const data of result) {
let newData={}
newData.paramName = data.paramName
newData.paramValue = data.paramValue
newData.tableIndex = i
linksData.push(newData);
i++;
}
this.hyperlinksData.data = linksData
},
fail:()=>{
this.hyperlinksData.data=[];
}
})
},
hyperlinksOk(name){
this.$refs[name].validate((valid) => {
if (valid) {
let data = this.linkData;
let linksData = this.hyperlinksData.data;
for(let item of linksData){
item.dbCode = this.currentDbCode
item.fieldName = this.fieldName
}
data.parameter=JSON.stringify(linksData);
if(!data.reportId){
data.reportId = excel_config_id
}
$http.post({
url:api.linkSaveAndEdit,
contentType:'json',
data:JSON.stringify(data),
success:(result)=>{
if(!vm.chartsflag){
let split = this.excel.split(",");
let linkIds = xs.cellProp(split[0],split[1], "linkIds")
if(linkIds){
result=linkIds+","+result
}
xs.cellProp(split[0],split[1], {linkIds: result})
xs.cellProp(split[0],split[1], {display: "link"})
this.$emit('lingcallback',result)
}else{
let dataIds = vm.dataSettings['linkIds'];
let linkIds = "";
if(dataIds){
linkIds = dataIds+","+result;
}else{
linkIds = result;
}
let dataSettings = vm.dataSettings;
dataSettings['linkIds'] = linkIds
//更新ExtData
xs.updateChartExtData(vm.selectedChartId,dataSettings);
this.$emit('lingcallback',linkIds)
}
this.close(name);
}
});
}
})
},
hyperlinksCancel(name){
if(this.linkData){
this.$emit('lingcallback',this.linkData.id)
}
this.close(name);
},
//清除数据
close(name){
this.linkData.id="";
this.linkData.reportId="";
this.linkData.parameter="";
this.linkData.ejectType="";
this.linkData.linkName="";
this.linkData.apiMethod="";
this.linkData.linkType="";
this.linkData.apiUrl="";
this.linkData.charId = "";
this.reportData=[];
this.hyperlinksData.data=[];
this.selectParamTables=[];
this.chartData=[];
this.paramData=[]
this.fieldList=[]
this.dbCode=""
this.fieldName=""
this.hyperlinksShow=false
this.currentChart=""
this.$refs[name].resetFields();
},
renderInput(h, params, field,tabIndex,placeholder) {
let key = params.column.key;
let paramName = params.row.paramName;
if(this.linkData.linkType==='2' && paramName==='charId'){
return h('i-input', {
props: {
"size":"small",
type: 'text',
readonly:true,
value: this[tabIndex].data[params.index][field]
}
})
}else{
return h('i-input', {
props: {
"size":"small",
type: 'text',
value: this[tabIndex].data[params.index][field],
placeholder: placeholder?placeholder:`请输入`+params.column.title
},
on: {
'on-blur': (event) => {
if(tabIndex==="hyperlinksData"){
let tableIndexArr = this.selectParamTables.map(item=>item.tableIndex);
this.hyperlinksData.data.forEach(item=>{
if(tableIndexArr.includes(item.tableIndex)){
item._checked = true;
}
});
}
this[tabIndex].data[params.index][field] = event.target.value;
}
},
})
}
},
charsClick(val) {
this.linkData.charId=val
let id = api.checkParam(excel_config_id);
let that = this
$http.get({
url: id,
success: (result) => {
that.hyperlinksData.data = []
let i=2
let dataStr="";
for (const data of result) {
let newData = {}
if(dataStr.indexOf(data.paramName) == -1){
newData.paramName = data.paramName
newData.paramValue = data.paramValue
newData.tableIndex = i
that.hyperlinksData.data.push(newData);
dataStr = dataStr +data.paramName+",";
i++;
}
}
}
})
},
validateHttpExist(rule, value, callback){
if(value){
if(value.includes("http")){
callback();
}else{
callback(new Error('请输入http或https'));
}
}
},
/**
* 获取报表参数下拉选项
* @param data
* @returns {*[]|[{title: string, value: *}, {title: string, value: *}]}
*/
getChartParamSelectOptions() {
//判断是选择图表还是单元格
if(!vm.chartsflag){
let arr = []
for(let item of this.fieldList){
arr.push({
title: item.fieldText, value: item.title
})
}
return arr;
}else{
let data = this.currentChart
if(!data){
return []
}
if(!data.x || !data.y){
return []
}
let arr = [{
title: '图表分类属性', value: 'name',
},{
title: '图表值属性', value: 'value'
}]
if(data.z){
arr.push({
title: '图表系列属性', value: 'seriesName'
})
}
return arr;
}
},
//渲染select_input组件中的props
randerSelectInput(params,paramSelectOptions) {
//判断是选择图表还是单元格
let assembly = new Map();
let props = {};
if (!vm.chartsflag) {
props = {
options: paramSelectOptions,
size: 'small',
transfer: true,
value: this.hyperlinksData.data[params.index].paramValue,
clearable: true
}
assembly.set("select","j-select-input")
}else{
props = {
size:'small',
transfer: true,
value: this.hyperlinksData.data[params.index].paramValue,
clearable: true,
}
assembly.set("select","i-select")
}
assembly.set("props",props)
return assembly;
},
//判断是否选中图表
ifSelectChart(){
if(vm && vm.chartsflag){
return true;
}
return false;
}
},
})
</script>
<style>
.ivu-form-item-error-tip{
position:relative;
}
</style>

View File

@@ -0,0 +1,187 @@
<script type="text/x-template" id="jurisdiction">
<div>
<Modal
:loading="loading"
v-model="shareModal"
:title="moduleTitle"
@on-cancel="handleShareCancel"
@on-ok="handleShareOk"
ok-text="创建连接"
>
<i-form>
<form-item label="过期时间:">
<RadioGroup v-model="jurisdictionData.termOfValidity">
<Radio v-for="item in termValidity" :label="item.value" :key="item.value">
<span>{{item.label}}</span>
</Radio>
</RadioGroup>
</form-item>
<form-item label="是否开启密码:">
<RadioGroup v-model="jurisdictionData.previewLockStatus">
<Radio v-for="item in lockOption" :label="item.value" :key="item.value">
<span>{{item.label}}</span>
</Radio>
</RadioGroup>
</form-item>
</i-form>
</Modal>
<Modal
:loading="loading"
v-model="shareUrlModal"
title="分享链接"
@on-cancel="handleShareUrlCancel"
>
<p slot="footer">
<Button type="primary" @click="handleShareUrlOk">取消分享</Button>
</p>
<i-form>
<form-item label="预览链接:" style="display: flex">
<i-input v-model="jurisdictionData.previewUrl" readonly style="width: 400px"/>
</form-item>
<form-item label="预览密码" style="display: flex" v-if="jurisdictionData.previewLockStatus=='1'">
<i-input v-model="jurisdictionData.previewLock" readonly style="width: 100px"/>
<Button type="primary" style="position: relative;left: 242px;" @click="copyClick">复制</Button>
</form-item>
<div v-else style="margin-top: 20px;height: 40px">
<Button type="primary" style="float: right;margin-right: 16px" @click="copyClick">复制</Button>
</div>
</template>
</i-form>
</Modal>
</div>
</script>
<script>
Vue.component('j-jurisdiction', {
template: '#jurisdiction',
data() {
return {
id: "",
loading: false,
moduleTitle: "创建分享链接",
shareModal: false,
shareUrlModal:false,
jurisdictionData: {
"id": "",
"reportId": "",
"previewUrl": "",
"previewLock": "",
"status": "",
"termOfValidity": "1",
"previewLockStatus": "0"
},
termValidity: [
{
label: '永久有效',
value: '1'
},
{
label: '7天',
value: '2'
},
{
label: '1天',
value: '3'
}
],//过期时间
lockOption: [
{
label: '否',
value: '0'
},
{
label: '是',
value: '1'
}
],//是否开启密码
}
},
created() {
},
methods: {
//创建分享连接关闭事件
handleShareCancel() {
this.shareModal = false
this.close();
},
close(){
this.jurisdictionData.id="";
this.jurisdictionData.reportId="";
this.jurisdictionData.previewUrl="";
this.jurisdictionData.previewLock="";
this.jurisdictionData.status="";
this.jurisdictionData.termOfValidity="1";
this.jurisdictionData.previewLockStatus="0"
},
//创建分享连接确定事件
handleShareOk() {
this.jurisdictionData.status="0"
$http.post({
contentType:'json',
url: api.addAndEdit,
data: this.jurisdictionData,
success: (res) => {
if (res) {
let protocol = window.location.protocol;
let host = window.location.host;
//update-begin---author:wangshuai ---date:20220215 for[issues/I4RQSO]配置了customPrePath值但分享链接中没有/test
let url = protocol+"//"+host+baseFull;
//update-end---author:wangshuai ---date:20220215 for[issues/I4RQSO]配置了customPrePath值但分享链接中没有/test
res.previewUrl = url+res.previewUrl;
this.jurisdictionData = res
this.shareModal = false
this.shareUrlModal=true
}
},
error:()=>{
this.shareModal = true
this.$Message.warning("创建连接失败!")
}
})
},
//取消分享
handleShareUrlOk(){
let jurisdictionData={}
jurisdictionData.id= this.jurisdictionData.id
jurisdictionData.status= '1'
jurisdictionData.reportId= this.jurisdictionData.reportId
// console.log("我进来了")
$http.post({
contentType:'json',
url: api.addAndEdit,
data: jurisdictionData,
success: (res) => {
if (res) {
this.$Message.success("取消分享成功!")
localStorage.removeItem(this.jurisdictionData.reportId);
this.shareUrlModal=false
this.close()
}
}
})
},
handleShareUrlCancel(){
this.close()
},
//复制预览地址和密码
copyClick(){
let previewUrl = this.jurisdictionData.previewUrl;
let previewLock = this.jurisdictionData.previewLock;
let textarea = document.createElement('textarea');
//update-begin---author:wangshuai ---date:20220315 for[issues/I4WWKE]分享链接的预览密码能否忽略------------
textarea.value = "预览地址: "+previewUrl+" \n"
//兼容老数据,如果是否分享密码为空的话,也得需要加上预览密码
//previewLockStatus 密码锁状态(0不存在密码锁1存在密码锁)
if("0" != this.jurisdictionData.previewLockStatus){
textarea.value = textarea.value + "预览密码: "+previewLock+"\n"
}
textarea.value = textarea.value + "复制预览地址在浏览器打开";
//update-end---author:wangshuai ---date:20220315 for[issues/I4WWKE]分享链接的预览密码能否忽略------------
document.body.appendChild(textarea);
textarea.select(); // 选择对象;
document.execCommand("Copy"); // 执行浏览器复制命令
document.body.removeChild(textarea)
this.$Message.success('复制成功');
}
}
})
</script>

View File

@@ -0,0 +1,114 @@
<script type="text/x-template" id="legend-setting-template">
<div>
<Submenu name="legend" style="border-bottom: inset 1px;" class="rightFontSize dataSourceForm">
<template slot="title">
<span>图例设置</span>
</template>
<div class="blockDiv">
<Row class="ivurow">
<p>显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 141px;" v-model="legendOptions.show" @on-change="onLegendChange"/>
</Row>
<Row class="ivurow">
<p>字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="legendOptions.textStyle_fontSize" @on-blur="onLegendChange" class="iSelect"></i-input>
</Row>
<Row class="ivurow" v-if="typeof legendOptions.textStyle_color !== 'undefined'">
<p>字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="legendOptions.textStyle_color" size="small" class="iSelect" @on-change="onLegendChange">
<span slot="append">
<color-picker class="colorPicker" v-model="legendOptions.textStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onLegendChange"/>
</span>
</i-input>
</Col>
</Row>
<#--<Row class="ivurow">
<p>图例宽度&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="echartInfo.legendItemWidth" @on-blur="styleChanges" style="width: 111px;margin-bottom: 10px;"></i-input>
</Row>-->
<Row class="ivurow">
<p>纵向位置&nbsp;&nbsp;</p>
<i-select size="small" class="iSelect" v-model="legendOptions.top" @on-change="onLegendChange">
<i-option class="rightFontSize" value="top">顶部</i-option>
<i-option class="rightFontSize" value="bottom">底部</i-option>
</i-select>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">横向位置&nbsp;&nbsp;</p>
<i-select size="small" class="iSelect" v-model="legendOptions.left" @on-change="onLegendChange" style="width: 125%">
<i-option class="rightFontSize" value="left">左对齐</i-option>
<i-option class="rightFontSize" value="center">居中</i-option>
<i-option class="rightFontSize" value="right">右对齐</i-option>
</i-select>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">布局朝向&nbsp;&nbsp;</p>
<i-select size="small" v-model="legendOptions.orient" @on-change="onLegendChange" class="iSelect">
<i-option class="rightFontSize" value="horizontal">横排</i-option>
<i-option class="rightFontSize" value="vertical">竖排</i-option>
</i-select>
</Row>
<Row class="ivurow">
<p>上边距&nbsp;&nbsp;</p>
<slider :disabled="legendOptions.top!=='top'" v-model="paddingTop" @on-change="onLegendTopChange" :tip-format="formatTop" style="margin-top: -9px;width: 148px;margin-left: 5px;"></slider>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-legend-setting', {
template: '#legend-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
legendOptions: {
textStyle_color:'',
top:"top",
left:"left",
orient:"horizontal",
textStyle_fontSize:""
},
paddingTop:'' //边距单独提出来
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.legendOptions = Object.assign(this.legendOptions, this.settings)
//update-begin---author:wangshuai ---date:20220628 for[issues/I58YJG]图表中图例设置-纵向位置如果设置为底部,在挪动上边距的话那个图例就会跑到顶部去------------
this.paddingTop = this.legendOptions.padding[0]
//update-end---author:wangshuai ---date:20220628 for[issues/I58YJG]图表中图例设置-纵向位置如果设置为底部,在挪动上边距的话那个图例就会跑到顶部去--------------
}
},
onLegendChange (){
this.$emit('change','legend',this.legendOptions)
},
onLegendTopChange(){
this.legendOptions.padding[0] = this.paddingTop;
this.onLegendChange()
},
formatTop(val){
return val
},
}
})
</script>

View File

@@ -0,0 +1,108 @@
<script type="text/x-template" id="line-setting-template">
<Submenu name="3" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
折线设置
</template>
<div class="blockDiv">
<Row class="ivurow">
<p>平滑曲线&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 116px;" v-model="lineOptions.smooth" @on-change="onLineChange"/>
</Row>
<Row class="ivurow">
<p>标记点&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 128px;" v-model="lineOptions.showSymbol" @on-change="onLineChange"/>
</Row>
<Row class="ivurow">
<p>点大小&nbsp;&nbsp;</p>
<slider v-model="lineOptions.symbolSize" @on-change="onLineChange" style="margin-top: -9px;width: 144px;margin-left: 12px;"></slider>
</Row>
<Row class="ivurow">
<p>阶梯线图&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 116px;" v-model="lineOptions.step" @on-change="onLineChange"/>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">线条宽度&nbsp;&nbsp;</p>
<slider max="5" v-model="lineOptions.lineStyle_width" @on-change="onLineChange" style="margin-top: -9px;width: 134px;margin-left: 9px;"></slider>
</Row>
<Row v-if=" isMultiChart === false && typeof lineOptions.itemStyle_color!== 'undefined' " class="ivurow">
<p style="margin-bottom: 10px;">线条颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="lineOptions.itemStyle_color" size="small" class="iSelect" @on-change="onLineChange">
<span slot="append">
<color-picker class="colorPicker" v-model="lineOptions.itemStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onLineChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="isMultiChart === false">
<p>面积折线&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 116px;" v-model="lineOptions.isArea" @on-change="onLineChange"/>
</Row>
<Row v-if="lineOptions.isArea" class="ivurow">
<p style="margin-bottom: 10px;">面积颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="lineOptions.areaStyle_color" size="small" class="iSelect" @on-change="onLineChange">
<span slot="append">
<color-picker class="colorPicker" v-model="lineOptions.areaStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onLineChange"/>
</span>
</i-input>
</Col>
</Row>
<Row v-if="lineOptions.isArea" class="ivurow" style="z-index:9999">
<p style="margin-bottom: 10px;">面积透明度&nbsp;&nbsp;</p>
<slider max="1" step="0.1" v-model="lineOptions.areaStyle_opacity" @on-change="onLineChange" style="margin-top: -9px;width: 114px;margin-left: 12px;"></slider>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-line-setting', {
template: '#line-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
},
isMultiChart: {
type: Boolean,
default: false
}
},
data(){
return {
lineOptions: {
smooth: false,
showSymbol: true,
symbolSize: 5,
step: false,
lineStyle_width: 2,
itemStyle_color: '#c43632',
isArea:false,
areaStyle_color:'rgba(220,38,38,0)',
areaStyle_opacity:1
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.lineOptions = Object.assign(this.lineOptions, this.settings)
}
},
onLineChange(){
this.$emit('change', this.lineOptions)
}
}
})
</script>

View File

@@ -0,0 +1,538 @@
<style>
/*地图相关样式 -begin*/
.page{
float:right;
margin-top:20px;
}
.vertical-center-modal-big{
margin: 2% 4%;
}
.ivu-modal-confirm-head-icon {
font-size: 28px;
}
.ivu-cascader-transfer .ivu-cascader-menu-item{
font-size: 12px !important;
}
/*地图相关样式 -end*/
</style>
<script type="text/x-template" id="map-setting-template">
<div>
<Submenu name="10" style="border-bottom: inset 1px;" class="rightFontSize dataSourceForm">
<template slot="title">
<span>地图设置</span>
</template>
<div class="blockDiv">
<Row class="ivurow">
<p>地图级别&nbsp;&nbsp;</p>
<div class="iSelect">
<i-select clearable transfer="true" size="small" @on-change="mapLevelChange" v-model="mapOption.mapLevel">
<i-option class="rightFontSize" v-for="(map,index) in mapLevelData" :value="map.value" :index="index">
{{ map.label}}
</i-option>
</i-select>
</div>
</Row>
<Row class="ivurow" v-if="mapOption.mapType=='1' || mapOption.mapType=='2' || mapOption.mapType=='3'">
<p v-if="mapOption.mapType=='1'">选择省份&nbsp;&nbsp;</p>
<p v-if="mapOption.mapType=='2'">选择城市&nbsp;&nbsp;</p>
<p v-if="mapOption.mapType=='3'">选择区域&nbsp;&nbsp;</p>
<div class="iSelect">
<Cascader v-if="mapOption.mapType=='1' " clearable transfer="true" :data="provinceData" size="small" @on-change="(value, selectedData) => provinceChange(value, selectedData)" v-model="mapOption.mapCode"></Cascader>
<Cascader v-if="mapOption.mapType=='2' " clearable transfer="true" :data="cityData" size="small" @on-change="(value, selectedData) => provinceChange(value, selectedData)" v-model="mapOption.mapCode"></Cascader>
<Cascader v-if="mapOption.mapType=='3' " clearable transfer="true" :data="areaData" size="small" @on-change="(value, selectedData) => provinceChange(value, selectedData)" v-model="mapOption.mapCode"></Cascader>
</div>
</Row>
<Row class="ivurow">
<p>比例&nbsp;&nbsp;</p>
<slider v-model="mapOption.zoom" step="0.1" max="2" @on-change="onGeoChange" style="margin-top: -9px;width: 158px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>名称显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 116px;" v-model="mapOption.label_show" @on-change="onGeoChange"/>
</Row>
<Row class="ivurow" v-if="mapOption.label_show">
<p>字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="mapOption.label_fontSize" @on-blur="onGeoChange" style="width: 141px"></i-input>
</Row>
<Row class="ivurow" v-if="typeof mapOption.label_color !== 'undefined' && mapOption.label_show">
<p>字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="mapOption.label_color" size="small" style="width: 141px" @on-change="onGeoChange">
<span slot="append">
<color-picker class="colorPicker" v-model="mapOption.label_color" :editable="false" alpha :transfer="true" size="small" @on-change="onGeoChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="typeof mapOption.emphasis_label_color !== 'undefined'">
<p>字体高亮颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="mapOption.emphasis_label_color" size="small" style="width: 117px;" @on-change="onGeoChange">
<span slot="append">
<color-picker class="colorPicker" v-model="mapOption.emphasis_label_color" :editable="false" alpha :transfer="true" size="small" @on-change="onGeoChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow">
<p>区域线&nbsp;&nbsp;</p>
<slider v-model="mapOption.itemStyle_borderWidth" step="0.1" max="5" @on-change="onGeoChange" style="margin-top: -9px;width: 147px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow" v-if="typeof mapOption.itemStyle_areaColor !== 'undefined'">
<p>区域颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="mapOption.itemStyle_areaColor" size="small" style="width: 141px" @on-change="onGeoChange">
<span slot="append">
<color-picker class="colorPicker" v-model="mapOption.itemStyle_areaColor" :editable="false" alpha :transfer="true" size="small" @on-change="onGeoChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="typeof mapOption.emphasis_itemStyle_areaColor !== 'undefined'">
<p>区域高亮颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="mapOption.emphasis_itemStyle_areaColor" size="small" style="width: 117px;" @on-change="onGeoChange">
<span slot="append">
<color-picker class="colorPicker" v-model="mapOption.emphasis_itemStyle_areaColor" :editable="false" alpha :transfer="true" size="small" @on-change="onGeoChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="typeof mapOption.itemStyle_borderColor !== 'undefined'">
<p>边框颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="mapOption.itemStyle_borderColor" size="small" style="width: 141px" @on-change="onGeoChange">
<span slot="append">
<color-picker class="colorPicker" v-model="mapOption.itemStyle_borderColor" :editable="false" alpha :transfer="true" size="small" @on-change="onGeoChange"/>
</span>
</i-input>
</Col>
</Row>
</div>
</Submenu>
<#--地图弹窗-->
<div>
<Modal
class-name="vertical-center-modal-big"
fullscreen=true
:loading="loading"
v-model="mapListModal"
title="地图维护"
@on-cancel="callMapDb">
<i-form inline :label-width="85">
<Row >
<i-col span="6">
<form-item label="名称:">
<i-input style="width: 253px" type="text" v-model="queryParams.label" placeholder="请输入名称">
</i-input>
</form-item>
</i-col>
<i-col span="6">
<form-item label="编码:">
<i-input type="text" style="width: 300px" v-model="queryParams.name" placeholder="请输入编码">
</i-input>
</form-item>
</i-col>
<i-col span="2" style="margin-left: 60px">
<i-button @click="loadData(1)" type="primary" icon="ios-search">查询</i-button>
</i-col>
<i-col span="2">
<i-button @click="clearQuery" type="primary" icon="ios-refresh">重置</i-button>
</i-col>
</Row>
</i-form>
<Row style="margin-top:25px">
<i-col span="3">
<i-button @click="addMapData" type="primary">新增</i-button>
</i-col>
</Row>
<template>
<i-table border stripe :columns="mapTab.columns" :data="mapTab.data" style="margin-top: 1%;"></i-table>
<div class="page">
<Page :total="page.total"
show-total
show-elevator
@on-change="handleCurrentChange"
@on-page-size-change="handleSizeChange">
</Page>
</div>
</template>
<template slot="footer">
<i-button type="primary" @click="callMapDb">关闭</i-button>
</template>
</Modal>
<Modal :loading="loading" v-model="mapDataModal" title="数据源" :width="35" @on-cancel="clearMapDb" @on-ok="saveMapDb">
<div style="padding-right: 30px">
<i-form ref="mapSource" :model="mapSource" :rules="dataFormValidate" label-colon :label-width="100" >
<form-item prop="label" label="地图名称" style="height:50px">
<i-input v-model="mapSource.label" placeholder="请输入地图名称"></i-input>
</form-item>
<form-item prop="name" label="地图编码" style="height:50px">
<i-input v-model="mapSource.name" placeholder="请输入地图编码"></i-input>
</form-item>
<form-item prop="data" label="地图数据">
<i-input type="textarea" :autosize="{minRows: 15,maxRows:15}" v-model="mapSource.data" placeholder="请输入地图数据"></i-input>
<a href="http://datav.aliyun.com/tools/atlas" target="_blank">地图数据json下载</a>
</form-item>
</i-form>
</div>
</Modal>
</div>
</div>
</script>
<script>
Vue.component('j-map-setting', {
template: '#map-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
mapOption: {
map:100000,//map code编码
mapCode:[100000],
mapName:"中国人民共和国",
mapLevel:"",//地图等级
mapType:"0", //地图显示
zoom:0.5,
label_color:'#000',
label_fontSize:12,
itemStyle_borderWidth :0.5,
itemStyle_areaColor :'#fff',
itemStyle_borderColor:'#000',
emphasis_label_color:'#fff',
emphasis_itemStyle_areaColor:'red',
label_show:false //地图是否显示
},
mapListModal:false,
mapList:[],
allMapList:[],
loading:true,
mapDataModal: false,
page: { //分页参数
page: 1,
size: 10,
total: 0,
},
queryParams:{
label:"",
name:"",
},
mapSource:{
id:"",
label:"",
name:"",
data:""
},
dataFormValidate:{
label:[
{ required: true, message: '地图名称不能为空', trigger: 'blur' }
],
name:[
{ required: true, message: '地图编码不能为空', trigger: 'blur' }
],
data:[
{ required: true, message: '地图数据不能为空', trigger: 'blur' }
]
},
mapTab:{
data: [],
columns: [
{
type: 'index',
title: '序号',
width: 80,
align: 'center'
},
{
title: '地图名称',
key: 'label'
},
{
title: '地图编码',
key: 'name'
},
{
title: '操作',
key: 'action',
width: 150,
align: 'center',
render: (h, params) => {
return this.renderButton(h, params);
}
}
]
},
provinceData:[],//省的json结合
cityData:[],//城市的json结合
areaData:[],//地区的json结合
mapLevelData: [{
"label": "全国",
"value": "0"
}, {
"label": "省级",
"value": "1"
}, {
"label": "市级",
"value": "2"
}, {
"label": "区级",
"value": "3"
}],//地图级别集合
mapUrl:"/jmreport/desreport_/regionaljson/", //请求路径
mapData:[], //地图的集合
initShow:false
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
mounted : function() {
this.loadAllData()
},
methods: {
initData: function (){
if (this.settings){
this.mapOption = Object.assign(this.mapOption, this.settings)
}
},
onGeoChange(){
this.$emit('change','geo',this.mapOption)
},
//地图数据集维护Modal
mapManage(flag){
this.clearQuery();
this.mapListModal=flag;
},
loadData(){
//加载数据列表
let that=this;
$http.get({
url: api.mapList,
data:{
label:that.queryParams.label,
name:that.queryParams.name,
current:that.page.page,
size:that.page.size,
token:this.token
},
success:(result)=>{
// console.log('result',result)
let records=result.records;
that.page.total = result.total
that.$nextTick(()=>{
that.mapTab.data=JSON.parse(JSON.stringify(records));
});
that.mapList = records && records.length>0?records:mapTypeList;
}
});
},
loadAllData(){
this.loadMapData("province.json",1)
this.loadMapData("province.city.json",2)
this.loadMapData("province.city.area.json",3)
},
//地图级别点击事件
mapLevelChange(val){
this.mapOption.mapType= val
this.mapOption.mapCode=[]
//如果是0代表全国
if(val == 0){
let value =[100000]
let selectedData =[{label:"中华人民共和国",value:100000}]
this.provinceChange(value,selectedData)
}
},
//省市区点击事件
provinceChange(value, selectedData){
this.mapOption.mapCode = value;
this.mapOption.map = selectedData[selectedData.length-1].value;
let label = selectedData[selectedData.length-1].label;
let name = selectedData[selectedData.length-1].value;
this.mapOption.mapName = label;
$http.post({
contentType:'json',
url: api.queryMapByCode,
data:JSON.stringify({name:name,label:label,mapType:this.mapOption.mapType}),
success:(result)=>{
xs.registerMap(result.name,result.data);
this.$emit('change','geo',this.mapOption)
}
})
},
handleSizeChange(val){
this.page.size = val;
this.loadData();
},
handleCurrentChange (val) {
this.page.page = val;
this.loadData();
},
saveMapDb() {
//保存地图数据
this.$refs.mapSource.validate((valid)=>{
if(valid){
//保存地图表单数据
$http.post({
contentType:'json',
url: api.addMapData,
data:JSON.stringify(this.mapSource),
success:(res)=>{
this.$Notice.success({
title: '保存成功'
});
this.clearMapDb()
this.loadData();
}
});
return;
}else{
setTimeout(() => {
this.loading = false
this.$nextTick(() => {
this.loading = true
})
}, 500)
return;
}
});
},
clearMapDb(){
this.mapSource.id=""
this.mapSource.label=""
this.mapSource.name=""
this.mapSource.data=""
this.loadData();
this.$refs["mapSource"].resetFields();
this.mapDataModal = false;
},
callMapDb() {
this.loadAllData();
this.mapManage(false)
},
addMapData() {
//新增地图
this.mapDataModal=true;
},
clearQuery(){
//清除地图查询数据
for(let key in this.queryParams){
this.queryParams[key] = "";
}
this.page.page=1;
this.page.size=10;
this.loadData();
},
//渲染删除编辑button
renderButton(h, params) {
return h('div',[
h('i-button', {
props: {
type: 'primary',
size: 'small'
},
style:{
'margin-right':'5px'
},
on: {
click: () => {
this.mapTab.data.forEach((item)=>{
if (item.id === params.row.id){
this.mapSource = item;
}
})
this.mapDataModal = true;
}
}
},'编辑'),
h('i-button', {
props: {
type: 'primary',
size: 'small'
},
on: {
click: () => {
this.$Modal.confirm({
title:"提示",
content: '是否确认删除?',
onOk: () => {
let mapSource = {};
mapSource.id = params.row.id;
$http.post({
contentType:'json',
url: api.delMapSource,
data:JSON.stringify(mapSource),
success:(result)=>{
this.$Notice.success({
title: '删除成功'
});
this.loadData();
}
});
}
});
}
}
},'删除')
])
},
//type 1 省的json 2省市的json 3省市区的json
loadMapData(url,type) {
$http.get({
//update-begin---author:wangshuai ---date:20220412 for[issues/890]微服务下customPrePath不起作用------------
url:"${base}"+"${customPrePath}"+this.mapUrl+url,
//update-end---author:wangshuai ---date:20220412 for[issues/890]微服务下customPrePath不起作用--------------
fail:(res)=>{
if(type == 1){
this.provinceData = res.data
}
if(type == 2){
this.cityData = res.data
}
if(type == 3){
this.areaData = res.data
}
}
})
},
}
})
//初始化地图数据
function loadMap(item){
let config = JSON.parse(item.config);
this.initShow = true
let map = config.geo.map;
if(map=="china"){
map=100000;
}
$http.post({
contentType:'json',
url: api.queryMapByCode,
data:JSON.stringify({name:map,label:config.geo.mapName}),
success:(result)=>{
let data=JSON.parse(result.data);
xs.registerMap(result.name,data);
xs.updateChart(item.layer_id ,config);
}
});
}
</script>

View File

@@ -0,0 +1,96 @@
<script type="text/x-template" id="margin-setting-template">
<div >
<Submenu name="5" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>边距设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>左边距(%)</p>
<slider :tip-format="percentFormat" :value="getNumberFromPercent(marginOptions.left)" @on-change="(value)=>onPercentChange(value, 'marginOptions.left','onPieChange')" style="margin-top: -9px;width: 135px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow" v-if="marginOptions.right">
<p>右边距(%)</p>
<slider :tip-format="percentFormat" :value="getNumberFromPercent(marginOptions.right)" @on-change="(value)=>onPercentChange(value, 'marginOptions.right','onPieChange')" style="margin-top: -9px;width: 135px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>顶边距&nbsp;&nbsp;</p>
<slider v-model="marginOptions.top" @on-change="onMarginChange" style="margin-top: -9px;width: 148px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">底边距&nbsp;&nbsp;</p>
<slider v-model="marginOptions.bottom" @on-change="onMarginChange" style="margin-top: -9px;width: 148px;margin-left: 5px;"></slider>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-margin-setting', {
template: '#margin-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
},
isMultiChart:{
type: Boolean,
default: false
}
},
data(){
return {
marginOptions: {
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
percentFormat (val) {
return val + '%';
},
//通过百分数转化 获取实际数字
getNumberFromPercent(p,suffix=''){
if(!p){
return 0;
}
return Number((p+'').replace('%','').replace(suffix,''))
},
initData: function (){
if (this.settings){
this.marginOptions = Object.assign(this.marginOptions, this.settings)
}
},
//slider 百分数改变事件
onPercentChange(value, key, eventName,suffix=''){
let arr = key.split('.')
if(arr.length>1){
let temp = this
for(let i=0;i<arr.length-1;i++){
temp = temp[arr[i]]
}
temp[arr[arr.length-1]] = value+'%'+suffix
}else{
this[key] = value+'%'+suffix
}
//this[eventName]();
this.$emit('change',this.marginOptions)
},
onMarginChange (){
this.$emit('change',this.marginOptions)
}
}
})
</script>

View File

@@ -0,0 +1,376 @@
<script type="text/x-template" id="match-setting-template">
<div class="match_setting rightFontSize" >
<Submenu name="19">
<template slot="title">
<span>自定义配色</span>
<Tooltip placement="top" content="【边缘颜色】选用相对更深色" :transfer="true" v-if="selectedChartType.indexOf('scatter.bubble')!==-1">
<Icon size="16" style="margin-left: 10px;" type="ios-help-circle-outline"/>
</Tooltip>
</template>
<div style="margin-left: 25px;margin-top: -15px;">
<Row class="ivurow" style="margin-bottom: 5px;">
<i-button type="primary" size="small" @click="colorMatchModalOpen">新增</i-button>
</Row>
<i-table class="rightFontSize" :columns="columns2" :data="colorMatchData"></i-table>
</div>
</Submenu>
<Modal :loading="loading" v-model="colorMatchModal" title="自定义配色" :width="30" @on-ok="addColorMatch" @on-cancel="onCancel">
<div style="padding-right: 50px" class="dataSourceForm">
<i-form :model="colorMatch" label-colon :label-width="90">
<form-item :label="colorLabel">
<row>
<i-col span="12">
<i-input v-model="colorMatch.color" size="small" style="width: 111px;" >
<span slot="append">
<color-picker class="colorPicker" v-model="colorMatch.color" :editable="false" :transfer="true" size="small" />
</span>
</i-input>
</i-col>
</row>
</form-item>
<form-item label="边缘颜色" v-if="selectedChartType.indexOf('scatter.bubble') !== -1">
<row>
<i-col span="12">
<i-input v-model="colorMatch.edgeColor" size="small" style="width: 111px;" >
<span slot="append">
<color-picker class="colorPicker" v-model="colorMatch.edgeColor" :editable="false" :transfer="true" size="small" />
</span>
</i-input>
</i-col>
</row>
</form-item>
<form-item label="边框颜色" v-if="selectedChartType.indexOf('radar')>-1">
<row>
<i-col span="12">
<i-input v-model="colorMatch.lineColor" size="small" style="width: 111px;" >
<span slot="append">
<color-picker class="colorPicker" v-model="colorMatch.lineColor" :editable="false" :transfer="true" size="small" />
</span>
</i-input>
</i-col>
</row>
</form-item>
</i-form>
</div>
</Modal>
</div>
</script>
<script>
Vue.component('j-match-setting', {
template: '#match-setting-template',
props: {
chartOptions: {
type: Object,
default: () => {
}
},
dataSettings: {
type: [Object, String],
default: () => {
}
}
},
data(){
return {
colorMatchData: [],
colorMatch: {name:'',color:'',edgeColor:"",opacity:1,lineColor:''},
seriesList: [],
selectedChartType: '',
colorMatchModal: false,
loading: true,
columns2: [
{
title: '系列颜色',
key: 'color',
align: 'left',
width: 110,
render: (h, params) => {
return this.renderColorButton(h, params, 'color', 1);
}
},
{
title: '操作',
key: 'action',
align: 'right',
width: 80,
render: (h, params) => {
return this.renderColorButton(h, params, 'action', 1);
}
}
],
colorMatchModal: false
}
},
watch: {
chartOptions: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
computed: {
colorLabel: function (){
return this.selectedChartType.indexOf('scatter.bubble') !== -1 ? '中心颜色' : '颜色'
}
},
methods: {
//渲染button
renderColorButton(h, params, key, type){
// console.log('params', params)
if (key == 'action'){
return h('div', {style: {display: 'flex'}}, [
h('i-button', {
props: Object.assign({}, {
type: 'default',
size: 'small',
type: "text"
}, {
icon: 'md-create',
}),
on: {
"click": () => {
if (type == 1){
this.colorMatch = params.row;
this.colorMatchModal = true;
} else {
this.seriesObj = params.row;
this.seriesModal = true;
}
}
}
}),
h('i-button', {
props: Object.assign({}, {
size: 'small',
type: "text"
}, {
icon: 'md-close',
}),
on: {
click: () => {
this.$Modal.confirm({
title: '提示',
content: '是否确认删除?',
onOk: () => {
if (type == 1){
this.colorMatchData.splice(params.index, 1);
this.onColorChange()
} else {
this.seriesTypeData.splice(params.index, 1);
this.runChart();
}
}
});
}
}
})
])
} else {
//行数据显示渲染和编辑操作
return h('div', {
style: {
display: 'flex',
width: '100px',
alignItems: 'center'
}
},
[
(type === 1) ? h('div', {style: {'background': params.row.color, 'width': '15px', 'height': '15px'}}) : h('div', {style: {}}, params.row.type),
h('div', [
h('div', {style: {display: 'inherit', width: type === 1 ? '75px' : '60px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}}, '\xa0' + params.row.name)
])
])
}
},
colorMatchModalOpen(){
this.colorMatchModal = true
},
initData: function (){
if (this.chartOptions){
// console.info("########", JSON.stringify(this.dataSettings))
this.selectedChartType = this.dataSettings.chartType;
let colorArr = [];
let seriesList = []
let arr = this.chartOptions.series
arr.forEach(object => {
let type = object.type
if (type == 'bar' || type == 'line'){
if (object.itemStyle && object.itemStyle.color){
colorArr.push({name: object.name, color: object.itemStyle.color})
}
seriesList.push(object.name)
} else if(type=='graph'){
//关系图自定义的数据
object.categories.forEach(categoryObj=>{
if(categoryObj.itemStyle && categoryObj.itemStyle.color){
let isExis = colorArr.filter(item=>item.name===categoryObj.name);
if(isExis.length===0){
colorArr.push({name:categoryObj.name,color:categoryObj.itemStyle.color})
}
}
})
seriesList=object.categories.map(item=>{return item.name}).filter(function(item, index, self){ return self.indexOf(item) == index; });
}else if (type == 'scatter'){
if (object.itemStyle && object.itemStyle.color && object.itemStyle.color.colorStops){
let colorStops = object.itemStyle.color.colorStops;
colorArr.push({name: object.name, color: colorStops[0].color, edgeColor: colorStops[1].color})
}
seriesList.push(object.name)
} else if (type == 'radar'){
object.data.forEach(item => {
if (item.areaStyle && item.areaStyle.color && item.areaStyle.color != ''){
colorArr.push({name:item.name,color:item.areaStyle.color,opacity:item.areaStyle.opacity,lineColor:item.lineStyle.color})
}
seriesList.push(item.name)
});
} else if (type == 'pie' || type == 'funnel'){
object.data.map(item => {
if (item.itemStyle && item.itemStyle.color){
colorArr.push({name: item.name, color: item.itemStyle.color})
}
seriesList.push(item.name)
})
} else if (type == 'gauge'){
let arr = object.axisLine.lineStyle.color;
for (let j = 0, len = arr.length; j < len; j++) {
if ((arr[0] && arr[0][1] == '#91c7ae') && (arr[1] && arr[1][1] == '#63869E')){
break;
}
colorArr.push({color: arr[j][1], name: ""})
}
}
})
// console.info("自定义颜色", colorArr)
//已设置的颜色配置
this.colorMatchData = colorArr
//系列下拉框数据
this.seriesList = seriesList
}
},
addColorMatch(){
let obj={...this.colorMatch};
if(obj._index>=0){
this.colorMatchData.splice(obj._index,1,obj);
}else{
this.colorMatchData.push(obj)
}
//运行到图表
this.onColorChange();
this.colorMatchModal=false;
this.colorMatch={name:'',color:'',edgeColor:"",opacity:1,lineColor:''};
},
onColorChange(){
// console.log('this.colorMatchData==>',JSON.stringify(this.colorMatchData));
// console.log('this.seriesTypeData==>',JSON.stringify(this.seriesTypeData));
if(!this.colorMatchData){
return;
}
let arr = []
if(this.selectedChartType.indexOf('pie')>=0 || this.selectedChartType.indexOf('funnel')>=0|| this.selectedChartType.indexOf('radar')>=0){
arr = this.chartOptions['series'][0]['data']
}else if(this.selectedChartType.indexOf('graph')>=0){
//处理关系图的自定义配色
arr = this.chartOptions['series'][0]['categories']
}else{
arr = this.chartOptions['series']
}
// console.log('this.arr==>',JSON.stringify(arr));
let seriesArray = []
let i = 0;
for(let item of arr){
//删除背景色
delete item['areaStyle']
delete item['lineStyle']
if(this.selectedChartType.indexOf('gauge')>=0){
break;
}
if(this.selectedChartType.indexOf('radar')>=0) {
let color = ''
let lineColor = ''
let opacity = 1
if(i<=this.colorMatchData.length) {
let colorMatchDatum = this.colorMatchData[i];
if (colorMatchDatum) {
color = colorMatchDatum['color']
lineColor = colorMatchDatum['lineColor']
opacity = colorMatchDatum['opacity']
//设置雷达图背景色和透明度
if(color)
{
item['areaStyle'] = {color: color, opacity: opacity}
} else {
item['areaStyle'] = {color: "", opacity: 0}
}
//设置雷达图边框颜色
if(lineColor)
{
item['lineStyle'] = {color: lineColor}
} else {
item['lineStyle'] = {color: ""}
}
}
i++;
}
}else if(this.selectedChartType.indexOf('scatter')>=0){
if(i<=this.colorMatchData.length) {
let colorMatchDatum = this.colorMatchData[i];
if(colorMatchDatum){
let color =colorMatchDatum['color']//0%处的颜色 中心
let edgeColor = colorMatchDatum['edgeColor']//100%处的颜色 边缘
let tempColorStyle={type:'radial',r: 0.5,colorStops: [{offset: 0, color:color}, {offset: 1, color: edgeColor}]}
if (!item['itemStyle']) {
item['itemStyle'] = {color:tempColorStyle};
}else{
item['itemStyle']['color'] = tempColorStyle;
}
}
i++;
}
}else{
if (!item['itemStyle']) {
item['itemStyle'] = {color: ''}
}
let color = ''
if (i<=this.colorMatchData.length){
let colorMatchDatum = this.colorMatchData[i];
if(colorMatchDatum){
color = this.colorMatchData[i]['color']
item['itemStyle']['color'] = color
}else{
item['itemStyle']['color'] = ""
}
i++;
}
}
if(this.selectedChartType.indexOf('mixed')>=0){
seriesArray.push(JSON.parse(JSON.stringify(item)))
}
}
if(this.selectedChartType.indexOf('mixed')>=0){
this.chartOptions['series'] = seriesArray
}
//TODO 仪表盘目前只支持设置三色0.2/0.8/1后期优化修改
if(this.selectedChartType.indexOf('gauge')>=0){
let c1=this.colorMatchData[0]?this.colorMatchData[0].color:"#91c7ae";
let c2=this.colorMatchData[1]?this.colorMatchData[1].color:"#63869E";
let c3=this.colorMatchData[2]?this.colorMatchData[2].color:"#C23531";
let arr= [[0.2, c1], [0.8, c2], [1, c3]];
this.chartOptions['series'][0]['axisLine']['lineStyle'].color =arr
}
// console.info("this.chartOptions",JSON.stringify(this.chartOptions))
let id = this.dataSettings.id;
xs.updateChart(id , this.chartOptions);
},
onCancel(){
this.colorMatch={color:'',edgeColor:'',lineColor:''}
}
}
})
</script>

View File

@@ -0,0 +1,146 @@
<script type="text/x-template" id="pictorial-setting-template">
<Submenu name="8" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>象形图设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow" >
<span title="建议上传至服务器本地,若上传至云服务器,可能导出/打印等功能不可用" style="display: inline-block;line-height:0px;height: 20px;width: 53px;vertical-align:middle">图标</span>
<Upload
:headers = "uploadHeaders"
ref="upload"
:show-upload-list="false"
:default-file-list="pictorialIcon"
:on-exceeded-size="(e)=>handleMaxSize(e,2)"
:on-success="uploadSuccess"
:format="['jpg','jpeg','png']"
:max-size="2048"
:data="localUpload"
:action=" actionUrlPre + '/jmreport/upload' "
style="display: inline-block;width:58px;">
<div class="pictorial-icon-upload">
<img style="width: 36px;height:36px" ref="symbol" :src="getPathBySymbol()"/>
<div class="cover">
<Icon type="ios-create-outline"/>
</div>
</div>
</Upload>
</Row>
<Row class="ivurow" >
<p>图标大小&nbsp;&nbsp;</p>
<i-input size="small" v-model="pictorialOptions.symbolSize" @on-blur="onPictorialChange" class="iSelect"></i-input>
</Row>
<Row class="ivurow">
<p>图标间距&nbsp;&nbsp;</p>
<i-input type="number" size="small" :value="util.getNumberFromPercent(pictorialOptions.symbolMargin,'!')" @on-blur="(e)=>onPercentChange(e.target.value, 'pictorialOptions.symbolMargin','onPictorialChange','!')" class="iSelect"> <span slot="append">%</span></i-input>
</Row>
<Row class="ivurow" >
<p>最大值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<i-input size="small" v-model="pictorialOptions.symbolBoundingData" @on-blur="onPictorialChange" class="iSelect"></i-input>
</Row>
<Row class="ivurow">
<p>是否补全&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 119px;" v-model="pictorialOptions.double" @on-change="onPictorialChange"/>
</Row>
<Row class="ivurow" v-if="pictorialOptions.double">
<p>透明度&nbsp;&nbsp;</p>
<slider max="1" step="0.1" v-model="pictorialOptions.secondOpacity" @on-change="onPictorialChange" style="margin-top: -9px;width: 110px;margin-left: 5px;" ></slider>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-pictorial-setting', {
template: '#pictorial-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
},
isMultiChart: {
type: Boolean,
default: false
}
},
data(){
return {
//象形图 图标配置
pictorialIcon:[{'name': 'pictorialIcon','url': '' }],
actionUrlPre: baseFull,
pictorialOptions: {
},
localUpload:{
bizType: 'local'
},
uploadHeaders:{}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.pictorialOptions = Object.assign(this.pictorialOptions, this.settings)
}
this.uploadHeaders = vm.uploadHeaders
},
getPathBySymbol(){
let symbol = this.pictorialOptions['symbol']
if(!symbol){
let path = baseFull+'/jmreport/desreport_/chartsImg/pictorialIcon/spirits.png'
return path;
}else{
return symbol.replace('image://','')
}
},
//图片上传文件大小
handleMaxSize (file,size) {
// console.log("file===>",file)
// console.log("size===>",size)
this.$Notice.warning({
title: '超出文件大小限制',
desc: '文件 ' + file.name + ' 太大,请上传'+size+'M以内图片',
duration: 6
});
},
//slider 百分数改变事件
onPercentChange(value, key, eventName,suffix=''){
let arr = key.split('.')
if(arr.length>1){
let temp = this
for(let i=0;i<arr.length-1;i++){
temp = temp[arr[i]]
}
temp[arr[arr.length-1]] = value+'%'+suffix
}else{
this[key] = value+'%'+suffix
}
//this[eventName]();
this.onPictorialChange();
},
uploadSuccess(res){
this.$emit('upload-success',res, (symbol)=>{
this.pictorialOptions['symbol'] = symbol
this.$forceUpdate(()=>{
this.getPathBySymbol();
})
})
},
onPictorialChange(){
this.$emit('change', this.pictorialOptions)
}
}
})
</script>

View File

@@ -0,0 +1,91 @@
<script type="text/x-template" id="pie-setting-template">
<Submenu name="4" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>饼图设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>环形饼图&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 117px;" v-model="pieOption.isRadius" @on-change="pieTypeChange"/>
</Row>
<Row class="ivurow">
<p>南丁格尔玫瑰&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 93px;" v-model="pieOption.isRose" @on-change="pieTypeChange('1')"/>
</Row>
<template v-if="pieOption.isRadius">
<Row class="ivurow" >
<p>饼块半径&nbsp;&nbsp;</p>
<i-input size="small" v-model="pieOption.radius[1]" @on-blur="onPieChange" class="iSelect"></i-input>
</Row>
<Row class="ivurow">
<p>内环半径&nbsp;&nbsp;</p>
<i-input size="small" v-model="pieOption.radius[0]" @on-blur="onPieChange" class="iSelect"></i-input>
</Row>
</template>
<Row class="ivurow" v-else>
<p>饼块半径&nbsp;&nbsp;</p>
<i-input size="small" v-model="pieOption.radius" @on-blur="onPieChange" class="iSelect"></i-input>
</Row>
<Row class="ivurow">
<span>最小角度&nbsp;&nbsp;</span>
<i-input size="small" type="number" v-model="pieOption.minAngle" @on-blur="onPieChange" class="iSelect"></i-input>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-pie-setting', {
template: '#pie-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
pieOption: {
"isRadius":false,
"isRose":true,
"radius": "55%",
"roseType": "radius",
"minAngle": 0
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
formatTop(val){
return val + 'px';
},
initData: function (){
if (this.settings){
this.pieOption = Object.assign(this.pieOption, this.settings)
}
},
pieTypeChange(type){
if(type==='1'){
this.pieOption.roseType=this.pieOption.isRose?'radius':'';
}else{
this.pieOption.radius=this.pieOption.isRadius?typeJudge(this.pieOption.radius,'Array')?this.pieOption.radius :["45%",this.pieOption.radius]:typeJudge(this.pieOption.radius,'Array')?this.pieOption.radius[1] : this.pieOption.radius;
}
this.onPieChange();
},
onPieChange(){
this.$emit('change',this.pieOption)
}
}
})
</script>

View File

@@ -0,0 +1,312 @@
<script type="text/x-template" id="primary-sub-report-template">
<Modal
:title="title"
v-model="subReportShow"
width="600px"
:closable="false"
>
<div slot="footer">
<i-button @click="hyperlinksCancel('linkData')">取消</i-button>
<i-button type="primary" @click="hyperlinksOk('linkData')">确定</i-button>
</div>
<i-form ref="linkData" :model="linkData" :label-width="100" :rules="linkDataRule">
<form-item label="名称" prop="linkName">
<i-input placeholder="请填写名称" v-model="linkData.linkName"></i-input>
</form-item>
<form-item label="主表数据源" prop="mainReport">
<i-select :transfer="true" clearable v-model="linkData.mainReport" @on-change="mainReportChange">
<i-option v-for="item in mainReportData" :value="item.dbCode">{{item.dbChName}}</i-option>
</i-select>
</form-item>
<form-item label="子表数据源" prop="subReport">
<i-select :transfer="true" clearable v-model="linkData.subReport" @on-change="subReportChange">
<i-option v-for="item in subReportData" :value="item.dbCode">{{item.dbChName}}</i-option>
</i-select>
</form-item>
<span>参数传递</span>
<div style="margin-top: 10px">
<i-button type="primary" @click="addParamTable">新增</i-button>
<i-button type="primary" @click="removeParamTable" v-if="selectParamTables.length>0">删除</i-button>
<i-table style="margin-top: 10px" ref="paramTable" @on-select="selectParam" @on-select-all="selectParamAll"
@on-select-all-cancel="cancelParamAll" @on-select-cancel="cancelParam" stripe
:columns="hyperlinksData.columns" :data="hyperlinksData.data" :height="paramTableHeight"></i-table>
</div>
</i-form>
</Modal>
</script>
<script>
Vue.component('j-primary-sub-report', {
template: '#primary-sub-report-template',
props: {
excel: {
type: String,
required: true,
default: ""
}
},
data() {
return {
title: "",
subReportShow: false,
hyperlinksData: {
columns: [
{
type: 'selection',
width: 35,
align: 'center'
},
{
title: '子表参数',
key: 'subParam',
align: 'center',
render: (h, params) => {
if (this.subReportFiled) {
return h('i-select', {
props: {
value: params.row.subParam,
size: 'small',
transfer: true,
filterable: true,
clearable:true
},
on: {
'on-change': e => {
// 改变下拉框赋值
this.hyperlinksData.data[params.index].subParam = e
}
}
}, this.subReportFiled.map((item) => {
if (item) {
if(!item.paramTxt){
item.paramTxt = item.paramName
}
return h('i-option', {
// 下拉框的值
props: {
value: item.paramName,
label: item.paramTxt
}
})
}
}))
}
}
},
{
title: '主表字段',
key: 'mainField',
align: 'center',
render: (h, params) => {
if (this.mianReportFiled) {
return h('i-select', {
props: {
value: params.row.mainField, // 获取选择的下拉框的值
size: 'small',
transfer: true,
filterable: true,
clearable:true
},
on: {
'on-change': e => {
// 改变下拉框赋值
this.hyperlinksData.data[params.index].mainField = e
}
}
}, this.mianReportFiled.map((item) => {
return h('i-option', {
// 下拉框的值
props: {
value: item.title,
label: item.fieldText
}
})
}))
}
}
},
],
data: [],
},
selectParamTables: [],
paramTableHeight: 0,
linkData: {
id: "",
reportId: "",//积木设计器id
parameter: "",//参数JSON串
linkName: "",
mainReport: "",
subReport: ""
},
linkDataRule: {
linkName: [
{required: true, message: '请填写参数名称', trigger: 'change'},
],
mainReport: [
{required: true, message: '请选择主表数据源', trigger: 'change'},
],
subReport: [
{required: true, message: '请选择子表数据源', trigger: 'change'},
]
},
mainReportData: [], //主报表数据集合
subReportData: [], //子报表数据集合
dbFiled: [], //字段的集合
dbParam: [], //参数的集合
mainReportFiled: [],//主报表的字段集合
subReportFiled: [],//子报表的字段集合
paramData:[]//父向子传递参数
}
},
watch: {
'paramData': function (val) {
//先清空数据
this.hyperlinksData.data = [];
for (const valElement of val) {
//为参数table添加数据
this.hyperlinksData.data.push(valElement)
}
}
},
methods: {
addParamTable() {
let indexArr = this.hyperlinksData.data.map(item => item.tableIndex);
if (indexArr.length == 0) {
indexArr = [0];
}
this.selectParamTables = [];
this.hyperlinksData.data = [...this.hyperlinksData.data, {
'mainField': "",
'subParam': "",
'tableIndex': Math.max(...indexArr) + 1
}];
},
removeParamTable() {
// this.deleteParamModel = true;
let tableIndexArr = this.selectParamTables.map(item => item.tableIndex);
this.hyperlinksData.data = this.hyperlinksData.data.filter(item => !tableIndexArr.includes(item.tableIndex));
this.selectParamTables = [];
},
selectParamAll() {
this.selectParamTables = this.hyperlinksData.data.map(item => {
return {"tableIndex": item.tableIndex, "id": item.id}
});
},
cancelParamAll() {
this.selectParamTables = [];
},
selectParam(selection, row) {
this.selectParamTables = [...this.selectParamTables, {"tableIndex": row.tableIndex, "id": row.id}];
},
cancelParam(selection, row) {
this.selectParamTables = this.selectParamTables.filter(item => item.tableIndex != row.tableIndex);
},
getReportByUser() {
$http.get({
url: api.getReportByUser,
data: {reportId: excel_config_id},
success: (result) => {
this.reportData = result
}
})
},
//网络报表点击事件
hyperlinksOk(name) {
this.$refs[name].validate((valid) => {
if (valid) {
let mainReport = this.linkData.mainReport
let subReport = this.linkData.subReport
let linkData = this.linkData
linkData.parameter = JSON.stringify({
"main": mainReport,
"sub": subReport,
"subReport": this.hyperlinksData.data
})
linkData.linkType = "4"
linkData.reportId = excel_config_id
$http.post({
url: api.linkSaveAndEdit,
contentType: 'json',
data: JSON.stringify(linkData),
success: (result) => {
this.close(name);
}
});
}
})
},
hyperlinksCancel(name) {
this.close(name);
},
close(name) {
this.subReportShow = false
this.mainReportData=[]
this.subReportData=[]
this.dbFiled=[]
this.dbParam=[]
this.mainReportFiled=[]
this.subReportFiled=[]
this.paramData=[]
this.title=""
this.selectParamTables=[]
this.linkData={}
this.$refs[name].resetFields();
this.$emit('mainsubreport')
},
//获取数据源的数据,用于主子表选择
getListReportDb(treeData,data) {
$http.get({
url: api.getListReportDb,
data: {"reportId": excel_config_id},
success: (res) => {
if (res) {
this.dbParam = res.reportDbParam
if(data){
//为主表数据源赋值
this.mainReportChange(data.main)
//为子表数据源赋值
this.subReportChange(data.sub)
this.linkData.mainReport = data.main
this.linkData.subReport = data.sub
//参数赋值
this.paramData = data.subReport
}
}
}
})
let map = new Map();
//获取treeData,并为字段,主表数据源,子表数据源赋值
for (const treeDatum of treeData) {
let tree = treeDatum[0]["children"];
let code = treeDatum[0]["code"];
let title = treeDatum[0]["title"];
if(!title){
title = code
}
map.set(code,tree);
this.dbFiled.push({"code":code,"list":tree});
this.mainReportData.push({"dbCode":code,"dbChName":title})
this.subReportData.push({"dbCode":code,"dbChName":title})
}
},
//主报表值改变事件
mainReportChange(val) {
let dbFiled = this.dbFiled;
//判断当前主表数据源的code,并为参数中主表字段赋值
dbFiled=dbFiled.filter(item=>item.code == val)
if(dbFiled){
this.mianReportFiled = dbFiled[0]?dbFiled[0].list:[];
}
},
//子报表值改变事件
subReportChange(val) {
this.subReportFiled = this.dbParam[val]
}
},
})
</script>
<style>
.ivu-form-item-error-tip {
position: relative;
}
</style>

View File

@@ -0,0 +1,314 @@
<script type="text/x-template" id="print-setting-template">
<div>
<Modal :loading="true" v-model="show" :width="500" @on-ok="onPrintSettingSave" @on-cancel="onPrintSettingCancel" class="print-setting expression">
<p slot="header">
<span>打印设置
<Tooltip :transfer="true" content="打印文档" placement="top">
<a class="jimu-table-tip help-color" href="https://help.jeecg.com/jimureport/print.html" target="_blank"><Icon size="14" type="ios-help-circle-outline" style="margin-top: 2px"/></a>
</Tooltip>
</span>
</p>
<i-form label-colon :label-width="90">
<Row>
<i-col span="6">
<span>打印纸张:</span>
</i-col>
<i-col span="18">
<i-select v-model="paper" @on-change="onPaperChange">
<i-option v-for="(item, index) in paperList" :index="index" :value="item.paper">
{{ getPaperText(item) }}
</i-option>
</i-select>
</i-col>
</Row>
<Row style="margin-top: 8px">
<i-col span="6">
<span>打印布局:</span>
</i-col>
<i-col span="18">
<RadioGroup v-model="layout" @on-change="onLayoutChange">
<Radio label="portrait" border>
<span>纵向</span>
</Radio>
<Radio label="landscape" border>
<span>横向</span>
</Radio>
</RadioGroup>
</i-col>
</Row>
<Row style="margin-top: 8px">
<i-col span="6">
<span>打印边距(mm)</span>
</i-col>
<i-col span="18">
<i-input type="number" v-model="marginX" style="width: 40%" @on-change="onPaperMarginXChange"></i-input>
-
<i-input type="number" v-model="marginY" style="width: 40%" @on-change="onPaperMarginYChange"></i-input>
</i-col>
</Row>
<Row style="margin-top: 8px">
<i-col span="6">
<span>像素宽高(px)</span>
</i-col>
<i-col span="18">
<i-input v-model="pxWidth" readonly style="width: 40%"></i-input>
-
<i-input v-model="pxHeight" readonly style="width: 40%"></i-input>
</i-col>
</Row>
<Row style="margin-top: 8px">
<i-col span="6">
<span>打印清晰度:</span>
</i-col>
<i-col span="18">
<slider :min="1" :max="10" v-model="definition"></slider>
</i-col>
</Row>
<Row style="margin-top: 8px">
<i-col span="6">
<span>回调接口:</span>
</i-col>
<i-col span="18">
<i-input v-model="printCallBackUrl" style="width: 100%"></i-input>
</i-col>
</Row>
</i-form>
</Modal>
</div>
</script>
<script>
const papers = [
{paper: 'A4', width: 210, height: 297},
{paper: 'A3', width: 297, height: 420},
{paper: 'Letter', width: 216, height: 279},
{paper: 'Legal', width: 216, height: 355},
{paper: 'Executive', width: 184, height: 266}
]
Vue.component('j-print-setting', {
template: '#print-setting-template',
props: {
show:{
type: Boolean,
required: false,
default: false
},
config: {
type: String,
required: false,
default:()=>{}
},
settings: {
type: Object,
required: true,
default:()=>{}
}
},
data(){
return {
paperList: [],
//纸张标识
paper: '',
// 纸张宽高
width: '',
height: '',
//清晰度
definition: '',
//是否套打
isBackend: '',
dpi:'',
pxWidth: '',
pxHeight: '',
marginX: 10,
marginY: 10,
layout: 'portrait',
printCallBackUrl: ''
}
},
created(){
this.initPaperList()
this.getWindowDpi()
},
watch:{
config:{
immediate: true,
handler: function(){
this.initPaperList()
}
},
settings:{
deep: true,
immediate: true,
handler: function(){
this.resetForm(this.settings)
}
}
},
methods:{
onPrintSettingSave(){
// console.log('this.getEmitParam()', this.getEmitParam())
this.$emit('change', this.getEmitParam())
},
onPrintSettingCancel(){
this.$emit('change', false)
},
// 获取回传的参数
getEmitParam(){
return {
paper: this.paper,
width: this.width,
height: this.height,
definition: this.definition,
isBackend: this.isBackend,
marginX: this.marginX || 0,
marginY: this.marginY || 0,
layout: this.layout,
printCallBackUrl: this.printCallBackUrl
}
},
// 纸张大小改变事件
onPaperChange(value){
let arr = this.paperList.filter(item=>{
return item.paper === value
})
this.resetForm(arr[0])
},
onPaperMarginYChange(event){
let temp = parseInt(event.target.value || 0)
if(temp<0){
temp = 0
}
this.marginY = temp
if(this.layout == 'portrait'){
this.pxHeight = this.getPxHeight(this.height)+'px'
}else{
this.pxWidth = this.getPxHeight(this.height)+'px'
}
},
onPaperMarginXChange(event){
let temp = parseInt(event.target.value || 0)
if(temp<0){
temp = 0
}
this.marginX = temp
if(this.layout == 'portrait'){
this.pxWidth = this.getPxWidth(this.width)+'px'
}else{
this.pxHeight = this.getPxWidth(this.width)+'px'
}
},
getPaperText(item){
return item.paper+''+item.width+'mm x '+item.height+'mm'
},
initPaperList(){
let printPaper = []
if(this.config){
let config2 = JSON.parse(this.config)
if(config2 && config2['printPaper']){
printPaper = config2['printPaper']
}
}
let arr = []
for(let item of papers){
arr.push(item)
}
for(let item of printPaper){
arr.push({
paper: item.title, width: item['size'][0], height: item['size'][1]
})
}
this.paperList = [...arr]
},
resetForm: function (param) {
if(param){
this.paper = param.paper
this.width = param.width
this.height = param.height
if(param.marginX || param.marginX==0){
this.marginX = param.marginX
}
if(param.marginY || param.marginY==0){
this.marginY = param.marginY
}
if(param.layout){
this.layout = param.layout
}
this.resetPrintPx();
if(param.definition){
this.definition = param.definition
}
if(param.isBackend===true || param.isBackend===false){
this.isBackend = param.isBackend
}
this.printCallBackUrl = param.printCallBackUrl || ''
}
},
// 重置宽高px的值
resetPrintPx(){
let pxWidth = this.getPxWidth(this.width)+'px'
let pxHeight = this.getPxHeight(this.height)+'px'
if(this.layout == 'portrait'){
this.pxWidth = pxWidth
this.pxHeight = pxHeight
}else{
this.pxWidth = pxHeight
this.pxHeight = pxWidth
}
},
//获取窗口dpi
getWindowDpi(){
//25.41 1英寸=25.41mm 96是window默认dpi,mac:72
let arrDPI = new Array();
if ( window.screen.deviceXDPI != undefined ) {
arrDPI[0] = window.screen.deviceXDPI;
arrDPI[1] = window.screen.deviceYDPI;
}
else {
let tmpNode = document.createElement( "DIV" );
tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
document.body.appendChild( tmpNode );
arrDPI[0] = parseInt( tmpNode.offsetWidth );
arrDPI[1] = parseInt( tmpNode.offsetHeight );
tmpNode.parentNode.removeChild( tmpNode );
}
this.dpi = [...arrDPI]
},
//获取像素宽
getPxWidth(width){
let margin = this.marginX
if(this.isBackend==true){
margin = 0
}
return Math.ceil((width - margin*2)/25.41 * this.dpi[0]);
},
//获取像素高
getPxHeight(height){
let margin = this.marginY
if(this.isBackend==true){
margin = 0
}
return Math.ceil((height-margin*2)/25.41 * this.dpi[1]);
},
// 布局改变
onLayoutChange(value){
this.layout = value
this.resetPrintPx();
}
}
})
</script>
<style>
.print-setting .ivu-col-span-6>span{
display: inline-block;
height: 32px;
line-height: 32px;
}
</style>

View File

@@ -0,0 +1,88 @@
<#--width: 150,
height: 150, // 高度
text: this.qrcode // 二维码内容
// render: 'canvas' // 设置渲染方式(有两种方式 table和canvas默认是canvas
// background: '#f0f'
// foreground: '#ff0'-->
<script type="text/x-template" id="qrcode-setting-template">
<div style="height:auto;overflow: hidden;padding-bottom: 300px;padding-top: 10px;padding-left: 7px">
<i-form class="jm-form-barcode dataSourceForm rightFontSize">
<form-item label="二维码内容">
<i-input v-model="text" type="textarea" :rows="2" @on-blur="onCodeChange" style="width: 99%"></i-input>
</form-item>
<form-item label="宽度">
<i-input v-model="width" placeholder="请输入宽度" :min="1" type="number" @on-blur="onCodeChange" style="width: 99%"></i-input>
</form-item>
<form-item label="高度">
<i-input v-model="height" placeholder="请输入高度" :min="1" type="number" @on-blur="onCodeChange" style="width: 99%"></i-input>
</form-item>
<form-item label="前景色" class="colorHeight">
<i-input v-model="colorDark" size="small" style="width: 111px;" @on-change="onCodeChange">
<span slot="append">
<color-picker class="colorPicker colorHeight" v-model="colorDark" :editable="false" :transfer="true" size="small" @on-change="onCodeChange"/>
</span>
</i-input>
</form-item>
<form-item label="背景色" class="colorHeight">
<i-input v-model="colorLight" size="small" style="width: 111px;" @on-change="onCodeChange">
<span slot="append">
<color-picker class="colorPicker" v-model="colorLight" :editable="false" :transfer="true" size="small" @on-change="onCodeChange"/>
</span>
</i-input>
</form-item>
</i-form>
</div>
</script>
<script>
Vue.component('j-qrcode-setting', {
template: '#qrcode-setting-template',
props: {
settings: {
type: Object,
required: true,
default:()=>{}
}
},
data(){
return {
text: '',
width:'',
height:'',
colorLight: '#fff',
colorDark: '#000'
}
},
watch:{
settings:{
deep: true,
immediate: true,
handler: function(){
this.resetForm()
}
}
},
methods:{
resetForm: function () {
if(this.settings){
Object.keys(this.settings).map(k=>{
this[k] = this.settings[k]
})
}
},
onCodeChange(){
let obj = {}
Object.keys(this.settings).map(k=>{
obj[k] = this[k]
})
//清除颜色后恢复默认
obj.colorLight=this.colorLight?obj.colorLight:'#ffffff'
obj.colorDark=this.colorDark?this.colorDark:'#000000'
this.$emit('change', obj)
}
}
})
</script>

View File

@@ -0,0 +1,73 @@
<script type="text/x-template" id="radar-setting-template">
<Submenu name="10" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>雷达图设置</span>
</template>
<div class="blockDiv" >
<Row class="ivurow" v-for="(item,index) in radarOption[0].indicator" :key="index">
<Tooltip :content="item.name" placement="bottom">
<p>{{item.name.substr(0,2)}}..最大值&nbsp;&nbsp;</p>
</Tooltip>
<i-input size="small" type="number" v-model="item.max" @on-blur="onRadarChange" style="width: 126px;"></i-input>
</Row>
<Row class="ivurow">
<p>字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="radarOption[0].name_textStyle_fontSize" @on-blur="onRadarChange" class="iSelect"></i-input>
</Row>
<Row class="ivurow" v-if="typeof radarOption[0].name_textStyle_color!== 'undefined'">
<p>字体颜色&nbsp;&nbsp;</p>
<i-input v-model="radarOption[0].name_textStyle_color" size="small" class="iSelect" @on-change="onRadarChange">
<span slot="append">
<color-picker class="colorPicker" v-model="radarOption[0].name_textStyle_color" :editable="false" :transfer="true" size="small" @on-change="onRadarChange"/>
</span>
</i-input>
</Row>
<Row class="ivurow" v-if="typeof radarOption[0].axisLine_lineStyle_color!== 'undefined'">
<p>轴线颜色&nbsp;&nbsp;</p>
<i-input v-model="radarOption[0].axisLine_lineStyle_color" size="small" class="iSelect" @on-change="onRadarChange">
<span slot="append">
<color-picker class="colorPicker" v-model="radarOption[0].axisLine_lineStyle_color" :editable="false" :transfer="true" size="small" @on-change="onRadarChange"/>
</span>
</i-input>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-radar-setting', {
template: '#radar-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
radarOption: []
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.radarOption = Object.assign(this.radarOption, this.settings)
}
},
onRadarChange(){
this.$emit('change','radar',this.radarOption)
}
}
})
</script>

View File

@@ -0,0 +1,68 @@
<script type="text/x-template" id="scatter-setting-template">
<div >
<Submenu name="9" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>散点设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>大小&nbsp;&nbsp;</p>
<slider v-model="scatterOption.symbolSize" @on-change="onScatterChange" style="margin-top: -9px;width: 160px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow" v-if="typeof scatterOption.itemStyle_color !== 'undefined'">
<p>颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="scatterOption.itemStyle_color" size="small" style="width: 165px;" @on-change="onScatterChange">
<span slot="append">
<color-picker class="colorPicker" v-model="scatterOption.itemStyle_color" :editable="false" alpha :transfer="true" size="small" @on-change="onScatterChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" style="z-index:9999">
<p style="margin-bottom: 10px;">透明度&nbsp;&nbsp;</p>
<slider max="1" step="0.1" v-model="scatterOption.itemStyle_opacity" @on-change="onScatterChange" style="margin-top: -9px;width: 148px;margin-left: 5px;" ></slider>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-scatter-setting', {
template: '#scatter-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
scatterOption: {
itemStyle_color:"#C23531"
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.scatterOption = Object.assign(this.scatterOption, this.settings)
}
},
onScatterChange(){
this.$emit('change',this.scatterOption)
}
}
})
</script>

View File

@@ -0,0 +1,105 @@
<!-- 下拉输入框 支持下拉框、输入框切换 -->
<style>
.jimu-cust-component .ivu-input-group{
top: 0;
}
</style>
<script type="text/x-template" id="select-input-template">
<div class="jimu-cust-component">
<i-select v-if="selectFlag" filterable size="small" :value="selectedValue" :transfer="true" :clearable="true" @on-change="selectChange">
<i-option v-for="(item, index) in selectOptions" :value="item.value" :key="index">{{ item.title }}</i-option>
</i-select>
<i-input v-else size="small" v-model="inputValue" @on-change="inputChange" placeholder="请输入自定义表达式">
<i-button size="small" slot="append" icon="arrow-return-left" @click="backSelect">返回下拉框</i-button>
</i-input>
</div>
</script>
<script>
Vue.component('j-select-input', {
template: '#select-input-template',
props: {
options: {
type: Object,
required: false,
default:()=>{}
},
value:{
type: String,
required: false,
default: ''
}
},
data(){
return {
selectFlag: true,
selectedValue: '',
inputValue: '',
selectOptions: []
}
},
watch:{
options:{
deep: true,
immediate: true,
handler: function(){
this.resetOptions()
}
},
value:{
immediate: true,
handler: function(){
if(!this.value){
this.selectFlag = true
this.selectedValue = ''
this.inputValue = ''
}else{
if(this.value.startsWith('=')){
this.selectFlag = false
this.selectedValue = ''
this.inputValue = this.value
}else{
this.selectFlag = true
this.selectedValue = this.value
this.inputValue = ''
}
}
}
}
},
methods:{
// 清空
resetOptions(){
let arr = []
for(let item of this.options){
arr.push({
title: item.title,
value: item.value
})
}
arr.push({
title: '自定义表达式',
value: '-1'
})
this.selectOptions = [...arr]
},
inputChange(e){
this.$emit('on-change', e.target.value)
},
selectChange(value){
if(value == -1){
this.selectFlag = false
this.selectedValue = ''
this.inputValue = ''
}else{
this.selectedValue = value
this.$emit('on-change', this.selectedValue)
}
},
backSelect(){
this.selectFlag = true
}
}
})
</script>

View File

@@ -0,0 +1,496 @@
<#--多选组件,用于远程搜索查询
item:传递的参数包含字典code查询key
value:view组件传递的值 v-model
index:下标-->
<script type="text/x-template" id="select-scroll-multiple-template">
<div :id="'click'+index">
<div class="ivu-select ivu-select-multiple ivu-select-small" style="width: 100%">
<div class="ivu-select-selection" @click="handleClick">
<span class="select-dict-text" v-if="dictText!=''">{{dictText}}</span>
<span v-else class="ivu-select-input" style="color: rgb(197,201,203)">{{'请选择'+dataList.title}}</span>
</div>
<i class="ivu-icon ivu-icon-md-close ivu-select-arrow" @click="handleIconClick"></i>
</div>
<div class="scroll-class" v-if="scrollShow">
<Scroll :class="noData == true?'no-loading':''" :height="dictHeight" :on-reach-bottom="handleReachBottom"
:distance-to-edge="1">
<input v-model="searchText" type="text" placeholder="请输入查询条件" class="ivu-select-input bottom-border" />
<ul v-for="(item,index) in dictList" :key="index" @mousedown="scrollListClick(item,index)"
class="scroll-list-class">
<li :class="item.active == true?'select-item-selected':''"><span>{{ item.text }}</span></li>
</ul>
<ul class="no-more-data" v-if="noData">
<li style="font-size: 12px;text-align: center;margin-top:5px">暂无更多数据</li>
</ul>
</Scroll>
</div>
</div>
</script>
<script>
Vue.component('j-select-scroll-multiple', {
template: '#select-scroll-multiple-template',
props: {
item: {
type: Object,
default: () => []
},
value: {
type: String,
default: () => ""
},
index: {
type: Number
}
},
data() {
return {
// 表格高度
dictHeight: 200,
// 数据总数
tableCount: 0,
//下拉框数据
dataList: {},
dictList: [],
//字典文本
dictText: "",
// 是否加载中
tableLoading: false,
//滚动组件是否显示
scrollShow: false,
userpage: 1,
noData: false,
//初始字典text
initText:"",
//是否初始值
initValue:true,
//复制一份字典集合
copyDictList:[],
//搜索的文本
searchText:"",
//字典值
dictValue:""
}
},
create() {
},
watch: {
item: {
deep: true,
immediate: true,
handler: function () {
this.dictData();
}
},
value: {
immediate: true,
handler: function () {
this.setDictText();
}
},
searchText(){
this.handleOnChange();
}
},
mounted() {
//页面初始化监听click事件
document.addEventListener("click", e => {
this.closeScroll(e);
});
},
beforeDestroy() {
//页面销毁移除监听事件
document.removeEventListener("click", this.closeScroll);
},
methods: {
/**
* 关闭滚动弹窗
*/
closeScroll(e) {
let self = this;
let click = document.getElementById("click"+this.index);
if (click && !click.contains(e.target)) {
if (self.scrollShow == true){
self.scrollShow = false;
}
}
},
/**
* 获取字典数据
*/
dictData() {
if (this.item) {
this.dataList = JSON.parse(this.item)
if (this.dataList) {
this.dictList = this.dataList.dictList
this.copyDictList = this.dataList.dictList
//目前只有不勾选复选框并且不是select的时候才会分页api和普通的字典不用去后台查数据
if(this.dataList.dictCode && this.dataList.dictCode.indexOf("select") ==-1 || this.dataList.dictList.length<7) {
this.noData = true
}
}
this.dictHeight = this.dictList.length>6?200:this.dictList.length*32+82
}
},
/**
*为字典值赋值
*/
setDictText() {
if (this.value.length == 0) {
this.dictText = "";
this.searchText = ""
//重置选中事件
this.restActive();
}else{
this.loopData(this.dictList);
}
},
/**
*赋值字典集合及是否选中
* @param dictList 字典集合
*/
loopData(dictList){
//初始化的时候才赋默认值
let dictText = this.dictText
let values = this.value
for (let i = 0; i <dictList.length ; i++) {
let value = dictList[i].value;
if(values.indexOf(value)!=-1){
//字典文本不为空,得判断时候包含此文本
if(dictText && dictText.indexOf(dictText) != 0){
dictText = dictText + dictList[i].text +","
}
//字典文本是空,直接相等即可
if(!dictText){
dictText = dictList[i].text;
}
dictList[i].active = true
}
}
if(dictText && dictText.charAt(dictText.length-1) == ","){
dictText = dictText.substring(0,dictText.length-1)
}
this.dictText = dictText
this.dictList = dictList
},
/**
* 重置选中状态
*/
restActive(){
let dictList = this.dictList
for (let i = 0; i <dictList.length ; i++) {
if(dictList[i].active){
dictList[i].active = false
}
}
},
/**
* 列表点击事件
* @param val 字典对象value,text
* @param index 当前循环的到第几个
*/
scrollListClick(val,index) {
if(this.dictText){
let dictTextArray = this.dictText.split(",");
let dictValueArray = this.value
//是否是已删除的
let remove = false
for (let i = 0; i < dictTextArray.length; i++) {
if(dictTextArray[i]==val.text){
dictTextArray.splice(i,1)
dictValueArray.splice(i,1)
remove =true
}
}
if(!remove){
dictTextArray.push(val.text)
dictValueArray.push(val.value)
}
if(dictTextArray.length>0){
this.dictText = dictTextArray.toString()
this.value = dictValueArray
}else{
this.dictText = ""
this.value = []
}
}else{
this.dictText = val.text
let valueArray = [];
valueArray.push(val.value)
this.value =valueArray
}
this.scollShow = true;
let active = this.dictList[index].active;
this.dictList[index].active = !active;
//返回值
this.returnDictValue(val.value);
},
/**
*输入框点击事件
*/
handleClick() {
this.scrollShow = !this.scrollShow;
},
/**
*滚动条无限加载
*/
handleReachBottom() {
if (!this.noData) {
return new Promise(resolve => {
if (this.noData) {
resolve();
}
this.userpage = this.userpage + 1;
setTimeout(() => {
if(!this.dataList.dictCode || this.dataList.dictCode.indexOf("select") !=-1) {
this.getDictData(0);
}else{
//前台进行搜索
if(this.dictText){
this.searchDictByText();
}else{
this.dictList = this.copyDictList
}
}
resolve();
}, 500);
});
}
},
/**
*值发生改变请求后台
*/
handleOnChange() {
this.userpage = 1;
this.scrollShow = true
//字典为空或者包含select语句才会后台搜索否则直接在前台搜索
if(!this.dataList.dictCode || this.dataList.dictCode.indexOf("select") !=-1) {
//后台进行搜索
this.getDictData(1);
}else{
//前台进行搜索
//update-begin---author:wangshuai ---date:20221117 for[issues/1316]查询栏 下拉多选搜索无效------------
if(this.searchText){
//update-end---author:wangshuai ---date:20221117 for[issues/1316]查询栏 下拉多选搜索无效--------------
this.searchDictByText();
}else{
this.dictList = this.copyDictList
}
this.dictHeight = this.dictList.length>6?200:this.dictList.length*32+82
}
},
/**
* 查询字典数据
* @param type 字典值需要拼接还是直接替换 0拼接 1 替换
*/
getDictData(type) {
let paramSearch = this.dataList.paramSearch
let dbKey = this.dataList.dbCode + "__" + this.dataList.name
let params = getRequestUrlParam();
let dataStr = {
"reportId": configId,
"text": this.searchText,
"key": dbKey,
"paramSearch": paramSearch,
"params": params,
"pageNo": this.userpage
}
$http.get({
url: api.dictCodeSearch,
data: dataStr,
success: (res) => {
if (res && res.length > 0) {
let dictList = this.dictList;
//滚动条无限加载中直接push
if (type == 0) {
for (let i = 0; i < res.length; i++) {
dictList.push(res[i])
}
} else {
//查询直接赋值给字典数组
dictList = res
}
//循环数据赋是否已点击
this.loopData(dictList);
//判断长度,是否有数据
if(res.length<7){
this.noData = true
}else{
this.noData = false
}
} else {
if (type == 1) {
this.dictList = []
}
this.noData = true
}
//为下拉框设置高度
this.dictHeight = this.dictList.length>6?200:this.dictList.length*32+82
}
})
},
/**
*前台搜索
*/
searchDictByText(){
let dictList = this.dictList
let searchText = this.searchText
let newDictList = [];
if(!this.searchText){
this.dictList = this.copyDictList;
}else{
for (let i = 0; i <dictList.length; i++) {
let value = dictList[i].value;
let text = dictList[i].text;
if(value.indexOf(searchText) >= 0 || value === searchText){
newDictList.push(dictList[i])
}else if(text.indexOf(searchText) >= 0 || text ===searchText){
newDictList.push(dictList[i])
}
}
if(newDictList.length>0){
this.dictList = newDictList;
}
}
this.dictHeight = this.dictList.length>6?150:this.dictList.length*32+82
},
/**
*返回父组件的值
*/
returnDictValue() {
let val = {};
val.value = this.value
val.key = this.dataList.key;
this.$emit('dictmultipleok', val)
},
/**
* 图标点击事件
*/
handleIconClick(){
this.dictText = ""
this.value = []
let val = {};
val.value = []
val.key = this.dataList.key;
this.$emit('dictmultipleok', val)
this.scollShow = false
}
}
})
</script>
<style scoped>
::-webkit-scrollbar {
width: 6px;
height: 16px;
background-color: #F5F5F5;
}
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track {
border-radius: 3px;
background-color: #f5f7f9;
}
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb {
border-radius: 3px;
background-color: #ccc;
}
.scroll-class {
position: absolute;
background: white;
z-index: 9999;
overflow: hidden;
border: 1px solid #dddee1;
border-radius: 4px;
top: 35px;
-webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
}
.scroll-list-class {
cursor: pointer;
z-index: 9999;
list-style-type: none;
}
.scroll-list-class li span {
margin-left: 15px;
font-size: 14px;
}
.scroll-list-class :hover {
background: #f3f3f3;
}
.no-more-data {
border-top: 1px solid #f0f0f0;
}
.no-loading .ivu-spin-text {
display: none;
}
.no-loading .ivu-scroll-content-loading {
opacity: 1;
}
.ivu-scroll-loader {
margin-top: -5px;
}
.select-item-selected{
color:rgba(45,140,240,.9);
position:relative;
}
.select-item-selected :after{
display: inline-block;
font-family: Ionicons, serif;
speak: none;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
text-rendering: optimizeLegibility;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
vertical-align: -0.125em;
text-align: center;
font-size: 24px;
content: "\F171";
color: rgba(45,140,240,.9);
position: absolute;
top: 2px;
right: 8px;
}
.select-dict-text{
display:inline;
float: left;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
white-space:nowrap;
margin-left: 5px;
max-width:80%;
position:relative;
}
.bottom-border{
border-bottom:1px solid #f0f0f0;
}
.ivu-select-input{
display: inline;
height: 32px;
line-height: 32px;
width: 190px;
font-size: 14px;
outline: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #515a6e;
position: relative;
cursor: pointer;
padding-left: 16px;
}
.ivu-select-multiple .ivu-select-selection{
padding: 0 0 0 4px;
float: left;
}
.icon-position{
position: relative;
right: 25px;
top: 6px;
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,320 @@
<#--单选组件,用于远程搜索查询
item:传递的参数包含字典code查询key
value:view组件传递的值 v-model-->
<script type="text/x-template" id="select-scroll-radio-template">
<div>
<div style="display: flex">
<input ref="clickInput" class="ivu-input ivu-input-default" v-model="dictText"
:placeholder="'请选择'+dataList.title" @blur="clickBlur"
@click="handleClick" style="cursor: pointer"/>
<i class="ivu-icon ivu-icon-md-close ivu-select-arrow" @click="handleIconClick" v-if="dictText"></i>
</div>
<div class="scoll-class" v-if="scollShow">
<Scroll :class="noData == true?'no-loading':''" :height="dictHeight" :on-reach-bottom="handleReachBottom"
:distance-to-edge="1">
<ul v-for="(item,index) in dictList" :key="index" @mousedown="scollListClick(item)"
class="scoll-list-class">
<li><span>{{ item.text }}</span></li>
</ul>
<ul class="no-more-data" v-if="noData">
<li style="font-size: 12px;text-align: center;margin-top:5px">暂无更多数据</li>
</ul>
</Scroll>
</div>
</div>
</script>
<script>
Vue.component('j-select-scroll-radio', {
template: '#select-scroll-radio-template',
props: {
item: {
type: Object,
default: () => []
},
value: {
type: String,
default: () => ""
}
},
data() {
return {
// 表格高度
dictHeight: 200,
// 数据总数
tableCount: 0,
dataList: {},
dictList: [],
//字典文本
dictText: "",
// 是否加载中
tableLoading: false,
//滚动组件是否显示
scollShow: false,
userpage: 1,
noData: false,
//初始字典text
initText: "",
//是否初始值
initValue: true,
//复制一份字典集合
copyDictList: []
}
},
create() {
},
watch: {
item: {
deep: true,
immediate: true,
handler: function () {
this.dictData();
}
},
value: {
deep: true,
immediate: true,
handler: function () {
this.setDictText();
}
},
dictText:{
immediate: true,
handler: function () {
this.handleOnChange()
}
}
},
methods: {
/**
* 获取字典数据
*/
dictData() {
if (this.item) {
this.dataList = JSON.parse(this.item)
if (this.dataList) {
this.dictList = this.dataList.dictList
this.copyDictList = this.dataList.dictList
//目前只有不勾选复选框并且不是select的时候才会分页api和普通的字典不用去后台查数据
if (this.dataList.dictCode && this.dataList.dictCode.indexOf("select") == -1 || this.dataList.dictList.length < 7) {
this.noData = true
}
}
}
},
/**
*为字典值赋值
*/
setDictText() {
if (!this.value) {
this.dictText = "";
this.searchLocalOrApi();
} else {
//赋值默认值
let dict = this.dictList.filter(item => item.value == this.value)
if (dict && dict.length > 0) {
this.dictText = dict[0].text
this.initText = dict[0].text
}
//update-begin---author:wangshuai ---date:20220315 for下拉单选样式出现混乱--------
this.dictHeight = this.dictList.length > 6 ? 200 : this.dictList.length * 32 + 50
//update-end---author:wangshuai ---date:20220315 for下拉单选样式出现混乱--------
}
},
//无限加载中的事件
scollListClick(val) {
this.scollShow = false;
this.dictText = val.text;
this.value = val.value
val.key = this.dataList.key;
this.$emit('dictok', val)
this.searchLocalOrApi();
},
handleClick() {
this.scollShow = !this.scollShow;
},
clickBlur() {
this.scollShow = false;
},
//滚动条无限加载
handleReachBottom() {
if (!this.noData) {
return new Promise(resolve => {
if (this.noData) {
resolve();
}
this.userpage = this.userpage + 1;
setTimeout(() => {
this.getDictData(0);
resolve();
}, 500);
});
}
},
handleOnChange() {
let val = {}
val.key = this.dataList.key
//update-begin---author:wangshuai ---date:20220315 for[JMREP-2552]下拉单选重置就出不来了--------
if(!this.dictText){
val.value = ""
}else{
val.value = this.value
}
//update-end---author:wangshuai ---date:20220315 for[JMREP-2552]下拉单选重置就出不来了--------
this.$emit('dictok', val)
this.searchLocalOrApi();
},
searchLocalOrApi() {
this.userpage = 1;
//字典为空或者包含select语句才会后台搜索否则直接在前台搜索
if (!this.dataList.dictCode || this.dataList.dictCode.indexOf("select") != -1) {
//后台进行搜索
this.getDictData(1);
} else {
//前台进行搜索
if (this.dictText) {
this.searchDictByText();
} else {
this.dictList = this.copyDictList
//update-begin---author:wangshuai ---date:20220315 for下拉单选样式出现混乱--------
this.dictHeight = this.dictList.length > 6 ? 200 : this.dictList.length * 32 + 50
//update-end---author:wangshuai ---date:20220315 for下拉单选样式出现混乱--------
}
}
},
/**
* 查询字典数据
* @param type 字典值需要拼接还是直接替换 0拼接 1 替换
*/
getDictData(type) {
let paramSearch = this.dataList.paramSearch
let dbKey = this.dataList.dbCode + "__" + this.dataList.name
let params = getRequestUrlParam();
let dataStr = {
"reportId": configId,
"text": this.dictText,
"key": dbKey,
"paramSearch": paramSearch,
params: params,
pageNo: this.userpage
}
$http.get({
url: api.dictCodeSearch,
data: dataStr,
success: (res) => {
if (res && res.length > 0) {
if (type == 0) {
for (let i = 0; i < res.length; i++) {
this.dictList.push(res[i])
}
} else {
this.dictList = res
}
if (res.length < 7) {
this.noData = true
} else {
this.noData = false
}
} else {
//如果是输入框搜索数据为空的情况下直接清空
if (type == 1) {
this.dictList = []
}
this.noData = true
}
this.dictHeight = this.dictList.length > 6 ? 200 : this.dictList.length * 32 + 50
}
})
},
searchDictByText() {
let dictList = this.dictList
let dictText = this.dictText
let newDictList = [];
for (let i = 0; i < dictList.length; i++) {
let value = dictList[i].value;
let text = dictList[i].text;
if (value.indexOf(dictText) >= 0 || value === dictText) {
newDictList.push(dictList[i])
}else if(text.indexOf(dictText) >= 0 || text === dictText){
newDictList.push(dictList[i])
}
}
this.dictList = newDictList;
//update-begin---author:wangshuai ---date:20220315 for下拉单选样式出现混乱--------
this.dictHeight = this.dictList.length > 6 ? 200 : this.dictList.length * 32 + 50
//update-end---author:wangshuai ---date:20220315 for下拉单选样式出现混乱--------
},
/**
* 点击叉数据清空
*/
handleIconClick(){
this.dictText=""
this.handleOnChange()
}
}
})
</script>
<style scoped>
::-webkit-scrollbar {
width: 6px;
height: 16px;
background-color: #F5F5F5;
}
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track {
border-radius: 3px;
background-color: #f5f7f9;
}
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb {
border-radius: 3px;
background-color: #ccc;
}
.scoll-class {
position: absolute;
background: white;
z-index: 9999;
width: 100%;
overflow: hidden;
border: 1px solid #dddee1;
border-radius: 4px;
top: 35px;
-webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
}
.scoll-list-class {
cursor: pointer;
z-index: 9999;
}
.scoll-list-class li span {
margin-left: 15px;
font-size: 14px;
}
.scoll-list-class :hover {
background: #f3f3f3;
}
.no-more-data {
border-top: 1px solid #f0f0f0;
}
.no-loading .ivu-spin-text {
display: none;
}
.no-loading .ivu-scroll-content-loading {
opacity: 1;
}
.ivu-scroll-loader {
margin-top: -5px;
}
</style>

View File

@@ -0,0 +1,149 @@
<script type="text/x-template" id="series-setting-template">
<Submenu name="15" style="border-bottom: inset 1px;" class="dataSourceForm">
<template slot="title">
<span class="rightFontSize">数值设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 141px;" v-model="seriesOption.show" @on-change="onSeriesLabelChange"/>
</Row>
<Row class="ivurow">
<p>字体大小&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" size="small" type="number" v-model="seriesOption.textStyle_fontSize" @on-blur="onSeriesLabelChange"></i-input>
</Row>
<Row class="ivurow" v-if="typeof seriesOption.textStyle_color !== 'undefined'">
<p>字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="seriesOption.textStyle_color" size="small" @on-change="onSeriesLabelChange">
<span slot="append">
<color-picker class="colorPicker" v-model="seriesOption.textStyle_color" :editable="false" :transfer="true" size="small" @on-change="onSeriesLabelChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow rightFontSize">
<p>字体粗细&nbsp;&nbsp;</p>
<i-select size="small" class="iSelect" v-model="seriesOption.textStyle_fontWeight" @on-change="onSeriesLabelChange" style="width: 115%">
<i-option class="rightFontSize" value="normal">正常</i-option>
<i-option class="rightFontSize" value="bold">粗体</i-option>
<i-option class="rightFontSize" value="bolder">特粗</i-option>
<i-option class="rightFontSize" value="lighter">细体</i-option>
</i-select>
</Row>
<Row class="ivurow rightFontSize">
<p style="margin-bottom: 10px;">字体位置&nbsp;&nbsp;</p>
<i-select size="small" class="iSelect" v-model="seriesOption.position" @on-change="onSeriesLabelChange">
<i-option class="rightFontSize" v-for="(item,index) in seriesOption.labelPositionArray" :value="item.value" :index="index">
{{ item.text }}
</i-option>
</i-select>
</Row>
<Row class="ivurow rightFontSize">
<p style="margin-bottom: 10px;">数值旋转&nbsp;&nbsp;</p>
<input-number :max="90" :min="-90" size="small" v-model="seriesOption.rotate" @on-change="onSeriesLabelChange"/>
</i-select>
</Row>
<Row class="ivurow rightFontSize">
<p style="margin-bottom: 10px;">是否显示数值&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 6px;" v-model="izShowNumber" @on-change="onSeriesFormatterChange"/>
</i-select>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-series-setting', {
template: '#series-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
seriesOption: {
textStyle_color:'',
textStyle_fontSize:'',
textStyle_fontWeight:'',
position:'',
formatter:'',
rotate:0,
type:''
},
labelPositions:[],
izShowNumber:false
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.seriesOption = Object.assign(this.seriesOption, this.settings)
//update-begin---author:wangshuai ---date:20220626 for[JMREP-2655]图表数值倾斜度设置后,数值不显示了/[issues/I5CO1P、issues/1100 、issues/1086]图表的数值显示,会连轴名称一起显示 ------------
//显示名称,没有显示数值
let type = this.seriesOption.type;
if(type === 'pie' || type === 'funnel' || type === 'scatter' || type === 'graph'){
//update-begin---author:wangshuai ---date:20220407 for[issues/I50IKB]饼图 如何直接在图上显示各分类对应的数值------------
if(this.seriesOption.formatter && "{b}"!==this.seriesOption.formatter){
this.izShowNumber = true;
}else{
this.izShowNumber = false;
}
//update-end---author:wangshuai ---date:20220407 for[issues/I50IKB]饼图 如何直接在图上显示各分类对应的数值------------
}else{
//只显示数值如formatter值不为' ',则显示数值,否则不显示
if(this.seriesOption.formatter === " "){
this.izShowNumber = false
}else{
this.seriesOption.formatter="{c}"
this.izShowNumber = true
}
}
//update-end---author:wangshuai ---date:20220626 for[JMREP-2655]图表数值倾斜度设置后,数值不显示了/[issues/I5CO1P、issues/1100 、issues/1086]图表的数值显示,会连轴名称一起显示 --------------
}
},
onSeriesLabelChange(){
let {labelPositionArray,...otherOptions}=this.seriesOption;
this.$emit('change', otherOptions,'label')
},
/**
* 图表设置格式化
*/
onSeriesFormatterChange(){
//update-begin---author:wangshuai ---date:20220626 for[JMREP-2655]图表数值倾斜度设置后,数值不显示了/[issues/I5CO1P、issues/1100 、issues/1086]图表的数值显示,会连轴名称一起显示 ------------
let type = this.seriesOption.type;
if(type === 'pie' || type === 'funnel' || type === 'scatter' || type === 'graph'){
//如果是选中数值状态
if(this.izShowNumber){
this.seriesOption.formatter="{b}:{c}"
}else{
this.seriesOption.formatter="{b}"
}
}else{
//如果是选中数值状态,并且初始值为数值
if(this.izShowNumber){
this.seriesOption.formatter="{c}"
}else{
this.seriesOption.formatter=" "
}
}
//update-end---author:wangshuai ---date:20220626 for[JMREP-2655]图表数值倾斜度设置后,数值不显示了/[issues/I5CO1P、issues/1100 、issues/1086]图表的数值显示,会连轴名称一起显示 ------------
let {labelPositionArray,...otherOptions}=this.seriesOption;
this.$emit('change', otherOptions,'label')
}
}
})
</script>

View File

@@ -0,0 +1,169 @@
<script type="text/x-template" id="sql-function-replace-template">
<div>
<!-- 新增数据集 弹框-begin -->
<Modal width="800px" :loading="loading" v-model="sqlFunctionShow" :title="moduleTitle">
<div slot="footer">
<Button type="text" size="small" @click="clearSqlFunction">取消</Button>
<Button type="primary" size="small" @click="saveSqlFunction">确定</Button>
</div>
<Table ref="paramTable" :columns="functionColumns" :data="functionData">
<template slot="paramValue" slot-scope="props">
<i-form :ref="'formDynamic'+props.idx" :model="props.row">
<form-item prop="paramValue" style="margin-top: 10px">
<i-input v-model="props.row.paramValue" size="small" />
</form-item>
</i-form>
</template>
</Table>
</Modal>
<!-- 新增数据集 弹框-end -->
</div>
</script>
<script>
Vue.component('j-sql-function-replace', {
template: '#sql-function-replace-template',
data(){
return {
moduleTitle:"函数参数替换",
sqlFunctionShow:false,
functionColumns: [
{
type: 'index',
width: 60,
align: 'center'
},
{
title: '参数',
key: 'paramName',
width: '200',
render: (h, params) => {
return this.renderInput(h, params, 'paramName','functionData')
}
},
{
title: '默认值',
key: 'paramValue',
width: '200',
render: (h, params) => {
this.functionData[params.index] = params.row;
return h(
"div",
this.$refs.paramTable.$scopedSlots.paramValue({
row: params.row,
idx: params.row._index
})
)
}
}
],//函数列
functionData:[], //函数数据
loading:false,
dbDynSql:"",
dbKey:""
}
},
methods: {
renderInput(h, params, field,tabIndex,placeholder) {
return h('i-input', {
props: {
"size":"small",
type: 'text',
readonly:true,
value: this.functionData[params.index][field],
placeholder: placeholder?placeholder:`请输入`+params.column.title
},
on: {
'on-change': (event) => {
this.functionData[params.index][field] = event.target.value;
}
},
})
},
//初始化参数解析
initDataSource(dbDynSql,dbKey,paramData){
this.dbDynSql = dbDynSql
this.dbKey = dbKey
//update-begin---author:wangshuai Date:20211221 for[JMREP-2505]存储过程没有空格参数会连接到一起------------
let reg=/\$\{[^}]*\}/g;
//update-end---author:wangshuai Date:20211221 for[JMREP-2505]存储过程没有空格参数会连接到一起------------
let dbDynSqlArr = dbDynSql.match(reg);
let paramsArr = [];
if(dbDynSqlArr && dbDynSqlArr.length>0){
let maxOrderNum = 1;
//防止参数重复
let paramExistArray = []
dbDynSqlArr.forEach((item,index)=>{
let paramName = item.replace("$\{","").replace("}","").trim();
if(paramExistArray.indexOf(item)<0 && item){
paramExistArray.push(item)
let paramObj = {};
let paramFilter = paramData.filter(item=> item.paramName==paramName);
paramObj.paramName = paramName;
paramObj.tableIndex = index;
if(!paramFilter[0]){
paramObj.paramValue = ""
}else{
let paramValue = paramFilter[0].paramValue;
if(paramValue){
paramObj.paramValue = paramValue
}
}
paramsArr.push(paramObj);
}
})
}
this.functionData = paramsArr;
},
//修改报表SQl确定事件
saveSqlFunction(){
let dbDynSql = this.dbDynSql;
let functionData = this.functionData;
let model = true
let that = this
for (const data of functionData) {
let paramName = data.paramName;
let paramValue = data.paramValue;
if(dbDynSql.indexOf("isNotEmpty")<0 && dbDynSql.indexOf("${'<#if'}")<0){
if(!paramValue){
that.sqlFunctionShow=true
that.$Message.warning("请输入"+paramName+"对应的值")
model = true;
break;
}else{
model = false;
}
}else{
model = false;
break;
}
}
if(model == false){
this.$emit("functionok", this.functionData)
this.clearSqlFunction()
}else{
this.sqlFunctionShow=true
}
},
clearSqlFunction(){
this.sqlFunctionShow=false
this.dbDynSql=""
this.dbKey= ""
this.functionData=[]
},
//默认值加验证不为空
async childrenRules(){
let success = true
for (let i = 0, len = this.functionData.length; i < len; i++) {
this.$refs['formDynamic' + i].validate(valid => {
if (!valid) {
success=false
}
})
}
return success;
},
}
})
</script>

View File

@@ -0,0 +1,103 @@
<script type="text/x-template" id="title-setting-template">
<div class="title-setting-fontsize">
<Submenu name="1" style="border-bottom: inset 1px;">
<template slot="title" ><span class="rightFontSize">标题设置</span></template>
<div class="blockDiv">
<Row class="ivurow">
<p>显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 142px;" v-model="titleOption.show" @on-change="onTitleChange"/>
</Row>
<Row class="ivurow">
<p>标题文字&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" size="small" v-model="titleOption.text" @on-blur="onTitleChange"></i-input>
</Row>
<Row class="ivurow" v-if="typeof titleOption.textStyle_color !== 'undefined'">
<p>字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input v-model="titleOption.textStyle_color" size="small" class="rightFontSize iSelect" @on-change="onTitleChange">
<span slot="append">
<color-picker class="colorPicker" v-model="titleOption.textStyle_color" :editable="false" :transfer="true" size="small" @on-change="onTitleChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow">
<p>字体加粗&nbsp;&nbsp;</p>
<#--:model.sync="echartInfo.titleFontWeight"-->
<i-select size="small" class="rightFontSize iSelect" v-model="titleOption.textStyle_fontWeight" @on-change="onTitleChange">
<i-option value="normal" class="rightFontSize">正常</i-option>
<i-option value="bold" class="rightFontSize">粗体</i-option>
<i-option value="bolder" class="rightFontSize">特粗</i-option>
<i-option value="lighter" class="rightFontSize">细体</i-option>
</i-select>
</Row>
<Row class="ivurow">
<p>字体大小&nbsp;&nbsp;</p>
<i-input size="small" type="number" v-model="titleOption.textStyle_fontSize" @on-change="onTitleChange"
class="iSelect rightFontSize"></i-input>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">标题位置&nbsp;&nbsp;</p>
<i-select size="small" class="iSelect rightFontSize" v-model="titleOption.left" @on-change="onTitleChange" style="width: 132%;">
<i-option value="left" class="rightFontSize">左对齐</i-option>
<i-option value="center" class="rightFontSize">居中</i-option>
<i-option value="right" class="rightFontSize">右对齐</i-option>
</i-select>
</Row>
<Row class="ivurow">
<p>顶边距&nbsp;&nbsp;</p>
<slider v-model="titleOption.top" @on-change="onTitleChange" :tip-format="formatTop" style="margin-top: -9px;width: 150px;margin-left: 5px;"></slider>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-title-setting', {
template: '#title-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
titleOption: {
show: true,
top: 5,
text: '',
textStyle_color: '',
textStyle_fontWeight: '',
textStyle_fontSize: '',
left: ''
}
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
formatTop(val){
return val + 'px';
},
initData: function (){
if (this.settings){
this.titleOption = Object.assign(this.titleOption, this.settings)
}
},
onTitleChange(){
this.$emit('change', 'title', this.titleOption)
}
}
})
</script>

View File

@@ -0,0 +1,86 @@
<script type="text/x-template" id="tooltip-setting-template">
<div>
<Submenu name="16" style="border-bottom: inset 1px;" class="rightFontSize">
<template slot="title">
<span>提示语设置</span>
</template>
<div class="blockDiv">
<Row class="ivurow">
<p>显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 141px;" v-model="tooltipOption.show" @on-change="onTooltipChange"/>
</Row>
<Row class="ivurow">
<p>字体大小&nbsp;&nbsp;</p>
<i-input class="iSelect" size="small" type="number" v-model="tooltipOption.textStyle_fontSize" @on-blur="onTooltipChange"></i-input>
</Row>
<Row class="ivurow" v-if="typeof tooltipOption.textStyle_color !== 'undefined'">
<p style="margin-bottom: 10px;">字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="iSelect" v-model="tooltipOption.textStyle_color" size="small" @on-change="onTooltipChange">
<span slot="append">
<color-picker class="colorPicker" v-model="tooltipOption.textStyle_color" :editable="false" :transfer="true" size="small" @on-change="onTooltipChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="selectedChartType =='pie.simple' || selectedChartType =='pie.doughnut' || selectedChartType =='pie.rose'">
<span>百分比&nbsp;&nbsp;</span>
<Checkbox size="small" v-model="tooltipOption.percentage" true-value="1" false-value="0" style="margin-left: 14px" @on-change="percentageChange"></Checkbox>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-tooltip-setting', {
template: '#tooltip-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
tooltipOption: {
textStyle_color: '',
percentage:0
},
selectedChartType:"pie.simple"
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
}
},
methods: {
initData: function (){
if (this.settings){
this.selectedChartType = vm.selectedChartType
this.tooltipOption = Object.assign(this.tooltipOption, this.settings)
}
},
onTooltipChange(){
this.$emit('change', 'tooltip', this.tooltipOption)
},
//是否为百分比显示
percentageChange(val){
let tooltip = this.tooltipOption;
let formatter = tooltip.formatter;
if(val == 1){
tooltip.formatter = formatter+ ' ({d}%)';
}else{
tooltip.formatter = formatter.substr(0,formatter.indexOf(" ({d}%)"))
}
this.$emit('change', 'tooltip', tooltip)
}
}
})
</script>

View File

@@ -0,0 +1,424 @@
<style>
.jmreport-comp .ivu-select-placeholder {
display: block;
height: 30px;
line-height: 30px;
color: #c5c8ce;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 8px;
padding-right: 22px;
}
.jmreport-comp .ivu-select-selected-value {
display: block;
height: 30px;
line-height: 30px;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 8px;
padding-right: 24px;
}
</style>
<script type="text/x-template" id="tree-select-template">
<div class="ivu-select ivu-select-default jmreport-comp">
<div tabindex="0" class="ivu-select-selection ivu-form-item-content" >
<div @mouseover="mouseover" @mouseleave="mouseleave">
<div @click="treeSelectContentShow" style="line-height: 23px;">
<div v-for="(item,index) in multipleShowVal" v-if="index<2" :key="item" class="ivu-tag ivu-tag-checked">
<span class="ivu-tag-text ">{{item}}</span>
<i class="ivu-icon ivu-icon-ios-close" @click.stop="removeVal(index)"></i>
</div>
<span v-if="multipleShowVal && multipleShowVal.length>2">
+{{ multipleShowVal.length - 2 }}
</span>
<span v-if="multipleShowVal.length === 0" class="ivu-select-placeholder">请选择</span>
<span class="" style="display: none;"></span>
</div>
<i :class="'ivu-icon ivu-icon-' +iconVal+ ' ivu-select-arrow'" @click="clickIcon"></i>
</div>
<div v-show="showTree" @mouseover="mouseover1" @mouseleave="mouseleave1" class="ivu-select-dropdown" style="max-height: 200px;overflow-y:auto;z-index:9999;min-width:100%;width: auto">
<#--<div style="width: 95%;margin-left: 10px;" v-show="showQuery">
<i-input v-model="queryTreeVal" placeholder="请输入筛选条件" @on-change="selectTreeChange" />
</div>-->
<div style="margin-left: 10px;">
<Tree
show-checkbox
check-strictly
:load-data="loadData"
:data="queryData"
:multiple="multiple"
ref="tree"
@on-check-change="treeCheckChange"
@on-select-change="selectChange">
</Tree>
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('j-tree-select', {
template: '#tree-select-template',
props: {
treeData: {
type: Array
},
value: {
type: String
},
url: {
type: String
},
loadtreeurl: {
type: String
}
},
data(){
return {
filterable: true,
multiple: true,
clearable: true,
showQuery: true,
disabled: true,
iconVal: 'ios-arrow-down',
showTree: false,
multipleShowVal: [],
multipleHideVal: [],
showData:[],
queryTreeVal: '',
queryData: [],
inputOver: false,
treeOver: false,
initValues:[] //初始化value值
}
},
watch:{
value:{
immediate: true,
handler: function(){
this.initTreeSelected()
}
}
},
mounted(){
this.loadRoot();
},
methods:{
combineTreeData(ls, callback, node){
let arr = []
if(ls && ls.length> 0){
for(let item of ls){
arr.push({
title: item.title,
id: item.id,
value: item.value,
loading: false,
children: []
})
}
}
//update-begin---author:wangshuai ---date:20220627 for[issues/965]报表下钻时返回上一页下拉树参数回显有问题------------
//如果没有配置通过value值获取树集合那么就不走孩子选中时间
if(this.loadtreeurl){
this.checkChildTreeData(arr,this.initValues)
}
//update-end---author:wangshuai ---date:20220627 for[issues/965]报表下钻时返回上一页下拉树参数回显有问题--------------
if(callback){
callback(arr)
}else{
this.queryData = [...arr]
}
if(arr.length==0){
delete node.children
delete node.loading
}
// console.log('this.queryData ', this.queryData)
},
// 加载子节点
loadData(item, callback){
// console.log("====")
// console.log("loadData")
// console.log("====")
let params = {
params: {pid: item.id}
}
$http.metaGet(this.url, params).then((res) => {
this.combineTreeData(res.data, callback, item)
}).catch(function (error){
console.log('加载树错误', error)
});
},
// 加载数据
loadRoot(){
// console.log("====")
// console.log("loadRoot")
// console.log("====")
$http.metaGet(this.url).then((res) => {
this.combineTreeData(res.data)
}).catch(function (error){
console.error('加载树错误', error)
});
},
initTreeSelected(){
// 如果有默认值 需要设置该方法
// console.log('initTreeSelected', this.value)
if(!this.value){
let arr = this.queryData;
this.clearTreeSelect(arr)
this.multipleShowVal = []
this.multipleHideVal = []
// 勾选状态去不掉
this.queryData = JSON.parse(JSON.stringify(arr))
}else{
//update-begin---author:wangshuai ---date:20220627 for[issues/965]报表下钻时返回上一页下拉树参数回显有问题------------
//如果没有配置通过值获取数集合,那么就不走请求接口,兼容老数据
if(this.loadtreeurl){
this.getTreeName(this.value);
}
//update-end---author:wangshuai ---date:20220627 for[issues/965]报表下钻时返回上一页下拉树参数回显有问题------------
}
},
clearTreeSelect(arr){
for (let i = 0; i < arr.length; i++) {
arr[i].selected = false
arr[i].checked = false
if (arr[i].children) {
this.clearTreeSelect(arr[i].children)
}
}
},
mouseover () {
this.inputOver = true;
},
mouseleave () {
this.inputOver = false;
setTimeout(()=>{
if(this.treeOver===false){
this.showTree = false
}
}, 200)
},
mouseover1 () {
this.treeOver = true;
},
mouseleave1 () {
this.treeOver = false;
setTimeout(()=>{
if(this.inputOver===false){
this.showTree = false
}
}, 200)
},
treeSelectContentShow(){
if (this.showTree) {
this.showTree = false
} else {
this.showTree = true
}
if (this.iconVal !== 'ios-close-circle') {
if (this.iconVal === 'ios-arrow-down') {
this.iconVal = 'ios-arrow-up'
} else if (this.iconVal === 'ios-arrow-up') {
this.iconVal = 'ios-arrow-down'
}
}
},
removeVal (index) {
let arr = this.queryData;
let removeValue = this.multipleHideVal[index]
for (let i = 0; i < arr.length; i++) {
if (arr[i].value === removeValue) {
arr[i].selected = false
arr[i].checked = false
} else if (arr[i].children) {
this.removeChildTreeData(arr[i].children, removeValue)
}
}
this.multipleShowVal.splice(index, 1)
this.multipleHideVal.splice(index, 1)
// update-begin-author:taoyan date:20211028 for:下拉树控件在多选的时候,如果选错了,察掉后不会及时生效,必须要重置才行。
//https://gitee.com/jeecg/JimuReport/issues/I4FKR0
let emitString = this.multipleHideVal.join(',')
this.$emit('input', emitString)
this.$emit('on-change', emitString)
// update-end-author:taoyan date:20211028 for:下拉树控件在多选的时候,如果选错了,察掉后不会及时生效,必须要重置才行。
},
removeChildTreeData(children, removeValue) {
for (let i = 0; i < children.length; i++) {
if (children[i].value === removeValue) {
children[i].selected = false
children[i].checked = false
return
} else if (children[i].children && children[i].children.length > 0) {
this.removeChildTreeData(children[i].children, removeValue)
}
}
},
clickIcon () {
if (this.iconVal === 'ios-close-circle') {
this.clearVal()
} else {
this.treeSelectContentShow()
}
},
clearVal () {
// console.log('clearVal')
/* if (this.clearable && !this.multiple && this.iconVal === 'ios-close-circle') {
this.pickTree(this.hideValue)
this.queryVal = ''
this.hideValue = ''
if (this.showTree) {
this.iconVal = 'ios-arrow-up'
} else {
this.iconVal = 'ios-arrow-down'
}
this.$emit('input', '')
}*/
},
selectTreeChange () {
this.queryData = JSON.parse(JSON.stringify(this.showData))
if (this.queryTreeVal !== '') {
let removeData = []
for (let i = 0; i < this.queryData.length; i++) {
let check = this.recursionTreeData(this.queryTreeVal, this.queryData[i])
if (!check) {
removeData.push(i)
}
}
this.queryData = this.queryData.filter((o, index) => {
return !removeData.includes(index)
})
}
},
recursionTreeData (query, data) {
let isCheck = false
let removeData = []
// 只验证最底层的节点是否有符合要求的值
if (data.children !== undefined) {
for (let i = 0; i < data.children.length; i++) {
if (!isCheck) {
isCheck = this.recursionTreeData(query, data.children[i])
if (!isCheck) {
removeData.push(i)
}
} else {
if (!this.recursionTreeData(query, data.children[i])) {
removeData.push(i)
}
}
}
} else {
// 验证当前节点是否有符合要求的值
if (data.title.indexOf(query) !== -1) {
return true
} else {
return false
}
}
data.children = data.children.filter((o, index) => {
return !removeData.includes(index)
})
// 如果子节点中有一个符合要求则父节点就直接返回true不做删除若子节点没有一个符合要求则再次验证当前的节点
if (isCheck) {
return isCheck
}
// 表示当前的节点有值在里面
if (data.title.indexOf(query) !== -1) {
return true
} else {
return false
}
},
selectChange (obj) {
//console.log('selectChange', obj)
},
treeCheckChange(arr){
//console.log('treeCheckChange', arr)
this.multipleShowVal = []
this.multipleHideVal = []
for (let i = 0; i < arr.length; i++) {
this.multipleShowVal.push(arr[i].title)
this.multipleHideVal.push(arr[i].value)
}
let emitString = this.multipleHideVal.join(',')
this.$emit('input', emitString)
this.$emit('on-change', emitString)
},
/**
* 获取树名称
* @param value
*/
getTreeName(value){
let params = {
params: {value: value}
}
$http.metaGet(this.loadtreeurl, params).then((res) => {
if(res.data && res.data.length> 0){
let initValues = [];
for (let i = 0; i < res.data.length; i++) {
if(res.data[i].value){
if(this.multipleShowVal.indexOf(res.data[i].title) === -1){
this.multipleShowVal.push(res.data[i].title)
}
initValues.push(res.data[i].value)
}
}
//如果有值默认选中
this.setChecked(initValues);
this.initValues = initValues
}
}).catch(function (error){
console.log('获取树名称失败', error)
});
},
/**
* 设置选中值
* @param children
* @param removeValue
*/
setChecked(values){
let arr = this.queryData;
for (let i = 0; i < arr.length; i++) {
if (values.indexOf(arr[i].value)!==-1 && !values.checked) {
Vue.set(arr[i],"checked",true)
} else {
Vue.set(arr[i],"checked",false)
}
}
},
/**
* 子级设置选中值
* @param children
* @param checkedValue
*/
checkChildTreeData(children, checkedValue) {
for (let i = 0; i < children.length; i++) {
if (checkedValue.indexOf(children[i].value)!==-1 && !checkedValue.checked) {
Vue.set(children[i],"checked",true)
}else{
Vue.set(children[i],"checked",false)
}
}
}
}
})
</script>

View File

@@ -0,0 +1,208 @@
<style>
.view-toolbar-container .ivu-icon{
width:22px;
height:22px;
background: #fff;
margin-left: 5px;
}
.view-toolbar-container .ivu-icon:hover{
background: #eee;
}
.view-toolbar-list .ivu-col{
border:1px solid #ddd;
padding:2px;
}
.view-toolbar-list .ivu-col:active{
background: #eee;
}
.view-toolbar-container .transform-icon, .view-toolbar-list .transform-icon{
transform: rotate(180deg);
padding-top: 1px;
}
</style>
<script type="text/x-template" id="view-setting-template">
<div style="">
<Modal :loading="true" v-model="show" title="预览页工具条设置" :width="650" @on-ok="onViewSettingSave" @on-cancel="onViewSettingCancel" class="expression">
<div style="height: 30px">
<Checkbox v-model="showViewToolbar">显示工具栏:</Checkbox>
<div style="height: 30px;float: right;margin-right: 5px">
<Button @click="resetViewToolbar" size="small">恢复默认</Button>
</div>
</div>
<div style="padding: 9px;margin-top:2px;background: rgb(228 229 230);border-bottom: 1px solid #e0e2e4;height: 40px;text-align: left;">
<div v-if="showViewToolbar" style="height: 22px;line-height: 22px;display: inline-block" class="view-toolbar-container">
<Icon
v-for="(item,index) in btnList"
v-if="isSelected(item.index)"
:key="index"
:type="item.icon"
:size="viewSettingFont"
:title="item.title"
:class="item.transform?'transform-icon':''"/>
<#-- <Icon type="ios-skip-backward" :size="viewSettingFont"/>
<Icon type="ios-play" class="transform-icon" :size="viewSettingFont"/>
<Icon type="ios-paper" :size="viewSettingFont"/>
<Icon type="md-podium" :size="viewSettingFont"/>
<Icon type="ios-play" :size="viewSettingFont"/>
<Icon type="ios-skip-forward" :size="viewSettingFont"/>
<Icon type="ios-print" :size="viewSettingFont"/>
<Icon type="ios-cloud-download" :size="viewSettingFont"/>-->
</div>
<div style="height: 22px;line-height: 22px;float: right;margin-right: 5px">
<Button @click="clearViewToolbar" size="small" style="">清空</Button>
</div>
</div>
<div style="cursor: pointer;background: #fff;margin-top:5px;padding: 2px" class="view-toolbar-list">
<Row>
<Col span="8" v-for="(item,index) in btnList" :key="index">
<div style="height: 30px;line-height: 30px" @click="handleClickToolbarBtn(item)">
<Icon :type="item.icon" :size="viewSettingFont" :class="item.transform?'transform-icon':''"/>
{{ item.title }}
<span v-if="isSelected(item.index)" style="float: right;font-size: 20px">·</span>
</div>
</Col>
<#--<Col span="8">
<div style="height: 30px;line-height: 30px">
&nbsp;
</div>
</Col>-->
</Row>
</div>
<div style="margin-top: 10px">
<Row>
<Col span="4">
<span style="display:inline-block;height: 30px;line-height: 30px;">每页展示条数:</span>
</Col>
<Col span="4">
<i-input type="number" v-model="pageSize" @on-change="handleViewPageSizeChange"></i-input>
</Col>
</Row>
</div>
</Modal>
</div>
</script>
<script>
Vue.component('j-view-setting', {
template: '#view-setting-template',
props: {
show:{
type: Boolean,
required: false,
default: false
},
settings:{
type: Object,
required: false,
default: ()=>{}
}
},
data(){
return {
enableViewSetting: true,
viewSettingFont: 20,
btnList:[
{ icon: 'ios-skip-backward', title: '首页', index: 1 },
{ icon: 'ios-play', title: '上一页', transform:true, index: 2 },
{ icon: 'ios-paper', title: '当前页/总页数', index: 3 },
{ icon: 'md-podium', title: '分页显示数', index: 4 },
{ icon: 'ios-play', title: '下一页', index: 5 },
{ icon: 'ios-skip-forward', title: '末页', index: 6 },
{ icon: 'ios-print', title: '打印', index: 7 },
{ icon: 'ios-cloud-download', title: '导出', index: 8, code:'' },
{ icon: 'md-switch', title: '清晰度设置', index: 9, code:'' }
],
selectList:[],
selectedIndexList:[1, 2, 3, 4, 5, 6, 7, 8, 9],
showViewToolbar:true,
pageSize: ''
}
},
watch:{
settings:{
deep: true,
immediate: true,
handler: function(){
this.resetForm()
}
}
},
methods:{
onViewSettingSave(){
let btnList = this.selectedIndexList
if(btnList.length==0){
btnList.push(999)
}
let param = {
show: this.showViewToolbar,
btnList: btnList,
pageSize: this.pageSize
}
this.$emit('change', param)
},
resetForm(){
if(this.settings){
const { show, btnList, pageSize } = this.settings;
if(show===false){
this.showViewToolbar = false;
}else{
this.showViewToolbar = true;
}
if(btnList){
if(btnList.length==0){
this.selectedIndexList = [1,2,3,4,5,6,7,8,9]
}else{
this.selectedIndexList = [...btnList];
}
}
if(pageSize){
this.pageSize = pageSize;
}
}
},
onViewSettingCancel(){
this.$emit('change', false)
},
handleClickToolbarBtn(item){
// console.log('handleClickToolbarBtn', item)
let index = item.index;
let position = this.selectedIndexList.indexOf(index)
if(position>=0){
this.selectedIndexList.splice(position, 1)
}else{
this.selectedIndexList.push(index)
}
},
isSelected(index){
if(this.selectedIndexList.indexOf(index)>=0){
return true
}else{
return false
}
},
resetViewToolbar(){
this.showViewToolbar = true
this.selectedIndexList = [1,2,3,4,5,6,7,8,9]
},
clearViewToolbar(){
this.selectedIndexList = []
},
hideViewToolbar(){
this.showViewToolbar = false
},
handleViewPageSizeChange(e){
if(!e.target.value){
this.pageSize = ''
}else if(e.target.value<1){
this.pageSize = 10
}
}
}
})
</script>

View File

@@ -0,0 +1,127 @@
<script type="text/x-template" id="xAxis-setting-template">
<Submenu name="11" style="border-bottom: inset 1px;">
<template slot="title">
<span class="rightFontSize">X轴设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 141px;" v-model="xAxisOption.show" @on-change="onXAxisChange"/>
</Row>
<Row class="ivurow">
<p>X轴名称&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" style="margin-left: 4px" size="small" v-model="xAxisOption.name" @on-blur="onXAxisChange"></i-input>
</Row>
<Row class="ivurow" v-if="isCharHasXMin">
<p>最小值&nbsp;&nbsp;</p>
<i-input size="small" class="rightFontSize iSelect" style="margin-left: 12px;" v-model="xAxisOption.min" @on-blur="onXAxisChange"/>
</Row>
<Row class="ivurow">
<p>分隔线&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 128px;" v-model="xAxisOption.splitLine_show" @on-change="onXAxisChange"/>
</Row>
<Row class="ivurow" v-if="typeof xAxisOption.splitLine_show !== 'undefined' && xAxisOption.splitLine_show == true">
<p>颜色设置&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="xAxisOption.splitLine_lineStyle_color" size="small" @on-change="onXAxisChange">
<span slot="append">
<color-picker class="colorPicker" v-model="xAxisOption.splitLine_lineStyle_color" :editable="false" :transfer="true" size="small" @on-change="onXAxisChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" style="z-index: 2021">
<p>文字角度&nbsp;&nbsp;</p>
<slider v-model="xAxisOption.axisLabel_rotate" @on-change="onXAxisChange" style="margin-top: -9px;width: 140px;margin-left: 5px;"></slider>
</Row>
<Row class="ivurow">
<p>字体大小&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" size="small" type="number" v-model="xAxisOption.axisLabel_textStyle_fontSize" @on-blur="onXAxisChange"></i-input>
</Row>
<Row class="ivurow" v-if="typeof xAxisOption.axisLabel_textStyle_color !== 'undefined'">
<p>字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="xAxisOption.axisLabel_textStyle_color" size="small" @on-change="onXAxisChange">
<span slot="append">
<color-picker class="colorPicker" v-model="xAxisOption.axisLabel_textStyle_color" :editable="false" :transfer="true" size="small" @on-change="onXAxisChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="typeof xAxisOption.axisLine_lineStyle_color !== 'undefined'">
<p>轴线颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="xAxisOption.axisLine_lineStyle_color" size="small" @on-change="onXAxisChange">
<span slot="append">
<color-picker class="colorPicker" v-model="xAxisOption.axisLine_lineStyle_color" :editable="false" :transfer="true" size="small" @on-change="onXAxisChange"/>
</span>
</i-input>
</Col>
</Row>
</div>
</Submenu>
</script>
<script>
Vue.component('j-xaxis-setting', {
template: '#xAxis-setting-template',
props: {
settings: {
type: Object,
required: true,
default: () => {
}
}
},
data(){
return {
xAxisOption: {
splitLine_lineStyle_color:'',
axisLabel_textStyle_color:'',
axisLine_lineStyle_color:'',
splitLine_show:false
},
isCharHasXMin:true //是否显示x轴最小值
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
},
//update-begin--Author:wangshuai Date:20211215 for监听图表选中类型----
'vm.selectedChartType':{
immediate: true,
handler() {
//判断选中的图表是否为象形图,象形图不用设置最小值
if(vm.selectedChartType == 'pictorial.spirits'){
this.isCharHasXMin=false;
}else{
this.isCharHasXMin=true;
}
}
}
//update-end--Author:wangshuai Date:20211215 for监听图表选中类型----
},
methods: {
initData: function (){
if (this.settings){
this.xAxisOption = Object.assign(this.xAxisOption, this.settings)
}
},
onXAxisChange(){
//update-begin--Author:wangshuai Date:20211213 for[issues/I4LZ63]折线图Y设置最小值;当存在最小值并且为空的时候那么就清空,保证数据初始化----
if(this.xAxisOption.hasOwnProperty("min") && !this.xAxisOption.min){
delete this.xAxisOption.min
}
//update-end--Author:wangshuai Date:20211213 for[issues/I4LZ63]折线图Y设置最小值;当存在最小值并且为空的时候那么就清空,保证数据初始化----
this.$emit('change','xAxis', this.xAxisOption)
}
}
})
</script>

View File

@@ -0,0 +1,161 @@
<script type="text/x-template" id="yAxis-setting-template">
<div>
<Submenu :name="'yAxis'+index" style="border-bottom: inset 1px;" v-for="(item,index) in yAxisOptions">
<template slot="title">
<span class="rightFontSize">{{getTitle(index)}}Y轴设置</span>
</template>
<div class="blockDiv" style="padding-bottom: 10px">
<Row class="ivurow">
<p>显示&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 141px;" v-model="item.show" @on-change="onYAxisChange"/>
</Row>
<Row class="ivurow">
<p>Y轴名称&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" size="small" v-model="item.name" @on-blur="onYAxisChange" style="margin-left: 4px"></i-input>
</Row>
<Row class="ivurow" v-if="isCharHasYMin">
<p>最小值&nbsp;&nbsp;</p>
<i-input size="small" class="rightFontSize iSelect" style="margin-left: 12px;" v-model="item.min" @on-blur="onYAxisChange"/>
</Row>
<Row class="ivurow">
<p>分隔线&nbsp;&nbsp;</p>
<i-switch size="small" style="margin-left: 128px;" v-model="item.splitLine_show" @on-change="onYAxisChange"/>
</Row>
<Row class="ivurow" v-if="typeof item.splitLine_show !== 'undefined' && item.splitLine_show == true">
<p>颜色设置&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="item.splitLine_lineStyle_color" size="small" @on-change="onYAxisChange">
<span slot="append">
<color-picker class="colorPicker" v-model="item.splitLine_lineStyle_color" :editable="false" :transfer="true" size="small" @on-change="onYAxisChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow">
<p style="margin-bottom: 10px;">字体大小&nbsp;&nbsp;</p>
<i-input class="rightFontSize iSelect" size="small" type="number" v-model="item.axisLabel_textStyle_fontSize" @on-blur="onYAxisChange"></i-input>
</Row>
<Row class="ivurow" v-if="typeof item.axisLabel_textStyle_color !== 'undefined'">
<p>字体颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="item.axisLabel_textStyle_color" size="small" @on-change="onYAxisChange">
<span slot="append">
<color-picker class="colorPicker" v-model="item.axisLabel_textStyle_color" :editable="false" :transfer="true" size="small" @on-change="onYAxisChange"/>
</span>
</i-input>
</Col>
</Row>
<Row class="ivurow" v-if="typeof item.axisLine_lineStyle_color !== 'undefined'">
<p>轴线颜色&nbsp;&nbsp;</p>
<Col>
<i-input class="rightFontSize iSelect" v-model="item.axisLine_lineStyle_color" size="small" @on-change="onYAxisChange">
<span slot="append">
<color-picker class="colorPicker" v-model="item.axisLine_lineStyle_color" :editable="false" :transfer="true" size="small" @on-change="onYAxisChange"/>
</span>
</i-input>
</Col>
</Row>
</div>
</Submenu>
</div>
</script>
<script>
Vue.component('j-yaxis-setting', {
template: '#yAxis-setting-template',
props: {
settings: {
type: [Object, Array],
required: true,
default: null
},
dataIndex: 0
},
data(){
return {
yAxisOption: {
splitLine_show:false
},
yAxisOptions: [],
isCharHasYMin: true //是否显示y轴最小值
}
},
watch: {
settings: {
deep: true,
immediate: true,
handler: function (){
this.initData()
}
},
//update-begin--Author:wangshuai Date:20211215 for监听图表选中类型----
'vm.selectedChartType':{
immediate: true,
handler() {
//判断选中的图表是否为象形图,象形图不用设置最小值
if(vm.selectedChartType == 'pictorial.spirits'){
this.isCharHasYMin=false;
}else{
this.isCharHasYMin=true;
}
}
}
//update-end--Author:wangshuai Date:20211215 for监听图表选中类型----
},
methods: {
getTitle: function(index) {
if (this.settings instanceof Array){
if (index == 0){
return '左'
}
if (index == 1){
return '右'
}
}else{
return ''
}
},
initData: function (){
if (this.settings){
if (this.settings instanceof Array){
this.yAxisOptions = this.settings;
this.yAxisOption = Object.assign(this.yAxisOption, this.settings[this.dataIndex])
} else {
this.yAxisOptions=[];
this.yAxisOptions.push(this.settings);
this.yAxisOption = Object.assign(this.yAxisOption, this.settings)
}
}
},
onYAxisChange(){
if (this.settings instanceof Array){
//update-begin--Author:wangshuai Date:20211213 for[issues/I4LZ63]折线图Y设置最小值;当存在最小值并且为空的时候那么就清空,保证数据初始化----
this.initYAxisOptionsMin(this.yAxisOptions,true)
//update-end--Author:wangshuai Date:20211213 for[issues/I4LZ63]折线图Y设置最小值;当存在最小值并且为空的时候那么就清空,保证数据初始化----
this.$emit('change', 'yAxis', this.yAxisOptions)
} else {
//update-begin--Author:wangshuai Date:20211213 for[issues/I4LZ63]折线图Y设置最小值;当存在最小值并且为空的时候那么就清空,保证数据初始化----
this.initYAxisOptionsMin(this.yAxisOptions[0],false)
//update-end--Author:wangshuai Date:20211213 for[issues/I4LZ63]折线图Y设置最小值;当存在最小值并且为空的时候那么就清空,保证数据初始化----
this.$emit('change', 'yAxis', this.yAxisOptions[0])
}
},
/**
* 初始化最小值
* @param yAxisOptions y轴数组对象
* @param isArray 是否为数组 true是 false不是
*/
initYAxisOptionsMin(yAxisOptions,isArray){
if(!yAxisOptions.min){
delete yAxisOptions.min
if(isArray){
this.yAxisOptions = yAxisOptions
}else{
this.yAxisOptions[0] = yAxisOptions
}
}
}
}
})
</script>

View File

@@ -0,0 +1,35 @@
<#include "components/select_input.ftl">
<#include "components/barcode.ftl">
<#include "components/qrcode.ftl">
<#include "components/title_setting.ftl">
<#include "components/bar_setting.ftl">
<#include "components/line_setting.ftl">
<#include "components/pie_setting.ftl">
<#include "components/margin_setting.ftl">
<#include "components/funnel_setting.ftl">
<#include "components/pictorial_setting.ftl">
<#include "components/scatter_setting.ftl">
<#include "components/map_setting.ftl">
<#include "components/radar_setting.ftl">
<#include "components/gauge_setting.ftl">
<#include "components/xAxis_setting.ftl">
<#include "components/yAxis_setting.ftl">
<#include "components/series_setting.ftl">
<#include "components/tooltip_setting.ftl">
<#include "components/grid_setting.ftl">
<#include "components/legend_setting.ftl">
<#include "components/background_setting.ftl">
<#include "components/match_setting.ftl">
<#include "components/data_source_setting.ftl">
<#include "components/javabean_setting.ftl">
<#include "components/central_point_setting.ftl">
<#include "components/function_interpretation.ftl">
<#include "components/data_dictionary.ftl">
<#include "components/hyperlinks.ftl">
<#include "components/print_setting.ftl">
<#include "components/view_setting.ftl">
<#include "components/chart_linkage.ftl">
<#include "components/cell_linkage.ftl">
<#include "components/primary_sub_report.ftl">
<#include "components/sql_function_replace.ftl">
<#include "components/bar_series_setting.ftl">

View File

@@ -0,0 +1 @@
<#include "components/jurisdiction.ftl">

View File

@@ -0,0 +1,2 @@
<#include "components/select_scroll_radio.ftl">
<#include "components/select_scroll_multiple.ftl">

View File

@@ -0,0 +1,308 @@
<#assign CACHE_VERSION = "v=1693888295.10">
<#assign config_id = "${id!''}">
<#assign shareView = "${shareView}">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<script>
/**
* 获取url参数
*/
function getLocalRequestUrl() {
var url = location.search;
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("&");
for(var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]]=decodeURI(strs[i].split("=")[1]);
}
}
return theRequest;
}
</script>
<script>
let configId= '${config_id}';
var reportMode = "${mode!''}"
let base = '${base}';
let customPrePath = '${customPrePath}';
let baseFull = "${base}"+"${customPrePath}";
let shareView = "${shareView}";
let token = getLocalRequestUrl().token;
if(token && token!=null && token!=""){
window.localStorage.setItem('JmReport-Access-Token',token);
}
if (token == "" || token == null){
token = window.localStorage.getItem('JmReport-Access-Token');
}
/**
* 获取后台配置的报表配置
*/
function getReportConfigJson() {
let str = '${reportConfig}';
return JSON.parse(str)
}
</script>
<#include "./common/resource.ftl">
<#include "./template/components/tree_select.ftl">
<#include "./template/view.ftl">
<!-- Import via CDN -->
<link rel="stylesheet" href="${base}${customPrePath}/jmreport/desreport_/corelib/jmsheet.css?${CACHE_VERSION}">
<script src="${base}${customPrePath}/jmreport/desreport_/corelib/jmsheet.js?${CACHE_VERSION}"></script>
<script src="${base}${customPrePath}/jmreport/desreport_/corelib/locale/zh-cn.js?${CACHE_VERSION}"></script>
<script src="${base}${customPrePath}/jmreport/desreport_/jquery/jquery-3.4.1.min.js"></script>
<link rel="shortcut icon" href="${base}${customPrePath}/jmreport/desreport_/corelib/logo.png?${CACHE_VERSION}" type="image/x-ico">
<script>
// $http.get({
// url : api.show,
// data:{"id":configId},
// success : function(result) {
// document.title = result.name;
// }
// });
</script>
<style>
#jm-sheet-wrapper * {
color: #000000;
-webkit-tap-highlight-color: #000000!important;
}
body{
overflow-y:hidden !important;
}
/*--查询区域的样式设置 --*/
.ty-bar-container{
padding-left: 12px;
}
.jm-query-collapse .ivu-collapse-header .ivu-icon{
font-size: 20px;
font-weight: 700;
margin-right: 5px !important;
}
.jm-query-form .ivu-input{
padding: 3px 7px;
height: 28px;
border-radius: 3px;
width: 100% !important;
}
.jm-query-form .jmreport-query-datetime .ivu-input{
width: 160px;
}
.jm-query-form .ivu-select-selection{
width: 200px;
}
/*--多选 --*/
.jm-query-form .ivu-select-multiple .ivu-select-selection{
width: 200px;
}
/*多选输入框鼠标位置显示问题*/
/*.jm-query-form .ivu-select-multiple .ivu-tag{*/
/* height: 20px;*/
/* line-height: 20px;*/
/* margin: 3px 4px 3px 0;*/
/* vertical-align: baseline;*/
/* max-width: 62% !important;*/
/*}*/
.jm-query-form .ivu-select-multiple .ivu-tag i{
top: 3px;
}
.jm-query-form .ivu-btn{height:30px !important;}
.jm-query-form .ivu-btn>.ivu-icon{
font-size:16px;
}
.jm-query-form .ivu-select-selection,
.jm-query-form .ivu-select-placeholder,
.jm-query-form .ivu-select-selected-value{
height: 28px !important;
line-height: 24px !important;
}
.jm-query-form .ivu-input-prefix i,
.jm-query-form .ivu-input-suffix i{
line-height: 28px !important;
}
/*--查询区域的样式设置 --*/
.jm-search-btns .ivu-form-item-content{
margin-left: 30px !important;
}
.jm-query-form .ivu-select-dropdown{
z-index: 99999;
}
[v-cloak]{
display: none;
}
.jm-select-box{
width: 200px
}
.jm-select-box .ivu-select-input{
height: 28px
}
</style>
<body onload="view.load('${config_id}')" style="overflow: hidden">
<div id="app" style="overflow: hidden" v-cloak>
<!-- 查询条件 -begin -->
<div v-if="configQueryList && configQueryList.length>0">
<Collapse class="jm-query-collapse" @on-change="onQueryAreaSwitch" v-model="queryPanel">
<Panel name="1">
<span style="color: #000000;" title="点击展开显示查询信息">查 询 栏</span>
<div slot="content">
<i-form ref="queryForm" :model="queryInfo" inline :label-width="100" class="jm-query-form" @keydown.native.enter.prevent="doReportQuery">
<Row>
<i-col :span="6" v-for="(item, index) in configQueryList" :key="index">
<form-item style="margin-bottom: 12px !important;" :label="getQueryItemLabel(item)" :index="index">
<!-- 日期选择器 yyyy-MM-dd HH:mm:ss -->
<template v-if="item.type=='date'">
<Row v-if="item.mode==2" :class="'jmreport-query-'+item.realType">
<i-col span="11">
<date-picker :ref="item.key+'_begin'" @on-change="(str)=>handleQueryDateChange(str, item.key+'_begin')" :type="item.realType" :format="item.format" :transfer="true" v-model="queryInfo['onlyshow_'+item.key+'_begin']" :placeholder="'请选择起始值'"></date-picker>
</i-col>
<i-col span="2" style="text-align: center">&nbsp;~</i-col>
<i-col span="11">
<date-picker :ref="item.key+'_end'" @on-change="(str)=>handleQueryDateChange(str, item.key+'_end')" :type="item.realType" :format="item.format" :transfer="true" v-model="queryInfo['onlyshow_'+item.key+'_end']" :placeholder="'请选择结束值'"></date-picker>
</i-col>
</Row>
<date-picker v-else :ref="item.key" :type="item.realType" class="jm-select-box" :transfer="true" :format="item.format" :class="'jmreport-query-'+item.type" v-model="queryInfo['onlyshow_'+item.key]" @on-change="(str)=>handleQueryDateChange(str, item.key)" :placeholder="'请选择'+item.title"></date-picker>
</template>
<!-- 时间选择器 HH:mm:ss -->
<template v-else-if="item.type=='time'">
<Row v-if="item.mode==2" :class="'jmreport-query-'+item.realType">
<i-col span="11">
<time-picker :ref="item.key+'_begin'" @on-change="(str)=>handleQueryDateChange(str, item.key+'_begin')" :type="item.realType" :format="item.format" :transfer="true" v-model="queryInfo['onlyshow_'+item.key+'_begin']" :placeholder="'请选择起始值'"></time-picker>
</i-col>
<i-col span="2" style="text-align: center">&nbsp;~</i-col>
<i-col span="11">
<time-picker :ref="item.key+'_end'" @on-change="(str)=>handleQueryDateChange(str, item.key+'_end')" :type="item.realType" :format="item.format" :transfer="true" v-model="queryInfo['onlyshow_'+item.key+'_end']" :placeholder="'请选择结束值'"></time-picker>
</i-col>
</Row>
<time-picker :ref="item.key" :time-picker-options="{disabledHours:true}" v-else :type="item.realType" class="jm-select-box" :transfer="true" :format="item.format" :class="'jmreport-query-'+item.type" v-model="queryInfo['onlyshow_'+item.key]" @on-change="(str)=>handleQueryDateChange(str, item.key)" :placeholder="'请选择'+item.title"></time-picker>
</template>
<!-- 下拉树 -->
<template v-else-if="item.mode==6">
<j-tree-select :ref="item.key" :url="item.loadTree" :loadtreeurl="item.loadTreeByValue" v-model="queryInfo[item.key]"></j-tree-select>
</template>
<!-- 自定义下拉框 -->
<template v-else-if="item.mode==7">
<i-select :ref="item.key" class="jm-select-box" clearable :transfer="true" v-model="queryInfo[item.key]" :placeholder="'请选择'+item.title">
<i-option v-for="(dict, dIndex) in item.dictList" :key="dIndex" :index="index" :value="dict.value">{{ dict.text }}</i-option>
</i-select>
</template>
<template v-else>
<template v-if="item.dictList && item.dictList.length>0 && (item.mode==4 ||item.mode==3)">
<!-- 多选 -->
<j-select-scroll-multiple v-if="item.mode==3" v-model="queryInfo['onlyshow_'+item.key]" :item="JSON.stringify(item)" @dictmultipleok="handleDictMultipleOk" :index="index"></j-select-scroll-multiple>
<!-- 单选 -->
<j-select-scroll-radio v-if="item.mode==4" v-model="queryInfo[item.key]" :item="JSON.stringify(item)" @dictok="handleDictOk"></j-select-scroll-radio>
</template>
<!-- 数值查询 -->
<template v-else-if="item.type=='number'">
<Row v-if="item.mode==2">
<i-col span="11">
<i-input :ref="item.key+'_begin'" v-model="queryInfo[item.key+'_begin']" type="number" :placeholder="'请输入起始值'" clearable></i-input>
</i-col>
<i-col span="2" style="text-align: center">&nbsp;~</i-col>
<i-col span="11">
<i-input :ref="item.key+'_end'" v-model="queryInfo[item.key+'_end']" type="number" :placeholder="'请输入结束值'" clearable></i-input>
</i-col>
</Row>
<i-input v-else :ref="item.key" class="jm-select-box" type="number" v-model="queryInfo[item.key]" :placeholder="'请输入'+item.title" clearable></i-input>
</template>
<!-- 默认输入框 模糊查询参数加* -->
<template v-else>
<i-input v-if="item.mode==5" :ref="item.key" @on-change="(e)=>handleLikeQueryChange(e, item.key)" class="jm-select-box" v-model="queryInfo['onlyshow_'+item.key]" :placeholder="'请输入'+item.title" clearable></i-input>
<i-input v-else :ref="item.key" class="jm-select-box" v-model="queryInfo[item.key]" :placeholder="'请输入'+item.title" clearable></i-input>
</template>
</template>
</form-item>
</i-col>
<i-col :span="6">
<form-item class="jm-search-btns">
<i-button type="primary" icon="ios-search-outline" @click="doReportQuery">查询</i-button>
<i-button style="margin-left: 8px" icon="ios-redo-outline" @click="resetReportQuery">重置</i-button>
</form-item>
</i-col>
</Row>
</i-form>
</div>
</Panel>
</Collapse>
</div>
<!-- 查询条件 -end -->
<#-- <div>
<a v-if="returnPreviousPage" onclick="returnPreviousPageClick()">返回上一页</a>
</div>-->
<div id="jm-sheet-wrapper" style="width:100%;height: 100%"></div>
<!-- 报表参数弹框 -->
<Modal
:closable="false"
:mask-closable="false"
:loading="loading"
v-model="visible"
title="请填写报表参数"
:width="500">
<div slot="footer">
<i-button type="primary" @click="onSave" style="color:#fff !important;">确定</i-button>
</div>
<div style="padding-right: 30px">
<i-form :model="reportParamObj" label-colon :label-width="90">
<form-item :label="item.paramTxt" v-for="(item, index) in reportParamList">
<i-input style="width: 90%" :key="index" v-model="reportParamObj[item.paramName]" :placeholder="'请输入'+ item.paramTxt "></i-input>
</form-item>
</i-form>
</div>
</Modal>
<Modal
:closable="false"
:mask-closable="false"
:loading="lockLoading"
v-model="lockVisible"
title="请填写密码"
:width="500">
<div slot="footer">
<i-button type="primary" @click="lockClick('${config_id}')">确定</i-button>
</div>
<div style="padding-right: 30px">
<i-form label-colon :label-width="90">
<form-item label="密码">
<i-input v-model="lock" placeholder="请输入密码"></i-input>
</form-item>
</i-form>
</div>
</Modal>
</div>
<#--预览js-->
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/js/util.js?${CACHE_VERSION}"></script>
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/js/biz/row.express.js?${CACHE_VERSION}"></script>
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/js/biz/row.cycle.js?${CACHE_VERSION}"></script>
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/cdn/vue/xss-0.3.3.min.js?${CACHE_VERSION}"></script>
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/js/biz/view.js?${CACHE_VERSION}"></script>
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/cdn/vue/md5.min.js?${CACHE_VERSION}"></script>
<script type="text/javascript" src="${base}${customPrePath}/jmreport/desreport_/js/biz/SignMd5Util.js?${CACHE_VERSION}"></script>
<#include "./common/tj.ftl">
</body>
</html>