forked from github/dataease
Merge branch 'dev' into pr@dev@refactor_watermark
This commit is contained in:
commit
7f1728dfa6
@ -1,26 +1,99 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import org.apache.shiro.web.filter.authc.AnonymousFilter;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.license.DefaultLicenseService;
|
||||
import io.dataease.commons.license.F2CLicenseResponse;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.web.filter.AccessControlFilter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.dataease.commons.license.F2CLicenseResponse.Status;
|
||||
|
||||
public class F2CDocFilter extends AccessControlFilter {
|
||||
|
||||
private static final String RESULT_URI_KEY = "result_uri_key";
|
||||
private static final String NOLIC_PAGE = "nolic.html";
|
||||
private static final String NO_LOGIN_PAGE = "/nologin.html";
|
||||
private static final String DEFAULT_FAILED_PAGE = "/";
|
||||
|
||||
public class F2CDocFilter extends AnonymousFilter {
|
||||
|
||||
@Override
|
||||
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
String path = "/deApi";
|
||||
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
try {
|
||||
req.getRequestDispatcher(path).forward(req, response);
|
||||
} catch (ServletException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
DefaultLicenseService defaultLicenseService = CommonBeanFactory.getBean(DefaultLicenseService.class);
|
||||
F2CLicenseResponse f2CLicenseResponse = defaultLicenseService.validateLicense();
|
||||
Status status = f2CLicenseResponse.getStatus();
|
||||
if (status != Status.valid) {
|
||||
request.setAttribute(RESULT_URI_KEY, NOLIC_PAGE);
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
request.setAttribute(RESULT_URI_KEY, NOLIC_PAGE);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Boolean isLogin = validateLogin(request);
|
||||
if (!isLogin) {
|
||||
request.setAttribute(RESULT_URI_KEY, NO_LOGIN_PAGE);
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
request.setAttribute(RESULT_URI_KEY, NO_LOGIN_PAGE);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean validateLogin(HttpServletRequest request) throws Exception{
|
||||
String authorization = request.getHeader("Authorization");
|
||||
if (StringUtils.isBlank(authorization)) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (ArrayUtil.isNotEmpty(cookies)) {
|
||||
Cookie cookie = Arrays.stream(cookies).filter(item -> StringUtils.equals(item.getName(), "Authorization")).findFirst().orElse(null);
|
||||
if (ObjectUtils.isNotEmpty(cookie) && StringUtils.isNotBlank(cookie.getValue())) {
|
||||
authorization = cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(authorization)) {
|
||||
return false;
|
||||
}
|
||||
TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(authorization);
|
||||
AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class);
|
||||
SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId());
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
String password = user.getPassword();
|
||||
boolean verify = JWTUtils.verify(authorization, tokenInfo, password);
|
||||
return verify;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest req, ServletResponse res) throws Exception {
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
Object attribute = request.getAttribute(RESULT_URI_KEY);
|
||||
String path = ObjectUtils.isNotEmpty(attribute) ? attribute.toString() : DEFAULT_FAILED_PAGE;
|
||||
request.getRequestDispatcher(path).forward(request, response);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import io.dataease.auth.entity.ASKToken;
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
@ -23,8 +24,10 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
||||
public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
@ -158,4 +161,18 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
httpServletResponse.setHeader("authentication-status", "login_expire");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest req, ServletResponse res, Object mappedValue) throws Exception {
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
String requestURI = request.getRequestURI();
|
||||
String msg = requestURI + " has been denied";
|
||||
String encode = URLUtil.encode(msg, Charset.forName("UTF-8"));
|
||||
Cookie cookie_error = new Cookie("onAccessDeniedMsg", encode);
|
||||
cookie_error.setPath("/");
|
||||
response.addCookie(cookie_error);
|
||||
response.sendRedirect("/");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import java.util.Map;
|
||||
public class ShiroServiceImpl implements ShiroService {
|
||||
|
||||
private final static String ANON = "anon";
|
||||
private final static String DOC = "doc";
|
||||
|
||||
@Override
|
||||
public Map<String, String> loadFilterChainDefinitionMap() {
|
||||
@ -20,15 +21,18 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
// ----------------------------------------------------------
|
||||
// 放行Swagger2页面,需要放行这些
|
||||
|
||||
filterChainDefinitionMap.put("/doc.html**", "doc");
|
||||
filterChainDefinitionMap.put("/deApi**", ANON);
|
||||
filterChainDefinitionMap.put("/doc.html**", DOC);
|
||||
filterChainDefinitionMap.put("/deApi**", DOC);
|
||||
filterChainDefinitionMap.put("/swagger-ui.html", ANON);
|
||||
filterChainDefinitionMap.put("/swagger-ui/**", ANON);
|
||||
filterChainDefinitionMap.put("/swagger/**", ANON);
|
||||
filterChainDefinitionMap.put("/webjars/**", ANON);
|
||||
filterChainDefinitionMap.put("/swagger-resources/**", ANON);
|
||||
filterChainDefinitionMap.put("/v2/**", ANON);
|
||||
filterChainDefinitionMap.put("/v3/**", ANON);
|
||||
filterChainDefinitionMap.put("/swagger-resources/**", DOC);
|
||||
filterChainDefinitionMap.put("/v2/**", DOC);
|
||||
filterChainDefinitionMap.put("/v3/**", DOC);
|
||||
|
||||
filterChainDefinitionMap.put("/**.gif", ANON);
|
||||
filterChainDefinitionMap.put("/**.png", ANON);
|
||||
|
||||
filterChainDefinitionMap.put("/static/**", ANON);
|
||||
filterChainDefinitionMap.put("/css/**", ANON);
|
||||
@ -108,6 +112,8 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
filterChainDefinitionMap.put("/plugin/larksuite/getQrParam", ANON);
|
||||
filterChainDefinitionMap.put("/cas/reset/**", ANON);
|
||||
filterChainDefinitionMap.put("/cas/loginPage", ANON);
|
||||
filterChainDefinitionMap.put("/pdf-template/queryAll", ANON);
|
||||
|
||||
|
||||
filterChainDefinitionMap.put("/unauth", ANON);
|
||||
filterChainDefinitionMap.put("/display/**", ANON);
|
||||
@ -122,6 +128,7 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
filterChainDefinitionMap.put("/panel/group/exportDetails", ANON);
|
||||
filterChainDefinitionMap.put("/dataset/field/linkMultFieldValues", "link");
|
||||
filterChainDefinitionMap.put("/dataset/field/linkMappingFieldValues", "link");
|
||||
filterChainDefinitionMap.put("/systemInfo/proxyUserLoginInfo/**", ANON);
|
||||
|
||||
filterChainDefinitionMap.put("/**", "authc");
|
||||
|
||||
|
@ -2,17 +2,16 @@ package io.dataease.controller;
|
||||
|
||||
import io.dataease.commons.exception.DEException;
|
||||
import io.dataease.commons.license.DefaultLicenseService;
|
||||
import io.dataease.commons.license.F2CLicenseResponse;
|
||||
import io.dataease.commons.utils.CodingUtil;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import io.dataease.service.panel.PanelLinkService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -42,13 +41,7 @@ public class IndexController {
|
||||
|
||||
@GetMapping("/deApi")
|
||||
public String deApi() {
|
||||
F2CLicenseResponse f2CLicenseResponse = defaultLicenseService.validateLicense();
|
||||
switch (f2CLicenseResponse.getStatus()) {
|
||||
case valid:
|
||||
return "doc.html";
|
||||
default:
|
||||
return "nolic.html";
|
||||
}
|
||||
return "doc.html";
|
||||
}
|
||||
|
||||
@GetMapping("/link/{index}")
|
||||
@ -64,8 +57,8 @@ public class IndexController {
|
||||
// TODO 增加仪表板外部参数
|
||||
HttpServletRequest request = ServletUtils.request();
|
||||
String attachParams = request.getParameter("attachParams");
|
||||
if(StringUtils.isNotEmpty(attachParams)){
|
||||
url = url+"&attachParams="+attachParams;
|
||||
if (StringUtils.isNotEmpty(attachParams)) {
|
||||
url = url + "&attachParams=" + attachParams;
|
||||
}
|
||||
response.sendRedirect(url);
|
||||
} catch (IOException e) {
|
||||
|
@ -3,6 +3,7 @@ package io.dataease.controller.sys;
|
||||
import io.dataease.dto.UserLoginInfoDTO;
|
||||
import io.dataease.service.SystemInfoService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
@ -19,6 +20,11 @@ public class SystemInfoController {
|
||||
|
||||
@GetMapping("userLoginInfo")
|
||||
public UserLoginInfoDTO userLoginInfo() throws IOException {
|
||||
return systemInfoService.getUserLoginInfo();
|
||||
return systemInfoService.getUserLoginInfo(null);
|
||||
}
|
||||
|
||||
@GetMapping("proxyUserLoginInfo/{userId}")
|
||||
public UserLoginInfoDTO proxyUserLoginInfo(@PathVariable String userId) throws IOException {
|
||||
return systemInfoService.getUserLoginInfo(userId);
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,30 @@
|
||||
package io.dataease.service;
|
||||
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.commons.utils.AuthUtils;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.IPUtils;
|
||||
import io.dataease.dto.UserLoginInfoDTO;
|
||||
import io.dataease.plugins.common.base.domain.SysUser;
|
||||
import io.dataease.plugins.common.base.mapper.SysUserMapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@Service
|
||||
public class SystemInfoService {
|
||||
@Resource
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
public UserLoginInfoDTO getUserLoginInfo() {
|
||||
public UserLoginInfoDTO getUserLoginInfo(String userId) {
|
||||
if (StringUtils.isNotEmpty(userId)) {
|
||||
SysUser userInfo = sysUserMapper.selectByPrimaryKey(Long.parseLong(userId));
|
||||
CurrentUserDto userDto = new CurrentUserDto();
|
||||
BeanUtils.copyBean(userDto, userInfo);
|
||||
return new UserLoginInfoDTO(userDto, IPUtils.get());
|
||||
}
|
||||
return new UserLoginInfoDTO(AuthUtils.getUser(), IPUtils.get());
|
||||
}
|
||||
|
||||
|
@ -908,7 +908,7 @@ public class ChartViewService {
|
||||
if (StringUtils.equalsIgnoreCase(table.getType(), DatasetType.DB.name())) {
|
||||
datasourceRequest.setTable(dataTableInfoDTO.getTable());
|
||||
if (StringUtils.equalsAnyIgnoreCase(view.getType(), "text", "gauge", "liquid")) {
|
||||
datasourceRequest.setQuery(qp.getSQLSummary(dataTableInfoDTO.getTable(), yAxis, fieldCustomFilter, rowPermissionsTree, extFilterList, view, ds));
|
||||
querySql = qp.getSQLSummary(dataTableInfoDTO.getTable(), yAxis, fieldCustomFilter, rowPermissionsTree, extFilterList, view, ds);
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "stack")) {
|
||||
querySql = qp.getSQLStack(dataTableInfoDTO.getTable(), xAxis, yAxis, fieldCustomFilter, rowPermissionsTree, extFilterList, extStack, ds, view);
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "scatter")) {
|
||||
|
BIN
frontend/public/dynamic.gif
Normal file
BIN
frontend/public/dynamic.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 MiB |
BIN
frontend/public/lic.png
Normal file
BIN
frontend/public/lic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
@ -1,13 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>DataEase</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0 !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.no-login-dynamic {
|
||||
height: 100%;
|
||||
background: url(./lic.png) no-repeat;
|
||||
background-size: cover;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #000;
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
top: 130px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body style="height: 100%;">
|
||||
<div>缺少许可</div>
|
||||
|
||||
<div class="no-login-dynamic">
|
||||
<span>缺少许可</span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
document.getElementsByTagName("body")
|
||||
</script>
|
||||
|
||||
|
||||
</html>
|
50
frontend/public/nologin.html
Normal file
50
frontend/public/nologin.html
Normal file
@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>DataEase</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0 !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.no-login-dynamic {
|
||||
height: 100%;
|
||||
background: url(./dynamic.gif) no-repeat;
|
||||
|
||||
background-size: cover;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
top: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body style="height: 100%;">
|
||||
|
||||
<div id="de-nologin-div" class="no-login-dynamic">
|
||||
<span>请先登录,即将跳转!</span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script>
|
||||
const timer = setTimeout(() => {
|
||||
window.location.href = "/";
|
||||
}, 3500)
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</html>
|
@ -8,6 +8,15 @@ export function userLoginInfo() {
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
userLoginInfo
|
||||
export function proxyUserLoginInfo(userId) {
|
||||
return request({
|
||||
url: '/systemInfo/proxyUserLoginInfo/' + userId,
|
||||
method: 'get',
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
userLoginInfo,
|
||||
proxyUserLoginInfo
|
||||
}
|
||||
|
@ -1,18 +1,35 @@
|
||||
<template>
|
||||
|
||||
<div
|
||||
v-show="existLinkage"
|
||||
class="bar-main"
|
||||
:class="containerClass"
|
||||
>
|
||||
|
||||
<div
|
||||
v-show="isPublicLink && !isNewBlank"
|
||||
class="bar-main-left"
|
||||
v-if="isPublicLink"
|
||||
class="function-div"
|
||||
>
|
||||
<el-button
|
||||
size="mini"
|
||||
@click="back2Last"
|
||||
><i class="icon iconfont el-icon-back" />{{ $t('chart.back') }}</el-button>
|
||||
<el-button-group size="mini">
|
||||
<el-button
|
||||
v-if="!isNewBlank"
|
||||
size="mini"
|
||||
@click="back2Last"
|
||||
><i class="icon iconfont el-icon-back" />{{ $t('chart.back') }}</el-button>
|
||||
<el-button
|
||||
v-if="existLinkage"
|
||||
size="mini"
|
||||
@click="clearAllLinkage"
|
||||
><i class="icon iconfont icon-quxiaoliandong" />{{ $t('panel.remove_all_linkage') }}</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
@click="exportPDF"
|
||||
><i class="icon iconfont el-icon-download" />{{ $t('panel.down') }}</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
<div class="bar-main-right">
|
||||
|
||||
<div
|
||||
v-else-if="existLinkage"
|
||||
class="bar-main-right"
|
||||
>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="warning"
|
||||
@ -43,6 +60,9 @@ export default {
|
||||
isNewBlank() {
|
||||
return window.history.length === 1
|
||||
},
|
||||
containerClass() {
|
||||
return this.isPublicLink ? 'trans-pc' : 'bar-main'
|
||||
},
|
||||
...mapState([
|
||||
'componentData'
|
||||
])
|
||||
@ -54,6 +74,9 @@ export default {
|
||||
},
|
||||
back2Last() {
|
||||
this.$router.back(-1)
|
||||
},
|
||||
exportPDF() {
|
||||
this.$emit('link-export-pdf')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,4 +109,31 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.trans-pc {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-top: 60px solid rgba(245, 74, 69, 0.2);
|
||||
border-left: 60px solid transparent;
|
||||
cursor: pointer;
|
||||
z-index: 999;
|
||||
.function-div {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: -50px;
|
||||
width: max-content;
|
||||
text-align: end;
|
||||
z-index: 999;
|
||||
|
||||
}
|
||||
&:hover {
|
||||
border-top: 60px solid rgba(245, 74, 69, 0.8);;
|
||||
.function-div {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -137,7 +137,7 @@
|
||||
:target="curComponent.hyperlinks.openMode "
|
||||
:href="curComponent.hyperlinks.content "
|
||||
>
|
||||
<i class="icon iconfont icon-com-jump" />
|
||||
<i class="icon iconfont icon-com-jump"/>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
@ -167,6 +167,7 @@
|
||||
<el-dialog
|
||||
:visible.sync="boardSetVisible"
|
||||
width="750px"
|
||||
top="5vh"
|
||||
class="dialog-css"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
|
@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<div
|
||||
:id="previewMainDomId"
|
||||
v-loading="dataLoading"
|
||||
:element-loading-text="$t('panel.data_loading')"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(220,220,220,1)"
|
||||
class="bg"
|
||||
:style="customStyle"
|
||||
@scroll="canvasScroll"
|
||||
>
|
||||
<canvas-opt-bar />
|
||||
<canvas-opt-bar @link-export-pdf="downloadAsPDF" />
|
||||
<div
|
||||
:id="previewDomId"
|
||||
:ref="previewRefId"
|
||||
@ -57,6 +61,40 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-if="pdfExportShow"
|
||||
:title="'['+panelInfo.name+']'+'PDF导出'"
|
||||
:visible.sync="pdfExportShow"
|
||||
width="80%"
|
||||
:top="'8vh'"
|
||||
:destroy-on-close="true"
|
||||
class="dialog-css2"
|
||||
>
|
||||
<span style="position: absolute;right: 70px;top:15px">
|
||||
<svg-icon
|
||||
icon-class="PDF"
|
||||
class="ds-icon-pdf"
|
||||
/>
|
||||
<el-select
|
||||
v-model="pdfTemplateSelectedIndex"
|
||||
:placeholder="'切换PDF模板'"
|
||||
@change="changePdfTemplate()"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in pdfTemplateAll"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="index"
|
||||
/>
|
||||
</el-select>
|
||||
</span>
|
||||
<PDFPreExport
|
||||
:snapshot="snapshotInfo"
|
||||
:panel-name="panelInfo.name"
|
||||
:template-content="pdfTemplateContent"
|
||||
@closePreExport="closePreExport"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -74,12 +112,13 @@ import bus from '@/utils/bus'
|
||||
import { buildFilterMap, buildViewKeyMap, formatCondition, valueValid, viewIdMatch } from '@/utils/conditionUtil'
|
||||
import { hasDataPermission } from '@/utils/permission'
|
||||
import { activeWatermark } from '@/components/canvas/tools/watermark'
|
||||
import { userLoginInfo } from '@/api/systemInfo/userLogin'
|
||||
|
||||
import { proxyUserLoginInfo, userLoginInfo } from '@/api/systemInfo/userLogin'
|
||||
import html2canvas from 'html2canvasde'
|
||||
import { queryAll } from '@/api/panel/pdfTemplate'
|
||||
const erd = elementResizeDetectorMaker()
|
||||
|
||||
import PDFPreExport from '@/views/panel/export/PDFPreExport'
|
||||
export default {
|
||||
components: { ComponentWrapper, CanvasOptBar },
|
||||
components: { ComponentWrapper, CanvasOptBar, PDFPreExport },
|
||||
model: {
|
||||
prop: 'show',
|
||||
event: 'change'
|
||||
@ -140,10 +179,15 @@ export default {
|
||||
type: String,
|
||||
require: false,
|
||||
default: 'canvas-main'
|
||||
},
|
||||
userId: {
|
||||
type: String,
|
||||
require: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
canvasInfoTemp: 'preview-temp-canvas-main',
|
||||
previewMainDomId: 'preview-main-' + this.canvasId,
|
||||
previewDomId: 'preview-' + this.canvasId,
|
||||
previewRefId: 'preview-ref-' + this.canvasId,
|
||||
@ -171,7 +215,15 @@ export default {
|
||||
searchCount: 0,
|
||||
// 布局展示 1.pc pc端布局 2.mobile 移动端布局
|
||||
terminal: 'pc',
|
||||
buttonFilterMap: null
|
||||
buttonFilterMap: null,
|
||||
pdfExportShow: false,
|
||||
dataLoading: false,
|
||||
exporting: false,
|
||||
snapshotInfo: '',
|
||||
pdfTemplateSelectedIndex: 0,
|
||||
pdfTemplateContent: '',
|
||||
templateInfo: {},
|
||||
pdfTemplateAll: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -309,6 +361,7 @@ export default {
|
||||
}
|
||||
bus.$on('trigger-search-button', this.triggerSearchButton)
|
||||
bus.$on('trigger-reset-button', this.triggerResetButton)
|
||||
this.initPdfTemplate()
|
||||
},
|
||||
beforeDestroy() {
|
||||
erd.uninstall(this.$refs[this.previewTempRefId])
|
||||
@ -544,6 +597,36 @@ export default {
|
||||
})
|
||||
}
|
||||
}, 1500)
|
||||
},
|
||||
downloadAsPDF() {
|
||||
this.dataLoading = true
|
||||
const domId = this.canvasInfoTemp
|
||||
setTimeout(() => {
|
||||
this.exporting = true
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById(domId)).then(canvas => {
|
||||
const snapshot = canvas.toDataURL('image/jpeg', 1) // 是图片质量
|
||||
this.dataLoading = false
|
||||
this.exporting = false
|
||||
if (snapshot !== '') {
|
||||
this.snapshotInfo = snapshot
|
||||
this.pdfExportShow = true
|
||||
}
|
||||
})
|
||||
}, 1500)
|
||||
}, 500)
|
||||
},
|
||||
closePreExport() {
|
||||
this.pdfExportShow = false
|
||||
},
|
||||
changePdfTemplate() {
|
||||
this.pdfTemplateContent = this.pdfTemplateAll[this.pdfTemplateSelectedIndex] ? this.pdfTemplateAll[this.pdfTemplateSelectedIndex].templateContent : ''
|
||||
},
|
||||
initPdfTemplate() {
|
||||
queryAll().then(res => {
|
||||
this.pdfTemplateAll = res.data
|
||||
this.changePdfTemplate()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -640,7 +640,7 @@ export default {
|
||||
},
|
||||
viewInCache(param) {
|
||||
this.view = param.view
|
||||
if (this.view.customAttr) {
|
||||
if (this.view && this.view.customAttr) {
|
||||
this.currentPage.pageSize = parseInt(JSON.parse(this.view.customAttr).size.tablePageSize)
|
||||
}
|
||||
param.viewId && param.viewId === this.element.propValue.viewId && this.getDataEdit(param)
|
||||
@ -703,7 +703,7 @@ export default {
|
||||
requestInfo.proxy = { userId: this.panelInfo.proxy }
|
||||
}
|
||||
// table-info明细表增加分页
|
||||
if (this.view.customAttr) {
|
||||
if (this.view && this.view.customAttr) {
|
||||
const attrSize = JSON.parse(this.view.customAttr).size
|
||||
if (this.chart.type === 'table-info' && this.view.datasetMode === 0 && (!attrSize.tablePageMode || attrSize.tablePageMode === 'page')) {
|
||||
requestInfo.goPage = this.currentPage.page
|
||||
@ -1162,7 +1162,7 @@ export default {
|
||||
queryFrom: 'panel'
|
||||
}
|
||||
// table-info明细表增加分页
|
||||
if (this.view.customAttr) {
|
||||
if (this.view && this.view.customAttr) {
|
||||
const attrSize = JSON.parse(this.view.customAttr).size
|
||||
if (this.chart.type === 'table-info' && this.view.datasetMode === 0 && (!attrSize.tablePageMode || attrSize.tablePageMode === 'page')) {
|
||||
requestInfo.goPage = this.currentPage.page
|
||||
|
@ -1865,8 +1865,12 @@ export default {
|
||||
sure_bt: 'Confirm'
|
||||
},
|
||||
panel: {
|
||||
|
||||
down: 'Down',
|
||||
|
||||
mobile_style_setting: 'Style setting',
|
||||
mobile_style_setting_tips: 'Customize the mobile background',
|
||||
|
||||
board: 'Border',
|
||||
text: 'Text',
|
||||
board_background: 'Background',
|
||||
|
@ -1865,8 +1865,12 @@ export default {
|
||||
sure_bt: '確定'
|
||||
},
|
||||
panel: {
|
||||
|
||||
down: '下載',
|
||||
|
||||
mobile_style_setting: '樣式設置',
|
||||
mobile_style_setting_tips: '自定義移動端背景',
|
||||
|
||||
board: '邊框',
|
||||
text: '文字',
|
||||
board_background: '背景',
|
||||
|
@ -1865,8 +1865,12 @@ export default {
|
||||
sure_bt: '确定'
|
||||
},
|
||||
panel: {
|
||||
|
||||
down: '下载',
|
||||
|
||||
mobile_style_setting: '样式设置',
|
||||
mobile_style_setting_tips: '自定义移动端背景',
|
||||
|
||||
board: '边框',
|
||||
text: '文字',
|
||||
board_background: '背景',
|
||||
|
@ -314,6 +314,16 @@ export const isSameVueObj = (source, target) => {
|
||||
return false
|
||||
}
|
||||
|
||||
export const isSameArr = (source, target) => {
|
||||
if (!source && !target) return true
|
||||
if (source?.length && target?.length && source.length === target.length) {
|
||||
const sortSource = source.sort()
|
||||
const sortTarget = target.sort()
|
||||
return JSON.stringify(sortSource) === JSON.stringify(sortTarget)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const changeFavicon = link => {
|
||||
let $favicon = document.querySelector('link[rel="icon"]')
|
||||
if ($favicon !== null) {
|
||||
|
@ -77,7 +77,7 @@ export default {
|
||||
|
||||
.testcase-template {
|
||||
display: inline-block;
|
||||
margin: 10px 0px;
|
||||
margin: 5px 0px;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@
|
||||
v-if="curComponent.commonBackground.enable"
|
||||
style="padding-left: 10px"
|
||||
>
|
||||
<el-row style="height: 80px;margin-top:10px;margin-bottom:20px;overflow: hidden">
|
||||
<el-row style="height: 80px;margin-top:0px;margin-bottom:20px;overflow: hidden">
|
||||
<el-col
|
||||
:span="4"
|
||||
style="padding-left: 10px"
|
||||
@ -112,7 +112,7 @@
|
||||
:http-request="upload"
|
||||
:file-list="fileList"
|
||||
>
|
||||
<i class="el-icon-plus" />
|
||||
<i class="el-icon-plus"/>
|
||||
</el-upload>
|
||||
<el-dialog
|
||||
top="25vh"
|
||||
@ -164,7 +164,6 @@
|
||||
:span="6"
|
||||
>
|
||||
<background-item
|
||||
:style="itemStyle"
|
||||
:template="item"
|
||||
/>
|
||||
</el-col>
|
||||
@ -377,7 +376,7 @@ export default {
|
||||
|
||||
.main-row {
|
||||
padding-left: 10px;
|
||||
height: 140px;
|
||||
height: 250px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
:component-data="mainCanvasComponentData"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:panel-info="panelInfo"
|
||||
:user-id="user"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -412,10 +412,6 @@ export default {
|
||||
this.myAttrs.fieldId = null
|
||||
this.myAttrs.activeName = null
|
||||
}
|
||||
|
||||
if (this.myAttrs.sort?.sort === 'custom') {
|
||||
this.myAttrs.sort.list = []
|
||||
}
|
||||
this.enableSureButton()
|
||||
},
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="widget.isCustomSortWidget && widget.isCustomSortWidget()"
|
||||
v-if="widget.isSortWidget && widget.isSortWidget()"
|
||||
style="padding-left: 10px;"
|
||||
>
|
||||
|
||||
|
@ -95,6 +95,7 @@
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item
|
||||
v-if="isCustomSortWidget"
|
||||
:command="beforeClickItem('custom')"
|
||||
>
|
||||
<span
|
||||
@ -146,6 +147,7 @@
|
||||
<script>
|
||||
import { fieldListWithPermission } from '@/api/dataset/dataset'
|
||||
import FilterCustomSort from './FilterCustomSort'
|
||||
import { isSameArr } from '@/utils'
|
||||
export default {
|
||||
name: 'FilterSort',
|
||||
components: { FilterCustomSort },
|
||||
@ -175,7 +177,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
fieldIds() {
|
||||
return this.element.options.attrs.fieldId || []
|
||||
return this.element.options.attrs.fieldId
|
||||
},
|
||||
isSortWidget() {
|
||||
return this.widget && this.widget.isSortWidget && this.widget.isSortWidget()
|
||||
@ -195,8 +197,24 @@ export default {
|
||||
watch: {
|
||||
firstTableId(val, old) {
|
||||
if (val !== old) {
|
||||
if (this.isSortWidget && (this.sortNode?.sort === 'asc' || this.sortNode?.sort === 'desc')) {
|
||||
this.sortNode = { sort: 'none' }
|
||||
this.$emit('sort-change', this.sortNode)
|
||||
}
|
||||
this.loadFields()
|
||||
}
|
||||
},
|
||||
fieldIds(val, old) {
|
||||
if (val !== old) {
|
||||
if (this.isCustomSortWidget && this.sortNode.sort === 'custom') {
|
||||
const valArr = val?.length ? val.split(',') : null
|
||||
const oldArr = old?.length ? old.split(',') : null
|
||||
if (!isSameArr(valArr, oldArr)) {
|
||||
this.sortNode = { sort: 'none' }
|
||||
this.$emit('sort-change', this.sortNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
@ -210,12 +228,12 @@ export default {
|
||||
this.customSortList = JSON.parse(JSON.stringify(this.sortNode.list))
|
||||
}
|
||||
}
|
||||
if (!this.sortNode) {
|
||||
this.sortNode = JSON.parse(JSON.stringify(this.defaultSortProp))
|
||||
}
|
||||
|
||||
this.loadFields()
|
||||
}
|
||||
if (!this.sortNode) {
|
||||
this.sortNode = JSON.parse(JSON.stringify(this.defaultSortProp))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
customSortChange(list) {
|
||||
|
Loading…
Reference in New Issue
Block a user