Merge branch 'dev' into pr@dev_memory_component

This commit is contained in:
dataeaseShu 2022-12-07 17:29:51 +08:00
commit 45a5909682
89 changed files with 3372 additions and 949 deletions

View File

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dataease-server</artifactId>
<groupId>io.dataease</groupId>
<version>1.17.0</version>
<version>1.18.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -203,7 +204,7 @@
<dependency>
<groupId>io.dataease</groupId>
<artifactId>dataease-plugin-interface</artifactId>
<version>1.17.0</version>
<version>1.18.0</version>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
@ -214,12 +215,12 @@
<dependency>
<groupId>io.dataease</groupId>
<artifactId>dataease-plugin-view</artifactId>
<version>1.17.0</version>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>io.dataease</groupId>
<artifactId>dataease-plugin-datasource</artifactId>
<version>1.17.0</version>
<version>1.18.0</version>
</dependency>
<!-- kettle及数据源依赖 -->
<dependency>
@ -502,7 +503,8 @@
<exclude name="*.html"/>
</fileset>
</copy>
<copy file="../mobile/dist/index.html" tofile="src/main/resources/templates/app.html"/>
<copy file="../mobile/dist/index.html"
tofile="src/main/resources/templates/app.html"/>
</target>
</configuration>
<goals>
@ -538,4 +540,4 @@
</repository>
</repositories>
</project>
</project>

View File

@ -0,0 +1,24 @@
package io.dataease.auth.annotation;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DeRateLimiter {
long DEFAULT_REQUEST = 2;
@AliasFor("max") long value() default DEFAULT_REQUEST;
@AliasFor("value") long max() default DEFAULT_REQUEST;
String key() default "";
long timeout() default 500;
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

View File

@ -0,0 +1,55 @@
package io.dataease.auth.aop;
import cn.hutool.core.util.StrUtil;
import io.dataease.auth.annotation.DeRateLimiter;
import io.dataease.auth.service.DeLimitService;
import io.dataease.commons.utils.IPUtils;
import io.dataease.commons.utils.ServletUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class DeRateLimiterHandler {
private final static String SEPARATOR = ":";
@Resource
private DeLimitService deLimitService;
@Around(value = "@annotation(io.dataease.auth.annotation.DeRateLimiter)")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DeRateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, DeRateLimiter.class);
if (rateLimiter != null) {
String key = rateLimiter.key();
if (StrUtil.isBlank(key)) {
key = method.getDeclaringClass().getName() + StrUtil.DOT + method.getName();
}
key = key + SEPARATOR + IPUtils.get();
long max = rateLimiter.max();
long timeout = rateLimiter.timeout();
TimeUnit timeUnit = rateLimiter.timeUnit();
Boolean limited = deLimitService.checkRestricted(key, max, timeout, timeUnit);
if (limited) {
String msg = "The current API [%s] is limited, please try again later!";
String requestURI = ServletUtils.request().getRequestURI();
throw new RuntimeException(String.format(msg, requestURI));
}
}
return point.proceed();
}
}

View File

@ -0,0 +1,8 @@
package io.dataease.auth.service;
import java.util.concurrent.TimeUnit;
public interface DeLimitService {
Boolean checkRestricted(String key, long max, long timeout, TimeUnit timeUnit);
}

View File

@ -0,0 +1,51 @@
package io.dataease.auth.service.impl;
import io.dataease.auth.service.DeLimitService;
import io.dataease.commons.condition.RedisStatusCondition;
import io.dataease.commons.utils.LogUtil;
import org.slf4j.Logger;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.Instant;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Conditional({RedisStatusCondition.class})
@Component
@Primary
public class RedisLimitServiceImpl implements DeLimitService {
Logger log = LogUtil.getLogger();
private final static String REDIS_LIMIT_KEY_PREFIX = "limit:";
@Resource
private RedisScript<Long> limitRedisScript;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Boolean checkRestricted(String key, long max, long timeout, TimeUnit timeUnit) {
key = REDIS_LIMIT_KEY_PREFIX + key;
long ttl = timeUnit.toMillis(timeout);
long now = Instant.now().toEpochMilli();
long expired = now - ttl;
Long executeTimes = stringRedisTemplate.execute(limitRedisScript, Collections.singletonList(key), now + "", ttl + "", expired + "", max + "");
if (executeTimes != null) {
if (executeTimes == 0) {
log.error("【{}】在单位时间 {} 毫秒内已达到访问上限,当前接口上限 {}", key, ttl, max);
return true;
} else {
log.info("【{}】在单位时间 {} 毫秒内访问 {} 次", key, ttl, executeTimes);
return false;
}
}
return false;
}
}

View File

@ -107,6 +107,7 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/plugin/lark/callBack*", ANON);
filterChainDefinitionMap.put("/plugin/lark/bind*", ANON);
filterChainDefinitionMap.put("/plugin/lark/getQrParam", ANON);
filterChainDefinitionMap.put("/plugin/lark/appId", ANON);
filterChainDefinitionMap.put("/plugin/larksuite/callBack*", ANON);
filterChainDefinitionMap.put("/plugin/larksuite/bind*", ANON);
filterChainDefinitionMap.put("/plugin/larksuite/getQrParam", ANON);

View File

@ -0,0 +1,26 @@
package io.dataease.auth.service.impl;
import com.google.common.util.concurrent.RateLimiter;
import io.dataease.auth.service.DeLimitService;
import org.springframework.stereotype.Service;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Service
public class StandaloneLimitServiceImpl implements DeLimitService {
private static ConcurrentHashMap<String, RateLimiter> RATE_LIMITER = new ConcurrentHashMap<>();
@Override
public Boolean checkRestricted(String key, long max, long timeout, TimeUnit timeUnit) {
RateLimiter rateLimiter = null;
if (!RATE_LIMITER.containsKey(key)) {
RATE_LIMITER.put(key, RateLimiter.create(max));
}
rateLimiter = RATE_LIMITER.get(key);
return !rateLimiter.tryAcquire(timeout, timeUnit);
}
}

View File

@ -12,10 +12,13 @@ import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class SqlFilter implements Filter {
private List<String> excludedUris = new ArrayList<>();
@Override
public void destroy() {
@ -34,38 +37,43 @@ public class SqlFilter implements Filter {
return;
}
String method = "GET";
String param;
XssAndSqlHttpServletRequestWrapper xssRequest = null;
if (request instanceof HttpServletRequest) {
method = ((HttpServletRequest) request).getMethod();
xssRequest = new XssAndSqlHttpServletRequestWrapper((HttpServletRequest) request);
}
if ("POST".equalsIgnoreCase(method)) {
param = this.getBodyString(xssRequest.getReader());
if (StringUtils.isNotBlank(param)) {
if (xssRequest.checkXSSAndSql(param)) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
String msg = ThreadLocalContextHolder.getData().toString();
DEException.throwException(msg);
return;
if(excludedUris.contains(((HttpServletRequest) request).getRequestURI())){
chain.doFilter(request, response);
}else {
String method = "GET";
String param;
XssAndSqlHttpServletRequestWrapper xssRequest = null;
if (request instanceof HttpServletRequest) {
method = ((HttpServletRequest) request).getMethod();
xssRequest = new XssAndSqlHttpServletRequestWrapper((HttpServletRequest) request);
}
if ("POST".equalsIgnoreCase(method)) {
param = this.getBodyString(xssRequest.getReader());
if (StringUtils.isNotBlank(param)) {
if (xssRequest.checkXSSAndSql(param)) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
String msg = ThreadLocalContextHolder.getData().toString();
DEException.throwException(msg);
return;
}
}
}
if (xssRequest.checkParameter()) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
String msg = ThreadLocalContextHolder.getData().toString();
DEException.throwException(msg);
return;
}
chain.doFilter(xssRequest, response);
}
if (xssRequest.checkParameter()) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
String msg = ThreadLocalContextHolder.getData().toString();
DEException.throwException(msg);
return;
}
chain.doFilter(xssRequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
excludedUris.add("/dataset/table/excel/upload");
}
// 获取request请求body中参数

View File

@ -6,10 +6,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.scripting.support.ResourceScriptSource;
@Conditional({RedisStatusCondition.class})
@ -36,4 +40,12 @@ public class RedisConfig {
return container;
}
@Bean
public RedisScript<Long> limitRedisScript() {
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/limit.lua")));
redisScript.setResultType(Long.class);
return redisScript;
}
}

View File

@ -149,7 +149,7 @@
</select>
<select id="findByTableIds" resultMap="BaseResultMapDTO">
select dataset_table.*
select distinct dataset_table.*
from dataset_table
where dataset_table.id in
<foreach collection="tableIds" item="item" open="(" separator="," close=")">

View File

@ -80,8 +80,7 @@ public class XDingtalkServer {
return dingtalkXpackService.getQrParam();
}
@GetMapping("/callBack")
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
private ModelAndView privateCallBack(String code, Boolean withoutLogin) {
ModelAndView modelAndView = new ModelAndView("redirect:/");
HttpServletResponse response = ServletUtils.response();
DingtalkXpackService dingtalkXpackService = null;
@ -95,7 +94,7 @@ public class XDingtalkServer {
if (!isOpen) {
DEException.throwException("未开启钉钉");
}
DingUserEntity dingUserEntity = dingtalkXpackService.userInfo(code);
DingUserEntity dingUserEntity = withoutLogin ? dingtalkXpackService.userInfoWithoutLogin(code) : dingtalkXpackService.userInfo(code);
String username = dingUserEntity.getUserid();
SysUserEntity sysUserEntity = authUserService.getUserByDingtalkId(username);
if (null == sysUserEntity) {
@ -139,6 +138,16 @@ public class XDingtalkServer {
return modelAndView;
}
@GetMapping("/callBackWithoutLogin")
public ModelAndView callBackWithoutLogin(@RequestParam("code") String code) {
return privateCallBack(code, true);
}
@GetMapping("/callBack")
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
return privateCallBack(code, false);
}
private void bindError(HttpServletResponse response, String url, String errorMsg) {
Cookie cookie_error = new Cookie("DingtalkError", errorMsg);
cookie_error.setPath("/");

View File

@ -1,8 +1,10 @@
package io.dataease.plugins.server;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.dataease.auth.annotation.DeRateLimiter;
import io.dataease.auth.api.dto.CurrentUserDto;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.model.excel.ExcelSheetModel;
@ -27,6 +29,9 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.HtmlUtils;
import springfox.documentation.annotations.ApiIgnore;
@ -150,7 +155,45 @@ public class XEmailTaskServer {
return xpackEmailCreate;
}
@PostMapping("/preview")
@DeRateLimiter
@PostMapping(value = "/screenshot", produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
public ResponseEntity<ByteArrayResource> screenshot(@RequestBody XpackEmailViewRequest request) {
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
String url = ServletUtils.domain() + "/#/previewScreenShot/" + request.getPanelId() + "/true";
byte[] bytes = null;
try {
String currentToken = ServletUtils.getToken();
Future<?> future = priorityExecutor.submit(() -> {
try {
return emailXpackService.print(url, currentToken, buildPixel(request.getPixel()));
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException("预览失败,请联系管理员");
}
return null;
}, 0);
Object object = future.get();
if (ObjectUtils.isNotEmpty(object)) {
bytes = (byte[]) object;
if (ArrayUtil.isNotEmpty(bytes)) {
String fileName = request.getPanelId() + ".jpeg";
ByteArrayResource bar = new ByteArrayResource(bytes);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
ContentDisposition contentDisposition = ContentDisposition.parse("attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
headers.setContentDisposition(contentDisposition);
return new ResponseEntity(bar, headers, HttpStatus.OK);
}
}
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException("预览失败,请联系管理员");
}
return null;
}
@PostMapping(value = "/preview")
public String preview(@RequestBody XpackEmailViewRequest request) {
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
String panelId = request.getPanelId();
@ -159,7 +202,6 @@ public class XEmailTaskServer {
String url = ServletUtils.domain() + "/#/previewScreenShot/" + panelId + "/true";
String token = ServletUtils.getToken();
String fileId = null;
try {
Future<?> future = priorityExecutor.submit(() -> {
try {
@ -172,19 +214,21 @@ public class XEmailTaskServer {
}, 0);
Object object = future.get();
if (ObjectUtils.isNotEmpty(object)) {
fileId = object.toString();
byte[] bytes = (byte[]) object;
String baseCode = Base64Utils.encodeToString(bytes);
String imageUrl = "data:image/jpeg;base64," + baseCode;
String html = "<div>" +
content +
"<img style='width: 100%;' id='" + panelId + "' src='" + imageUrl + "' />" +
"</div>";
return html;
}
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException("预览失败,请联系管理员");
}
String imageUrl = "/system/ui/image/" + fileId;
String html = "<div>" +
content +
"<img style='width: 100%;' id='" + panelId + "' src='" + imageUrl + "' />" +
"</div>";
return html;
return null;
}

View File

@ -6,6 +6,7 @@ import io.dataease.auth.service.AuthUserService;
import io.dataease.auth.util.JWTUtils;
import io.dataease.commons.constants.SysLogConstants;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.utils.BeanUtils;
import io.dataease.commons.utils.DeLogUtils;
import io.dataease.commons.utils.LogUtil;
import io.dataease.commons.utils.ServletUtils;
@ -15,8 +16,10 @@ import io.dataease.plugins.common.base.domain.SysUserAssist;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.display.dto.response.SysSettingDto;
import io.dataease.plugins.xpack.lark.dto.entity.LarkAppUserEntity;
import io.dataease.plugins.xpack.lark.dto.entity.LarkQrResult;
import io.dataease.plugins.xpack.lark.dto.entity.LarkUserInfo;
import io.dataease.plugins.xpack.lark.dto.response.LarkAppUserResult;
import io.dataease.plugins.xpack.lark.dto.response.LarkInfo;
import io.dataease.plugins.xpack.lark.service.LarkXpackService;
import io.dataease.service.sys.SysUserService;
@ -48,6 +51,13 @@ public class XLarkServer {
@Resource
private SysUserService sysUserService;
@ResponseBody
@GetMapping("/appId")
public String getAppId() {
LarkXpackService larkXpackService = SpringContextUtil.getBean(LarkXpackService.class);
return larkXpackService.appId();
}
@ResponseBody
@GetMapping("/info")
public LarkInfo getLarkInfo() {
@ -81,8 +91,12 @@ public class XLarkServer {
return larkXpackService.getQrParam();
}
@GetMapping("/callBack")
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
@GetMapping("/callBackWithoutLogin")
public ModelAndView callBackWithoutLogin(@RequestParam("code") String code) {
return privateCallBack(code, null, true);
}
private ModelAndView privateCallBack(String code, String state, Boolean withoutLogin) {
ModelAndView modelAndView = new ModelAndView("redirect:/");
HttpServletResponse response = ServletUtils.response();
LarkXpackService larkXpackService = null;
@ -96,7 +110,14 @@ public class XLarkServer {
if (!isOpen) {
DEException.throwException("未开启飞书");
}
LarkUserInfo larkUserInfo = larkXpackService.userInfo(code, state, false);
LarkUserInfo larkUserInfo = null;
if (withoutLogin) {
LarkAppUserResult larkAppUserResult = larkXpackService.userInfoWithoutLogin(code);
LarkAppUserEntity userResultData = larkAppUserResult.getData();
larkUserInfo = BeanUtils.copyBean(new LarkUserInfo(), userResultData);
} else {
larkUserInfo = larkXpackService.userInfo(code, state, false);
}
String username = larkUserInfo.getUser_id();
SysUserEntity sysUserEntity = authUserService.getUserByLarkId(username);
if (null == sysUserEntity) {
@ -140,6 +161,11 @@ public class XLarkServer {
return modelAndView;
}
@GetMapping("/callBack")
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
return privateCallBack(code, state, false);
}
private void bindError(HttpServletResponse response, String url, String errorMsg) {
Cookie cookie_error = new Cookie("LarkError", errorMsg);
cookie_error.setPath("/");

View File

@ -390,7 +390,11 @@ public class DorisQueryProvider extends QueryProvider {
originField = String.format(DorisConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getDataeaseName());
} else {
if (x.getDeType() == 2 || x.getDeType() == 3) {
originField = String.format(DorisConstants.CAST, String.format(DorisConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getDataeaseName()), DorisConstants.DEFAULT_FLOAT_FORMAT);
if (x.getDeExtractType() == 1) {
originField = String.format(DorisConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getDataeaseName());
} else {
originField = String.format(DorisConstants.CAST, String.format(DorisConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getDataeaseName()), DorisConstants.DEFAULT_FLOAT_FORMAT);
}
} else {
originField = String.format(DorisConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getDataeaseName());
}

View File

@ -1338,8 +1338,9 @@ public class SqlserverQueryProvider extends QueryProvider {
public List<Dateformat> dateformat() {
return JSONArray.parseArray("[\n" +
"{\"dateformat\": \"102\", \"desc\": \"yyyy.mm.dd\"},\n" +
"{\"dateformat\": \"23\", \"desc\": \"yyyy-mm-dd\"},\n" +
"{\"dateformat\": \"120\", \"desc\": \"yyyy-mm-dd\"},\n" +
"{\"dateformat\": \"111\", \"desc\": \"yyyy/mm/dd\"},\n" +
"{\"dateformat\": \"112\", \"desc\": \"yyyymmdd\"},\n" +
"{\"dateformat\": \"120\", \"desc\": \"yyyy-mm-dd hh:mi:ss\"}\n" +
"]", Dateformat.class);
}

View File

@ -982,7 +982,8 @@ public class ChartViewService {
}
if (StringUtils.isNotEmpty(totalPageSql) && StringUtils.equalsIgnoreCase((String) mapSize.get("tablePageMode"), "page")) {
datasourceRequest.setQuery(totalPageSql);
totalItems = Long.valueOf(datasourceProvider.getData(datasourceRequest).get(0)[0]);
java.util.List<java.lang.String[]> tmpData = datasourceProvider.getData(datasourceRequest);
totalItems = CollectionUtils.isEmpty(tmpData) ? 0 : Long.valueOf(tmpData.get(0)[0]);
totalPage = (totalItems / pageInfo.getPageSize()) + (totalItems % pageInfo.getPageSize() > 0 ? 1 : 0);
}

View File

@ -2,11 +2,16 @@ package io.dataease.service.dataset;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.dataease.ext.ExtChartViewMapper;
import io.dataease.commons.constants.*;
import io.dataease.commons.model.AuthURD;
import io.dataease.commons.utils.*;
import io.dataease.controller.request.datasource.ApiDefinition;
import io.dataease.dto.dataset.DataTableInfoDTO;
import io.dataease.dto.dataset.ExcelSheetData;
import io.dataease.dto.datasource.*;
import io.dataease.exception.DataEaseException;
import io.dataease.ext.ExtChartViewMapper;
import io.dataease.listener.util.CacheUtils;
import io.dataease.plugins.common.base.domain.*;
import io.dataease.plugins.common.constants.DatasetType;
import io.dataease.plugins.common.constants.DatasourceTypes;
@ -17,14 +22,9 @@ import io.dataease.plugins.datasource.entity.JdbcConfiguration;
import io.dataease.plugins.datasource.provider.Provider;
import io.dataease.plugins.datasource.query.QueryProvider;
import io.dataease.provider.DDLProvider;
import io.dataease.provider.datasource.JdbcProvider;
import io.dataease.provider.ProviderFactory;
import io.dataease.dto.datasource.*;
import io.dataease.provider.datasource.JdbcProvider;
import io.dataease.service.datasource.DatasourceService;
import io.dataease.dto.dataset.DataTableInfoDTO;
import io.dataease.dto.dataset.ExcelSheetData;
import io.dataease.exception.DataEaseException;
import io.dataease.listener.util.CacheUtils;
import io.dataease.service.engine.EngineService;
import io.dataease.service.kettle.KettleService;
import io.dataease.service.message.DeMsgutil;
@ -413,7 +413,7 @@ public class ExtractDataService {
}
private List<DatasetTableField> getDatasetTableFields(String datasetTableId) {
public List<DatasetTableField> getDatasetTableFields(String datasetTableId) {
List<DatasetTableField> datasetTableFields = dataSetTableFieldsService.list(DatasetTableField.builder().tableId(datasetTableId).build());
datasetTableFields = datasetTableFields.stream().filter(datasetTableField -> datasetTableField.getExtField() == 0).collect(Collectors.toList());
datasetTableFields.sort((o1, o2) -> {
@ -617,7 +617,7 @@ public class ExtractDataService {
dataSetTableTaskLogService.save(datasetTableTaskLog, hasTask);
}
private void createEngineTable(String tableName, List<DatasetTableField> datasetTableFields) throws Exception {
public void createEngineTable(String tableName, List<DatasetTableField> datasetTableFields) throws Exception {
Datasource engine = engineService.getDeEngine();
JdbcProvider jdbcProvider = CommonBeanFactory.getBean(JdbcProvider.class);
DatasourceRequest datasourceRequest = new DatasourceRequest();
@ -793,7 +793,7 @@ public class ExtractDataService {
Thread.sleep(1000);
}
if (jobStatus.getStatusDescription().equals("Finished")) {
LogUtil.info(datasetTable.getId()+ ": " + jobStatus.getLoggingString());
LogUtil.info(datasetTable.getId() + ": " + jobStatus.getLoggingString());
return;
} else {
DataEaseException.throwException(jobStatus.getLoggingString());
@ -1029,7 +1029,7 @@ public class ExtractDataService {
if (extractType.equalsIgnoreCase("all_scope") && datasetTable.getType().equalsIgnoreCase(DatasetType.SQL.name())) {
DataTableInfoDTO dataTableInfoDTO = new Gson().fromJson(datasetTable.getInfo(), DataTableInfoDTO.class);
selectSQL = dataTableInfoDTO.getSql();
if(dataTableInfoDTO.isBase64Encryption()){
if (dataTableInfoDTO.isBase64Encryption()) {
selectSQL = new String(java.util.Base64.getDecoder().decode(selectSQL));
}
QueryProvider qp = ProviderFactory.getQueryProvider(datasource.getType());
@ -1056,13 +1056,13 @@ public class ExtractDataService {
}
private List<StepMeta> excelInputStep(String Info, List<DatasetTableField> datasetTableFields) {
List<StepMeta>inputSteps = new ArrayList<>();
List<StepMeta> inputSteps = new ArrayList<>();
DataTableInfoDTO dataTableInfoDTO = new Gson().fromJson(Info, DataTableInfoDTO.class);
List<ExcelSheetData> excelSheetDataList = dataTableInfoDTO.getExcelSheetDataList();
List<String> sheetNames = new ArrayList<>();
int size =1;
int size = 1;
for (ExcelSheetData excelSheetData : excelSheetDataList) {
StepMeta fromStep = null;
String suffix = excelSheetData.getPath().substring(excelSheetDataList.get(0).getPath().lastIndexOf(".") + 1);
@ -1090,7 +1090,7 @@ public class ExtractDataService {
fromStep.setDraw(true);
fromStep.setLocation(100, 100 * size);
inputSteps.add(fromStep);
}else {
} else {
List<String> files = new ArrayList<>();
files.add(excelSheetData.getPath());
@ -1240,7 +1240,7 @@ public class ExtractDataService {
if (StringUtils.isNotEmpty(charset)) {
String varcharFields = datasetTableFields.stream().filter(datasetTableField -> datasetTableField.getDeExtractType() == 0).map(DatasetTableField::getOriginName).collect(Collectors.joining(","));
tmp_code = tmp_code.replace("handleCharset", handleCharset.replace("Datasource_Charset", charset).replace("Target_Charset", targetCharset).replace("varcharFields", varcharFields));
}else {
} else {
tmp_code = tmp_code.replace("handleCharset", "");
}
} else {

View File

@ -20,6 +20,7 @@ import io.dataease.service.chart.ChartViewService;
import io.dataease.service.dataset.DataSetGroupService;
import io.dataease.service.dataset.DataSetTableFieldsService;
import io.dataease.service.dataset.DataSetTableService;
import io.dataease.service.dataset.ExtractDataService;
import io.dataease.service.datasource.DatasourceService;
import io.dataease.service.staticResource.StaticResourceService;
import org.apache.commons.lang3.StringUtils;
@ -68,6 +69,8 @@ public class PanelAppTemplateService {
private DataSetGroupService dataSetGroupService;
@Resource
private StaticResourceService staticResourceService;
@Resource
private ExtractDataService extractDataService;
public List<PanelAppTemplateWithBLOBs> list(PanelAppTemplateRequest request) {
return extPanelAppTemplateMapper.queryBaseInfo(request.getNodeType(), request.getPid());
@ -209,6 +212,7 @@ public class PanelAppTemplateService {
DatasetTableField newTableField = dataSetTableFieldsService.save(datasetTableField);
datasetFieldsRealMap.put(oldId, newTableField.getId());
datasetFieldsMd5FormatRealMap.put(TableUtils.fieldNameShort(oldTableId + "_" + datasetTableField.getOriginName()), TableUtils.fieldNameShort(newTableField.getTableId() + "_" + datasetTableField.getOriginName()));
datasetFieldsMd5FormatRealMap.put(TableUtils.fieldName(oldTableId + "_" + datasetTableField.getDataeaseName()), TableUtils.fieldName(newTableField.getTableId() + "_" + datasetTableField.getDataeaseName()));
}
}
//数据集计算字段替换
@ -225,6 +229,8 @@ public class PanelAppTemplateService {
DatasetTableField newTableField = dataSetTableFieldsService.save(datasetTableField);
datasetFieldsRealMap.put(oldId, newTableField.getId());
datasetFieldsMd5FormatRealMap.put(TableUtils.fieldNameShort(oldTableId + "_" + oldOriginName), TableUtils.fieldNameShort(newTableField.getTableId() + "_" + datasetTableField.getOriginName()));
datasetFieldsMd5FormatRealMap.put(TableUtils.fieldName(oldTableId + "_" + datasetTableField.getDataeaseName()), TableUtils.fieldName(newTableField.getTableId() + "_" + datasetTableField.getDataeaseName()));
}
}
@ -233,13 +239,28 @@ public class PanelAppTemplateService {
if (DatasetType.UNION.name().equalsIgnoreCase(datasetTypeRealMap.get(datasetTableField.getTableId())) || DatasetType.CUSTOM.name().equalsIgnoreCase(datasetTypeRealMap.get(datasetTableField.getTableId()))) {
DatasetTableField updateField = new DatasetTableField();
updateField.setId(datasetTableField.getId());
updateField.setOriginName(datasetFieldsMd5FormatRealMap.get(datasetTableField.getOriginName()));
dataSetTableFieldsService.updateByPrimaryKeySelective(updateField);
String newOriginName = datasetFieldsMd5FormatRealMap.get(datasetTableField.getOriginName());
String dataeaseName = datasetFieldsMd5FormatRealMap.get(datasetTableField.getDataeaseName());
if (StringUtils.isNotEmpty(newOriginName) || StringUtils.isNotEmpty(dataeaseName)) {
updateField.setOriginName(datasetFieldsMd5FormatRealMap.get(datasetTableField.getOriginName()));
updateField.setDataeaseName(datasetFieldsMd5FormatRealMap.get(datasetTableField.getDataeaseName()));
dataSetTableFieldsService.updateByPrimaryKeySelective(updateField);
}
}
}
return datasetFieldsRealMap;
}
@Transactional(rollbackFor = Exception.class)
public void createDorisTable(List<DatasetTable> datasetTablesInfo) throws Exception {
for (DatasetTable datasetTable : datasetTablesInfo) {
if (1 == datasetTable.getMode() && !(DatasetType.CUSTOM.name().equalsIgnoreCase(datasetTable.getType()) || DatasetType.UNION.name().equalsIgnoreCase(datasetTable.getType()))) {
List<DatasetTableField> fields = extractDataService.getDatasetTableFields(datasetTable.getId());
extractDataService.createEngineTable(TableUtils.tableName(datasetTable.getId()), fields);
}
}
}
@Transactional(rollbackFor = Exception.class)
public void resetCustomAndUnionDataset(List<DatasetTable> datasetTablesInfo, Map<String, String> datasetRealMap, Map<String, String> datasetFieldsRealMap) throws Exception {
for (DatasetTable datasetTable : datasetTablesInfo) {

View File

@ -30,7 +30,6 @@ import io.dataease.listener.util.CacheUtils;
import io.dataease.plugins.common.base.domain.*;
import io.dataease.plugins.common.base.mapper.*;
import io.dataease.plugins.common.constants.DeTypeConstants;
import io.dataease.service.SystemInfoService;
import io.dataease.service.chart.ChartViewService;
import io.dataease.service.dataset.DataSetGroupService;
import io.dataease.service.dataset.DataSetTableService;
@ -135,8 +134,6 @@ public class PanelGroupService {
private DatasetGroupMapper datasetGroupMapper;
@Resource
private PanelWatermarkMapper panelWatermarkMapper;
@Resource
private SystemInfoService systemInfoService;
public List<PanelGroupDTO> tree(PanelGroupRequest panelGroupRequest) {
String userId = String.valueOf(AuthUtils.getUser().getUserId());
@ -811,29 +808,6 @@ public class PanelGroupService {
List<ChartViewField> chartViewFieldsInfo = extChartViewFieldMapper.findByPanelId(panelId);
//3.获取所有数据集信息
List<DatasetTable> datasetTablesInfo = extDataSetTableMapper.findByPanelId(panelId);
List<String> attachTableIds = new ArrayList<>();
if (CollectionUtils.isNotEmpty(datasetTablesInfo)) {
for (DatasetTable datasetTable : datasetTablesInfo) {
if ("union".equals(datasetTable.getType()) && StringUtils.isNotEmpty(datasetTable.getInfo())) {
DataTableInfoDTO dt = gson.fromJson(datasetTable.getInfo(), DataTableInfoDTO.class);
DatasetUtils.getUnionTable(attachTableIds, dt.getUnion());
} else if ("custom".equals(datasetTable.getType()) && StringUtils.isNotEmpty(datasetTable.getInfo())) {
Map result = gson.fromJson(datasetTable.getInfo(), Map.class);
List<Map> list = (List<Map>) result.get("list");
if (CollectionUtils.isNotEmpty(list)) {
for (Map details : list) {
attachTableIds.add(String.valueOf(details.get("tableId")));
}
}
}
}
if (CollectionUtils.isNotEmpty(attachTableIds)) {
List<DatasetTable> attachDatasetTables = extDataSetTableMapper.findByTableIds(attachTableIds);
if (CollectionUtils.isNotEmpty(attachDatasetTables)) {
datasetTablesInfo.addAll(attachDatasetTables);
}
}
}
// dataset check
if (CollectionUtils.isEmpty(datasetTablesInfo)) {
return new PanelExport2App(Translator.get("I18N_APP_NO_DATASET_ERROR"));
@ -841,6 +815,23 @@ public class PanelGroupService {
return new PanelExport2App(Translator.get("I18N_APP_ERROR_DATASET"));
}
List<String> allTableIds = datasetTablesInfo.stream().map(DatasetTable::getId).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(datasetTablesInfo)) {
for (DatasetTable datasetTable : datasetTablesInfo) {
if ("union".equals(datasetTable.getType()) && StringUtils.isNotEmpty(datasetTable.getInfo())) {
DataTableInfoDTO dt = gson.fromJson(datasetTable.getInfo(), DataTableInfoDTO.class);
DatasetUtils.getUnionTable(allTableIds, dt.getUnion());
} else if ("custom".equals(datasetTable.getType()) && StringUtils.isNotEmpty(datasetTable.getInfo())) {
Map result = gson.fromJson(datasetTable.getInfo(), Map.class);
List<Map> list = (List<Map>) result.get("list");
if (CollectionUtils.isNotEmpty(list)) {
for (Map details : list) {
allTableIds.add(String.valueOf(details.get("tableId")));
}
}
}
}
}
datasetTablesInfo = extDataSetTableMapper.findByTableIds(allTableIds);
//4.获取所有数据集字段信息
List<DatasetTableField> datasetTableFieldsInfo = extDataSetTableFieldMapper.findByTableIds(allTableIds);
//5.获取所有任务信息
@ -917,6 +908,8 @@ public class PanelGroupService {
Map<String, String> datasetFieldsRealMap = panelAppTemplateService.applyDatasetField(datasetTableFieldsInfo, datasetsRealMap, datasetTypeRealMap, datasetFieldsMd5FormatRealMap);
panelAppTemplateService.createDorisTable(datasetTablesInfo);
panelAppTemplateService.resetCustomAndUnionDataset(datasetTablesInfo, datasetsRealMap, datasetFieldsRealMap);
Map<String, String> chartViewsRealMap = panelAppTemplateService.applyViews(chartViewsInfo, datasetsRealMap, datasetFieldsRealMap, datasetFieldsMd5FormatRealMap, newPanelId);

File diff suppressed because one or more lines are too long

View File

@ -247,3 +247,16 @@ I18N_LOG_FORMAT_POSITION=IN\u3010%s\u3011
I18N_LOG_FORMAT=TO %s\u3010%s\u3011
I18N_LOG_FORMAT_PREFIX=With authority of %s\u3010%s\u3011
\u4E0A\u4F20\u63D2\u4EF6=Upload
\u5378\u8F7D\u63D2\u4EF6=Uninstall
\u67E5\u770B\u7CFB\u7EDF\u6A21\u677F=System templates
\u7F16\u8F91\u62A5\u544A=Edit report
\u521B\u5EFA\u62A5\u544A=Create report
\u5220\u9664\u62A5\u544A=Delete report
\u5BFC\u51FA\u65E5\u5FD7=Export log
\u5BFC\u5165\u7528\u6237=Import user
\u6570\u636E\u96C6\u8868\u5355=Dataset form
\u7F16\u8F91\u8BB0\u5F55=Edit record
\u5220\u9664\u8BB0\u5F55=Delete record
\u6C34\u5370\u7BA1\u7406=Watermark

View File

@ -247,3 +247,17 @@ I18N_LOG_FORMAT_POSITION=\u5728\u3010%s\u3011
I18N_LOG_FORMAT=\u7ED9%s\u3010%s\u3011
I18N_LOG_FORMAT_PREFIX=\u4EE5%s\u3010%s\u3011\u6743\u9650
\u4E0A\u4F20\u63D2\u4EF6=\u4E0A\u4F20\u63D2\u4EF6
\u5378\u8F7D\u63D2\u4EF6=\u5378\u8F7D\u63D2\u4EF6
\u67E5\u770B\u7CFB\u7EDF\u6A21\u677F=\u7CFB\u7EDF\u6A21\u7248
\u7F16\u8F91\u62A5\u544A=\u7F16\u8F91\u62A5\u544A
\u521B\u5EFA\u62A5\u544A=\u521B\u5EFA\u62A5\u544A
\u5220\u9664\u62A5\u544A=\u5220\u9664\u62A5\u544A
\u5BFC\u51FA\u65E5\u5FD7=\u5BFC\u51FA\u65E5\u5FD7
\u5BFC\u5165\u7528\u6237=\u5BFC\u5165\u7528\u6237
\u6570\u636E\u96C6\u8868\u5355=\u6570\u636E\u96C6\u8868\u5355
\u7F16\u8F91\u8BB0\u5F55=\u7F16\u8F91\u8BB0\u5F55
\u5220\u9664\u8BB0\u5F55=\u5220\u9664\u8BB0\u5F55
\u6C34\u5370\u7BA1\u7406=\u6C34\u5370\u7BA1\u7406

View File

@ -242,3 +242,16 @@ I18N_PROHIBIT_SCANNING_TO_CREATE_USER=\u7981\u6B62\u6383\u78BC\u5275\u5EFA\u7528
I18N_LOG_FORMAT_POSITION=\u5728\u3010%s\u3011
I18N_LOG_FORMAT=\u7D66%s\u3010%s\u3011
I18N_LOG_FORMAT_PREFIX=\u4EE5%s\u3010%s\u3011\u6B0A\u9650
\u4E0A\u4F20\u63D2\u4EF6=\u4E0A\u50B3\u63D2\u4EF6
\u5378\u8F7D\u63D2\u4EF6=\u5378\u8F09\u63D2\u4EF6
\u67E5\u770B\u7CFB\u7EDF\u6A21\u677F=\u7CFB\u7D71\u6A21\u7248
\u7F16\u8F91\u62A5\u544A=\u7DE8\u8F2F\u5831\u544A
\u521B\u5EFA\u62A5\u544A=\u5275\u5EFA\u5831\u544A
\u5220\u9664\u62A5\u544A=\u522A\u9664\u5831\u544A
\u5BFC\u51FA\u65E5\u5FD7=\u5C0E\u51FA\u65E5\u8A8C
\u5BFC\u5165\u7528\u6237=\u5C0E\u5165\u7528\u6236
\u6570\u636E\u96C6\u8868\u5355=\u6578\u64DA\u96C6\u8868\u55AE
\u7F16\u8F91\u8BB0\u5F55=\u7DE8\u8F2F\u8A18\u9304
\u5220\u9664\u8BB0\u5F55=\u522A\u9664\u8A18\u9304
\u6C34\u5370\u7BA1\u7406=\u6C34\u5370\u7BA1\u7406

View File

@ -0,0 +1,27 @@
-- 下标从 1 开始 获取key
local key = KEYS[1]
-- 下标从 1 开始 获取参数
local now = tonumber(ARGV[1]) -- 当前时间错
local ttl = tonumber(ARGV[2]) -- 有效
local expired = tonumber(ARGV[3]) --
local max = tonumber(ARGV[4])
-- 清除过期的数据
-- 移除指定分数区间内的所有元素expired 即已经过期的 score
-- 根据当前时间毫秒数 - 超时毫秒数,得到过期时间 expired
redis.call('zremrangebyscore', key, 0, expired)
-- 获取 zset 中的当前元素个数
local current = tonumber(redis.call('zcard', key))
local next = current + 1
if next > max then
-- 达到限流大小 返回 0
return 0;
else
-- 往 zset 中添加一个值、得分均为当前时间戳的元素,[value,score]
redis.call("zadd", key, now, now)
-- 每次访问均重新设置 zset 的过期时间,单位毫秒
redis.call("pexpire", key, ttl)
return next
end

View File

@ -1,6 +1,6 @@
{
"name": "dataease",
"version": "1.17.0",
"version": "1.18.0",
"description": "dataease front",
"private": true,
"scripts": {

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dataease-server</artifactId>
<groupId>io.dataease</groupId>
<version>1.17.0</version>
<version>1.18.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -62,4 +62,4 @@
</plugins>
</build>
</project>
</project>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -130,6 +130,13 @@ export function larkStatus() {
})
}
export function larkAppId() {
return request({
url: '/plugin/lark/appId',
method: 'get'
})
}
export function larksuiteStatus() {
return request({
url: '/api/auth/isOpenLarksuite',

View File

@ -293,14 +293,17 @@ export default {
}
},
elementMouseDown(e) {
// private
// // private
this.$store.commit('setClickComponentStatus', true)
if (this.config.component !== 'v-text' && this.config.component !== 'rect-shape' && this.config.component !== 'de-input-search' && this.config.component !== 'de-select-grid' && this.config.component !== 'de-number-range' && this.config.component !== 'de-date') {
e.preventDefault()
}
//
e.stopPropagation()
this.$store.commit('setCurComponent', { component: this.config, index: this.index })
const _this = this
setTimeout(() => {
_this.$store.commit('setCurComponent', { component: _this.config, index: _this.index })
}, 200)
},
showViewDetails(params) {
this.$refs.wrapperChild.openChartDetailsDialog(params)

View File

@ -13,6 +13,7 @@
<script>
import { mapState } from 'vuex'
export default {
props: {
element: {
@ -55,7 +56,7 @@ export default {
},
deleteComponent() {
this.$emit('amRemoveItem')
this.$store.commit('deleteComponent')
this.$store.commit('deleteComponentWithId', this.element.id)
this.$store.commit('setCurComponent', { component: null, index: null })
},
updateMobileSelected(id, mobileSelected) {
@ -70,29 +71,30 @@ export default {
</script>
<style lang="scss" scoped>
.bar-main{
position: absolute;
float:right;
z-index: 10000;
border-radius:2px;
padding-left: 1px;
padding-right: 1px;
cursor:pointer!important;
text-align: center;
background-color: var(--primary,#3370ff);
}
.bar-main i{
color: white;
float: right;
margin-right: 3px;
}
.bar-main {
position: absolute;
float: right;
z-index: 10000;
border-radius: 2px;
padding-left: 1px;
padding-right: 1px;
cursor: pointer !important;
text-align: center;
background-color: var(--primary, #3370ff);
}
.bar-main ::v-deep .el-checkbox__inner{
width: 16px;
height: 16px;
}
.bar-main i {
color: white;
float: right;
margin-right: 3px;
}
.bar-main ::v-deep .el-checkbox__inner::after{
width: 4.5px;
}
.bar-main ::v-deep .el-checkbox__inner {
width: 16px;
height: 16px;
}
.bar-main ::v-deep .el-checkbox__inner::after {
width: 4.5px;
}
</style>

View File

@ -63,7 +63,7 @@
</div>
<el-dialog
v-if="pdfExportShow"
:title="'['+panelInfo.name+']'+'PDF导出'"
:title="'['+panelInfo.name+']'+$t('panel.pdf_export')"
:visible.sync="pdfExportShow"
width="80%"
:top="'8vh'"
@ -77,7 +77,7 @@
/>
<el-select
v-model="pdfTemplateSelectedIndex"
:placeholder="'切换PDF模板'"
:placeholder="$t('panel.switch_pdf_template')"
@change="changePdfTemplate()"
>
<el-option
@ -635,7 +635,7 @@ export default {
component.style[key] = this.format(component.style[key], this.scaleHeight)
}
if (this.needToChangeWidth.includes(key)) {
if (key === 'fontSize' && (this.terminal === 'mobile' || component.type === 'custom')) {
if ((key === 'fontSize' || key === 'activeFontSize') && (this.terminal === 'mobile' || component.type === 'custom')) {
// do nothing ( v-text )
} else {
component.style[key] = this.format(component.style[key], this.scaleWidth)

View File

@ -85,6 +85,7 @@
:ref="element.propValue.id"
class="chart-class"
:chart="chart"
:terminal-type="scaleCoefficientType"
:track-menu="trackMenu"
:search-count="searchCount"
@onChartClick="chartClick"

View File

@ -5,40 +5,49 @@ export default {
mutations: {
upComponent({ componentData, curComponent }) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 上移图层 index表示元素在数组中越往后
if (curComponentIndex < componentData.length - 1) {
moveUp(componentData, curComponentIndex)
} else {
toast('已经到顶了')
if (curComponent) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 上移图层 index表示元素在数组中越往后
if (curComponentIndex < componentData.length - 1) {
moveUp(componentData, curComponentIndex)
} else {
toast('已经到顶了')
}
}
},
downComponent({ componentData, curComponent }) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 下移图层 index表示元素在数组中越往前
if (curComponentIndex > 0) {
moveDown(componentData, curComponentIndex)
} else {
toast('已经到底了')
if (curComponent) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 下移图层 index表示元素在数组中越往前
if (curComponentIndex > 0) {
moveDown(componentData, curComponentIndex)
} else {
toast('已经到底了')
}
}
},
topComponent({ componentData, curComponent }) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 置顶
if (curComponentIndex < componentData.length - 1) {
toTop(componentData, curComponentIndex)
if (curComponent) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 置顶
if (curComponentIndex < componentData.length - 1) {
toTop(componentData, curComponentIndex)
}
}
},
bottomComponent({ componentData, curComponent }) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 置底
if (curComponentIndex > 0) {
toBottom(componentData, curComponentIndex)
} else {
toast('已经到底了')
if (curComponent) {
const curComponentIndex = findCurComponentIndex(componentData, curComponent)
// 置底
if (curComponentIndex > 0) {
toBottom(componentData, curComponentIndex)
} else {
toast('已经到底了')
}
}
}
}

View File

@ -17,7 +17,7 @@
:active-color="activeColor"
:border-color="borderColor"
:border-active-color="borderActiveColor"
:addable="isEdit"
:addable="isEdit && !mobileLayoutStatus"
@tab-add="addTab"
@tab-click="handleClick"
>
@ -707,29 +707,27 @@ export default {
border-color: blueviolet;
}
::v-deep .el-tabs__nav {
display: flex;
}
::v-deep .el-tabs__nav-prev {
line-height: 25px;
}
::v-deep .el-tabs__nav-next {
line-height: 25px;
}
.tab-head-left ::v-deep .el-tabs__nav {
.tab-head-left ::v-deep .el-tabs__nav-scroll {
display: flex;
text-align: left;
justify-content: flex-start;
}
.tab-head-right ::v-deep .el-tabs__nav {
.tab-head-right ::v-deep .el-tabs__nav-scroll {
display: flex;
text-align: right;
justify-content: flex-end;
}
.tab-head-center ::v-deep .el-tabs__nav {
.tab-head-center ::v-deep .el-tabs__nav-scroll {
display: flex;
text-align: center;
justify-content: center;
}
.frame-mask {

View File

@ -135,6 +135,7 @@ export default {
default_login: 'Normal'
},
commons: {
collapse_navigation: 'Collapse navigation',
operate_cancelled: 'Operation cancelled',
bind: 'Bind',
unbind: 'Unbind',
@ -151,7 +152,7 @@ export default {
params_value: 'Param Value',
input_role_name: 'Enter a role name',
publish: 'publish',
unpublished: 'unpublished',
unpublished: 'Unpublished',
default_pwd: 'Default Pwd',
stop: 'Stop',
first_login_tips: 'Please change the initial password',
@ -311,6 +312,7 @@ export default {
validate: 'Validate',
batch_add: 'Batch Add',
tag_tip: 'Enter add label',
search_keywords: 'Enter keywords to search',
table: {
select_tip: '{0} data selected'
},
@ -322,7 +324,10 @@ export default {
start_date_time: 'Start date time',
end_date_time: 'End date time',
range_separator: 'to',
data_time_error: 'The start date cannot be greater than the end date.'
data_time_error: 'The start date cannot be greater than the end date.',
one_day: 'One day',
one_week: 'One week',
one_month: 'One month'
},
adv_search: {
title: 'Advanced search',
@ -531,7 +536,10 @@ export default {
set_saved_successfully: 'Data set saved successfully',
to_start_using: 'Browse the contents of your database, tables and columns. Choose a database to get started.',
to_run_query: 'Click to run query',
the_running_results: 'You can view the running results'
the_running_results: 'You can view the running results',
item: 'item',
logic_filter: 'Condition Filter',
enum_filter: 'Enum Filter'
},
detabs: {
custom_sort: 'Custom Sort',
@ -655,6 +663,7 @@ export default {
input_password: 'Please input a password',
input_phone: 'Please enter the phone number',
input_roles: 'Please select role',
select_users: 'Please select user',
user_name_pattern_error: 'IDs can only contain alphanumeric and ._- and start with a letter!',
special_characters_are_not_supported: 'Special characters are not supported',
mobile_number_format_is_incorrect: 'Incorrect format of mobile phone number',
@ -811,6 +820,7 @@ export default {
edite_organization: 'Edit organization'
},
system_parameter_setting: {
email_server_config: 'Mailbox server configuration',
edit_success: 'Edit success',
mailbox_service_settings: 'Mail Setting',
test_connection: 'Test connection',
@ -1021,12 +1031,12 @@ export default {
line_symbol_size: 'Break point size',
line_type_solid: 'Solid line',
line_type_dashed: 'Dotted line',
line_symbol_circle: 'circular',
line_symbol_circle: 'Circular',
line_symbol_emptyCircle: 'Hollow circle',
line_symbol_rect: 'rectangle',
line_symbol_rect: 'Rectangle',
line_symbol_roundRect: 'Rounded rectangle',
line_symbol_triangle: 'triangle',
line_symbol_diamond: 'diamond',
line_symbol_triangle: 'Triangle',
line_symbol_diamond: 'Diamond',
line_symbol_pin: 'nail',
line_symbol_arrow: 'arrow',
line_symbol_none: 'None',
@ -1036,7 +1046,7 @@ export default {
funnel_width: 'width',
line_smooth: 'Smooth polyline',
title_style: 'Title Style',
text_fontsize: 'font size',
text_fontsize: 'Font size',
text_color: 'Font color',
text_h_position: 'Horizontal position',
text_v_position: 'Vertical position',
@ -1054,7 +1064,7 @@ export default {
shape: 'shape',
polygon: 'polygon',
circle: 'circular',
label: 'label',
label: 'Label',
label_position: 'Label location',
label_bg: 'Label BG',
label_shadow: 'Label Shadow',
@ -1460,7 +1470,28 @@ export default {
empty_data_strategy: 'Empty Data Strategy',
break_line: 'Disconnection',
set_zero: 'Set Zero',
ignore_data: 'Ignore Data'
ignore_data: 'Ignore Data',
sub_dimension_tip: 'This field is required, and cannot be included in the type axis, you should choose non-group chart if you don\'t need it, or you will get unexpected chart.',
drill_dimension_tip: 'Only fields in the dataset can be drilled',
table_scroll_tip: 'The detail table is only effective when the pagination mode is "Drop-down".',
table_threshold_tip: 'Tip: Do not select fields repeatedly. If the same field is configured repeatedly, only the last field will take effect.',
table_column_width_tip: `Column width do not always work.<br/>
The priority of the container width is higher than the column width, <br/>
which means if the result of dividing the width of the table container by the number of columns is greater than specified column width, <br/>
the former will take effect.`,
reference_field_tip: `Reference fields start with "[" and end with "]". <br/>
Do not modify the reference content, otherwise the reference will fail.<br/>
If you enter content in the same format as the reference field, it will be treated as a reference field.`,
scatter_tip: 'When this indicator is in effect, the bubble size attribute in the style size will be invalid',
place_name_mapping: 'Place name mapping',
axis_tip: 'The minimum value, maximum value, and interval are all numeric types; it will be regarded as automatic if left blank.<br/>Please make sure that the filled values can be calculated correctly, otherwise the axis values will not be displayed normally.',
format_tip: `The template variables include {a}, {b}, {c}, {d}, which represent series name, data name, data value, etc. respectively.<br>
When the trigger position is 'coordinate axis', there will be multiple series of data. At this time, the index of the series can be represented by {a0}, {a1}, {a2} followed by an index.<br>
{a}, {b}, {c}, {d} have different meanings under different graph types. Among them, variables {a}, {b}, {c}, {d} represent data meanings in different chart types:<br><br>
Line (area) chart, Column (Bar) chart, Dashboard: {a} is series name, {b} is category value, {c} is value<br>
Pie chart, Funnel chart: {a} is series name, {b} is data item name, {c} is value, {d} is percentage<br>
Map : {a} (series name), {b} is area name, {c} is merged values, {d} is none<br>
Scatter (Bubble) plot: {a} is series name, {b} is data name, {c} is numeric array, {d} is none`
},
dataset: {
spend_time: 'Spend',
@ -1722,7 +1753,17 @@ export default {
export_dataset: 'Export',
filename: 'Filename',
export_filter: 'Filter',
pls_input_filename: 'Please input filename'
pls_input_filename: 'Please input filename',
calc_tips: {
tip1: 'The expression syntax should follow the database syntax corresponding to the data source.',
tip2: 'Aggregation operation is not supported in the dataset.',
tip3: 'The reference field starts with "[" and ends with "]"',
tip4: 'Do not modify the reference content, otherwise the reference will fail',
tip5: 'If you enter content in the same format as the reference field, it will be treated as a reference field',
tip6: 'Use the functions supported by the database type corresponding to the dataset. The syntax is the same as that of the corresponding database',
tip7: 'For example, date format: MySQL uses DATE_ FORMAT(date,format) Oracle uses TO_ DATE(X,[,fmt])',
tip8: 'Non direct connection mode data set, use Doris database functions, refer to Doris official website'
}
},
driver: {
driver: 'Driver',
@ -1892,7 +1933,7 @@ export default {
},
panel: {
position_adjust_component: 'Position adjust',
active_font_size: 'Active font size',
active_font_size: 'Selected font size',
carousel: 'Carousel',
switch_time: 'Switch time',
position_adjust: 'Position',
@ -1983,7 +2024,7 @@ export default {
inner_padding: 'Inner Padding',
board_radio: 'Board Radio',
background: 'Background',
component_style: 'component Style',
component_style: 'Component Style',
web_set_tips: 'Some Websites Cannot Be Displayed Because Of Not Allow Embedded ',
repeat_params: 'Repeat Params Exist',
enable_outer_param_set: 'Enable Outer Param Set',
@ -2036,6 +2077,7 @@ export default {
delete_success: 'Delete Success',
confirm: 'Confirm',
cancel: 'Cancel',
save: 'Save',
search: 'Search',
back: 'Back',
view: 'Chart',
@ -2226,7 +2268,11 @@ export default {
select_view: 'Please select a view...',
visual: 'Visual',
prohibit_multiple: 'Prohibit multiple fields in the same dataset',
be_empty_dir: 'is empty dir'
be_empty_dir: 'is empty dir',
fold: 'Fold',
expand: 'Expand',
pdf_export: 'PDF Export',
switch_pdf_template: 'Switch PDF Template'
},
plugin: {
local_install: 'Local installation',
@ -2543,6 +2589,14 @@ export default {
},
emailtask: {
week_mon: 'Mon',
week_tue: 'Tue',
week_wed: 'Wed',
week_thu: 'Thu',
week_fri: 'Fri',
week_sat: 'Sat',
week_sun: 'Sun',
send_config: 'Send configuration',
title: 'Title',
panel: 'Panel',
content: 'Content',
@ -2727,5 +2781,24 @@ export default {
logout: {
oidc_logout_error: 'OIDC failed to exit, do you continue to exit DataEase?',
cas_logout_error: 'The CAS service is abnormal, please contact the administrator!'
},
watermark: {
support_params: 'Currently supported parameters:',
enable: 'Enable',
enable_panel_custom: 'Allow the dashboard to open or close the watermark independently',
content: 'content',
custom_content: 'Custom Content',
account: 'Account',
nick_name: 'Nick Name',
ip: 'IP',
now: 'Now Time',
watermark_color: 'Watermark Color',
watermark_font_size: 'Watermark Fontsize',
watermark_space: 'Watermark Space',
horizontal: 'Horizontal',
vertical: 'Vertical',
reset: 'Reset',
preview: 'Preview',
save: 'Save'
}
}

View File

@ -135,6 +135,7 @@ export default {
default_login: '普通登錄'
},
commons: {
collapse_navigation: '收起導航',
operate_cancelled: '已取消操作',
bind: '綁定',
unbind: '解綁',
@ -311,6 +312,7 @@ export default {
validate: '校驗',
batch_add: '批量添加',
tag_tip: '輸入回車添加標簽',
search_keywords: '輸入關鍵字搜索',
table: {
select_tip: '已選中 {0} 條數據'
},
@ -322,7 +324,10 @@ export default {
start_date_time: '開始日期時間',
end_date_time: '結束日期時間',
range_separator: '至',
data_time_error: '開始日期不能大於結束日期'
data_time_error: '開始日期不能大於結束日期',
one_day: '一天',
one_week: '一周',
one_month: '一個月'
},
adv_search: {
title: '高級搜索',
@ -531,7 +536,10 @@ export default {
set_saved_successfully: '數據集保存成功',
to_start_using: '瀏覽您的數據庫,表和列的內容。 選擇一個數據庫即可開始使用。',
to_run_query: '點擊運行査詢',
the_running_results: '即可查看運行結果'
the_running_results: '即可查看運行結果',
item: '項',
logic_filter: '條件篩選',
enum_filter: '枚舉篩選'
},
detabs: {
custom_sort: '自定義排序',
@ -811,6 +819,7 @@ export default {
edite_organization: '編輯組織'
},
system_parameter_setting: {
email_server_config: '郵箱服務器配置',
edit_success: '編輯成功',
mailbox_service_settings: '郵件設置',
test_connection: '測試連接',
@ -1460,7 +1469,23 @@ export default {
empty_data_strategy: '空值處理',
break_line: '線條斷開',
set_zero: '置為0線條不斷開',
ignore_data: '跳過空值,不展示'
ignore_data: '跳過空值,不展示',
sub_dimension_tip: '該字段為必填項,且不應使用類別軸中的字段,若無需該字段,請選擇基礎圖表進行展示,否則展示效果不理想',
drill_dimension_tip: '鑽取字段僅支持數據集中的字段',
table_scroll_tip: '明細表僅在分頁模式為"下拉"時生效。',
table_threshold_tip: '提示:請勿重複選擇字段,若同一字段重複配置,則只有最後的字段配置生效。',
table_column_width_tip: '列寬並非任何時候都能生效。<br/>容器寬度優先級高於列寬。即(表格容器寬度 / 列數 > 指定列寬),則列寬優先取(容器寬度 / 列數)',
reference_field_tip: '引用字段以 "[" 開始,"]" 結束。請<br/>勿修改引用內容,否則將引用失敗。<br/>若輸入與引用字段相同格式的內容,將被當做引用字段處理。',
scatter_tip: '該指標生效時,樣式大小中的氣泡大小屬性將失效',
place_name_mapping: '地名映射',
axis_tip: '最小值、最大值、間隔均為數值類型;若不填,則該項視為自動。<br/>請確保填寫數值能正確計算,否則將無法正常顯示值軸',
format_tip: `模板變量有 {a}, {b}{c}{d},分別表示系列名,數據名,數據值等。<br>
觸發位置 '坐標軸' 的時候會有多個系列的數據此時可以通過 {a0}, {a1}, {a2} 這種後面加索引的方式表示系列的索引<br>
不同圖表類型下的 {a}{b}{c}{d} 含義不一樣 其中變量{a}, {b}, {c}, {d}在不同圖表類型下代表數據含義為<br><br>
折線區域柱狀條形儀表盤 : {a}系列名稱{b}類目值{c}數值<br>
餅圖漏鬥圖: {a}系列名稱{b}數據項名稱{c}數值, {d}百分比<br>
地圖 : {a}系列名稱{b}區域名稱{c}合並數值, {d}<br>
散點圖氣泡 : {a}系列名稱{b}數據名稱{c}數值數組, {d}`
},
dataset: {
spend_time: '耗時',
@ -1722,7 +1747,17 @@ export default {
export_dataset: '數據集導出',
filename: '文件名稱',
export_filter: '篩選條件',
pls_input_filename: '請輸入文件名稱'
pls_input_filename: '請輸入文件名稱',
calc_tips: {
tip1: '表達式語法請遵循該數據源對應的數據庫語法。',
tip2: '數據集中不支持聚合運算。',
tip3: '引用字段以 "[" 開始, "]" 結束',
tip4: '請勿修改引用內容,否則將引用失敗',
tip5: '若輸入與引用字段相同格式的內容,將被當作引用字段處理',
tip6: '使用數據集對應數據庫類型所支持的函數,語法同對應數據庫',
tip7: '如日期格式化MySQL使用DATE_FORMAT(date,format)Oracle使用TO_DATE(X,[,fmt])',
tip8: '非直連模式數據集使用Doris數據庫函數可參考Doris官網'
}
},
driver: {
driver: '驅動',
@ -1892,7 +1927,7 @@ export default {
},
panel: {
position_adjust_component: '位置調整',
active_font_size: '激活字體大小',
active_font_size: '选中字體大小',
carousel: '輪播',
switch_time: '切換時間',
position_adjust: '位置',
@ -2227,7 +2262,11 @@ export default {
select_view: '請選擇視圖...',
visual: '虛擬化',
prohibit_multiple: '禁止同數據集多字段',
be_empty_dir: '是空目錄'
be_empty_dir: '是空目錄',
fold: '收起',
expand: '展開',
pdf_export: 'PDF 導出',
switch_pdf_template: '切換 PDF 模板'
},
plugin: {
local_install: '本地安裝',
@ -2544,6 +2583,14 @@ export default {
},
emailtask: {
week_mon: '周一',
week_tue: '周二',
week_wed: '周三',
week_thu: '周四',
week_fri: '周五',
week_sat: '周六',
week_sun: '周日',
send_config: '發送設置',
title: '報告主題',
panel: '儀表闆',
content: '報告正文',
@ -2568,9 +2615,9 @@ export default {
emial_preview: '報告預覽',
chart_data_range: '視圖數據範圍',
simple_repeat: '簡單重複',
once_a_day: '每天一次',
once_a_week: '每周一次',
once_a_month: '每月一次',
once_a_day: '每天',
once_a_week: '每周',
once_a_month: '每月',
complex_repeat: '複雜重複',
pixel_tip: '可直接輸入分辨率(例如:2560 * 1600)或者選擇',
task_type: '任務類型',
@ -2727,5 +2774,24 @@ export default {
logout: {
oidc_logout_error: 'OIDC退出失敗是否繼續退出DataEase',
cas_logout_error: 'CAS服務異常請聯系管理員'
},
watermark: {
support_params: '當前支持的參數:',
enable: '啟用',
enable_panel_custom: '允許儀表板單獨打開或者關閉水印',
content: '內容',
custom_content: '自定義公式',
account: '賬號',
nick_name: '昵稱',
ip: 'IP',
now: '當前時間',
watermark_color: '水印顏色',
watermark_font_size: '水印字號',
watermark_space: '水印間距',
horizontal: '橫向',
vertical: '縱向',
reset: '重置',
preview: '預覽',
save: '保存'
}
}

View File

@ -135,6 +135,7 @@ export default {
default_login: '普通登录'
},
commons: {
collapse_navigation: '收起导航',
operate_cancelled: '已取消操作',
bind: '绑定',
unbind: '解绑',
@ -310,6 +311,7 @@ export default {
validate: '校验',
batch_add: '批量添加',
tag_tip: '输入回车添加标签',
search_keywords: '输入关键字搜索',
table: {
select_tip: '已选中 {0} 条数据'
},
@ -321,7 +323,10 @@ export default {
start_date_time: '开始日期时间',
end_date_time: '结束日期时间',
range_separator: '至',
data_time_error: '开始日期不能大于结束日期'
data_time_error: '开始日期不能大于结束日期',
one_day: '一天',
one_week: '一周',
one_month: '一个月'
},
adv_search: {
title: '高级搜索',
@ -530,7 +535,10 @@ export default {
set_saved_successfully: '数据集保存成功',
to_start_using: '浏览您的数据库,表和列的内容。 选择一个数据库即可开始使用。',
to_run_query: '点击运行查询',
the_running_results: '即可查看运行结果'
the_running_results: '即可查看运行结果',
item: '项',
logic_filter: '条件筛选',
enum_filter: '枚举筛选'
},
detabs: {
custom_sort: '自定义排序',
@ -810,6 +818,7 @@ export default {
edite_organization: '编辑组织'
},
system_parameter_setting: {
email_server_config: '邮箱服务器配置',
edit_success: '编辑成功',
mailbox_service_settings: '邮件设置',
test_connection: '测试连接',
@ -1459,7 +1468,23 @@ export default {
empty_data_strategy: '空值处理',
break_line: '线条断开',
set_zero: '置为0,线条不断开',
ignore_data: '跳过空值,不展示'
ignore_data: '跳过空值,不展示',
sub_dimension_tip: '该字段为必填项,且不应使用类别轴中的字段,若无需该字段,请选择基础图表进行展示,否则展示效果不理想。',
drill_dimension_tip: '钻取字段仅支持数据集中的字段',
table_scroll_tip: '明细表仅在分页模式为"下拉"时生效。',
table_threshold_tip: '提示:请勿重复选择字段,若同一字段重复配置,则只有最后的字段配置生效',
table_column_width_tip: '列宽并非任何时候都能生效。<br/>容器宽度优先级高于列宽,即(表格容器宽度 / 列数 > 指定列宽),则列宽优先取(容器宽度 / 列数)。',
reference_field_tip: '引用字段以 "[" 开始, "]" 结束。<br/>请勿修改引用内容,否则将引用失败。<br/>若输入与引用字段相同格式的内容,将被当作引用字段处理。',
scatter_tip: '该指标生效时,样式大小中的气泡大小属性将失效',
place_name_mapping: '地名映射',
axis_tip: '最小值、最大值、间隔均为数值类型;若不填,则该项视为自动。<br/>请确保填写数值能正确计算,否则将无法正常显示轴值。',
format_tip: `模板变量有 {a}, {b}{c}{d},分别表示系列名,数据名,数据值等。<br>
触发位置 '坐标轴' 的时候会有多个系列的数据此时可以通过 {a0}, {a1}, {a2} 这种后面加索引的方式表示系列的索引<br>
不同图表类型下的 {a}{b}{c}{d} 含义不一样 其中变量{a}, {b}, {c}, {d}在不同图表类型下代表数据含义为<br><br>
折线区域柱状条形仪表盘 : {a}系列名称{b}类目值{c}数值<br>
饼图漏斗图: {a}系列名称{b}数据项名称{c}数值, {d}百分比<br>
地图 : {a}系列名称{b}区域名称{c}合并数值, {d}<br>
散点图气泡 : {a}系列名称{b}数据名称{c}数值数组, {d}`
},
dataset: {
spend_time: '耗时',
@ -1721,7 +1746,17 @@ export default {
export_dataset: '数据集导出',
filename: '文件名称',
export_filter: '筛选条件',
pls_input_filename: '请输入文件名称'
pls_input_filename: '请输入文件名称',
calc_tips: {
tip1: '表达式语法请遵循该数据源对应的数据库语法。',
tip2: '数据集中不支持聚合运算。',
tip3: '引用字段以 "[" 开始, "]" 结束',
tip4: '请勿修改引用内容,否则将引用失败',
tip5: '若输入与引用字段相同格式的内容,将被当作引用字段处理',
tip6: '使用数据集对应数据库类型所支持的函数,语法同对应数据库',
tip7: '如日期格式化MySQL使用DATE_FORMAT(date,format)Oracle使用TO_DATE(X,[,fmt])',
tip8: '非直连模式数据集使用Doris数据库函数可参考Doris官网'
}
},
driver: {
driver: '驱动',
@ -1892,7 +1927,7 @@ export default {
},
panel: {
position_adjust_component: '位置调整',
active_font_size: '激活字体大小',
active_font_size: '选中字体大小',
carousel: '轮播',
switch_time: '切换时间',
position_adjust: '位置',
@ -2227,7 +2262,11 @@ export default {
select_view: '请选择视图...',
visual: '虚拟化',
prohibit_multiple: '禁止同数据集多字段',
be_empty_dir: '是空目录!'
be_empty_dir: '是空目录!',
fold: '收起',
expand: '展开',
pdf_export: 'PDF 导出',
switch_pdf_template: '切换 PDF 模板'
},
plugin: {
local_install: '本地安装',
@ -2544,6 +2583,14 @@ export default {
},
emailtask: {
week_mon: '周一',
week_tue: '周二',
week_wed: '周三',
week_thu: '周四',
week_fri: '周五',
week_sat: '周六',
week_sun: '周日',
send_config: '发送设置',
title: '报告主题',
panel: '仪表板',
content: '报告正文',
@ -2568,9 +2615,9 @@ export default {
emial_preview: '报告预览',
chart_data_range: '视图数据范围',
simple_repeat: '简单重复',
once_a_day: '每天一次',
once_a_week: '每周一次',
once_a_month: '每月一次',
once_a_day: '每天',
once_a_week: '每周',
once_a_month: '每月',
complex_repeat: '复杂重复',
pixel_tip: '可直接输入自定义分辨率(例如:2560 * 1600)或选择',
task_type: '任务类型',
@ -2727,5 +2774,24 @@ export default {
logout: {
oidc_logout_error: 'OIDC退出失败是否继续退出DataEase',
cas_logout_error: 'CAS服务异常请联系管理员'
},
watermark: {
support_params: '当前支持的参数:',
enable: '启用',
enable_panel_custom: '允许仪表板单独打开或者关闭水印',
content: '内容',
custom_content: '自定义公式',
account: '账号',
nick_name: '昵称',
ip: 'IP',
now: '当前时间',
watermark_color: '水印颜色',
watermark_font_size: '水印字号',
watermark_space: '水印间距',
horizontal: '横向',
vertical: '纵向',
reset: '重置',
preview: '预览',
save: '保存'
}
}

View File

@ -33,7 +33,7 @@
:style="{ transform: isCollapse ? 'rotate(90deg)' : 'rotate(-90deg)' }"
class="el-icon-upload2"
/>
{{ isCollapse ? "" : "收起导航" }}
{{ isCollapse ? "" : $t('commons.collapse_navigation') }}
</div>
</div>
</template>

View File

@ -26,7 +26,7 @@ NProgress.configure({
showSpinner: false
}) // NProgress Configuration
const whiteList = ['/login', '/401', '/404', '/delink', '/nolic'] // no redirect whitelist
const whiteList = ['/login', '/401', '/404', '/delink', '/nolic', '/de-auto-login'] // no redirect whitelist
const routeBefore = (callBack) => {
let uiInfo = getSysUI()
@ -53,7 +53,7 @@ const routeBefore = (callBack) => {
callBack()
}
}
router.beforeEach(async(to, from, next) => routeBefore(() => {
router.beforeEach(async (to, from, next) => routeBefore(() => {
// start progress bar
NProgress.start()
const mobileIgnores = ['/delink']

View File

@ -91,6 +91,11 @@ export const constantRoutes = [
path: '/previewFullScreen',
component: () => import('@/components/canvas/components/editor/PreviewFullScreen'),
hidden: true
},
{
path: '/de-auto-login',
component: () => import('@/views/DeAutoLogin'),
hidden: true
}
// {
@ -208,11 +213,11 @@ export const constantRoutes = [
// ]
// },
// 404 page must be placed at the end !!!
// { path: '*', redirect: '/404', hidden: true }
// { path: '*', redirect: '/404', hidden: true }
]
const createRouter = () => new Router({
// mode: 'history', // require service support
// mode: 'history', // require service support
mode: 'hash',
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes

View File

@ -232,8 +232,8 @@ const data = {
}
},
setShapeStyle({ curComponent, canvasStyleData, curCanvasScaleMap }, { top, left, width, height, rotate }) {
const curCanvasScaleSelf = curCanvasScaleMap[curComponent.canvasId]
if (curComponent) {
const curCanvasScaleSelf = curCanvasScaleMap[curComponent.canvasId]
if (top || top === 0) curComponent.style.top = Math.round((top / curCanvasScaleSelf.scalePointHeight))
if (left || left === 0) curComponent.style.left = Math.round((left / curCanvasScaleSelf.scalePointWidth))
if (width || width === 0) curComponent.style.width = Math.round((width / curCanvasScaleSelf.scalePointWidth))
@ -569,7 +569,7 @@ const data = {
// 移动端布局转换
state.componentData.forEach(item => {
item.mobileStyle = (item.mobileStyle || BASE_MOBILE_STYLE)
if (item.mobileSelected || item.canvasId !== 'canvas-main') {
if (item.mobileSelected && item.canvasId === 'canvas-main') {
item.style.width = item.mobileStyle.style.width
item.style.height = item.mobileStyle.style.height
item.style.top = item.mobileStyle.style.top
@ -581,6 +581,8 @@ const data = {
item.sizey = item.mobileStyle.sizey
item.auxiliaryMatrix = item.mobileStyle.auxiliaryMatrix
mainComponentData.push(item)
} else if (item.canvasId !== 'canvas-main') {
mainComponentData.push(item)
}
})
state.componentData = mainComponentData

View File

@ -29,7 +29,7 @@ const actions = {
commit('SET_CURRENT_PATH', path)
}
}
export const fullScreenRouters = ['XpackThemeForm', 'system/datasource/DsForm', 'dataset/Form']
export const fullScreenRouters = ['XpackThemeForm', 'system/datasource/DsForm', 'dataset/Form', 'DeAutoLogin']
export const filterAsyncRouter = (routers) => { // 遍历后台传来的路由字符串,转换为组件对象
return routers.map(router => {
if (!fullScreenRouters.includes(router.component) && router.type === 1 && router.pid === 0 && router.component && router.component !== 'Layout') {

View File

@ -1703,4 +1703,4 @@ div:focus {
margin-bottom: 8px;
display: inline-block;
}
}
}

View File

@ -0,0 +1,142 @@
<template>
<div
v-loading="loading"
class="de-auto-login"
>
<plugin-com
v-if="isDingTalkLink && dingtalkOpen && corpId"
ref="DTWithoutLogin"
:corp-id="corpId"
component-name="DTWithoutLogin"
/>
<plugin-com
v-else-if="isLarkLink && larkOpen && appId"
ref="LKWithoutLogin"
:app-id="appId"
component-name="LKWithoutLogin"
/>
<plugin-com
v-else-if="isLarksuiteLink && larksuiteOpen"
ref="LKSWithoutLogin"
component-name="LKSWithoutLogin"
/>
<div
v-if="isDingTalkLink && !loading && !dingtalkOpen"
class="auto-login-missing"
>
<span>未开启钉钉</span>
</div>
<div
v-else-if="isDingTalkLink && !loading && !corpId"
class="auto-login-missing"
>
<span>缺失企业ID参数</span>
</div>
<div
v-if="isLarkLink && !loading && !larkOpen"
class="auto-login-missing"
>
<span>未开启飞书</span>
</div>
<div
v-else-if="isLarkLink && !loading && !appId"
class="auto-login-missing"
>
<span>缺失应用ID参数</span>
</div>
<div
v-if="isLarksuiteLink && !loading && !larksuiteOpen"
class="auto-login-missing"
>
<span>未开启国际飞书</span>
</div>
</div>
</template>
<script>
import PluginCom from '@/views/system/plugin/PluginCom'
import { dingtalkStatus, larkStatus, larksuiteStatus, larkAppId } from '@/api/user'
export default {
name: 'DeAutoLogin',
components: { PluginCom },
data() {
return {
type: 'dingtalk',
corpId: null,
appId: null,
dingtalkOpen: false,
larkOpen: false,
larksuiteOpen: false,
loading: true
}
},
computed: {
isDingTalkLink() {
return this.type === 'dingtalk' || !this.type
},
isLarkLink() {
return this.type === 'lark'
},
isLarksuiteLink() {
return this.type === 'larksuite'
}
},
created() {
this.corpId = this.$route.query.corpId
if (this.$route.query.type) {
this.type = this.$route.query.type
}
this.isDingTalkLink && dingtalkStatus().then(res => {
if (res.success && res.data) {
this.dingtalkOpen = true
}
this.loading = false
}).catch(e => {
this.loading = false
})
this.isLarkLink && larkStatus().then(res => {
if (res.success && res.data) {
larkAppId().then(resp => {
this.appId = resp.data
this.larkOpen = true
this.loading = false
})
}
}).catch(e => {
this.loading = false
})
this.isLarksuiteLink && larksuiteStatus().then(res => {
if (res.success && res.data) {
this.larksuiteOpen = true
}
this.loading = false
}).catch(e => {
this.loading = false
})
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.de-auto-login {
width: 100%;
height: 100vh;
.auto-login-missing {
text-align: center;
}
}
</style>

View File

@ -43,7 +43,7 @@
:span="3"
style="padding-left: 10px;padding-top: 5px"
>
<el-checkbox v-model="curComponent.commonBackground.backgroundColorSelect">颜色</el-checkbox>
<el-checkbox v-model="curComponent.commonBackground.backgroundColorSelect">{{ $t('chart.color') }}</el-checkbox>
</el-col>
<el-col
:span="1"
@ -58,7 +58,7 @@
/>
</el-col>
<el-col :span="3">
<span class="params-title-small">不透明度</span>
<span class="params-title-small">{{ $t('chart.not_alpha') }}</span>
</el-col>
<el-col :span="11">
<el-slider
@ -137,7 +137,7 @@
v-model="curComponent.commonBackground.backgroundType"
label="innerImage"
@change="onChangeType"
>边框
>{{ $t('panel.board') }}
</el-radio>
<el-color-picker
v-model="curComponent.commonBackground.innerImageColor"

View File

@ -378,7 +378,7 @@ export function getTooltip(chart) {
} else {
// 百分比堆叠柱状图隐藏 tooltip 设置 show 为 false 或者直接设置 tooltip 为 false 都无效,会变成分组显示,
// 需要将容器(container)或者内容框(showContent)设置为 false 或者 null 才可以隐藏
if (chart.type === 'percentage-bar-stack') {
if (chart.type.includes('percentage')) {
tooltip.showContent = false
} else {
tooltip = false

View File

@ -156,6 +156,7 @@ export function getCustomTheme(chart) {
theme.colCell.text.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
theme.colCell.measureText.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
theme.dataCell.cell.crossBackgroundColor = i_c
theme.dataCell.cell.backgroundColor = i_c
theme.dataCell.cell.horizontalBorderColor = b_c
theme.dataCell.cell.verticalBorderColor = b_c

View File

@ -435,7 +435,6 @@ export function baseTablePivot(s2, container, chart, action, tableData) {
}
sortParams.push(sort)
}
totalCfg.col.totalSort = false
if (totalCfg.col.totalSort && totalCfg.col.totalSort !== 'none' && r.length > 0 && totalCfg.col.showGrandTotals && v.indexOf(totalCfg.col.totalSortField) > -1) {
const sort = {
sortFieldId: r[0],

View File

@ -1163,7 +1163,6 @@ export const TYPE_CONFIGS = [
icon: 'percentage-bar-stack-horizontal',
properties: [
'color-selector',
'size-selector-ant-v',
'label-selector-ant-v',
'tooltip-selector-ant-v',
'x-axis-selector-ant-v',
@ -1179,10 +1178,6 @@ export const TYPE_CONFIGS = [
'gradient',
'alpha'
],
'size-selector-ant-v': [
'barDefault',
'barGap'
],
'label-selector-ant-v': [
'show',
'fontSize',
@ -1478,7 +1473,6 @@ export const TYPE_CONFIGS = [
icon: 'percentage-bar-stack',
properties: [
'color-selector',
'size-selector-ant-v',
'label-selector-ant-v',
'tooltip-selector-ant-v',
'x-axis-selector-ant-v',
@ -1494,10 +1488,6 @@ export const TYPE_CONFIGS = [
'gradient',
'alpha'
],
'size-selector-ant-v': [
'barDefault',
'barGap'
],
'label-selector-ant-v': [
'show',
'fontSize',

View File

@ -18,7 +18,7 @@
:style="title_class"
style="cursor: default;display: block;"
>
<div style="padding:6px 4px 0;margin: 0;">
<div style="padding:4px 4px 0;margin: 0;">
<chart-title-update
:title-class="title_class"
:chart-info="chartInfo"

View File

@ -18,7 +18,7 @@
:style="title_class"
style="cursor: default;display: block;"
>
<div style="padding:6px 4px 0;margin: 0;">
<div style="padding:4px 4px 0;margin: 0;">
<chart-title-update
:title-class="title_class"
:chart-info="chartInfo"
@ -67,8 +67,8 @@
>
{{ $t('chart.total') }}
<span>{{
chart.datasetMode === 0 ? chart.totalItems : ((chart.data && chart.data.tableRow) ? chart.data.tableRow.length : 0)
}}</span>
(chart.datasetMode === 0 && !not_support_page_dataset.includes(chart.datasourceType)) ? chart.totalItems : ((chart.data && chart.data.tableRow) ? chart.data.tableRow.length : 0)
}}</span>
{{ $t('chart.items') }}
</span>
<de-pagination
@ -101,10 +101,15 @@ import { DEFAULT_TITLE_STYLE, NOT_SUPPORT_PAGE_DATASET } from '@/views/chart/cha
import ChartTitleUpdate from './ChartTitleUpdate.vue'
import { mapState } from 'vuex'
import DePagination from '@/components/deCustomCm/pagination.js'
export default {
name: 'ChartComponentS2',
components: { TitleRemark, ViewTrackBar, ChartTitleUpdate, DePagination },
props: {
terminalType: {
type: String,
default: 'pc'
},
chart: {
type: Object,
required: true
@ -173,7 +178,8 @@ export default {
},
totalStyle: {
color: '#606266'
}
},
not_support_page_dataset: NOT_SUPPORT_PAGE_DATASET
}
},
@ -182,13 +188,18 @@ export default {
return this.previewCanvasScale.scalePointWidth
},
autoStyle() {
return {
height: (100 / this.scale) + '%!important',
width: (100 / this.scale) + '%!important',
left: 50 * (1 - 1 / this.scale) + '%', // 2
top: 50 * (1 - 1 / this.scale) + '%', // 2
transform: 'scale(' + this.scale + ')'
if (this.terminalType === 'pc') {
return {
height: (100 / this.scale) + '%!important',
width: (100 / this.scale) + '%!important',
left: 50 * (1 - 1 / this.scale) + '%', // 2
top: 50 * (1 - 1 / this.scale) + '%', // 2
transform: 'scale(' + this.scale + ')'
}
} else {
return {}
}
},
trackBarStyleTime() {
return this.trackBarStyle

View File

@ -84,11 +84,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
最小值最大值间隔均为数值类型若不填则该项视为自动
<br>
请确保填写数值能正确计算否则将无法正常显示轴值
</div>
<div
slot="content"
v-html="$t('chart.axis_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -84,11 +84,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
最小值最大值间隔均为数值类型若不填则该项视为自动
<br>
请确保填写数值能正确计算否则将无法正常显示轴值
</div>
<div
slot="content"
v-html="$t('chart.axis_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -81,11 +81,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
最小值最大值间隔均为数值类型若不填则该项视为自动
<br>
请确保填写数值能正确计算否则将无法正常显示轴值
</div>
<div
slot="content"
v-html="$t('chart.axis_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -84,11 +84,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
最小值最大值间隔均为数值类型若不填则该项视为自动
<br>
请确保填写数值能正确计算否则将无法正常显示轴值
</div>
<div
slot="content"
v-html="$t('chart.axis_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -84,11 +84,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
最小值最大值间隔均为数值类型若不填则该项视为自动
<br>
请确保填写数值能正确计算否则将无法正常显示轴值
</div>
<div
slot="content"
v-html="$t('chart.axis_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -84,11 +84,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
最小值最大值间隔均为数值类型若不填则该项视为自动
<br>
请确保填写数值能正确计算否则将无法正常显示轴值
</div>
<div
slot="content"
v-html="$t('chart.axis_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -67,7 +67,8 @@ export default {
min_height: 200,
max_height: 500,
elementpath: false,
statusbar: false
statusbar: false,
convert_urls: false
}
}
},

View File

@ -2,7 +2,7 @@
<div
ref="tableContainer"
:style="bg_class"
style="padding: 8px;width: 100%;height: 100%;overflow: hidden;"
style="padding: 4px;width: 100%;height: 100%;overflow: hidden;"
>
<span
v-show="title_show"

View File

@ -2,7 +2,7 @@
<div
ref="tableContainer"
:style="bg_class"
style="width: 100%;height: 100%;overflow: hidden;"
style="padding: 4px;width: 100%;height: 100%;overflow: hidden;"
>
<view-track-bar
ref="viewTrack"

View File

@ -56,7 +56,7 @@
:id="scope.$index"
v-model="keyWord"
size="mini"
placeholder="输入关键字搜索"
:placeholder="$t('commons.search_keywords')"
/>
</template>

View File

@ -21,7 +21,7 @@
placement="bottom"
>
<div slot="content">
明细表仅在分页模式为"下拉"时生效
{{ $t('chart.table_scroll_tip') }}
</div>
<i
class="el-icon-info"

View File

@ -369,7 +369,7 @@ export default {
const arr = this.thresholdForm.gaugeThreshold.split(',')
for (let i = 0; i < arr.length; i++) {
const ele = arr[i]
if (parseFloat(ele).toString() === 'NaN' || parseFloat(ele) < 1 || parseFloat(ele) > 99) {
if (parseFloat(ele).toString() === 'NaN' || parseFloat(ele) <= 0 || parseFloat(ele) >= 100) {
this.$message({
message: this.$t('chart.gauge_threshold_format_error'),
type: 'error',

View File

@ -164,7 +164,7 @@
</el-row>
</div>
</div>
<div class="tip">提示请勿重复选择字段若同一字段重复配置则只有最后的字段配置生效</div>
<div class="tip">{{ $t('chart.table_threshold_tip') }}</div>
</el-col>
</template>

View File

@ -331,11 +331,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
列宽并非任何时候都能生效
<br>
容器宽度优先级高于列宽(表格容器宽度 / 列数 > 指定列宽)则列宽优先取(容器宽度 / 列数)
</div>
<div
slot="content"
v-html="$t('chart.table_column_width_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;color: #606266;margin-left: 4px;"

View File

@ -87,21 +87,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
模板变量有 {a}, {b}{c}{d}分别表示系列名数据名数据值等
<br>
触发位置 '坐标轴' 的时候会有多个系列的数据此时可以通过 {a0}, {a1}, {a2} 这种后面加索引的方式表示系列的索引
<br>
不同图表类型下的 {a}{b}{c}{d} 含义不一样 其中变量{a}, {b}, {c}, {d}在不同图表类型下代表数据含义为
<br><br>
折线区域柱状条形仪表盘 : {a}系列名称{b}类目值{c}数值
<br>
饼图漏斗图: {a}系列名称{b}数据项名称{c}数值, {d}百分比
<br>
地图 : {a}系列名称{b}区域名称{c}合并数值, {d}
<br>
散点图气泡 : {a}系列名称{b}数据名称{c}数值数组, {d}
</div>
<div
slot="content"
v-html="$t('chart.format_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -225,7 +225,7 @@
</el-select>
</el-form-item>
<el-form-item
v-if="false && chart.type === 'table-pivot'"
v-if="chart.type === 'table-pivot'"
:label="$t('chart.total_sort')"
class="form-item"
>
@ -239,7 +239,7 @@
</el-radio-group>
</el-form-item>
<el-form-item
v-if="false && chart.type === 'table-pivot' && totalForm.col.totalSort !== 'none'"
v-if="chart.type === 'table-pivot' && totalForm.col.totalSort !== 'none'"
:label="$t('chart.total_sort_field')"
class="form-item"
>

View File

@ -55,7 +55,7 @@
>
{{ $t('chart.total') }}
<span>{{
chart.datasetMode === 0 ? chart.totalItems : ((chart.data && chart.data.tableRow) ? chart.data.tableRow.length : 0)
(chart.datasetMode === 0 && !not_support_page_dataset.includes(chart.datasourceType)) ? chart.totalItems : ((chart.data && chart.data.tableRow) ? chart.data.tableRow.length : 0)
}}</span>
{{ $t('chart.items') }}
</span>
@ -166,7 +166,8 @@ export default {
scrollBarHoverColor: DEFAULT_COLOR_CASE.tableScrollBarHoverColor,
totalStyle: {
color: '#606266'
}
},
not_support_page_dataset: NOT_SUPPORT_PAGE_DATASET
}
},
computed: {

View File

@ -32,9 +32,9 @@
placement="bottom"
>
<div slot="content">
表达式语法请遵循该数据源对应的数据库语法
{{ $t('dataset.calc_tips.tip1') }}
<br>
字段类型将使用原始类型如有需要请在表达式中自行转换
{{ $t('dataset.calc_tips.tip2') }}
</div>
<i
class="el-icon-info"
@ -112,11 +112,11 @@
placement="bottom"
>
<div slot="content">
引用字段以 "[" 开始 "]" 结束
{{ $t('dataset.calc_tips.tip3') }}
<br>
请勿修改引用内容否则将引用失败
{{ $t('dataset.calc_tips.tip4') }}
<br>
若输入与引用字段相同格式的内容将被当作引用字段处理
{{ $t('dataset.calc_tips.tip5') }}
</div>
<i
class="el-icon-info"
@ -239,11 +239,11 @@
placement="bottom"
>
<div slot="content">
使用数据集对应数据库类型所支持的函数语法同对应数据库
{{ $t('dataset.calc_tips.tip6') }}
<br>
如日期格式化MySQL使用DATE_FORMAT(date,format)Oracle使用TO_DATE(X,[,fmt])
{{ $t('dataset.calc_tips.tip7') }}
<br>
非直连模式数据集使用Doris数据库函数可参考Doris官网 https://doris.apache.org/zh-CN/
{{ $t('dataset.calc_tips.tip8') }} https://doris.apache.org/zh-CN/
</div>
<i
class="el-icon-info"

View File

@ -581,7 +581,7 @@
placement="bottom"
>
<div slot="content">
该字段为必填项且不应使用类别轴中字段若无需该字段请选择基础柱状图展示否则展示结果不理想
{{ $t('chart.sub_dimension_tip') }}
</div>
<i
class="el-icon-info"
@ -820,7 +820,7 @@
placement="bottom"
>
<div slot="content">
该指标生效时样式大小中的气泡大小属性将失效
{{ $t('chart.scatter_tip') }}
</div>
<i
class="el-icon-info"
@ -914,7 +914,7 @@
placement="bottom"
>
<div slot="content">
钻取字段仅支持数据集中的字段
{{ $t('chart.drill_dimension_tip') }}
</div>
<i
class="el-icon-info"
@ -1084,7 +1084,7 @@
>
<el-collapse-item
title="地名映射"
:title="$t('chart.place_name_mapping')"
name="map-mapping"
>
<map-mapping

View File

@ -14,7 +14,9 @@
v-model="styleInfo.top"
type="number"
:min="0"
:max="maxTop"
class="hide-icon-number"
@change="topOnChange"
>
<template slot="append">px</template>
</el-input>
@ -44,8 +46,11 @@
>
<el-input
v-model="styleInfo.width"
:min="0"
:max="maxWidth"
type="number"
class="hide-icon-number"
@change="widthOnChange"
>
<template slot="append">px</template>
</el-input>
@ -59,7 +64,10 @@
<el-input
v-model="styleInfo.height"
type="number"
:min="0"
:max="maxHeight"
class="hide-icon-number"
@change="heightOnChange"
>
<template slot="append">px</template>
</el-input>
@ -77,12 +85,18 @@ export default {
name: 'PositionAdjust',
props: {},
data() {
return {}
return {
maxHeight: 2000,
maxTop: 40000
}
},
computed: {
maxLeft() {
return 1600 - this.styleInfo.width - this.componentGap
},
maxWidth() {
return 1600 - this.styleInfo.left - this.componentGap
},
styleInfo() {
return this.$store.state.curComponent.style
},
@ -97,7 +111,34 @@ export default {
leftOnChange() {
if (this.styleInfo.left > this.maxLeft) {
this.styleInfo.left = this.maxLeft
} else if (this.styleInfo.left < 0) {
this.styleInfo.left = 0
}
this.$store.commit('canvasChange')
},
widthOnChange() {
if (this.styleInfo.width > this.maxWidth) {
this.styleInfo.width = this.maxWidth
} else if (this.styleInfo.width < 0) {
this.styleInfo.left = 0
}
this.$store.commit('canvasChange')
},
heightOnChange() {
if (this.styleInfo.height > this.maxHeight) {
this.styleInfo.height = this.maxHeight
} else if (this.styleInfo.height < 0) {
this.styleInfo.height = 0
}
this.$store.commit('canvasChange')
},
topOnChange() {
if (this.styleInfo.top > this.maxTop) {
this.styleInfo.top = this.maxTop
} else if (this.styleInfo.top < 0) {
this.styleInfo.top = 0
}
this.$store.commit('canvasChange')
}
}
}

View File

@ -39,7 +39,7 @@
v-if="['db', 'excel', 'api'].includes(datasetType)"
class="table-num"
>{{ $t('deDataset.selected') }} {{ tableNum }}
{{ ['excel'].includes(datasetType) ? $t('deDataset.table') : '项' }}</span>
{{ ['excel'].includes(datasetType) ? $t('deDataset.table') : $t('deDataset.item') }}</span>
<deBtn
:disabled="['db', 'excel', 'api'].includes(datasetType) && !tableNum"
type="primary"

View File

@ -29,9 +29,9 @@
placement="bottom"
>
<div slot="content">
表达式语法请遵循该数据源对应的数据库语法
{{ $t('dataset.calc_tips.tip1') }}
<br>
数据集中不支持聚合运算
{{ $t('dataset.calc_tips.tip2') }}
</div>
<i
class="el-icon-info"
@ -90,11 +90,11 @@
placement="bottom"
>
<div slot="content">
引用字段以 "[" 开始 "]" 结束
{{ $t('dataset.calc_tips.tip3') }}
<br>
请勿修改引用内容否则将引用失败
{{ $t('dataset.calc_tips.tip4') }}
<br>
若输入与引用字段相同格式的内容将被当作引用字段处理
{{ $t('dataset.calc_tips.tip5') }}
</div>
<i
class="el-icon-info"
@ -214,11 +214,11 @@
placement="bottom"
>
<div slot="content">
使用数据集对应数据库类型所支持的函数语法同对应数据库
{{ $t('dataset.calc_tips.tip6') }}
<br>
如日期格式化MySQL使用DATE_FORMAT(date,format)Oracle使用TO_DATE(X,[,fmt])
{{ $t('dataset.calc_tips.tip7') }}
<br>
非直连模式数据集使用Doris数据库函数可参考Doris官网
{{ $t('dataset.calc_tips.tip8') }}
https://doris.apache.org/zh-CN/
</div>
<i

View File

@ -859,6 +859,9 @@ export default {
if (item.dateFormatType !== 'custom') {
item.dateFormat = item.dateFormatType
}
} else {
item.dateFormatType = ''
item.dateFormat = ''
}
if (item.dateFormatType === 'custom' && !item.dateFormat) {
return

View File

@ -398,11 +398,11 @@ export default {
this.filterList = [
{
value: 'logic',
label: '条件筛选'
label: this.$t('deDataset.logic_filter')
},
{
value: 'enum',
label: '枚举筛选'
label: this.$t('deDataset.enum_filter')
}
]
if ([1, 2, 3].includes(deType)) {

View File

@ -44,7 +44,7 @@
<el-date-picker
v-model="form.overTime"
type="datetime"
placeholder="选择日期时间"
:placeholder="$t('commons.date.select_date_time')"
align="right"
value-format="timestamp"
:picker-options="pickerOptions"
@ -148,17 +148,17 @@ export default {
},
shortcuts: [{
text: '一天',
text: this.$t('commons.date.one_day'),
onClick: function(picker) {
picker.$emit('pick', this.limitDate('day'))
}.bind(this)
}, {
text: '一周',
text: this.$t('commons.date.one_week'),
onClick: (picker) => {
picker.$emit('pick', this.limitDate('week'))
}
}, {
text: '一月',
text: this.$t('commons.date.one_month'),
onClick: (picker) => {
picker.$emit('pick', this.limitDate('month'))
}

View File

@ -1,6 +1,7 @@
<template>
<el-row class="component-wait">
<el-tabs
class="wait-tab"
v-model="activeName"
style="padding-left: 10px"
>
@ -36,7 +37,7 @@
class="component-wait-main"
style="padding:10px"
>
<mobile-background-selector />
<mobile-background-selector/>
</el-row>
</el-row>
</template>
@ -141,7 +142,8 @@ export default {
height: 100%;
}
::v-deep .el-tabs--top {
.wait-tab {
height: 40px !important;
background-color: #9ea6b2;
}

View File

@ -292,7 +292,9 @@
v-else
class="view-selected-message-class"
>
<span style="font-size: 14px;margin-left: 10px;font-weight: bold;line-height: 20px">{{ $t('panel.select_view') }}</span>
<span style="font-size: 14px;margin-left: 10px;font-weight: bold;line-height: 20px">
{{ $t('panel.select_view') }}
</span>
</div>
</el-row>
</div>
@ -452,7 +454,9 @@
/>
</el-col>
<el-col :span="21">
<span style="font-size: 13px;margin-left: 10px;font-weight: bold;line-height: 20px">{{ $t('panel.panel_cache_use_tips') }}</span>
<span style="font-size: 13px;margin-left: 10px;font-weight: bold;line-height: 20px">
{{ $t('panel.panel_cache_use_tips') }}
</span>
</el-col>
</el-row>
<div
@ -651,7 +655,7 @@ export default {
},
//
showViewToolsAside() {
return !this.batchOptStatus && this.curComponent && (this.curComponent.type === 'view' || this.curComponent.type === 'de-tabs')
return !this.batchOptStatus && this.curComponent && (this.curComponent.type === 'view' || (this.curComponent.type === 'de-tabs' && this.$store.state.chart.viewId))
},
showBatchViewToolsAside() {
return this.batchOptStatus
@ -966,11 +970,10 @@ export default {
if (this.showIndex === -1 || this.showIndex === type) {
this.$nextTick(() => {
if (this.show) {
this.showIndex === -1
this.showIndex = -1
}
this.show = !this.show
}
)
})
}
this.showIndex = type
},
@ -1376,6 +1379,7 @@ export default {
this.$store.commit('setComponentWithId', this.currentFilterCom)
this.$store.commit('recordSnapshot', 'sureFilter')
this.$store.commit('setCurComponent', { component: this.currentFilterCom, index: this.curComponentIndex })
this.$store.commit('setComponentFromList', this.currentFilterCom)
bus.$emit('refresh-button-info')
this.closeButton()
},

View File

@ -23,12 +23,14 @@
<el-button
size="mini"
@click="cancel()"
>{{ $t('commons.cancel') }}</el-button>
>{{ $t('commons.cancel') }}
</el-button>
<el-button
type="primary"
size="mini"
@click="save()"
>{{ $t('panel.export_pdf') }}</el-button>
>{{ $t('panel.export_pdf') }}
</el-button>
</el-row>
</el-row>
</template>
@ -41,7 +43,7 @@ import { pdfTemplateReplaceAll } from '@/utils/StringUtils.js'
export default {
name: 'PDFPreExport',
components: { },
components: {},
props: {
// eslint-disable-next-line vue/require-default-prop
panelName: {
@ -132,36 +134,35 @@ export default {
setTimeout(() => {
html2canvas(document.getElementById('exportPdf')).then(function(canvas) {
_this.exportLoading = false
const contentWidth = canvas.width
const contentHeight = canvas.height
const contentWidth = canvas.width / 4
const contentHeight = canvas.height / 4
const pageData = canvas.toDataURL('image/jpeg', 1.0)
const lp = contentWidth > contentHeight ? 'l' : 'p'
const PDF = new JsPDF(lp, 'pt', [contentWidth, contentHeight])
PDF.addImage(pageData, 'JPEG', 0, 0, contentWidth, contentHeight)
PDF.save(_this.panelName + '.pdf')
_this.$emit('closePreExport')
}
)
})
}, 1500)
}, 500)
}
}
}
</script>
<style scoped>
.root_class {
margin: 15px 0px 5px;
text-align: center;
}
.export_body_class{
border: 1px solid #dcdfe6 ;
height: 65vh;
overflow-y: auto;
}
.root_class {
margin: 15px 0px 5px;
text-align: center;
}
.export_body_inner_class{
margin: 10px;
}
.export_body_class {
border: 1px solid #dcdfe6;
height: 65vh;
overflow-y: auto;
}
.export_body_inner_class {
margin: 10px;
}
</style>

View File

@ -283,13 +283,10 @@
effect="dark"
placement="bottom"
>
<div slot="content">
引用字段以 "[" 开始 "]" 结束
<br>
请勿修改引用内容否则将引用失败
<br>
若输入与引用字段相同格式的内容将被当作引用字段处理
</div>
<div
slot="content"
v-html="$t('chart.reference_field_tip')"
/>
<i
class="el-icon-info"
style="cursor: pointer;"

View File

@ -69,7 +69,7 @@
</span>
<span
v-if="hasDataPermission('manage', data.privileges)"
:title="'置顶'"
:title="$t('panel.to_top')"
class="child"
@click.stop
>
@ -121,7 +121,7 @@
class="default-expansion"
@click="defaultExpansion = !defaultExpansion"
>
{{ defaultExpansion ? '收起' : '展开' }}
{{ defaultExpansion ? $t('panel.fold') : $t('panel.expand') }}
<i
:class="[
defaultExpansion ? 'el-icon-arrow-up' : 'el-icon-arrow-down'
@ -373,7 +373,7 @@
<el-dialog
v-dialogDrag
:title="linkTitle"
:title="$t('panel.link_share')"
:visible.sync="linkVisible"
width="500px"
@closed="removeLink"
@ -512,7 +512,6 @@ export default {
node: {},
optType: 'newFirstFolder'
},
linkTitle: '链接分享',
linkVisible: false,
linkResourceId: null,
authTitle: null,

View File

@ -235,7 +235,7 @@
<el-dialog
v-if="templateSaveShow"
:title="templateSaveTitle"
:title="$t('panel.save_to_panel')"
:visible.sync="templateSaveShow"
width="500px"
>
@ -246,7 +246,7 @@
</el-dialog>
<el-dialog
v-if="pdfExportShow"
:title="'['+panelInfo.name+']'+'PDF导出'"
:title="'['+panelInfo.name+']'+$t('panel.pdf_export')"
:visible.sync="pdfExportShow"
width="80%"
:top="'8vh'"
@ -260,7 +260,7 @@
/>
<el-select
v-model="pdfTemplateSelectedIndex"
:placeholder="'切换PDF模板'"
:placeholder="$t('panel.switch_pdf_template')"
@change="changePdfTemplate()"
>
<el-option
@ -295,7 +295,7 @@
/>
<el-select
v-model="pdfTemplateSelectedIndex"
:placeholder="'切换PDF模板'"
:placeholder="$t('panel.switch_pdf_template')"
@change="changePdfTemplate()"
>
<el-option
@ -359,7 +359,6 @@ export default {
pdfTemplateContent: '',
templateInfo: {},
pdfTemplateAll: [],
templateSaveTitle: '保存为模板',
templateSaveShow: false,
hasStar: false,
fullscreen: false,

View File

@ -1,7 +1,7 @@
<template>
<div style="width: 100%">
<el-row>
<el-col class="custom-item el-form-item">
<el-row type="flex">
<el-col class="el-form-item">
<el-checkbox
v-model="componentStyleForm.backgroundColorSelect"
style="margin-right: 10px;float: right"
@ -10,7 +10,7 @@
<span style="font-size: 12px">{{ $t('chart.chart_background') }}</span>
</el-checkbox>
</el-col>
<el-col :span="10">
<el-col>
<el-color-picker
v-model="componentStyleForm.color"
:disabled="!componentStyleForm.backgroundColorSelect"

View File

@ -81,7 +81,7 @@
:placeholder="$t('system_parameter_setting.SMTP_password')"
/>
</el-form-item>
<el-form-item :label="$t('system_parameter_setting.test_recipients')">
<el-form-item :label="$t('ç.test_recipients')">
<template slot="label">
{{ $t("system_parameter_setting.test_recipients") }}
<el-tooltip
@ -98,7 +98,7 @@
:placeholder="$t('system_parameter_setting.test_recipients')"
/>
</el-form-item>
<el-form-item label="邮箱服务器配置">
<el-form-item :label="$t('system_parameter_setting.email_server_config')">
<el-checkbox v-model="formInline.ssl">{{ $t('chart.open') }}SSL
<el-tooltip
class="item"

View File

@ -109,18 +109,18 @@
<!--提供修改个人电话邮箱和昵称的功能-->
<el-form-item v-if="formType!=='modify'">
<el-button @click="formType = 'modify'">修改个人信息</el-button>
<el-button @click="formType = 'modify'">{{ $t('member.modify_personal_info') }}</el-button>
</el-form-item>
<el-form-item v-else>
<el-button
v-if="formType==='modify'"
type="primary"
@click="save"
>保存</el-button>
>{{ $t('commons.save') }}</el-button>
<el-button
v-if="formType==='modify'"
@click="reset"
>取消</el-button>
>{{ $t('commons.cancel') }}</el-button>
</el-form-item>
</el-form>

View File

@ -1,6 +1,6 @@
{
"name": "dataease-mobile",
"version": "1.17.0",
"version": "1.18.0",
"private": true,
"scripts": {
"serve": "npm run dev:h5",

View File

@ -6,7 +6,7 @@
<parent>
<artifactId>dataease-server</artifactId>
<groupId>io.dataease</groupId>
<version>1.17.0</version>
<version>1.18.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -61,5 +61,5 @@
</plugin>
</plugins>
</build>
</project>

View File

@ -1,11 +1,11 @@
<?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>
<groupId>io.dataease</groupId>
<artifactId>dataease-server</artifactId>
<version>1.17.0</version>
<version>1.18.0</version>
<packaging>pom</packaging>
<parent>
@ -16,7 +16,7 @@
</parent>
<name>dataease</name>
<modules>
<module>frontend</module>
<module>mobile</module>