forked from github/dataease
Merge branch 'dev-v2' into heatmap
This commit is contained in:
commit
4b492d29ca
@ -1,6 +1,6 @@
|
||||
FROM registry.cn-qingdao.aliyuncs.com/dataease/alpine-openjdk17-jre
|
||||
FROM registry.cn-qingdao.aliyuncs.com/dataease/alpine-openjdk21-jre
|
||||
|
||||
RUN mkdir -p /opt/apps/config /opt/dataease2.0/drivers/ /opt/dataease2.0/cache/ /opt/dataease2.0/data/map /opt/dataease2.0/data/static-resource/ /opt/dataease2.0/data/appearance/
|
||||
RUN mkdir -p /opt/apps/config /opt/dataease2.0/drivers/ /opt/dataease2.0/cache/ /opt/dataease2.0/data/map /opt/dataease2.0/data/static-resource/ /opt/dataease2.0/data/appearance/ /opt/dataease2.0/data/exportData/
|
||||
|
||||
ADD drivers/* /opt/dataease2.0/drivers/
|
||||
ADD mapFiles/ /opt/dataease2.0/data/map/
|
||||
@ -11,8 +11,9 @@ WORKDIR /opt/apps
|
||||
ADD core/core-backend/target/CoreApplication.jar /opt/apps/app.jar
|
||||
|
||||
ENV JAVA_APP_JAR=/opt/apps/app.jar
|
||||
ENV RUNNING_PORT=8100
|
||||
ENV JAVA_OPTIONS="-Dfile.encoding=utf-8 -Dloader.path=/opt/apps -Dspring.config.additional-location=/opt/apps/config/"
|
||||
|
||||
HEALTHCHECK --interval=15s --timeout=5s --retries=20 --start-period=30s CMD nc -zv 127.0.0.1 8100
|
||||
HEALTHCHECK --interval=15s --timeout=5s --retries=20 --start-period=30s CMD nc -zv 127.0.0.1 $RUNNING_PORT
|
||||
|
||||
CMD ["/deployments/run-java.sh"]
|
||||
|
@ -48,6 +48,10 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<classifier>de</classifier>
|
||||
</dependency>
|
||||
@ -83,6 +87,10 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fit2cloud</groupId>
|
||||
<artifactId>quartz-spring-boot-starter</artifactId>
|
||||
|
@ -5,13 +5,16 @@ import io.dataease.api.chart.dto.ChartViewDTO;
|
||||
import io.dataease.api.chart.dto.ViewDetailField;
|
||||
import io.dataease.api.chart.request.ChartExcelRequest;
|
||||
import io.dataease.chart.manage.ChartDataManage;
|
||||
import io.dataease.constant.AuthConstant;
|
||||
import io.dataease.constant.CommonConstants;
|
||||
import io.dataease.engine.constant.DeTypeConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.exportCenter.manage.ExportCenterManage;
|
||||
import io.dataease.result.ResultCode;
|
||||
import io.dataease.utils.LogUtil;
|
||||
import io.dataease.visualization.manage.VisualizationTemplateExtendDataManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
@ -22,12 +25,13 @@ import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -38,10 +42,11 @@ import java.util.stream.Collectors;
|
||||
public class ChartDataServer implements ChartDataApi {
|
||||
@Resource
|
||||
private ChartDataManage chartDataManage;
|
||||
@Resource
|
||||
private ExportCenterManage exportCenterManage;
|
||||
|
||||
@Resource
|
||||
private VisualizationTemplateExtendDataManage extendDataManage;
|
||||
|
||||
@Value("${export.views.limit:500000}")
|
||||
private Integer limit;
|
||||
|
||||
@ -76,6 +81,12 @@ public class ChartDataServer implements ChartDataApi {
|
||||
|
||||
@Override
|
||||
public void innerExportDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception {
|
||||
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
String linkToken = httpServletRequest.getHeader(AuthConstant.LINK_TOKEN_KEY);
|
||||
if (StringUtils.isEmpty(linkToken)) {
|
||||
exportCenterManage.addTask(request.getViewId(), "chart", request);
|
||||
return;
|
||||
}
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
try {
|
||||
findExcelData(request);
|
||||
|
@ -207,7 +207,7 @@ public class DatasetDataManage {
|
||||
Order2SQLObj.getOrders(sqlMeta, fields, datasetGroupInfoDTO.getSortFields(), crossDs, dsMap);
|
||||
String querySQL;
|
||||
if (start == null || count == null) {
|
||||
querySQL = SQLProvider.createQuerySQL(sqlMeta, false, false, needOrder);
|
||||
querySQL = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, false);
|
||||
} else {
|
||||
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, false, start, count);
|
||||
}
|
||||
@ -231,7 +231,7 @@ public class DatasetDataManage {
|
||||
map.put("allFields", fieldList);
|
||||
}
|
||||
map.put("sql", Base64.getEncoder().encodeToString(querySQL.getBytes()));
|
||||
String replaceSql = SqlUtils.rebuildSQL(SQLProvider.createQuerySQL(sqlMeta, false, false, needOrder), sqlMeta, crossDs, dsMap);
|
||||
String replaceSql = SqlUtils.rebuildSQL(SQLProvider.createQuerySQL(sqlMeta, false, false, false), sqlMeta, crossDs, dsMap);
|
||||
map.put("total", getDatasetTotal(datasetGroupInfoDTO, replaceSql, null));
|
||||
return map;
|
||||
}
|
||||
|
@ -220,11 +220,12 @@ public class PermissionManage {
|
||||
|
||||
private String handleSysVariable(UserFormVO userEntity, String sysVariable) {
|
||||
String value = null;
|
||||
System.out.println(sysVariable);
|
||||
System.out.println(JsonUtil.toJSONString(userEntity));
|
||||
if (StringUtils.isNotBlank(sysVariable) && sysVariable.startsWith("${") && sysVariable.endsWith("}")) {
|
||||
String variableId = sysVariable.substring(2, sysVariable.length() - 1);
|
||||
for (SysVariableValueItem variable : userEntity.getVariables()) {
|
||||
if (!variable.isValid()){
|
||||
continue;
|
||||
}
|
||||
if (variableId.equalsIgnoreCase(variable.getVariableId().toString())) {
|
||||
if (variable.getSysVariableDto().getType().equalsIgnoreCase("text")) {
|
||||
for (SysVariableValueDto sysVariableValueDto : variable.getValueList()) {
|
||||
|
@ -932,9 +932,9 @@ public class CalciteProvider {
|
||||
Properties props = new Properties();
|
||||
if (StringUtils.isNotBlank(configuration.getUsername())) {
|
||||
props.setProperty("user", configuration.getUsername());
|
||||
if (StringUtils.isNotBlank(configuration.getPassword())) {
|
||||
props.setProperty("password", configuration.getPassword());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(configuration.getPassword())) {
|
||||
props.setProperty("password", configuration.getPassword());
|
||||
}
|
||||
String driverClassName = configuration.getDriver();
|
||||
ExtendedJdbcClassLoader jdbcClassLoader = extendedJdbcClassLoader;
|
||||
|
@ -7,7 +7,7 @@ import java.util.Optional;
|
||||
*/
|
||||
public class SQLUtils {
|
||||
public static String transKeyword(String value) {
|
||||
return Optional.ofNullable(value).orElse("").replaceAll("'", "\\\\'");
|
||||
return Optional.ofNullable(value).orElse("").replaceAll("'", "''");
|
||||
}
|
||||
|
||||
public static String buildOriginPreviewSql(String sql, int limit, int offset) {
|
||||
|
@ -68,7 +68,8 @@ public class Utils {
|
||||
String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), ele.getDataeaseName()));
|
||||
} else {
|
||||
originField = originField.replaceAll("\\[" + ele.getId() + "]",
|
||||
tableObj.getTableAlias() + "." + datasourceType.getPrefix() + ele.getDataeaseName() + datasourceType.getSuffix());
|
||||
datasourceType.getPrefix() + tableObj.getTableAlias() + datasourceType.getSuffix() +
|
||||
"." + datasourceType.getPrefix() + ele.getDataeaseName() + datasourceType.getSuffix());
|
||||
}
|
||||
} else {
|
||||
originField = originField.replaceAll("\\[" + ele.getId() + "]", "(" + ele.getOriginName() + ")");
|
||||
|
BIN
core/core-backend/src/main/java/io/dataease/exportCenter/.DS_Store
vendored
Normal file
BIN
core/core-backend/src/main/java/io/dataease/exportCenter/.DS_Store
vendored
Normal file
Binary file not shown.
@ -0,0 +1,159 @@
|
||||
package io.dataease.exportCenter.dao.auto.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 导出任务表
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2024-05-23
|
||||
*/
|
||||
@TableName("core_export_task")
|
||||
public class CoreExportTask implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String fileName;
|
||||
|
||||
private Double fileSize;
|
||||
|
||||
private String fileSizeUnit;
|
||||
|
||||
private String exportFrom;
|
||||
|
||||
private String exportStatus;
|
||||
|
||||
private String exportFromType;
|
||||
|
||||
private Long exportTime;
|
||||
|
||||
private String exportProgress;
|
||||
|
||||
private String exportMachineName;
|
||||
|
||||
/**
|
||||
* 过滤参数
|
||||
*/
|
||||
private String params;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public Double getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(Double fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public String getFileSizeUnit() {
|
||||
return fileSizeUnit;
|
||||
}
|
||||
|
||||
public void setFileSizeUnit(String fileSizeUnit) {
|
||||
this.fileSizeUnit = fileSizeUnit;
|
||||
}
|
||||
|
||||
public String getExportFrom() {
|
||||
return exportFrom;
|
||||
}
|
||||
|
||||
public void setExportFrom(String exportFrom) {
|
||||
this.exportFrom = exportFrom;
|
||||
}
|
||||
|
||||
public String getExportStatus() {
|
||||
return exportStatus;
|
||||
}
|
||||
|
||||
public void setExportStatus(String exportStatus) {
|
||||
this.exportStatus = exportStatus;
|
||||
}
|
||||
|
||||
public String getExportFromType() {
|
||||
return exportFromType;
|
||||
}
|
||||
|
||||
public void setExportFromType(String exportFromType) {
|
||||
this.exportFromType = exportFromType;
|
||||
}
|
||||
|
||||
public Long getExportTime() {
|
||||
return exportTime;
|
||||
}
|
||||
|
||||
public void setExportTime(Long exportTime) {
|
||||
this.exportTime = exportTime;
|
||||
}
|
||||
|
||||
public String getExportProgress() {
|
||||
return exportProgress;
|
||||
}
|
||||
|
||||
public void setExportProgress(String exportProgress) {
|
||||
this.exportProgress = exportProgress;
|
||||
}
|
||||
|
||||
public String getExportMachineName() {
|
||||
return exportMachineName;
|
||||
}
|
||||
|
||||
public void setExportMachineName(String exportMachineName) {
|
||||
this.exportMachineName = exportMachineName;
|
||||
}
|
||||
|
||||
public String getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(String params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CoreExportTask{" +
|
||||
"id = " + id +
|
||||
", userId = " + userId +
|
||||
", fileName = " + fileName +
|
||||
", fileSize = " + fileSize +
|
||||
", fileSizeUnit = " + fileSizeUnit +
|
||||
", exportFrom = " + exportFrom +
|
||||
", exportStatus = " + exportStatus +
|
||||
", exportFromType = " + exportFromType +
|
||||
", exportTime = " + exportTime +
|
||||
", exportProgress = " + exportProgress +
|
||||
", exportMachineName = " + exportMachineName +
|
||||
", params = " + params +
|
||||
"}";
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package io.dataease.exportCenter.dao.auto.mapper;
|
||||
|
||||
import io.dataease.exportCenter.dao.auto.entity.CoreExportTask;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 导出任务表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2024-05-23
|
||||
*/
|
||||
@Mapper
|
||||
public interface CoreExportTaskMapper extends BaseMapper<CoreExportTask> {
|
||||
|
||||
}
|
@ -0,0 +1,413 @@
|
||||
package io.dataease.exportCenter.manage;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.dataease.api.chart.dto.ViewDetailField;
|
||||
import io.dataease.api.chart.request.ChartExcelRequest;
|
||||
import io.dataease.api.exportCenter.vo.ExportTaskDTO;
|
||||
import io.dataease.auth.bo.TokenUserBO;
|
||||
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
|
||||
import io.dataease.chart.server.ChartDataServer;
|
||||
import io.dataease.engine.constant.DeTypeConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.exportCenter.dao.auto.entity.CoreExportTask;
|
||||
import io.dataease.exportCenter.dao.auto.mapper.CoreExportTaskMapper;
|
||||
import io.dataease.utils.*;
|
||||
import io.dataease.visualization.server.DataVisualizationServer;
|
||||
import io.dataease.websocket.WsMessage;
|
||||
import io.dataease.websocket.WsService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ExportCenterManage {
|
||||
@Resource
|
||||
private CoreExportTaskMapper exportTaskMapper;
|
||||
@Resource
|
||||
DataVisualizationServer dataVisualizationServer;
|
||||
@Resource
|
||||
private CoreChartViewMapper coreChartViewMapper;
|
||||
@Autowired
|
||||
private WsService wsService;
|
||||
|
||||
@Value("${export.dataset.limit:100000}")
|
||||
private int limit;
|
||||
private final static String DATA_URL_TITLE = "data:image/jpeg;base64,";
|
||||
private static final String exportData_path = "/opt/dataease2.0/data/exportData/";
|
||||
@Value("${extract.page.size:50000}")
|
||||
private Integer extractPageSize;
|
||||
static private List<String> STATUS = Arrays.asList("SUCCESS", "FAILED", "PENDING", "IN_PROGRESS", "ALL");
|
||||
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
|
||||
private int corePoolSize = 10;
|
||||
private int keepAliveSeconds = 600;
|
||||
private Map<String, Future> Running_Task = new HashMap<>();
|
||||
@Resource
|
||||
private ChartDataServer chartDataServer;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(corePoolSize);
|
||||
scheduledThreadPoolExecutor.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 5000)
|
||||
public void checkRunningTask() {
|
||||
Iterator<Map.Entry<String, Future>> iterator = Running_Task.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Future> entry = iterator.next();
|
||||
if (entry.getValue().isDone()) {
|
||||
iterator.remove();
|
||||
try {
|
||||
CoreExportTask exportTask = exportTaskMapper.selectById(entry.getKey());
|
||||
ExportTaskDTO exportTaskDTO = new ExportTaskDTO();
|
||||
BeanUtils.copyBean(exportTaskDTO, exportTask);
|
||||
setExportFromName(exportTaskDTO);
|
||||
WsMessage message = new WsMessage(exportTask.getUserId(), "/task-export-topic", exportTaskDTO);
|
||||
wsService.releaseMessage(message);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void download(String id, HttpServletResponse response) throws Exception {
|
||||
CoreExportTask exportTask = exportTaskMapper.selectById(id);
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
response.setContentType("application/vnd.ms-excel");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + exportTask.getFileName());
|
||||
InputStream fileInputStream = new FileInputStream(exportData_path + id + "/" + exportTask.getFileName());
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
fileInputStream.close();
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
public void delete(String id) {
|
||||
Iterator<Map.Entry<String, Future>> iterator = Running_Task.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Future> entry = iterator.next();
|
||||
if (entry.getKey().equalsIgnoreCase(id)) {
|
||||
entry.getValue().cancel(true);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
FileUtils.deleteDirectoryRecursively(exportData_path + id);
|
||||
exportTaskMapper.deleteById(id);
|
||||
}
|
||||
|
||||
public void deleteAll(String type) {
|
||||
if (!STATUS.contains(type)) {
|
||||
DEException.throwException("无效的状态");
|
||||
}
|
||||
QueryWrapper<CoreExportTask> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_id", AuthUtils.getUser().getUserId());
|
||||
if (!type.equalsIgnoreCase("ALL")) {
|
||||
queryWrapper.eq("export_status", type);
|
||||
}
|
||||
List<CoreExportTask> exportTasks = exportTaskMapper.selectList(queryWrapper);
|
||||
exportTasks.parallelStream().forEach(exportTask -> {
|
||||
Iterator<Map.Entry<String, Future>> iterator = Running_Task.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Future> entry = iterator.next();
|
||||
if (entry.getKey().equalsIgnoreCase(exportTask.getId())) {
|
||||
entry.getValue().cancel(true);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
FileUtils.deleteDirectoryRecursively(exportData_path + exportTask.getId());
|
||||
exportTaskMapper.deleteById(exportTask.getId());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void delete(List<String> ids) {
|
||||
ids.forEach(this::delete);
|
||||
}
|
||||
|
||||
public void retry(String id) {
|
||||
CoreExportTask exportTask = exportTaskMapper.selectById(id);
|
||||
exportTask.setExportStatus("PENDING");
|
||||
exportTask.setExportProgress("0");
|
||||
exportTask.setExportMachineName(hostName());
|
||||
exportTask.setExportTime(System.currentTimeMillis());
|
||||
exportTaskMapper.updateById(exportTask);
|
||||
FileUtils.deleteDirectoryRecursively(exportData_path + id);
|
||||
if (exportTask.getExportFromType().equalsIgnoreCase("chart")) {
|
||||
ChartExcelRequest request = JsonUtil.parse(exportTask.getParams(), ChartExcelRequest.class);
|
||||
startViewTask(exportTask, request);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ExportTaskDTO> exportTasks(String status) {
|
||||
if (!STATUS.contains(status)) {
|
||||
DEException.throwException("Invalid status: " + status);
|
||||
}
|
||||
QueryWrapper<CoreExportTask> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_id", AuthUtils.getUser().getUserId());
|
||||
queryWrapper.orderByDesc("export_time");
|
||||
List<CoreExportTask> exportTasks = exportTaskMapper.selectList(queryWrapper);
|
||||
List<ExportTaskDTO> result = new ArrayList<>();
|
||||
exportTasks.forEach(exportTask -> {
|
||||
ExportTaskDTO exportTaskDTO = new ExportTaskDTO();
|
||||
BeanUtils.copyBean(exportTaskDTO, exportTask);
|
||||
if (status.equalsIgnoreCase("ALL")) {
|
||||
setExportFromAbsName(exportTaskDTO);
|
||||
}
|
||||
if (status.equalsIgnoreCase(exportTaskDTO.getExportStatus())) {
|
||||
setExportFromAbsName(exportTaskDTO);
|
||||
}
|
||||
result.add(exportTaskDTO);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setExportFromAbsName(ExportTaskDTO exportTaskDTO) {
|
||||
if (exportTaskDTO.getExportFromType().equalsIgnoreCase("chart")) {
|
||||
exportTaskDTO.setExportFromName(dataVisualizationServer.getAbsPath(exportTaskDTO.getExportFrom()));
|
||||
}
|
||||
}
|
||||
|
||||
private void setExportFromName(ExportTaskDTO exportTaskDTO) {
|
||||
if (exportTaskDTO.getExportFromType().equalsIgnoreCase("chart")) {
|
||||
exportTaskDTO.setExportFromName(coreChartViewMapper.selectById(exportTaskDTO.getExportFrom()).getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
private String hostName() {
|
||||
String hostname = null;
|
||||
try {
|
||||
InetAddress localMachine = InetAddress.getLocalHost();
|
||||
hostname = localMachine.getHostName();
|
||||
} catch (Exception e) {
|
||||
DEException.throwException("请设置主机名!");
|
||||
}
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public void addTask(String exportFrom, String exportFromType, ChartExcelRequest request) {
|
||||
CoreExportTask exportTask = new CoreExportTask();
|
||||
exportTask.setId(UUID.randomUUID().toString());
|
||||
exportTask.setUserId(AuthUtils.getUser().getUserId());
|
||||
exportTask.setExportFrom(exportFrom);
|
||||
exportTask.setExportFromType(exportFromType);
|
||||
exportTask.setExportStatus("PENDING");
|
||||
exportTask.setFileName(request.getViewName() + ".xlsx");
|
||||
exportTask.setExportProgress("0");
|
||||
exportTask.setExportTime(System.currentTimeMillis());
|
||||
exportTask.setParams(JsonUtil.toJSONString(request).toString());
|
||||
exportTask.setExportMachineName(hostName());
|
||||
exportTaskMapper.insert(exportTask);
|
||||
startViewTask(exportTask, request);
|
||||
}
|
||||
|
||||
private void startViewTask(CoreExportTask exportTask, ChartExcelRequest request) {
|
||||
String dataPath = exportData_path + exportTask.getId();
|
||||
File directory = new File(dataPath);
|
||||
boolean isCreated = directory.mkdir();
|
||||
TokenUserBO tokenUserBO = AuthUtils.getUser();
|
||||
Future future = scheduledThreadPoolExecutor.submit(() -> {
|
||||
AuthUtils.setUser(tokenUserBO);
|
||||
try {
|
||||
exportTask.setExportStatus("IN_PROGRESS");
|
||||
exportTaskMapper.updateById(exportTask);
|
||||
chartDataServer.findExcelData(request);
|
||||
List<Object[]> details = request.getDetails();
|
||||
Integer[] excelTypes = request.getExcelTypes();
|
||||
details.add(0, request.getHeader());
|
||||
Workbook wb = new SXSSFWorkbook();
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据");
|
||||
//给单元格设置样式
|
||||
CellStyle cellStyle = wb.createCellStyle();
|
||||
Font font = wb.createFont();
|
||||
//设置字体大小
|
||||
font.setFontHeightInPoints((short) 12);
|
||||
//设置字体加粗
|
||||
font.setBold(true);
|
||||
//给字体设置样式
|
||||
cellStyle.setFont(font);
|
||||
//设置单元格背景颜色
|
||||
cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||
//设置单元格填充样式(使用纯色背景颜色填充)
|
||||
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
|
||||
|
||||
Boolean mergeHead = false;
|
||||
ViewDetailField[] detailFields = request.getDetailFields();
|
||||
if (ArrayUtils.isNotEmpty(detailFields)) {
|
||||
cellStyle.setBorderTop(BorderStyle.THIN);
|
||||
cellStyle.setBorderRight(BorderStyle.THIN);
|
||||
cellStyle.setBorderBottom(BorderStyle.THIN);
|
||||
cellStyle.setBorderLeft(BorderStyle.THIN);
|
||||
String[] detailField = Arrays.stream(detailFields).map(field -> field.getName()).collect(Collectors.toList()).toArray(new String[detailFields.length]);
|
||||
Object[] header = request.getHeader();
|
||||
Row row = detailsSheet.createRow(0);
|
||||
int headLen = header.length;
|
||||
int detailFieldLen = detailField.length;
|
||||
for (int i = 0; i < headLen; i++) {
|
||||
Cell cell = row.createCell(i);
|
||||
cell.setCellValue(header[i].toString());
|
||||
if (i < headLen - 1) {
|
||||
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 1, i, i);
|
||||
detailsSheet.addMergedRegion(cellRangeAddress);
|
||||
} else {
|
||||
for (int j = i + 1; j < detailFieldLen + i; j++) {
|
||||
row.createCell(j).setCellStyle(cellStyle);
|
||||
}
|
||||
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, i, i + detailFieldLen - 1);
|
||||
detailsSheet.addMergedRegion(cellRangeAddress);
|
||||
}
|
||||
cell.setCellStyle(cellStyle);
|
||||
detailsSheet.setColumnWidth(i, 255 * 20);
|
||||
}
|
||||
|
||||
Row detailRow = detailsSheet.createRow(1);
|
||||
for (int i = 0; i < headLen - 1; i++) {
|
||||
Cell cell = detailRow.createCell(i);
|
||||
cell.setCellStyle(cellStyle);
|
||||
}
|
||||
for (int i = 0; i < detailFieldLen; i++) {
|
||||
int colIndex = headLen - 1 + i;
|
||||
Cell cell = detailRow.createCell(colIndex);
|
||||
cell.setCellValue(detailField[i]);
|
||||
cell.setCellStyle(cellStyle);
|
||||
detailsSheet.setColumnWidth(colIndex, 255 * 20);
|
||||
}
|
||||
details.add(1, detailField);
|
||||
mergeHead = true;
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(details) && (!mergeHead || details.size() > 2)) {
|
||||
int realDetailRowIndex = 2;
|
||||
for (int i = (mergeHead ? 2 : 0); i < details.size(); i++) {
|
||||
Row row = detailsSheet.createRow(realDetailRowIndex > 2 ? realDetailRowIndex : i);
|
||||
Object[] rowData = details.get(i);
|
||||
if (rowData != null) {
|
||||
for (int j = 0; j < rowData.length; j++) {
|
||||
Object cellValObj = rowData[j];
|
||||
if (mergeHead && j == rowData.length - 1 && (cellValObj.getClass().isArray() || cellValObj instanceof ArrayList)) {
|
||||
Object[] detailRowArray = ((List<Object>) cellValObj).toArray(new Object[((List<?>) cellValObj).size()]);
|
||||
int detailRowArrayLen = detailRowArray.length;
|
||||
int temlJ = j;
|
||||
while (detailRowArrayLen > 1 && temlJ-- > 0) {
|
||||
CellRangeAddress cellRangeAddress = new CellRangeAddress(realDetailRowIndex, realDetailRowIndex + detailRowArrayLen - 1, temlJ, temlJ);
|
||||
detailsSheet.addMergedRegion(cellRangeAddress);
|
||||
}
|
||||
|
||||
for (int k = 0; k < detailRowArrayLen; k++) {
|
||||
List<Object> detailRows = (List<Object>) detailRowArray[k];
|
||||
Row curRow = row;
|
||||
if (k > 0) {
|
||||
curRow = detailsSheet.createRow(realDetailRowIndex + k);
|
||||
}
|
||||
|
||||
for (int l = 0; l < detailRows.size(); l++) {
|
||||
Object col = detailRows.get(l);
|
||||
Cell cell = curRow.createCell(j + l);
|
||||
cell.setCellValue(col.toString());
|
||||
}
|
||||
}
|
||||
realDetailRowIndex += detailRowArrayLen;
|
||||
break;
|
||||
}
|
||||
|
||||
Cell cell = row.createCell(j);
|
||||
if (i == 0) {// 头部
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
cell.setCellStyle(cellStyle);
|
||||
//设置列的宽度
|
||||
detailsSheet.setColumnWidth(j, 255 * 20);
|
||||
} else if (cellValObj != null) {
|
||||
try {
|
||||
// with DataType
|
||||
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) {
|
||||
cell.setCellValue(Double.valueOf(cellValObj.toString()));
|
||||
} else {
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.warn("export excel data transform error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream outputStream = new FileOutputStream(dataPath + "/" + request.getViewName() + ".xlsx")) {
|
||||
wb.write(outputStream);
|
||||
outputStream.flush();
|
||||
}
|
||||
wb.close();
|
||||
|
||||
exportTask.setExportProgress("100");
|
||||
exportTask.setExportStatus("SUCCESS");
|
||||
setFileSize(dataPath + "/" + request.getViewName() + ".xlsx", exportTask);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error("Failed to export data", e);
|
||||
exportTask.setExportStatus("FAILED");
|
||||
} finally {
|
||||
exportTaskMapper.updateById(exportTask);
|
||||
}
|
||||
});
|
||||
Running_Task.put(exportTask.getId(), future);
|
||||
}
|
||||
|
||||
|
||||
private void setFileSize(String filePath, CoreExportTask exportTask) {
|
||||
File file = new File(filePath);
|
||||
long length = file.length();
|
||||
String unit = "Mb";
|
||||
Double size = 0.0;
|
||||
if ((double) length / 1024 / 1024 > 1) {
|
||||
if ((double) length / 1024 / 1024 / 1024 > 1) {
|
||||
unit = "Gb";
|
||||
size = Double.valueOf(String.format("%.2f", (double) length / 1024 / 1024 / 1024));
|
||||
} else {
|
||||
size = Double.valueOf(String.format("%.2f", (double) length / 1024 / 1024));
|
||||
}
|
||||
|
||||
} else {
|
||||
unit = "Kb";
|
||||
size = Double.valueOf(String.format("%.2f", (double) length / 1024));
|
||||
}
|
||||
exportTask.setFileSize(size);
|
||||
exportTask.setFileSizeUnit(unit);
|
||||
}
|
||||
|
||||
|
||||
private static final String LOG_RETENTION = "30";
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package io.dataease.exportCenter.server;
|
||||
|
||||
import io.dataease.api.exportCenter.ExportCenterApi;
|
||||
import io.dataease.api.exportCenter.vo.ExportTaskDTO;
|
||||
import io.dataease.exportCenter.manage.ExportCenterManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/exportCenter")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ExportCenterServer implements ExportCenterApi {
|
||||
@Resource
|
||||
private ExportCenterManage exportCenterManage;
|
||||
|
||||
@Override
|
||||
public List<ExportTaskDTO> exportTasks(String status) {
|
||||
return exportCenterManage.exportTasks(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
exportCenterManage.delete(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(List<String> ids) {
|
||||
exportCenterManage.delete(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(String type) {
|
||||
exportCenterManage.deleteAll(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String id, HttpServletResponse response) throws Exception {
|
||||
exportCenterManage.download(id, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retry(String id) {
|
||||
exportCenterManage.retry(id);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package io.dataease.home;
|
||||
|
||||
import io.dataease.utils.ModelUtils;
|
||||
import io.dataease.utils.RsaUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -11,6 +12,9 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping
|
||||
public class RestIndexController {
|
||||
|
||||
@Value("${dataease.xpack-front-distributed:false}")
|
||||
private boolean xpackFrontDistributed;
|
||||
|
||||
@GetMapping("/dekey")
|
||||
@ResponseBody
|
||||
public String dekey() {
|
||||
@ -23,4 +27,11 @@ public class RestIndexController {
|
||||
return ModelUtils.isDesktop();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/xpackModel")
|
||||
@ResponseBody
|
||||
public boolean xpackModel() {
|
||||
return xpackFrontDistributed;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ public class XpackShareManage {
|
||||
return pos.stream().map(po ->
|
||||
new XpackShareGridVO(
|
||||
po.getShareId(), po.getResourceId(), po.getName(), po.getCreator().toString(),
|
||||
po.getTime(), po.getExp(), 9,po.getExtFlag())).toList();
|
||||
po.getTime(), po.getExp(), 9,po.getExtFlag(),po.getType())).toList();
|
||||
}
|
||||
|
||||
private XpackShareManage proxy() {
|
||||
|
@ -13,6 +13,7 @@ import io.dataease.api.visualization.vo.DataVisualizationVO;
|
||||
import io.dataease.api.visualization.vo.VisualizationResourceVO;
|
||||
import io.dataease.api.visualization.vo.VisualizationWatermarkVO;
|
||||
import io.dataease.chart.dao.auto.entity.CoreChartView;
|
||||
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
|
||||
import io.dataease.chart.manage.ChartDataManage;
|
||||
import io.dataease.chart.manage.ChartViewManege;
|
||||
import io.dataease.commons.constants.DataVisualizationConstants;
|
||||
@ -30,10 +31,7 @@ import io.dataease.template.dao.auto.entity.VisualizationTemplateExtendData;
|
||||
import io.dataease.template.dao.auto.mapper.VisualizationTemplateExtendDataMapper;
|
||||
import io.dataease.template.dao.auto.mapper.VisualizationTemplateMapper;
|
||||
import io.dataease.template.manage.TemplateCenterManage;
|
||||
import io.dataease.utils.AuthUtils;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.utils.IDUtils;
|
||||
import io.dataease.utils.JsonUtil;
|
||||
import io.dataease.utils.*;
|
||||
import io.dataease.visualization.dao.auto.entity.DataVisualizationInfo;
|
||||
import io.dataease.visualization.dao.auto.entity.VisualizationWatermark;
|
||||
import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper;
|
||||
@ -41,6 +39,7 @@ import io.dataease.visualization.dao.auto.mapper.VisualizationWatermarkMapper;
|
||||
import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper;
|
||||
import io.dataease.visualization.manage.CoreVisualizationManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -48,10 +47,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@ -64,6 +60,8 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
|
||||
@Resource
|
||||
private ChartViewManege chartViewManege;
|
||||
@Resource
|
||||
private CoreChartViewMapper coreChartViewMapper;
|
||||
|
||||
@Resource
|
||||
private ExtDataVisualizationMapper extDataVisualizationMapper;
|
||||
@ -327,6 +325,15 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
Map<Long, VisualizationTemplateExtendDataDTO> extendDataInfo = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : dynamicDataMap.entrySet()) {
|
||||
String originViewId = entry.getKey();
|
||||
Object viewInfo = entry.getValue();
|
||||
try{
|
||||
// 旧模板图表过滤器适配
|
||||
if(viewInfo instanceof Map && ((Map)viewInfo).get("customFilter") instanceof ArrayList){
|
||||
((Map)viewInfo).put("customFilter",new HashMap<>());
|
||||
}
|
||||
}catch(Exception e){
|
||||
LogUtil.error("History Adaptor Error",e);
|
||||
}
|
||||
String originViewData = JsonUtil.toJSONString(entry.getValue()).toString();
|
||||
ChartViewDTO chartView = JsonUtil.parseObject(originViewData, ChartViewDTO.class);
|
||||
if (chartView == null) {
|
||||
@ -391,4 +398,42 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
}
|
||||
}
|
||||
|
||||
public String getAbsPath(String id) {
|
||||
CoreChartView coreChartView = coreChartViewMapper.selectById(id);
|
||||
if (coreChartView == null) {
|
||||
return null;
|
||||
}
|
||||
if (coreChartView.getSceneId() == null) {
|
||||
return coreChartView.getTitle();
|
||||
}
|
||||
List<DataVisualizationInfo> parents = getParents(coreChartView.getSceneId());
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
parents.forEach(ele -> {
|
||||
if (ObjectUtils.isNotEmpty(ele)) {
|
||||
stringBuilder.append(ele.getName()).append("/");
|
||||
}
|
||||
});
|
||||
stringBuilder.append(coreChartView.getTitle());
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
public List<DataVisualizationInfo> getParents(Long id) {
|
||||
List<DataVisualizationInfo> list = new ArrayList<>();
|
||||
DataVisualizationInfo dataVisualizationInfo = visualizationInfoMapper.selectById(id);
|
||||
list.add(dataVisualizationInfo);
|
||||
getParent(list, dataVisualizationInfo);
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public void getParent(List<DataVisualizationInfo> list, DataVisualizationInfo dataVisualizationInfo) {
|
||||
if (ObjectUtils.isNotEmpty(dataVisualizationInfo)) {
|
||||
if (dataVisualizationInfo.getPid() != null) {
|
||||
DataVisualizationInfo d = visualizationInfoMapper.selectById(dataVisualizationInfo.getPid());
|
||||
list.add(d);
|
||||
getParent(list, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
BIN
core/core-backend/src/main/java/io/dataease/websocket/.DS_Store
vendored
Normal file
BIN
core/core-backend/src/main/java/io/dataease/websocket/.DS_Store
vendored
Normal file
Binary file not shown.
@ -0,0 +1,33 @@
|
||||
package io.dataease.websocket.aop;
|
||||
|
||||
import io.dataease.websocket.WsMessage;
|
||||
import io.dataease.websocket.WsService;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class WSTrigger {
|
||||
|
||||
@Autowired
|
||||
private WsService wsService;
|
||||
|
||||
@AfterReturning(value = "execution(* io.dataease.service.message.service.strategy.SendStation.sendMsg(..))")
|
||||
public void after(JoinPoint point) {
|
||||
Object[] args = point.getArgs();
|
||||
Optional.ofNullable(args).ifPresent(objs -> {
|
||||
if (ArrayUtils.isEmpty(objs)) return;
|
||||
Object arg = args[0];
|
||||
Long userId = (Long) arg;
|
||||
WsMessage message = new WsMessage(userId, "/web-msg-topic", "refresh");
|
||||
wsService.releaseMessage(message);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package io.dataease.websocket.config;
|
||||
|
||||
import io.dataease.websocket.factory.DeWsHandlerFactory;
|
||||
import io.dataease.websocket.handler.PrincipalHandshakeHandler;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
public class WsConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/websocket")
|
||||
.setAllowedOriginPatterns("*")
|
||||
.setHandshakeHandler(new PrincipalHandshakeHandler())
|
||||
.withSockJS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/topic", "/user");
|
||||
registry.setUserDestinationPrefix("/user");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
|
||||
registry.addDecoratorFactory(new DeWsHandlerFactory());
|
||||
registry.setMessageSizeLimit(8192) //设置消息字节数大小
|
||||
.setSendBufferSizeLimit(8192)//设置消息缓存大小
|
||||
.setSendTimeLimit(10000); //设置消息发送时间限制毫秒
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.websocket.entity;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
public class DePrincipal implements Principal {
|
||||
|
||||
public DePrincipal(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package io.dataease.websocket.factory;
|
||||
|
||||
import io.dataease.websocket.util.WsUtil;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.WebSocketHandlerDecorator;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class DeWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
|
||||
|
||||
|
||||
public DeWebSocketHandlerDecorator(WebSocketHandler delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
Optional.ofNullable(session.getPrincipal()).ifPresent(principal -> {
|
||||
String name = principal.getName();
|
||||
Long userId = Long.parseLong(name);
|
||||
WsUtil.onLine(userId);
|
||||
});
|
||||
super.afterConnectionEstablished(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
|
||||
Optional.ofNullable(session.getPrincipal()).ifPresent(principal -> {
|
||||
String name = principal.getName();
|
||||
Long userId = Long.parseLong(name);
|
||||
WsUtil.offLine(userId);
|
||||
});
|
||||
|
||||
super.afterConnectionClosed(session, closeStatus);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.websocket.factory;
|
||||
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;
|
||||
|
||||
public class DeWsHandlerFactory implements WebSocketHandlerDecoratorFactory {
|
||||
|
||||
|
||||
@Override
|
||||
public WebSocketHandler decorate(WebSocketHandler webSocketHandler) {
|
||||
return new DeWebSocketHandlerDecorator(webSocketHandler);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.dataease.websocket.handler;
|
||||
|
||||
import io.dataease.websocket.entity.DePrincipal;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
|
||||
public class PrincipalHandshakeHandler extends DefaultHandshakeHandler {
|
||||
|
||||
@Override
|
||||
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
|
||||
if (request instanceof ServletServerHttpRequest) {
|
||||
ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
|
||||
HttpServletRequest httpRequest = servletServerHttpRequest.getServletRequest();
|
||||
final String userId = httpRequest.getParameter("userId");
|
||||
if (StringUtils.isEmpty(userId)) {
|
||||
return null;
|
||||
}
|
||||
return new DePrincipal(userId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.dataease.websocket.service.impl;
|
||||
|
||||
import io.dataease.websocket.WsMessage;
|
||||
import io.dataease.websocket.WsService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
@Service
|
||||
public class StandaloneWsService implements WsService {
|
||||
|
||||
@Resource
|
||||
private SimpMessagingTemplate messagingTemplate;
|
||||
|
||||
public void releaseMessage(WsMessage wsMessage){
|
||||
if(ObjectUtils.isEmpty(wsMessage) || ObjectUtils.isEmpty(wsMessage.getUserId()) || ObjectUtils.isEmpty(wsMessage.getTopic())) return;
|
||||
messagingTemplate.convertAndSendToUser(String.valueOf(wsMessage.getUserId()), wsMessage.getTopic(),wsMessage.getData());
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package io.dataease.websocket.util;
|
||||
|
||||
|
||||
import io.dataease.auth.bo.TokenUserBO;
|
||||
import io.dataease.utils.AuthUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class WsUtil {
|
||||
|
||||
private static final CopyOnWriteArraySet<Long> ONLINE_USERS = new CopyOnWriteArraySet();
|
||||
|
||||
public static boolean onLine() {
|
||||
TokenUserBO user = AuthUtils.getUser();
|
||||
if (ObjectUtils.isNotEmpty(user) && ObjectUtils.isNotEmpty(user.getUserId()))
|
||||
return onLine(user.getUserId());
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean onLine(Long userId) {
|
||||
return ONLINE_USERS.add(userId);
|
||||
}
|
||||
|
||||
public static boolean offLine() {
|
||||
TokenUserBO user = AuthUtils.getUser();
|
||||
if (ObjectUtils.isNotEmpty(user) && ObjectUtils.isNotEmpty(user.getUserId()))
|
||||
return offLine(user.getUserId());
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean offLine(Long userId) {
|
||||
return ONLINE_USERS.remove(userId);
|
||||
}
|
||||
|
||||
public static boolean isOnLine(Long userId) {
|
||||
return ONLINE_USERS.contains(userId);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -3,6 +3,10 @@ spring:
|
||||
url: jdbc:mysql://localhost:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: 123456
|
||||
# datasource:
|
||||
# url: jdbc:mysql://39.98.78.97:13306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
|
||||
# username: root
|
||||
# password: Password123@mysql
|
||||
messages:
|
||||
basename: i18n/lic,i18n/core,i18n/permissions,i18n/xpack
|
||||
flyway:
|
||||
|
@ -24,6 +24,24 @@ ALTER TABLE `xpack_setting_authentication`
|
||||
ADD COLUMN `valid` tinyint(1) NOT NULL DEFAULT 0 COMMENT '有效' AFTER `synced`;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `core_export_task`;
|
||||
CREATE TABLE `core_export_task`
|
||||
(
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` bigint(20) NOT NULL,
|
||||
`file_name` varchar(2048) DEFAULT NULL,
|
||||
`file_size` DOUBLE DEFAULT NULL,
|
||||
`file_size_unit` varchar(255) DEFAULT NULL,
|
||||
`export_from` varchar(255) DEFAULT NULL,
|
||||
`export_status` varchar(255) DEFAULT NULL,
|
||||
`export_from_type` varchar(255) DEFAULT NULL,
|
||||
`export_time` bigint(20) DEFAULT NULL,
|
||||
`export_progress` varchar(255) DEFAULT NULL,
|
||||
`export_machine_name` varchar(512) DEFAULT NULL,
|
||||
`params` longtext NOT NULL COMMENT '过滤参数',
|
||||
PRIMARY KEY (`id`)
|
||||
) COMMENT='导出任务表';
|
||||
|
||||
DROP TABLE IF EXISTS `xpack_platform_token`;
|
||||
CREATE TABLE `xpack_platform_token`
|
||||
(
|
||||
@ -33,3 +51,4 @@ CREATE TABLE `xpack_platform_token`
|
||||
`exp_time` bigint NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
"lodash-es": "^4.17.21",
|
||||
"mathjs": "^11.6.0",
|
||||
"mitt": "^3.0.0",
|
||||
"net": "^1.0.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.32",
|
||||
@ -63,6 +64,8 @@
|
||||
"@types/element-resize-detector": "^1.1.3",
|
||||
"@types/jquery": "^3.5.16",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/sockjs-client": "^1.5.4",
|
||||
"@types/stompjs": "^2.3.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@typescript-eslint/parser": "^5.53.0",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
@ -80,6 +83,8 @@
|
||||
"postcss-scss": "^4.0.6",
|
||||
"prettier": "^2.8.4",
|
||||
"rimraf": "^4.1.2",
|
||||
"sockjs-client": "^1.6.1",
|
||||
"stompjs": "^2.3.3",
|
||||
"stylelint": "^15.2.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recommended": "^10.0.1",
|
||||
@ -96,6 +101,7 @@
|
||||
"vite-plugin-style-import-secondary": "^2.0.0",
|
||||
"vite-plugin-stylelint": "^4.2.0",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-tsc": "^1.0.24"
|
||||
"vue-tsc": "^1.0.24",
|
||||
"xss": "^1.0.14"
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,10 @@ export interface DatasetDetail {
|
||||
fields: {
|
||||
dimensionList: Array<Field>
|
||||
quotaList: Array<Field>
|
||||
parameterList?: Array<Field>
|
||||
}
|
||||
activelist?: string
|
||||
hasParameter?: boolean
|
||||
checkList: string[]
|
||||
list: Array<Field>
|
||||
}
|
||||
@ -247,3 +250,39 @@ export const getFunction = async (): Promise<DatasetDetail[]> => {
|
||||
return res?.data
|
||||
})
|
||||
}
|
||||
|
||||
export const exportTasks = async (type): Promise<IResponse> => {
|
||||
return request.post({ url: '/exportCenter/exportTasks/' + type, data: {} }).then(res => {
|
||||
return res
|
||||
})
|
||||
}
|
||||
|
||||
export const exportRetry = async (id): Promise<IResponse> => {
|
||||
return request.post({ url: '/exportCenter/retry/' + id, data: {} }).then(res => {
|
||||
return res?.data
|
||||
})
|
||||
}
|
||||
|
||||
export const downloadFile = async (id): Promise<Blob> => {
|
||||
return request.get({ url: 'exportCenter/download/' + id, responseType: 'blob' }).then(res => {
|
||||
return res?.data
|
||||
})
|
||||
}
|
||||
|
||||
export const exportDelete = async (id): Promise<IResponse> => {
|
||||
return request.get({ url: '/exportCenter/delete/' + id }).then(res => {
|
||||
return res?.data
|
||||
})
|
||||
}
|
||||
|
||||
export const exportDeleteAll = async (type, data): Promise<IResponse> => {
|
||||
return request.post({ url: '/exportCenter/deleteAll/' + type, data }).then(res => {
|
||||
return res?.data
|
||||
})
|
||||
}
|
||||
|
||||
export const exportDeletePost = async (data): Promise<IResponse> => {
|
||||
return request.post({ url: '/exportCenter/delete', data }).then(res => {
|
||||
return res?.data
|
||||
})
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const load = (key: string) => request.get({ url: `/xpackComponent/content/${key}` })
|
||||
|
||||
export const loadDistributed = () => request.get({ url: '/DEXPack.umd.js' })
|
||||
|
||||
export const xpackModelApi = () => request.get({ url: '/xpackModel' })
|
||||
|
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716798774711" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3450" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M474.3168 450.56H369.3568l66.4576-73.3184 13.7216-6.144h40.96L549.4784 79.1552c-57.6512 3.584-104.448 20.992-141.312 52.224-40.6528 34.5088-60.8256 79.1552-60.8256 134.2464l1.024 24.1664-143.9744 67.9936 2.8672-32.768c9.6256-111.7184 54.6816-194.9696 134.8608-247.808C420.7616 25.6 537.3952 0 692.224 0H1024l-60.0064 184.832h-73.4208l8.192-25.088c4.096-11.8784 6.0416-23.552 6.0416-34.816C904.8064 96.256 840.3968 76.1856 706.56 76.1856h-7.5776l-59.6992 294.8096H892.928l-84.5824 85.2992-15.6672 5.4272a1191.424 1191.424 0 0 0-158.72-11.264h-10.6496l-27.648 136.9088c-26.624 131.3792-78.1312 236.9536-154.8288 316.2112C363.52 983.6544 272.4864 1024 169.1648 1024 111.3088 1024 59.392 1002.5984 14.336 960.3072L0 946.7904l110.1824-110.08 11.4688 23.3472c24.7808 50.3808 63.1808 74.6496 117.9648 74.6496 50.176 0 88.7808-21.7088 117.76-66.4576 30.72-47.5136 59.0848-134.144 84.48-258.8672L474.3168 450.56z" p-id="3451"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
core/core-frontend/src/assets/svg/variable.svg
Normal file
1
core/core-frontend/src/assets/svg/variable.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716884731544" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3731" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M872 561.7V93.4c0-17.3-15.1-31.4-33.8-31.4-18.6 0-33.8 14.1-33.8 31.4v468.3c-51.9 14.7-90 62.4-90 119.1s38.1 104.4 90 119.1v130.8c0 17.3 15.1 31.4 33.8 31.4 18.6 0 33.8-14.1 33.8-31.4V799.8c51.9-14.7 90-62.4 90-119.1s-38.1-104.3-90-119z m6 158.8c-11 11-24.2 16.5-39.8 16.5s-28.8-5.5-39.8-16.5c-11-11-16.5-24.2-16.5-39.8 0-15.5 5.5-28.8 16.5-39.8 11-11 24.2-16.5 39.8-16.5S867 630 878 641c11 11 16.5 24.2 16.5 39.8 0 15.5-5.5 28.7-16.5 39.7zM557 201.7V93.4c0-17.3-15.1-31.4-33.8-31.4-18.6 0-33.8 14.1-33.8 31.4v108.3c-51.9 14.7-90 62.4-90 119.1 0 56.6 38.1 104.4 90 119.1v490.8c0 17.3 15.1 31.4 33.8 31.4 18.6 0 33.8-14.1 33.8-31.4V439.8c51.9-14.7 90-62.4 90-119.1 0-56.6-38.1-104.4-90-119z m6 158.8c-11 11-24.2 16.5-39.8 16.5s-28.8-5.5-39.8-16.5c-11-11-16.5-24.2-16.5-39.8s5.5-28.8 16.5-39.8c11-11 24.2-16.5 39.8-16.5S552 270 563 281c11 11 16.5 24.2 16.5 39.8s-5.5 28.7-16.5 39.7zM219.5 561.7V93.4c0-17.3-15.1-31.4-33.8-31.4-18.6 0-33.7 14.1-33.7 31.4v468.3c-51.9 14.7-90 62.4-90 119.1s38.1 104.4 90 119.1v130.8c0 17.3 15.1 31.4 33.8 31.4 18.6 0 33.8-14.1 33.8-31.4V799.8c51.9-14.7 90-62.4 90-119.1s-38.2-104.3-90.1-119z m6 158.8c-11 11-24.2 16.5-39.8 16.5s-28.8-5.5-39.8-16.5c-11-11-16.5-24.2-16.5-39.8 0-15.5 5.5-28.8 16.5-39.8 11-11 24.2-16.5 39.8-16.5s28.8 5.5 39.8 16.5c11 11 16.5 24.2 16.5 39.8 0 15.6-5.5 28.8-16.5 39.8z" p-id="3732"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -13,6 +13,11 @@ const props = defineProps({
|
||||
themes: {
|
||||
type: String as PropType<EditorTheme>,
|
||||
default: 'dark'
|
||||
},
|
||||
showSwitch: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'modelChange'])
|
||||
@ -45,12 +50,15 @@ const switchValue = computed({
|
||||
<span>
|
||||
{{ title }}
|
||||
</span>
|
||||
<el-switch
|
||||
:effect="themes"
|
||||
size="small"
|
||||
v-model="switchValue"
|
||||
@click.stop="onSwitchChange"
|
||||
/>
|
||||
<div>
|
||||
<el-switch
|
||||
v-show="showSwitch"
|
||||
v-model="switchValue"
|
||||
:effect="themes"
|
||||
size="small"
|
||||
@click.stop="onSwitchChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<slot />
|
||||
|
@ -285,6 +285,14 @@ const batchOptStatusChange = value => {
|
||||
}
|
||||
|
||||
const openOuterParamsSet = () => {
|
||||
if (componentData.value.length === 0) {
|
||||
ElMessage.warning('当前仪表板为空,请先添加组件')
|
||||
return
|
||||
}
|
||||
if (!dvInfo.value.id) {
|
||||
ElMessage.warning('请先保存当前页面')
|
||||
return
|
||||
}
|
||||
outerParamsSetRef.value.optInit()
|
||||
}
|
||||
|
||||
|
@ -1391,6 +1391,7 @@ onMounted(() => {
|
||||
if (isMainCanvas(canvasId.value)) {
|
||||
initSnapshotTimer()
|
||||
initWatermark()
|
||||
dvMainStore.setEditMode('edit')
|
||||
}
|
||||
// 获取编辑器元素
|
||||
composeStore.getEditor(canvasId.value)
|
||||
|
@ -83,7 +83,7 @@ const { config, showPosition, index, canvasStyleData, canvasViewInfo, dvInfo, se
|
||||
toRefs(props)
|
||||
let currentInstance
|
||||
const component = ref(null)
|
||||
const emits = defineEmits(['userViewEnlargeOpen'])
|
||||
const emits = defineEmits(['userViewEnlargeOpen', 'onPointClick'])
|
||||
|
||||
const htmlToImage = () => {
|
||||
setTimeout(() => {
|
||||
@ -180,6 +180,10 @@ const commonBackgroundSvgInner = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const onPointClick = param => {
|
||||
emits('onPointClick', param)
|
||||
}
|
||||
|
||||
const deepScale = computed(() => scale.value / 100)
|
||||
</script>
|
||||
|
||||
@ -234,6 +238,7 @@ const deepScale = computed(() => scale.value / 100)
|
||||
:scale="deepScale"
|
||||
:disabled="true"
|
||||
:is-edit="false"
|
||||
@onPointClick="onPointClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -90,7 +90,7 @@ const paste = () => {
|
||||
}
|
||||
|
||||
const deleteComponent = () => {
|
||||
if (curComponent.value) {
|
||||
if (curComponent.value && !isGroupArea.value) {
|
||||
const curInfo = getCurInfo()
|
||||
dvMainStore.deleteComponentById(curComponent.value?.id, curInfo.componentData)
|
||||
} else if (areaData.value.components.length) {
|
||||
@ -153,6 +153,10 @@ const handleComposeMouseDown = e => {
|
||||
const composeDivider = computed(() => {
|
||||
return !(!curComponent || curComponent['isLock'] || curComponent['component'] != 'Group')
|
||||
})
|
||||
|
||||
const isGroupArea = computed(() => {
|
||||
return curComponent.value?.component === 'GroupArea'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -201,7 +205,7 @@ const composeDivider = computed(() => {
|
||||
取消组合
|
||||
</li>
|
||||
<el-divider class="custom-divider" v-show="composeDivider" />
|
||||
<template v-if="curComponent">
|
||||
<template v-if="curComponent && !isGroupArea">
|
||||
<template v-if="!curComponent['isLock']">
|
||||
<li @click="upComponent">上移一层</li>
|
||||
<li @click="downComponent">下移一层</li>
|
||||
|
@ -13,9 +13,10 @@ import { isMainCanvas } from '@/utils/canvasUtils'
|
||||
import { activeWatermark } from '@/components/watermark/watermark'
|
||||
import { personInfoApi } from '@/api/user'
|
||||
import router from '@/router'
|
||||
import { XpackComponent } from '@/components/plugin'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { pcMatrixCount, curComponent, mobileInPc } = storeToRefs(dvMainStore)
|
||||
|
||||
const openHandler = ref(null)
|
||||
const props = defineProps({
|
||||
canvasStyleData: {
|
||||
type: Object,
|
||||
@ -238,7 +239,6 @@ const initWatermark = (waterDomId = 'preview-canvas-main') => {
|
||||
|
||||
// 目标校验: 需要校验targetSourceId 是否是当前可视化资源ID
|
||||
const winMsgHandle = event => {
|
||||
console.info('PostMessage Params Received')
|
||||
const msgInfo = event.data
|
||||
// 校验targetSourceId
|
||||
if (
|
||||
@ -246,9 +246,9 @@ const winMsgHandle = event => {
|
||||
msgInfo.type === 'attachParams' &&
|
||||
msgInfo.targetSourceId === dvInfo.value.id + ''
|
||||
) {
|
||||
const attachParam = msgInfo.params
|
||||
if (attachParam) {
|
||||
dvMainStore.addOuterParamsFilter(attachParam, componentData.value, 'outer')
|
||||
const attachParams = msgInfo.params
|
||||
if (attachParams) {
|
||||
dvMainStore.addOuterParamsFilter(attachParams, componentData.value, 'outer')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -281,6 +281,32 @@ const userViewEnlargeOpen = (opt, item) => {
|
||||
const handleMouseDown = () => {
|
||||
dvMainStore.setCurComponent({ component: null, index: null })
|
||||
}
|
||||
|
||||
const onPointClick = param => {
|
||||
try {
|
||||
console.info('de_inner_params send')
|
||||
if (window['dataease-embedded-host'] && openHandler?.value) {
|
||||
const pm = {
|
||||
methodName: 'embeddedInteractive',
|
||||
args: {
|
||||
eventName: 'de_inner_params',
|
||||
args: param
|
||||
}
|
||||
}
|
||||
openHandler.value.invokeMethod(pm)
|
||||
} else {
|
||||
console.info('de_inner_params send to host')
|
||||
const targetPm = {
|
||||
type: 'dataease-embedded-interactive',
|
||||
eventName: 'de_inner_params',
|
||||
args: param
|
||||
}
|
||||
window.parent.postMessage(targetPm, '*')
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('de_inner_params send error')
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
restore
|
||||
})
|
||||
@ -316,17 +342,14 @@ defineExpose({
|
||||
:scale="mobileInPc ? 100 : scaleWidth"
|
||||
:is-selector="props.isSelector"
|
||||
@userViewEnlargeOpen="userViewEnlargeOpen($event, item)"
|
||||
@onPointClick="onPointClick"
|
||||
/>
|
||||
<user-view-enlarge ref="userViewEnlargeRef"></user-view-enlarge>
|
||||
</div>
|
||||
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
::-webkit-scrollbar {
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
background-size: 100% 100% !important;
|
||||
width: 100%;
|
||||
@ -334,6 +357,10 @@ defineExpose({
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
::-webkit-scrollbar {
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.fix-button {
|
||||
|
@ -1,9 +1,16 @@
|
||||
<script lang="ts" setup>
|
||||
import noLic from './nolic.vue'
|
||||
import { ref, useAttrs } from 'vue'
|
||||
import { ref, useAttrs, onMounted } from 'vue'
|
||||
import { execute, randomKey, formatArray } from './convert'
|
||||
import { load } from '@/api/plugin'
|
||||
import { load, loadDistributed, xpackModelApi } from '@/api/plugin'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { i18n } from '@/plugins/vue-i18n'
|
||||
import * as Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import * as Pinia from 'pinia'
|
||||
import * as vueI18n from 'vue-i18n'
|
||||
import * as vueRouter from 'vue-router'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
@ -73,11 +80,44 @@ const storeCacheProxy = byteArray => {
|
||||
})
|
||||
wsCache.set(`de-plugin-proxy`, JSON.stringify(result))
|
||||
}
|
||||
loadComponent()
|
||||
const pluginProxy = ref(null)
|
||||
const invokeMethod = param => {
|
||||
pluginProxy.value['invokeMethod'](param)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const key = 'xpack-model-distributed'
|
||||
let distributed = false
|
||||
if (wsCache.get(key) === null) {
|
||||
const res = await xpackModelApi()
|
||||
wsCache.set('xpack-model-distributed', res.data)
|
||||
distributed = res.data
|
||||
} else {
|
||||
distributed = wsCache.get(key)
|
||||
}
|
||||
if (distributed) {
|
||||
window['Vue'] = Vue
|
||||
window['Axios'] = axios
|
||||
window['Pinia'] = Pinia
|
||||
window['vueI18n'] = vueI18n
|
||||
window['vueRouter'] = vueRouter
|
||||
window['MittAll'] = useEmitt().emitter.all
|
||||
window['i18n'] = i18n
|
||||
if (window['DEXPack']) {
|
||||
const xpack = await window['DEXPack'].mapping[attrs.jsname]
|
||||
plugin.value = xpack.default
|
||||
} else {
|
||||
loadDistributed().then(async res => {
|
||||
new Function(res.data)()
|
||||
const xpack = await window['DEXPack'].mapping[attrs.jsname]
|
||||
plugin.value = xpack.default
|
||||
})
|
||||
}
|
||||
} else {
|
||||
loadComponent()
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['loadFail'])
|
||||
defineExpose({
|
||||
invokeMethod
|
||||
|
@ -4,6 +4,7 @@
|
||||
:append-to-body="true"
|
||||
v-model="dialogShow"
|
||||
width="340px"
|
||||
:show-close="false"
|
||||
trigger="click"
|
||||
>
|
||||
<el-row style="height: 20px">
|
||||
|
@ -146,7 +146,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, toRefs, watch } from 'vue'
|
||||
import { computed, h, onBeforeUnmount, onMounted, reactive, toRefs, watch } from 'vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
@ -156,7 +156,8 @@ import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { copyStoreWithOut } from '@/store/modules/data-visualization/copy'
|
||||
import { exportExcelDownload } from '@/views/chart/components/js/util'
|
||||
import FieldsList from '@/custom-component/rich-text/FieldsList.vue'
|
||||
import { ElTooltip } from 'element-plus-secondary'
|
||||
import { RefreshLeft } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElTooltip, ElButton } from 'element-plus-secondary'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const copyStore = copyStoreWithOut()
|
||||
@ -312,12 +313,45 @@ const showBarTooltipPosition = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const openMessageLoading = cb => {
|
||||
const iconClass = `el-icon-loading`
|
||||
const customClass = `de-message-loading de-message-export`
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
'后台导出中,可前往',
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'small',
|
||||
class: 'btn-text',
|
||||
onClick: () => {
|
||||
cb()
|
||||
}
|
||||
},
|
||||
t('data_export.export_center')
|
||||
),
|
||||
'查看进度,进行下载'
|
||||
]),
|
||||
iconClass,
|
||||
icon: h(RefreshLeft),
|
||||
showClose: true,
|
||||
customClass
|
||||
})
|
||||
}
|
||||
|
||||
const callbackExport = () => {
|
||||
useEmitt().emitter.emit('data-export-center')
|
||||
}
|
||||
|
||||
const exportAsExcel = () => {
|
||||
const viewDataInfo = dvMainStore.getViewDataDetails(element.value.id)
|
||||
const chartExtRequest = dvMainStore.getLastViewRequestInfo(element.value.id)
|
||||
const viewInfo = dvMainStore.getViewDetails(element.value.id)
|
||||
const chart = { ...viewInfo, chartExtRequest, data: viewDataInfo }
|
||||
exportExcelDownload(chart)
|
||||
exportExcelDownload(chart, () => {
|
||||
openMessageLoading(callbackExport)
|
||||
})
|
||||
}
|
||||
const exportAsImage = () => {
|
||||
// do export
|
||||
|
@ -71,7 +71,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import ComponentWrapper from '@/components/data-visualization/canvas/ComponentWrapper.vue'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { computed, h, nextTick, ref } from 'vue'
|
||||
import { toPng } from 'html-to-image'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
@ -79,8 +79,10 @@ import ChartComponentS2 from '@/views/chart/components/views/components/ChartCom
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { exportExcelDownload } from '@/views/chart/components/js/util'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { RefreshLeft } from '@element-plus/icons-vue'
|
||||
import { assign } from 'lodash-es'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { ElMessage, ElButton } from 'element-plus-secondary'
|
||||
const downLoading = ref(false)
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const dialogShow = ref(false)
|
||||
@ -201,10 +203,41 @@ const downloadViewDetails = () => {
|
||||
}
|
||||
exportLoading.value = true
|
||||
exportExcelDownload(chart, () => {
|
||||
openMessageLoading(exportData)
|
||||
exportLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const exportData = () => {
|
||||
useEmitt().emitter.emit('data-export-center')
|
||||
}
|
||||
|
||||
const openMessageLoading = cb => {
|
||||
const iconClass = `el-icon-loading`
|
||||
const customClass = `de-message-loading de-message-export`
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
'后台导出中,可前往',
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'small',
|
||||
class: 'btn-text',
|
||||
onClick: () => {
|
||||
cb()
|
||||
}
|
||||
},
|
||||
t('data_export.export_center')
|
||||
),
|
||||
'查看进度,进行下载'
|
||||
]),
|
||||
iconClass,
|
||||
icon: h(RefreshLeft),
|
||||
showClose: true,
|
||||
customClass
|
||||
})
|
||||
}
|
||||
const htmlToImage = () => {
|
||||
downLoading.value = true
|
||||
useEmitt().emitter.emit('renderChart-' + viewInfo.value.id)
|
||||
|
@ -171,6 +171,8 @@ service.interceptors.response.use(
|
||||
} else if (response.config.url.match(/^\/map|geo\/\d{3}\/\d+\.json$/)) {
|
||||
// TODO 处理静态文件
|
||||
return response
|
||||
} else if (response.config.url.includes('DEXPack.umd.js')) {
|
||||
return response
|
||||
} else {
|
||||
if (
|
||||
!response?.config?.url.startsWith('/xpackComponent/content') &&
|
||||
|
@ -2,6 +2,39 @@
|
||||
<el-row class="custom-row">
|
||||
<el-row class="custom-row-inner">
|
||||
<el-space wrap>
|
||||
<template v-for="styleOptionKey in styleOptionKeyArrayPre">
|
||||
<el-tooltip
|
||||
:key="styleOptionKey.value"
|
||||
v-if="styleForm[styleOptionKey.value] !== undefined"
|
||||
:effect="themes"
|
||||
placement="bottom"
|
||||
>
|
||||
<template #content> {{ styleOptionKey.label }} </template>
|
||||
<el-form-item class="form-item no-margin-bottom" :class="'form-item-' + themes">
|
||||
<el-select
|
||||
:style="{ width: styleOptionKey.width }"
|
||||
:effect="themes"
|
||||
v-model="styleForm[styleOptionKey.value]"
|
||||
size="small"
|
||||
@change="changeStyle"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon :class="{ 'dark-icon': themes === 'dark' }">
|
||||
<Icon :name="styleOptionKey.icon" />
|
||||
</el-icon>
|
||||
</template>
|
||||
<el-option
|
||||
class="custom-style-option"
|
||||
v-for="option in styleOptionKey.customOption"
|
||||
:key="option.value"
|
||||
:label="option.name"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<template v-for="styleColorKey in styleColorKeyArray">
|
||||
<el-tooltip
|
||||
:key="styleColorKey.value"
|
||||
@ -274,18 +307,25 @@ const styleMounted = ref({
|
||||
color: '#000000'
|
||||
})
|
||||
|
||||
const fontFamilyList = [
|
||||
{ name: '微软雅黑', value: 'Microsoft YaHei' },
|
||||
{ name: '宋体', value: 'SimSun, "Songti SC", STSong' },
|
||||
{ name: '黑体', value: 'SimHei, Helvetica' },
|
||||
{ name: '楷体', value: 'KaiTi, "Kaiti SC", STKaiti' }
|
||||
]
|
||||
|
||||
const scrollSpeedList = [
|
||||
{ name: '停止', value: 0 },
|
||||
{ name: '1', value: 20 },
|
||||
{ name: '2', value: 18 },
|
||||
{ name: '3', value: 16 },
|
||||
{ name: '4', value: 14 },
|
||||
{ name: '5', value: 12 },
|
||||
{ name: '6', value: 10 },
|
||||
{ name: '7', value: 8 },
|
||||
{ name: '8', value: 6 },
|
||||
{ name: '9', value: 4 },
|
||||
{ name: '10', value: 2 }
|
||||
{ name: '1', value: 80 },
|
||||
{ name: '2', value: 60 },
|
||||
{ name: '3', value: 40 },
|
||||
{ name: '4', value: 30 },
|
||||
{ name: '5', value: 20 },
|
||||
{ name: '6', value: 15 },
|
||||
{ name: '7', value: 10 },
|
||||
{ name: '8', value: 8 },
|
||||
{ name: '9', value: 6 },
|
||||
{ name: '10', value: 3 }
|
||||
]
|
||||
|
||||
const opacitySizeList = [
|
||||
@ -376,6 +416,16 @@ const borderStyleList = [
|
||||
{ name: '点线', value: 'dotted' }
|
||||
]
|
||||
|
||||
const styleOptionKeyArrayPre = [
|
||||
{
|
||||
value: 'fontFamily',
|
||||
label: '字体',
|
||||
customOption: fontFamilyList,
|
||||
width: '188px',
|
||||
icon: 'dv-style-fontFamily'
|
||||
}
|
||||
]
|
||||
|
||||
//大小随画布缩放动态变化
|
||||
const styleOptionMountedKeyArray = [
|
||||
{
|
||||
|
@ -498,7 +498,8 @@ const list = [
|
||||
color: '',
|
||||
padding: 4,
|
||||
verticalAlign: 'middle',
|
||||
scrollSpeed: 0
|
||||
scrollSpeed: 0,
|
||||
fontFamily: 'Microsoft YaHei'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -117,7 +117,6 @@ const destroyPlayer = () => {
|
||||
justify-content: center;
|
||||
background-color: rgba(245, 245, 220, 0.1);
|
||||
font-size: 12px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.move-bg {
|
||||
|
@ -88,7 +88,6 @@ watch(
|
||||
justify-content: center;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
font-size: 12px;
|
||||
color: #9ea6b2;
|
||||
}
|
||||
|
||||
.player {
|
||||
|
@ -467,11 +467,10 @@ defineExpose({
|
||||
height: 100%;
|
||||
overflow-y: auto !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
::-webkit-scrollbar {
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ol) {
|
||||
|
@ -78,8 +78,6 @@ const clearStyle = e => {
|
||||
if (text !== '') {
|
||||
document.execCommand('insertText', false, text)
|
||||
}
|
||||
|
||||
emit('input', element.value, e.target.innerHTML)
|
||||
}
|
||||
|
||||
const handleBlur = e => {
|
||||
@ -141,11 +139,12 @@ const textStyle = computed(() => {
|
||||
@mousedown="handleMousedown"
|
||||
@blur="handleBlur"
|
||||
@input="handleInput"
|
||||
v-html="element['propValue']"
|
||||
></div>
|
||||
>
|
||||
{{ element['propValue'] }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="v-text preview">
|
||||
<div class="marquee-txt" :style="textStyle" v-html="element['propValue']"></div>
|
||||
<div v-else class="v-text preview" :style="varStyle">
|
||||
<div class="marquee-txt" :style="textStyle">{{ element['propValue'] }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -71,6 +71,11 @@ const autoStyle = computed(() => {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
const emits = defineEmits(['onPointClick'])
|
||||
|
||||
const onPointClick = param => {
|
||||
emits('onPointClick', param)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -83,6 +88,7 @@ const autoStyle = computed(() => {
|
||||
:show-position="showPosition"
|
||||
:search-count="searchCount"
|
||||
:disabled="disabled"
|
||||
@onPointClick="onPointClick"
|
||||
></chart>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -107,7 +107,6 @@ const activeCondition = ref('')
|
||||
const isIndeterminate = ref(false)
|
||||
const datasetTree = shallowRef([])
|
||||
const fields = ref<DatasetDetail[]>()
|
||||
const parameters = ref([])
|
||||
|
||||
const { queryElement } = toRefs(props)
|
||||
|
||||
@ -191,6 +190,9 @@ const setParameters = () => {
|
||||
|
||||
if (!!curComponent.value.parameters.length) {
|
||||
curComponent.value.conditionType = 0
|
||||
if (curComponent.value.optionValueSource === 0) {
|
||||
curComponent.value.optionValueSource = 1
|
||||
}
|
||||
}
|
||||
})
|
||||
setType()
|
||||
@ -1386,7 +1388,9 @@ defineExpose({
|
||||
@change="handleValueSourceChange"
|
||||
v-model="curComponent.optionValueSource"
|
||||
>
|
||||
<el-radio :label="0">{{ t('chart.margin_model_auto') }}</el-radio>
|
||||
<el-radio :disabled="!!curComponent.parameters.length" :label="0">{{
|
||||
t('chart.margin_model_auto')
|
||||
}}</el-radio>
|
||||
<el-radio :label="1">{{ t('chart.select_dataset') }}</el-radio>
|
||||
<el-radio :label="2">手动输入</el-radio>
|
||||
</el-radio-group>
|
||||
|
@ -4,6 +4,7 @@ import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { isExternal } from '@/utils/validate'
|
||||
import { formatRoute } from '@/router/establish'
|
||||
import HeaderMenuItem from './HeaderMenuItem.vue'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { Icon } from '@/components/icon-custom'
|
||||
import { ElHeader, ElMenu } from 'element-plus-secondary'
|
||||
import SystemCfg from './SystemCfg.vue'
|
||||
@ -15,8 +16,8 @@ import { isDesktop } from '@/utils/ModelUtil'
|
||||
import { XpackComponent } from '@/components/plugin'
|
||||
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
||||
import AiComponent from '@/layout/components/AiComponent.vue'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { findBaseParams } from '@/api/aiComponent'
|
||||
import ExportExcel from '@/views/visualized/data/dataset/ExportExcel.vue'
|
||||
import AiTips from '@/layout/components/AiTips.vue'
|
||||
|
||||
const appearanceStore = useAppearanceStoreWithOut()
|
||||
@ -42,7 +43,10 @@ const activeIndex = computed(() => {
|
||||
})
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const ExportExcelRef = ref()
|
||||
const downloadClick = () => {
|
||||
ExportExcelRef.value.init()
|
||||
}
|
||||
const routers: any[] = formatRoute(permissionStore.getRoutersNotHidden as AppCustomRouteRecordRaw[])
|
||||
const showSystem = ref(false)
|
||||
const showToolbox = ref(false)
|
||||
@ -87,6 +91,10 @@ onMounted(() => {
|
||||
initShowSystem()
|
||||
initShowToolbox()
|
||||
initAiBase()
|
||||
useEmitt({
|
||||
name: 'data-export-center',
|
||||
callback: downloadClick
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -118,6 +126,9 @@ onMounted(() => {
|
||||
>
|
||||
<Icon name="dv-ai" @click="handleAiClick" />
|
||||
</el-icon>
|
||||
<el-icon style="margin: 0 10px">
|
||||
<Icon name="dv-preview-download" @click="downloadClick" />
|
||||
</el-icon>
|
||||
<ai-tips
|
||||
@confirm="aiTipsConfirm"
|
||||
v-if="showOverlay && appearanceStore.getShowAi"
|
||||
@ -134,6 +145,7 @@ onMounted(() => {
|
||||
<div v-if="showOverlay && appearanceStore.getShowAi" class="overlay"></div>
|
||||
</div>
|
||||
</el-header>
|
||||
<ExportExcel ref="ExportExcelRef"></ExportExcel>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -50,6 +50,37 @@ export default {
|
||||
filter_condition: '筛选条件',
|
||||
no_auth_tips: '缺少菜单权限,请联系管理员'
|
||||
},
|
||||
data_export: {
|
||||
export_center: '数据导出中心',
|
||||
export_info: '查看进度,进行下载',
|
||||
exporting: '后台导出中,可前往',
|
||||
del_all: '全部删除',
|
||||
export_failed: '导出失败',
|
||||
export_from: '导出来源',
|
||||
export_obj: '导出对象',
|
||||
export_time: '导出时间',
|
||||
sure_del_all: '确定删除全部导出记录吗?',
|
||||
sure_del: '确定删除该导出记录吗?',
|
||||
no_failed_file: '暂无失败文件',
|
||||
no_file: '暂无文件',
|
||||
no_task: '暂无任务',
|
||||
download_all: '下载全部',
|
||||
download: '下载'
|
||||
},
|
||||
driver: {
|
||||
driver: '驱动',
|
||||
please_choose_driver: '请选择驱动',
|
||||
mgm: '驱动管理',
|
||||
exit_mgm: '退出驱动管理',
|
||||
add: '添加驱动',
|
||||
modify: '修改',
|
||||
show_info: '驱动信息',
|
||||
file_name: '文件名',
|
||||
version: '版本',
|
||||
please_set_driverClass: '请指定驱动类',
|
||||
please_set_surpportVersions: '请输入支持的数据库大版本',
|
||||
surpportVersions: '支持版本'
|
||||
},
|
||||
login: {
|
||||
welcome: '欢迎使用',
|
||||
btn: '登录',
|
||||
@ -291,6 +322,7 @@ export default {
|
||||
please_input_host: '请输入主机',
|
||||
please_input_url: '请输入URL地址',
|
||||
please_input_port: '请输入端口',
|
||||
please_input_be_port: '请输入BE端口',
|
||||
modify: '编辑数据源',
|
||||
copy: '复制数据源',
|
||||
validate_success: '校验成功',
|
||||
@ -656,6 +688,7 @@ export default {
|
||||
table_show_row_tooltip: '开启行头提示',
|
||||
table_show_col_tooltip: '开启列头提示',
|
||||
table_show_cell_tooltip: '开启单元格提示',
|
||||
table_show_header_tooltip: '开启表头提示',
|
||||
stripe: '斑马纹',
|
||||
start_angle: '起始角度',
|
||||
end_angle: '结束角度',
|
||||
@ -680,11 +713,11 @@ export default {
|
||||
chart_bar: '基础柱状图',
|
||||
chart_bar_stack: '堆叠柱状图',
|
||||
chart_percentage_bar_stack: '百分比柱状图',
|
||||
chart_bar_horizontal: '横向柱状图',
|
||||
chart_bar_stack_horizontal: '横向堆叠柱状图',
|
||||
chart_percentage_bar_stack_horizontal: '横向百分比柱状图',
|
||||
chart_bar_horizontal: '基础条形图',
|
||||
chart_bar_stack_horizontal: '堆叠条形图',
|
||||
chart_percentage_bar_stack_horizontal: '百分比条形图',
|
||||
chart_bar_range: '区间条形图',
|
||||
chart_bidirectional_bar: '对称柱状图',
|
||||
chart_bidirectional_bar: '对称条形图',
|
||||
chart_progress_bar: '进度条',
|
||||
chart_line: '基础折线图',
|
||||
chart_area_stack: '堆叠折线图',
|
||||
@ -851,7 +884,7 @@ export default {
|
||||
chart_type_table: '表格',
|
||||
chart_type_quota: '指标',
|
||||
chart_type_trend: '线/面图',
|
||||
chart_type_compare: '柱状图',
|
||||
chart_type_compare: '柱/条图',
|
||||
chart_type_distribute: '分布图',
|
||||
chart_type_relation: '关系图',
|
||||
chart_type_dual_axes: '双轴图',
|
||||
@ -1141,7 +1174,10 @@ export default {
|
||||
top_n_input_2: ', 其余合并至其他',
|
||||
top_n_label: '其他项名称',
|
||||
progress_target: '目标值',
|
||||
progress_current: '实际值'
|
||||
progress_current: '实际值',
|
||||
gauge_axis_label: '显示刻度',
|
||||
gauge_percentage_tick: '百分比刻度',
|
||||
add_style: '添加样式'
|
||||
},
|
||||
dataset: {
|
||||
scope_edit: '仅编辑时生效',
|
||||
@ -1412,6 +1448,7 @@ export default {
|
||||
pls_input_filename: '请输入文件名称',
|
||||
calc_tips: {
|
||||
tip1: '表达式语法请遵循calcite语法。',
|
||||
tip1_1: '表达式语法请遵循该数据源对应的数据库语法。',
|
||||
tip2: '聚合运算仅能在图表中生效。',
|
||||
tip3: '引用字段以 "[" 开始, "]" 结束',
|
||||
tip4: '请勿修改引用内容,否则将引用失败',
|
||||
@ -1904,7 +1941,7 @@ export default {
|
||||
yes: '是',
|
||||
no: '否',
|
||||
live_tips: '优先HTTPS链接',
|
||||
stream_media_add_tips: '请在右侧添加流媒体信息...',
|
||||
stream_media_add_tips: '请添加流媒体信息...',
|
||||
stream_mobile_tips: 'IOS终端可能无法显示',
|
||||
json_params_error: '第三方参数解析失败,请检查参数格式是否正确',
|
||||
inner_padding: '内边距',
|
||||
@ -2142,8 +2179,8 @@ export default {
|
||||
play_circle: '循环播放',
|
||||
video_links: '视频链接',
|
||||
web_url: '网页地址',
|
||||
video_add_tips: '请在右侧添加视频信息...',
|
||||
link_add_tips_pre: '请在右侧配置网页信息..',
|
||||
video_add_tips: '请配置视频信息...',
|
||||
link_add_tips_pre: '请配置网页信息..',
|
||||
web_add_tips_suf: '添加网页信息...',
|
||||
panel_view_result_show: '图表结果',
|
||||
panel_view_result_tips: '选择{0}会覆盖图表的结果展示数量,取值范围1~10000',
|
||||
|
@ -104,6 +104,14 @@ declare interface ChartBasicStyle {
|
||||
* 仪表盘样式
|
||||
*/
|
||||
gaugeStyle: string
|
||||
/**
|
||||
* 仪表盘刻度显示
|
||||
*/
|
||||
gaugeAxisLine: boolean
|
||||
/**
|
||||
* 仪表盘百分比刻度
|
||||
*/
|
||||
gaugePercentLabel: boolean
|
||||
/**
|
||||
* 配色方案
|
||||
*/
|
||||
@ -274,13 +282,19 @@ declare interface ChartTableHeaderAttr {
|
||||
*/
|
||||
tableHeaderSort: boolean
|
||||
/**
|
||||
* @deprecated since version 2.7.0 由提示统一控制
|
||||
* 行头鼠标悬浮提示开关
|
||||
*/
|
||||
showRowTooltip: boolean
|
||||
/**
|
||||
* @deprecated since version 2.7.0 由提示统一控制
|
||||
* 列头鼠标悬浮提示开关
|
||||
*/
|
||||
showColTooltip: boolean
|
||||
/**
|
||||
* 表头显示开关
|
||||
*/
|
||||
showTableHeader: boolean
|
||||
}
|
||||
/**
|
||||
* 单元格属性
|
||||
@ -315,6 +329,7 @@ declare interface ChartTableCellAttr {
|
||||
*/
|
||||
tableItemSubBgColor: string
|
||||
/**
|
||||
* @deprecated since version 2.7.0 由提示统一控制
|
||||
* 鼠标悬浮提示
|
||||
*/
|
||||
showTooltip: boolean
|
||||
|
@ -14,6 +14,7 @@ import { setupCustomComponent } from '@/custom-component'
|
||||
import { installDirective } from '@/directive'
|
||||
import '@/utils/DateUtil'
|
||||
import '@/permission'
|
||||
import WebSocketPlugin from '../../websocket'
|
||||
const setupAll = async () => {
|
||||
const app = createApp(App)
|
||||
installDirective(app)
|
||||
@ -23,6 +24,7 @@ const setupAll = async () => {
|
||||
setupElementPlus(app)
|
||||
setupCustomComponent(app)
|
||||
setupElementPlusIcons(app)
|
||||
app.use(WebSocketPlugin)
|
||||
app.mount('#app')
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ const DashboardEditor = defineAsyncComponent(() => import('@/views/dashboard/ind
|
||||
|
||||
const Dashboard = defineAsyncComponent(() => import('./DashboardPreview.vue'))
|
||||
const ViewWrapper = defineAsyncComponent(() => import('./ViewWrapper.vue'))
|
||||
const Iframe = defineAsyncComponent(() => import('./Iframe.vue'))
|
||||
const Dataset = defineAsyncComponent(() => import('@/views/visualized/data/dataset/index.vue'))
|
||||
const Datasource = defineAsyncComponent(
|
||||
() => import('@/views/visualized/data/datasource/index.vue')
|
||||
@ -18,6 +19,9 @@ const ScreenPanel = defineAsyncComponent(() => import('@/views/data-visualizatio
|
||||
const DashboardPanel = defineAsyncComponent(
|
||||
() => import('@/views/dashboard/DashboardPreviewShow.vue')
|
||||
)
|
||||
|
||||
const Preview = defineAsyncComponent(() => import('@/views/data-visualization/PreviewCanvas.vue'))
|
||||
|
||||
const props = defineProps({
|
||||
componentName: propTypes.string.def('DashboardEditor')
|
||||
})
|
||||
@ -27,8 +31,10 @@ const componentMap = {
|
||||
DashboardEditor,
|
||||
VisualizationEditor,
|
||||
ViewWrapper,
|
||||
Preview,
|
||||
Dashboard,
|
||||
Dataset,
|
||||
Iframe,
|
||||
Datasource,
|
||||
ScreenPanel,
|
||||
DashboardPanel
|
||||
|
@ -39,7 +39,7 @@ onBeforeMount(async () => {
|
||||
}
|
||||
|
||||
// 添加外部参数
|
||||
let attachParam
|
||||
let attachParams
|
||||
await getOuterParamsInfo(embeddedStore.dvId).then(rsp => {
|
||||
dvMainStore.setNowPanelOuterParamsInfo(rsp.data)
|
||||
})
|
||||
@ -48,7 +48,7 @@ onBeforeMount(async () => {
|
||||
if (embeddedStore.outerParams) {
|
||||
try {
|
||||
const outerPramsParse = JSON.parse(embeddedStore.outerParams)
|
||||
attachParam = outerPramsParse.attachParam
|
||||
attachParams = outerPramsParse.attachParams
|
||||
dvMainStore.setEmbeddedCallBack(outerPramsParse.callBackFlag || 'no')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
@ -74,8 +74,8 @@ onBeforeMount(async () => {
|
||||
nextTick(() => {
|
||||
dashboardPreview.value.restore()
|
||||
})
|
||||
if (attachParam) {
|
||||
dvMainStore.addOuterParamsFilter(attachParam, canvasDataResult, 'outer')
|
||||
if (attachParams) {
|
||||
dvMainStore.addOuterParamsFilter(attachParams, canvasDataResult, 'outer')
|
||||
}
|
||||
}
|
||||
)
|
||||
|
19
core/core-frontend/src/pages/panel/Iframe.vue
Normal file
19
core/core-frontend/src/pages/panel/Iframe.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { useEmbedded } from '@/store/modules/embedded'
|
||||
const embeddedStore = useEmbedded()
|
||||
const outerUrl = computed(() => {
|
||||
return embeddedStore.outerUrl
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<iframe class="de-jump_outer_url" :src="outerUrl" frameborder="0"></iframe>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.de-jump_outer_url {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -9,6 +9,7 @@ import { getOuterParamsInfo } from '@/api/visualization/outerParams'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { XpackComponent } from '@/components/plugin'
|
||||
const { wsCache } = useCache()
|
||||
const interactiveStore = interactiveStoreWithOut()
|
||||
const embeddedStore = useEmbedded()
|
||||
@ -17,7 +18,7 @@ const viewInfo = ref()
|
||||
const userViewEnlargeRef = ref()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { t } = useI18n()
|
||||
|
||||
const openHandler = ref(null)
|
||||
const state = reactive({
|
||||
canvasDataPreview: null,
|
||||
canvasStylePreview: null,
|
||||
@ -29,13 +30,12 @@ const state = reactive({
|
||||
|
||||
// 目标校验: 需要校验targetSourceId 是否是当前可视化资源ID
|
||||
const winMsgHandle = event => {
|
||||
console.info('PostMessage Params Received')
|
||||
const msgInfo = event.data
|
||||
// 校验targetSourceId
|
||||
if (msgInfo && msgInfo.type === 'attachParams' && msgInfo.targetSourceId === state.chartId + '') {
|
||||
const attachParam = msgInfo.params
|
||||
if (attachParam) {
|
||||
dvMainStore.addOuterParamsFilter(attachParam, state.canvasDataPreview, 'outer')
|
||||
const attachParams = msgInfo.params
|
||||
if (attachParams) {
|
||||
dvMainStore.addOuterParamsFilter(attachParams, state.canvasDataPreview, 'outer')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ onBeforeMount(async () => {
|
||||
window.addEventListener('message', winMsgHandle)
|
||||
|
||||
// 添加外部参数
|
||||
let attachParam
|
||||
let attachParams
|
||||
await getOuterParamsInfo(embeddedStore.dvId).then(rsp => {
|
||||
dvMainStore.setNowPanelOuterParamsInfo(rsp.data)
|
||||
})
|
||||
@ -67,7 +67,7 @@ onBeforeMount(async () => {
|
||||
if (embeddedStore.outerParams) {
|
||||
try {
|
||||
const outerPramsParse = JSON.parse(embeddedStore.outerParams)
|
||||
attachParam = outerPramsParse.attachParam
|
||||
attachParams = outerPramsParse.attachParams
|
||||
dvMainStore.setEmbeddedCallBack(outerPramsParse.callBackFlag || 'no')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
@ -90,8 +90,8 @@ onBeforeMount(async () => {
|
||||
state.canvasViewInfoPreview = canvasViewInfoPreview
|
||||
state.dvInfo = dvInfo
|
||||
state.curPreviewGap = curPreviewGap
|
||||
if (attachParam) {
|
||||
dvMainStore.addOuterParamsFilter(attachParam, canvasDataResult)
|
||||
if (attachParams) {
|
||||
dvMainStore.addOuterParamsFilter(attachParams, canvasDataResult)
|
||||
}
|
||||
|
||||
viewInfo.value = canvasViewInfoPreview[embeddedStore.chartId]
|
||||
@ -124,6 +124,32 @@ onBeforeMount(async () => {
|
||||
const userViewEnlargeOpen = () => {
|
||||
userViewEnlargeRef.value.dialogInit(state.canvasStylePreview, viewInfo.value, config.value)
|
||||
}
|
||||
|
||||
const onPointClick = param => {
|
||||
try {
|
||||
console.info('de_inner_params send')
|
||||
if (window['dataease-embedded-host'] && openHandler?.value) {
|
||||
const pm = {
|
||||
methodName: 'embeddedInteractive',
|
||||
args: {
|
||||
eventName: 'de_inner_params',
|
||||
args: param
|
||||
}
|
||||
}
|
||||
openHandler.value.invokeMethod(pm)
|
||||
} else {
|
||||
console.info('de_inner_params send to host')
|
||||
const targetPm = {
|
||||
type: 'dataease-embedded-interactive',
|
||||
eventName: 'de_inner_params',
|
||||
args: param
|
||||
}
|
||||
window.parent.postMessage(targetPm, '*')
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('de_inner_params send error')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -136,9 +162,11 @@ const userViewEnlargeOpen = () => {
|
||||
:dv-info="state.dvInfo"
|
||||
:canvas-view-info="state.canvasViewInfoPreview"
|
||||
@userViewEnlargeOpen="userViewEnlargeOpen"
|
||||
@onPointClick="onPointClick"
|
||||
/>
|
||||
<user-view-enlarge ref="userViewEnlargeRef"></user-view-enlarge>
|
||||
</div>
|
||||
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -29,20 +29,24 @@ router.beforeEach(async (to, from, next) => {
|
||||
start()
|
||||
loadStart()
|
||||
checkPlatform()
|
||||
let isDesktop = wsCache.get('app.desktop')
|
||||
if (isDesktop === null) {
|
||||
await appStore.setAppModel()
|
||||
isDesktop = appStore.getDesktop
|
||||
}
|
||||
if (isMobile()) {
|
||||
done()
|
||||
loadDone()
|
||||
if (to.name === 'link') {
|
||||
window.location.href = window.origin + '/mobile.html#' + to.path
|
||||
} else if (!isPlatformClient() && !isLarkPlatform()) {
|
||||
} else if (
|
||||
wsCache.get('user.token') ||
|
||||
isDesktop ||
|
||||
(!isPlatformClient() && !isLarkPlatform())
|
||||
) {
|
||||
window.location.href = window.origin + '/mobile.html#/index'
|
||||
}
|
||||
}
|
||||
let isDesktop = wsCache.get('app.desktop')
|
||||
if (isDesktop === null) {
|
||||
await appStore.setAppModel()
|
||||
isDesktop = appStore.getDesktop
|
||||
}
|
||||
await appearanceStore.setAppearance()
|
||||
if (wsCache.get('user.token') || isDesktop) {
|
||||
if (!userStore.getUid) {
|
||||
|
@ -33,7 +33,7 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
datasetAreaCollapse: false
|
||||
},
|
||||
embeddedCallBack: 'no', // 嵌入模式是否允许反馈参数
|
||||
editMode: 'edit', // 编辑器模式 edit preview
|
||||
editMode: 'preview', // 编辑器模式 edit preview
|
||||
mobileInPc: false,
|
||||
firstLoadMap: [],
|
||||
canvasStyleData: { ...deepCopy(DEFAULT_CANVAS_STYLE_DATA_DARK), backgroundColor: null },
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { store } from '../index'
|
||||
import { clear } from '@/api/sync/syncTaskLog'
|
||||
interface AppState {
|
||||
type: string
|
||||
token: string
|
||||
@ -14,6 +13,8 @@ interface AppState {
|
||||
opt: string
|
||||
createType: string
|
||||
templateParams: string
|
||||
jumpInfoParam: string
|
||||
outerUrl: string
|
||||
}
|
||||
|
||||
export const userStore = defineStore('embedded', {
|
||||
@ -30,13 +31,21 @@ export const userStore = defineStore('embedded', {
|
||||
resourceId: '',
|
||||
opt: '',
|
||||
createType: '',
|
||||
templateParams: ''
|
||||
templateParams: '',
|
||||
outerUrl: '',
|
||||
jumpInfoParam: ''
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getType(): string {
|
||||
return this.type
|
||||
},
|
||||
getJumpInfoParam(): string {
|
||||
return this.jumpInfoParam
|
||||
},
|
||||
getOuterUrl(): string {
|
||||
return this.outerUrl
|
||||
},
|
||||
getCreateType(): string {
|
||||
return this.createType
|
||||
},
|
||||
@ -87,6 +96,12 @@ export const userStore = defineStore('embedded', {
|
||||
setType(type: string) {
|
||||
this.type = type
|
||||
},
|
||||
setOuterUrl(outerUrl: string) {
|
||||
this.outerUrl = outerUrl
|
||||
},
|
||||
setJumpInfoParam(jumpInfoParam: string) {
|
||||
this.jumpInfoParam = jumpInfoParam
|
||||
},
|
||||
setCreateType(createType: string) {
|
||||
this.createType = createType
|
||||
},
|
||||
@ -137,6 +152,8 @@ export const userStore = defineStore('embedded', {
|
||||
this.setTemplateParams('')
|
||||
this.setResourceId('')
|
||||
this.setDvId('')
|
||||
this.setJumpInfoParam('')
|
||||
this.setOuterUrl('')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -376,7 +376,7 @@ em {
|
||||
}
|
||||
|
||||
.color-dataV {
|
||||
background: rgb(0, 214, 185);
|
||||
background: rgb(0, 214, 185)!important;
|
||||
}
|
||||
|
||||
.color-dataset {
|
||||
@ -392,7 +392,7 @@ em {
|
||||
}
|
||||
|
||||
strong {
|
||||
font-synthesis: style weight!important;
|
||||
font-synthesis: style weight !important;
|
||||
}
|
||||
|
||||
.ed-date-editor .ed-range__icon {
|
||||
@ -400,12 +400,94 @@ strong {
|
||||
}
|
||||
|
||||
.ed-picker__popper {
|
||||
--ed-datepicker-border-color: #DEE0E3 !important;
|
||||
--ed-datepicker-border-color: #dee0e3 !important;
|
||||
}
|
||||
|
||||
.ed-dialog__headerbtn {
|
||||
top: 21px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.de-message-export {
|
||||
min-width: 20px !important;
|
||||
padding: 16px 20px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0px 4px 8px 0px #1f23291a;
|
||||
|
||||
& > p {
|
||||
font-family: AlibabaPuHuiTi;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
color: #1f2329;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
padding: 2px 4px;
|
||||
&:hover {
|
||||
background: var(--primary10, #3370ff1a);
|
||||
}
|
||||
}
|
||||
|
||||
.ed-message__closeBtn {
|
||||
margin-left: 28px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
position: relative;
|
||||
margin-right: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translateY(0);
|
||||
color: #646a73;
|
||||
}
|
||||
|
||||
.ed-message__icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.de-message-loading {
|
||||
border: 1px solid var(--primary, #3370ff) !important;
|
||||
background: #f0f4ff !important;
|
||||
@keyframes circle {
|
||||
0% {
|
||||
transform: rotate(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.ed-message__icon {
|
||||
color: var(--primary, #3370ff);
|
||||
animation: circle infinite 0.75s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.de-message-error {
|
||||
border: 1px solid var(--deDanger, #f54a45) !important;
|
||||
background: var(--deWhitemsgDeDanger, #fef1f1) !important;
|
||||
|
||||
.ed-message__icon {
|
||||
color: var(--deDanger, #f54a45);
|
||||
}
|
||||
}
|
||||
|
||||
.de-message-success {
|
||||
border: 1px solid var(--deSuccess, #34c724) !important;
|
||||
background: var(--deWhitemsgDeSuccess, #f0fbef) !important;
|
||||
|
||||
.ed-message__icon {
|
||||
color: var(--deSuccess, #34c724);
|
||||
}
|
||||
}
|
||||
|
@ -119,8 +119,8 @@ export function initCanvasDataPrepare(dvId, busiFlag, callBack) {
|
||||
const canvasStyleResult = JSON.parse(canvasInfo.canvasStyleData)
|
||||
const canvasViewInfoPreview = canvasInfo.canvasViewInfo
|
||||
//历史字段适配
|
||||
canvasStyleResult.component.seniorStyleSetting =
|
||||
canvasStyleResult.component.seniorStyleSetting || deepCopy(SENIOR_STYLE_SETTING_LIGHT)
|
||||
canvasStyleResult.component['seniorStyleSetting'] =
|
||||
canvasStyleResult.component['seniorStyleSetting'] || deepCopy(SENIOR_STYLE_SETTING_LIGHT)
|
||||
|
||||
canvasDataResult.forEach(componentItem => {
|
||||
componentItem['canvasActive'] = false
|
||||
@ -420,6 +420,9 @@ export async function decompressionPre(params, callBack) {
|
||||
}
|
||||
})
|
||||
const sourceCanvasStyle = JSON.parse(deTemplateDataTemp['canvasStyleData'])
|
||||
//历史字段适配
|
||||
sourceCanvasStyle.component['seniorStyleSetting'] =
|
||||
sourceCanvasStyle.component['seniorStyleSetting'] || deepCopy(SENIOR_STYLE_SETTING_LIGHT)
|
||||
deTemplateData = {
|
||||
canvasStyleData: sourceCanvasStyle,
|
||||
componentData: sourceComponentData,
|
||||
@ -432,19 +435,28 @@ export async function decompressionPre(params, callBack) {
|
||||
callBack(deTemplateData)
|
||||
}
|
||||
|
||||
export function trackBarStyleCheck(element, trackbarStyle, scale) {
|
||||
export function trackBarStyleCheck(element, trackbarStyle, _scale, trackMenuNumber) {
|
||||
const { width, height } = element.style
|
||||
const widthReal = width
|
||||
const heightReal = height
|
||||
// 浮窗高度
|
||||
function calculateTrackHeight(trackMenuNumber) {
|
||||
if (trackMenuNumber === 2) {
|
||||
return 75
|
||||
} else {
|
||||
const increment = Math.floor(trackMenuNumber - 2) * 35
|
||||
return 75 + increment
|
||||
}
|
||||
}
|
||||
if (trackbarStyle.left < 0) {
|
||||
trackbarStyle.left = 0
|
||||
} else if (widthReal - trackbarStyle.left < 60) {
|
||||
trackbarStyle.left = trackbarStyle.left - 60
|
||||
}
|
||||
|
||||
const trackMenuHeight = calculateTrackHeight(trackMenuNumber)
|
||||
if (trackbarStyle.top < 0) {
|
||||
trackbarStyle.top = 0
|
||||
} else if (heightReal - trackbarStyle.top < 100) {
|
||||
trackbarStyle.top = trackbarStyle.top - 100
|
||||
} else if (trackbarStyle.top + trackMenuHeight + 60 > heightReal) {
|
||||
trackbarStyle.top = trackbarStyle.top - trackMenuHeight
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ const canvasInit = (isFistLoad = true) => {
|
||||
}
|
||||
// afterInit
|
||||
dvMainStore.setDataPrepareState(true)
|
||||
if (isMainCanvas(canvasId.value.id) && isFistLoad) {
|
||||
if (isMainCanvas(canvasId.value) && isFistLoad) {
|
||||
snapshotStore.recordSnapshotCache('renderChart')
|
||||
}
|
||||
}, 500)
|
||||
@ -289,10 +289,9 @@ defineExpose({
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.render-active {
|
||||
|
@ -231,7 +231,12 @@ init()
|
||||
<div @keydown.stop @keyup.stop style="width: 100%; margin-bottom: 16px">
|
||||
<!--仪表盘-->
|
||||
<el-col v-show="showProperty('gaugeThreshold')">
|
||||
<el-form ref="thresholdForm" :model="state.thresholdForm" label-position="top">
|
||||
<el-form
|
||||
:model="state.thresholdForm"
|
||||
ref="thresholdForm"
|
||||
label-position="top"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item
|
||||
:label="t('chart.threshold_range') + '(%)'"
|
||||
class="form-item"
|
||||
@ -252,7 +257,7 @@ init()
|
||||
<el-tooltip effect="dark" placement="bottom">
|
||||
<el-icon style="margin-left: 10px"><InfoFilled /></el-icon>
|
||||
<template #content>
|
||||
阈值设置,决定仪表盘区间颜色,为空则不开启阈值,范围(0-100),逐级递增
|
||||
条件样式设置,决定仪表盘区间颜色,为空则不开启阈值,范围(0-100),逐级递增
|
||||
<br />
|
||||
例如:输入 30,70;表示:分为3段,分别为[0,30],(30,70],(70,100]
|
||||
</template>
|
||||
@ -261,7 +266,12 @@ init()
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col v-show="showProperty('liquidThreshold')">
|
||||
<el-form ref="thresholdForm" :model="state.thresholdForm" label-position="top">
|
||||
<el-form
|
||||
:model="state.thresholdForm"
|
||||
ref="thresholdForm"
|
||||
label-position="top"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item
|
||||
:label="t('chart.threshold_range') + '(%)'"
|
||||
class="form-item"
|
||||
@ -282,7 +292,7 @@ init()
|
||||
<el-tooltip effect="dark" placement="bottom">
|
||||
<el-icon style="margin-left: 10px"><InfoFilled /></el-icon>
|
||||
<template #content>
|
||||
阈值设置,决定水波图颜色,为空则不开启阈值,范围(0-100),逐级递增
|
||||
条件样式设置,决定水波图颜色,为空则不开启阈值,范围(0-100),逐级递增
|
||||
<br />
|
||||
例如:输入 30,70;表示:分为3段,分别为[0,30],(30,70],(70,100]
|
||||
</template>
|
||||
@ -360,7 +370,7 @@ init()
|
||||
<el-col v-if="props.chart.type && props.chart.type === 'indicator'">
|
||||
<el-col>
|
||||
<div class="inner-container">
|
||||
<span class="label" :class="'label-' + props.themes">阈值设置</span>
|
||||
<span class="label" :class="'label-' + props.themes">条件样式设置</span>
|
||||
<span class="right-btns">
|
||||
<span
|
||||
class="set-text-info"
|
||||
@ -458,7 +468,7 @@ init()
|
||||
<el-col v-show="showProperty('tableThreshold')">
|
||||
<el-col>
|
||||
<div class="inner-container">
|
||||
<span class="label" :class="'label-' + props.themes">阈值设置</span>
|
||||
<span class="label" :class="'label-' + props.themes">条件样式设置</span>
|
||||
<span class="right-btns">
|
||||
<span
|
||||
class="set-text-info"
|
||||
|
@ -436,7 +436,7 @@ init()
|
||||
<template #icon>
|
||||
<Icon name="icon_add_outlined" />
|
||||
</template>
|
||||
{{ t('chart.add_condition') }}
|
||||
{{ t('chart.add_style') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@ -451,7 +451,7 @@ init()
|
||||
<template #icon>
|
||||
<Icon name="icon_add_outlined" />
|
||||
</template>
|
||||
{{ t('chart.add_threshold') }}
|
||||
{{ t('chart.add_condition') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</template>
|
||||
|
@ -354,13 +354,14 @@ watch(
|
||||
/>
|
||||
</collapse-switch-item>
|
||||
<collapse-switch-item
|
||||
:themes="themes"
|
||||
v-if="showProperties('tooltip-selector')"
|
||||
v-model="chart.customAttr.tooltip.show"
|
||||
:themes="themes"
|
||||
:change-model="chart.customAttr.tooltip"
|
||||
@modelChange="val => onTooltipChange({ data: val }, 'show')"
|
||||
name="tooltip"
|
||||
:title="$t('chart.tooltip')"
|
||||
:show-switch="propertyInnerAll['tooltip-selector'].includes('show')"
|
||||
name="tooltip"
|
||||
@modelChange="val => onTooltipChange({ data: val }, 'show')"
|
||||
>
|
||||
<tooltip-selector
|
||||
class="attr-selector"
|
||||
@ -371,11 +372,15 @@ watch(
|
||||
@onExtTooltipChange="onExtTooltipChange"
|
||||
/>
|
||||
</collapse-switch-item>
|
||||
<el-collapse-item
|
||||
:effect="themes"
|
||||
name="tableHeader"
|
||||
:title="t('chart.table_header')"
|
||||
<collapse-switch-item
|
||||
v-if="showProperties('table-header-selector')"
|
||||
v-model="chart.customAttr.tableHeader.showTableHeader"
|
||||
:change-model="chart.customAttr.tableHeader"
|
||||
:effect="themes"
|
||||
:title="t('chart.table_header')"
|
||||
:show-switch="propertyInnerAll['table-header-selector'].includes('showTableHeader')"
|
||||
name="tableHeader"
|
||||
@modelChange="val => onTableHeaderChange(val, 'showTableHeader')"
|
||||
>
|
||||
<table-header-selector
|
||||
:property-inner="propertyInnerAll['table-header-selector']"
|
||||
@ -383,7 +388,7 @@ watch(
|
||||
:chart="chart"
|
||||
@onTableHeaderChange="onTableHeaderChange"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
</collapse-switch-item>
|
||||
<el-collapse-item
|
||||
:effect="themes"
|
||||
name="tableCell"
|
||||
@ -434,7 +439,7 @@ watch(
|
||||
:change-model="chart.customStyle.xAxis"
|
||||
@modelChange="val => onChangeXAxisForm(val, 'show')"
|
||||
name="xAxis"
|
||||
:title="chart.type === 'bidirectional-bar' ? $t('chart.yAxis') : t('chart.xAxis')"
|
||||
:title="selectorSpec['x-axis-selector']?.title"
|
||||
>
|
||||
<x-axis-selector
|
||||
class="attr-selector"
|
||||
@ -469,7 +474,7 @@ watch(
|
||||
:change-model="chart.customStyle.yAxis"
|
||||
@modelChange="val => onChangeYAxisForm(val, 'show')"
|
||||
name="yAxis"
|
||||
:title="chart.type === 'bidirectional-bar' ? $t('chart.xAxis') : $t('chart.yAxis')"
|
||||
:title="selectorSpec['dual-y-axis-selector']?.title"
|
||||
>
|
||||
<dual-y-axis-selector
|
||||
class="attr-selector"
|
||||
|
@ -834,6 +834,34 @@ onMounted(() => {
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="showProperty('gaugeAxisLine')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-checkbox
|
||||
v-model="state.basicStyleForm.gaugeAxisLine"
|
||||
:effect="themes"
|
||||
size="small"
|
||||
@change="changeBasicStyle('gaugeAxisLine')"
|
||||
>
|
||||
{{ t('chart.gauge_axis_label') }}</el-checkbox
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="showProperty('gaugePercentLabel') && state.basicStyleForm.gaugeAxisLine"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-checkbox
|
||||
v-model="state.basicStyleForm.gaugePercentLabel"
|
||||
:effect="themes"
|
||||
size="small"
|
||||
@change="changeBasicStyle('gaugePercentLabel')"
|
||||
>
|
||||
{{ t('chart.gauge_percentage_tick') }}</el-checkbox
|
||||
>
|
||||
</el-form-item>
|
||||
<!--gauge end-->
|
||||
<!--bar start-->
|
||||
<el-form-item
|
||||
|
@ -7,12 +7,11 @@ import cloneDeep from 'lodash-es/cloneDeep'
|
||||
import defaultsDeep from 'lodash-es/defaultsDeep'
|
||||
import { formatterType, unitType } from '../../../js/formatter'
|
||||
import { fieldType } from '@/utils/attr'
|
||||
import { partition, uniqWith, isEqual } from 'lodash-es'
|
||||
import { partition } from 'lodash-es'
|
||||
import chartViewManager from '../../../js/panel'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -41,55 +40,54 @@ const quotaData = ref<Axis[]>(inject('quotaData'))
|
||||
const showSeriesTooltipFormatter = computed(() => {
|
||||
return showProperty('seriesTooltipFormatter') && !batchOptStatus.value && props.chart.id
|
||||
})
|
||||
// 初始化系列提示
|
||||
const initSeriesTooltip = () => {
|
||||
// 切换图表类型直接重置为默认
|
||||
const changeChartType = () => {
|
||||
if (!showSeriesTooltipFormatter.value) {
|
||||
return
|
||||
}
|
||||
curSeriesFormatter.value = {}
|
||||
const formatter = state.tooltipForm.seriesTooltipFormatter
|
||||
const seriesAxisMap = formatter.reduce((pre, next) => {
|
||||
next.seriesId = next.seriesId ?? next.id
|
||||
pre[next.seriesId] = next
|
||||
return pre
|
||||
}, {})
|
||||
// 新增图表
|
||||
if (!quotaAxis.value?.length) {
|
||||
if (!formatter.length) {
|
||||
quotaData.value?.forEach(i => formatter.push({ ...i, seriesId: i.id, show: false }))
|
||||
}
|
||||
curSeriesFormatter.value = {}
|
||||
return
|
||||
}
|
||||
formatter.splice(0, formatter.length)
|
||||
const axisIds = quotaAxis.value?.map(i => i.id)
|
||||
const allQuotaAxis = quotaAxis.value?.concat(
|
||||
quotaData.value?.filter(ele => !axisIds.includes(ele.id))
|
||||
)
|
||||
const axisMap = allQuotaAxis.reduce((pre, next, index) => {
|
||||
let tmp = {
|
||||
...next,
|
||||
seriesId: next.seriesId ?? next.id,
|
||||
show: index <= quotaAxis.value.length - 1,
|
||||
summary: COUNT_DE_TYPE.includes(next.deType) ? 'count' : 'sum'
|
||||
} as SeriesFormatter
|
||||
if (seriesAxisMap[tmp.seriesId]) {
|
||||
tmp = {
|
||||
...tmp,
|
||||
formatterCfg: seriesAxisMap[tmp.seriesId].formatterCfg,
|
||||
show: seriesAxisMap[tmp.seriesId].show,
|
||||
summary: seriesAxisMap[tmp.seriesId].summary,
|
||||
chartShowName: seriesAxisMap[tmp.seriesId].chartShowName
|
||||
}
|
||||
const axisIds = []
|
||||
quotaAxis.value.forEach(axis => {
|
||||
formatter.push({
|
||||
...axis,
|
||||
show: true
|
||||
})
|
||||
axisIds.push(axis.id)
|
||||
})
|
||||
quotaData.value.forEach(quotaAxis => {
|
||||
if (!axisIds.includes(quotaAxis.id)) {
|
||||
formatter.push({
|
||||
...quotaAxis,
|
||||
seriesId: quotaAxis.id,
|
||||
show: false
|
||||
})
|
||||
}
|
||||
})
|
||||
emit('onTooltipChange', { data: state.tooltipForm, render: false }, 'seriesTooltipFormatter')
|
||||
emit('onExtTooltipChange', extTooltip.value)
|
||||
}
|
||||
// 切换数据集
|
||||
const changeDataset = () => {
|
||||
curSeriesFormatter.value = {}
|
||||
const formatter = state.tooltipForm.seriesTooltipFormatter
|
||||
const quotaIds = quotaData.value.map(i => i.id)
|
||||
for (let i = formatter.length - 1; i >= 0; i--) {
|
||||
if (!quotaIds.includes(formatter[i].id)) {
|
||||
formatter.splice(i, 1)
|
||||
}
|
||||
formatter.push(tmp)
|
||||
pre[tmp.seriesId] = tmp
|
||||
return pre
|
||||
}, {})
|
||||
if (!curSeriesFormatter.value || !axisMap[curSeriesFormatter.value.seriesId]) {
|
||||
curSeriesFormatter.value = axisMap[formatter[0].seriesId]
|
||||
return
|
||||
}
|
||||
curSeriesFormatter.value = axisMap[curSeriesFormatter.value.seriesId]
|
||||
const formatterIds = formatter.map(i => i.id)
|
||||
quotaData.value.forEach(axis => {
|
||||
if (!formatterIds.includes(axis.id)) {
|
||||
formatter.push({
|
||||
...axis,
|
||||
seriesId: axis.id,
|
||||
show: false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const AXIS_PROP: AxisType[] = ['yAxis', 'yAxisExt', 'extBubble']
|
||||
const quotaAxis = computed(() => {
|
||||
@ -173,16 +171,6 @@ watch(
|
||||
},
|
||||
{ deep: false }
|
||||
)
|
||||
watch(
|
||||
[quotaData, () => props.chart.type],
|
||||
newVal => {
|
||||
if (!newVal?.[0]?.length) {
|
||||
return
|
||||
}
|
||||
initSeriesTooltip()
|
||||
},
|
||||
{ deep: false }
|
||||
)
|
||||
|
||||
const state = reactive({
|
||||
tooltipForm: {
|
||||
@ -373,6 +361,8 @@ onMounted(() => {
|
||||
useEmitt({ name: 'addAxis', callback: updateSeriesTooltipFormatter })
|
||||
useEmitt({ name: 'removeAxis', callback: updateSeriesTooltipFormatter })
|
||||
useEmitt({ name: 'updateAxis', callback: updateSeriesTooltipFormatter })
|
||||
useEmitt({ name: 'chart-type-change', callback: changeChartType })
|
||||
useEmitt({ name: 'dataset-change', callback: changeDataset })
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -255,7 +255,11 @@ onMounted(() => {
|
||||
</el-form-item>
|
||||
</template>
|
||||
</template>
|
||||
<el-divider class="m-divider" :class="'m-divider--' + themes" />
|
||||
<el-divider
|
||||
v-if="showProperty('splitLine') || showProperty('axisLine')"
|
||||
class="m-divider"
|
||||
:class="'m-divider--' + themes"
|
||||
/>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" v-if="showProperty('axisLine')">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
@ -325,7 +329,11 @@ onMounted(() => {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-divider class="m-divider" :class="'m-divider--' + themes" />
|
||||
<el-divider
|
||||
v-if="showProperty('axisLabel')"
|
||||
class="m-divider"
|
||||
:class="'m-divider--' + themes"
|
||||
/>
|
||||
<el-form-item
|
||||
class="form-item form-item-checkbox"
|
||||
:class="{
|
||||
|
@ -234,20 +234,6 @@ onMounted(() => {
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('showTooltip')"
|
||||
>
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.tableCellForm.showTooltip"
|
||||
@change="changeTableCell('showTooltip')"
|
||||
>
|
||||
{{ t('chart.table_show_cell_tooltip') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
|
@ -66,7 +66,12 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form ref="tableHeaderForm" :model="state.tableHeaderForm" label-position="top">
|
||||
<el-form
|
||||
:model="state.tableHeaderForm"
|
||||
:disabled="!state.tableHeaderForm.showTableHeader"
|
||||
ref="tableHeaderForm"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item
|
||||
:label="t('chart.backgroundColor')"
|
||||
class="form-item"
|
||||
@ -245,34 +250,6 @@ onMounted(() => {
|
||||
{{ t('chart.table_header_sort') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('showColTooltip')"
|
||||
>
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.tableHeaderForm.showColTooltip"
|
||||
@change="changeTableHeader('showColTooltip')"
|
||||
>
|
||||
{{ t('chart.table_show_col_tooltip') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('showRowTooltip')"
|
||||
>
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.tableHeaderForm.showRowTooltip"
|
||||
@change="changeTableHeader('showRowTooltip')"
|
||||
>
|
||||
{{ t('chart.table_show_row_tooltip') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
|
@ -184,7 +184,7 @@ const state = reactive({
|
||||
})
|
||||
|
||||
const filedList = computed(() => {
|
||||
return [...state.dimension, ...state.quota].filter(ele => ele.id !== 'count')
|
||||
return [...state.dimension, ...state.quota].filter(ele => ele.id !== 'count' && !!ele.summary)
|
||||
})
|
||||
|
||||
provide('filedList', () => filedList.value)
|
||||
@ -211,6 +211,7 @@ const getFields = (id, chartId) => {
|
||||
state.quota = (res.quotaList as unknown as Field[]) || []
|
||||
state.dimensionData = JSON.parse(JSON.stringify(state.dimension))
|
||||
state.quotaData = JSON.parse(JSON.stringify(state.quota))
|
||||
emitter.emit('dataset-change')
|
||||
})
|
||||
.catch(() => {
|
||||
state.dimension = []
|
||||
@ -739,6 +740,7 @@ const onAreaChange = val => {
|
||||
const onTypeChange = (render, type) => {
|
||||
view.value.render = render
|
||||
view.value.type = type
|
||||
emitter.emit('chart-type-change')
|
||||
// 处理配置项默认值,不同图表的同一配置项默认值不同
|
||||
const chartViewInstance = chartViewManager.getChartView(view.value.render, view.value.type)
|
||||
if (chartViewInstance) {
|
||||
@ -3289,7 +3291,7 @@ span {
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__content) {
|
||||
height: calc(100% - 33px);
|
||||
height: calc(100% - 35px);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
@ -349,7 +349,8 @@ export const DEFAULT_TABLE_HEADER: ChartTableHeaderAttr = {
|
||||
tableTitleHeight: 36,
|
||||
tableHeaderSort: false,
|
||||
showColTooltip: false,
|
||||
showRowTooltip: false
|
||||
showRowTooltip: false,
|
||||
showTableHeader: true
|
||||
}
|
||||
export const DEFAULT_TABLE_CELL: ChartTableCellAttr = {
|
||||
tableFontColor: '#000000',
|
||||
@ -1445,7 +1446,9 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
|
||||
tableLayoutMode: 'grid',
|
||||
calcTopN: false,
|
||||
topN: 5,
|
||||
topNLabel: '其他'
|
||||
topNLabel: '其他',
|
||||
gaugeAxisLine: true,
|
||||
gaugePercentLabel: true
|
||||
}
|
||||
|
||||
export const BASE_VIEW_CONFIG = {
|
||||
|
@ -26,7 +26,7 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
||||
propertyInner = {
|
||||
...BAR_EDITOR_PROPERTY_INNER,
|
||||
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'y-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'], 'axisLabelFormatter']
|
||||
}
|
||||
protected baseOptions: ColumnOptions = {
|
||||
@ -236,7 +236,7 @@ export class StackBar extends Bar {
|
||||
propertyInner = {
|
||||
...this['propertyInner'],
|
||||
'label-selector': [...BAR_EDITOR_PROPERTY_INNER['label-selector'], 'vPosition'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter']
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
|
||||
}
|
||||
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
||||
const baseOptions = super.configLabel(chart, options)
|
||||
@ -372,7 +372,7 @@ export class PercentageStackBar extends GroupStackBar {
|
||||
propertyInner = {
|
||||
...this['propertyInner'],
|
||||
'label-selector': ['color', 'fontSize', 'vPosition', 'reserveDecimalCount'],
|
||||
'tooltip-selector': ['color', 'fontSize']
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show']
|
||||
}
|
||||
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
||||
const baseOptions = super.configLabel(chart, options)
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { Options } from '@antv/g2plot/esm'
|
||||
const { t } = useI18n()
|
||||
/**
|
||||
* 对称柱状图
|
||||
@ -87,7 +88,17 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
|
||||
'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'],
|
||||
'function-cfg': ['emptyDataStrategy'],
|
||||
'label-selector': ['hPosition', 'seriesLabelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter']
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show']
|
||||
}
|
||||
|
||||
selectorSpec: EditorSelectorSpec = {
|
||||
...this['selectorSpec'],
|
||||
'dual-y-axis-selector': {
|
||||
title: `${t('chart.xAxis')}`
|
||||
},
|
||||
'x-axis-selector': {
|
||||
title: `${t('chart.yAxis')}`
|
||||
}
|
||||
}
|
||||
|
||||
drawChart(drawOptions: G2PlotDrawOptions<G2BidirectionalBar>): G2BidirectionalBar {
|
||||
@ -118,11 +129,27 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
|
||||
},
|
||||
interactions: [{ type: 'active-region' }],
|
||||
yField: ['value', 'valueExt'],
|
||||
appendPadding: getPadding(chart)
|
||||
appendPadding: getPadding(chart),
|
||||
meta: {
|
||||
field: {
|
||||
type: 'cat'
|
||||
}
|
||||
}
|
||||
}
|
||||
const customOptions = this.setupOptions(chart, initOptions)
|
||||
const options = {
|
||||
...customOptions
|
||||
}
|
||||
const xAxis = chart.xAxis
|
||||
if (xAxis?.length === 1 && xAxis[0].deType === 1) {
|
||||
const values = data2.map(item => item.field)
|
||||
options.meta = {
|
||||
field: {
|
||||
type: 'cat',
|
||||
values: values.reverse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = this.setupOptions(chart, initOptions)
|
||||
|
||||
// 开始渲染
|
||||
const newChart = new G2BidirectionalBar(container, options)
|
||||
|
||||
@ -418,6 +445,45 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
|
||||
return { ...options, label }
|
||||
}
|
||||
|
||||
protected configEmptyDataStrategy(
|
||||
chart: Chart,
|
||||
options: BidirectionalBarOptions
|
||||
): BidirectionalBarOptions {
|
||||
const { data } = options as unknown as Options
|
||||
if (!data?.length) {
|
||||
return options
|
||||
}
|
||||
const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy
|
||||
if (strategy === 'ignoreData') {
|
||||
const emptyFields = data
|
||||
.filter(obj => obj['value'] === null || obj['valueExt'] === null)
|
||||
.map(obj => obj['field'])
|
||||
return {
|
||||
...options,
|
||||
data: data.filter(obj => {
|
||||
if (emptyFields.includes(obj['field'])) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
const updateValues = (strategy: 'breakLine' | 'setZero', data: any[]) => {
|
||||
data.forEach(obj => {
|
||||
if (obj['value'] === null) {
|
||||
obj['value'] = strategy === 'breakLine' ? null : 0
|
||||
}
|
||||
if (obj['valueExt'] === null) {
|
||||
obj['valueExt'] = strategy === 'breakLine' ? null : 0
|
||||
}
|
||||
})
|
||||
}
|
||||
if (strategy === 'breakLine' || strategy === 'setZero') {
|
||||
updateValues(strategy, data)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: BidirectionalBarOptions) {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
|
@ -30,7 +30,7 @@ export const BAR_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'gradient'],
|
||||
'label-selector': ['fontSize', 'color', 'labelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show'],
|
||||
'x-axis-selector': [
|
||||
'name',
|
||||
'color',
|
||||
|
@ -34,7 +34,7 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
||||
propertyInner = {
|
||||
...BAR_EDITOR_PROPERTY_INNER,
|
||||
'label-selector': ['hPosition', 'seriesLabelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'x-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'], 'axisLabelFormatter']
|
||||
}
|
||||
axis: AxisType[] = [...BAR_AXIS_TYPE]
|
||||
@ -267,7 +267,7 @@ export class HorizontalStackBar extends HorizontalBar {
|
||||
propertyInner = {
|
||||
...this['propertyInner'],
|
||||
'label-selector': ['color', 'fontSize', 'hPosition', 'labelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter']
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
|
||||
}
|
||||
protected configLabel(chart: Chart, options: BarOptions): BarOptions {
|
||||
const baseOptions = super.configLabel(chart, options)
|
||||
@ -328,7 +328,7 @@ export class HorizontalPercentageStackBar extends HorizontalStackBar {
|
||||
propertyInner = {
|
||||
...this['propertyInner'],
|
||||
'label-selector': ['color', 'fontSize', 'hPosition', 'reserveDecimalCount'],
|
||||
'tooltip-selector': ['color', 'fontSize']
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show']
|
||||
}
|
||||
protected configLabel(chart: Chart, options: BarOptions): BarOptions {
|
||||
const baseOptions = super.configLabel(chart, options)
|
||||
|
@ -49,7 +49,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
||||
'background-overall-component': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'gradient'],
|
||||
'label-selector': ['hPosition', 'color', 'fontSize'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'],
|
||||
'y-axis-selector': ['name', 'color', 'fontSize', 'axisForm', 'axisLabel', 'position'],
|
||||
'function-cfg': ['emptyDataStrategy']
|
||||
}
|
||||
@ -62,7 +62,8 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
||||
isGroup: false,
|
||||
isPercent: true,
|
||||
isStack: true,
|
||||
xAxis: false
|
||||
xAxis: false,
|
||||
appendPadding: [0, 0, 10, 0]
|
||||
}
|
||||
|
||||
drawChart(drawOptions: G2PlotDrawOptions<G2Progress>): G2Progress {
|
||||
@ -98,13 +99,15 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
||||
const data1 = defaultTo(sourceData[0]?.data, [])
|
||||
const data2 = defaultTo(sourceData[1]?.data, [])
|
||||
const currentData = data2.map(item => {
|
||||
const progress = getCompletionRate(data1.find(i => i.field === item.field)?.value, item.value)
|
||||
return {
|
||||
...item,
|
||||
type: 'current',
|
||||
title: item.field,
|
||||
id: item.quotaList[0].id,
|
||||
originalValue: item.value,
|
||||
progress: getCompletionRate(data1.find(i => i.field === item.field)?.value, item.value)
|
||||
originalProgress: progress,
|
||||
progress: progress >= 100 ? 100 : progress
|
||||
}
|
||||
})
|
||||
const targetData = data1.map(item => {
|
||||
@ -223,7 +226,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
||||
if (item.type === 'target') {
|
||||
return ''
|
||||
}
|
||||
return (item.progress * 100).toFixed(2) + '%'
|
||||
return item.originalProgress.toFixed(2) + '%'
|
||||
}
|
||||
}
|
||||
if (label.position === 'top') {
|
||||
|
@ -39,7 +39,14 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
|
||||
propertyInner = {
|
||||
...BAR_EDITOR_PROPERTY_INNER,
|
||||
'label-selector': ['hPosition', 'color', 'fontSize', 'labelFormatter', 'showGap'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'showGap'],
|
||||
'tooltip-selector': [
|
||||
'fontSize',
|
||||
'color',
|
||||
'backgroundColor',
|
||||
'tooltipFormatter',
|
||||
'showGap',
|
||||
'show'
|
||||
],
|
||||
'x-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'], 'axisLabelFormatter']
|
||||
}
|
||||
axis: AxisType[] = [...BAR_AXIS_TYPE, 'yAxisExt']
|
||||
@ -47,7 +54,7 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
|
||||
data: [],
|
||||
xField: 'values',
|
||||
yField: 'field',
|
||||
colorFiled: 'category',
|
||||
colorField: 'category',
|
||||
isGroup: true,
|
||||
interactions: [
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
|
||||
'background-overall-component': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'gradient'],
|
||||
'label-selector': ['fontSize', 'color', 'vPosition', 'labelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'title-selector': [
|
||||
'title',
|
||||
'fontSize',
|
||||
@ -187,7 +187,7 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
|
||||
let tmpValue = totalMap[id]
|
||||
let color = 'grey'
|
||||
if (id === yAxis[0].id) {
|
||||
tmpValue = parseFloat(head.value as unknown as string)
|
||||
tmpValue = head.data.value
|
||||
color = head.color
|
||||
}
|
||||
const value = valueFormatter(tmpValue, formatter.formatterCfg)
|
||||
|
@ -261,7 +261,7 @@ export class StackArea extends Area {
|
||||
propertyInner = {
|
||||
...this['propertyInner'],
|
||||
'label-selector': ['fontSize', 'color', 'labelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter']
|
||||
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show']
|
||||
}
|
||||
protected configLabel(chart: Chart, options: AreaOptions): AreaOptions {
|
||||
const customAttr = parseJson(chart.customAttr)
|
||||
|
@ -15,7 +15,7 @@ export const LINE_EDITOR_PROPERTY: EditorProperty[] = [
|
||||
export const LINE_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
'label-selector': ['fontSize', 'color'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'],
|
||||
'basic-style-selector': [
|
||||
'colors',
|
||||
'alpha',
|
||||
|
@ -95,7 +95,8 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
// 禁用线上地图数据
|
||||
customFetchGeoData: () => null
|
||||
}
|
||||
options = this.setupOptions(chart, options, drawOption, geoJson)
|
||||
const context = { drawOption, geoJson }
|
||||
options = this.setupOptions(chart, options, context)
|
||||
const view = new Choropleth(container, options)
|
||||
const dotLayer = this.getDotLayer(chart, geoJson, drawOption)
|
||||
this.configZoomButton(chart, view)
|
||||
@ -170,10 +171,10 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
private configBasicStyle(
|
||||
chart: Chart,
|
||||
options: ChoroplethOptions,
|
||||
extra: any[]
|
||||
context: Record<string, any>
|
||||
): ChoroplethOptions {
|
||||
const { areaId }: L7PlotDrawOptions<any> = extra[0]
|
||||
const geoJson: FeatureCollection = extra[1]
|
||||
const { areaId }: L7PlotDrawOptions<any> = context.drawOption
|
||||
const geoJson: FeatureCollection = context.geoJson
|
||||
const { basicStyle, label } = parseJson(chart.customAttr)
|
||||
const senior = parseJson(chart.senior)
|
||||
const curAreaNameMapping = senior.areaMapping?.[areaId]
|
||||
@ -208,7 +209,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
protected setupOptions(
|
||||
chart: Chart,
|
||||
options: ChoroplethOptions,
|
||||
...extra: any[]
|
||||
context: Record<string, any>
|
||||
): ChoroplethOptions {
|
||||
return flow(
|
||||
this.configEmptyDataStrategy,
|
||||
@ -216,6 +217,6 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
this.configStyle,
|
||||
this.configTooltip,
|
||||
this.configBasicStyle
|
||||
)(chart, options, extra)
|
||||
)(chart, options, context)
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export const MAP_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'showDimension',
|
||||
'showQuota'
|
||||
],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'tooltipFormatter'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'tooltipFormatter', 'show'],
|
||||
'function-cfg': ['emptyDataStrategy'],
|
||||
'map-mapping': ['']
|
||||
}
|
||||
|
@ -96,7 +96,8 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
// 禁用线上地图数据
|
||||
customFetchGeoData: () => null
|
||||
}
|
||||
options = this.setupOptions(chart, options, drawOption, geoJson)
|
||||
const context = { drawOption, geoJson }
|
||||
options = this.setupOptions(chart, options, context)
|
||||
const view = new Choropleth(container, options)
|
||||
this.configZoomButton(chart, view)
|
||||
view.once('loaded', () => {
|
||||
@ -120,10 +121,10 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
private configBasicStyle(
|
||||
chart: Chart,
|
||||
options: ChoroplethOptions,
|
||||
extra: any[]
|
||||
context: Record<string, any>
|
||||
): ChoroplethOptions {
|
||||
const { areaId }: L7PlotDrawOptions<any> = extra[0]
|
||||
const geoJson: FeatureCollection = extra[1]
|
||||
const { areaId }: L7PlotDrawOptions<any> = context.drawOption
|
||||
const geoJson: FeatureCollection = context.geoJson
|
||||
const { basicStyle, label } = parseJson(chart.customAttr)
|
||||
const senior = parseJson(chart.senior)
|
||||
const curAreaNameMapping = senior.areaMapping?.[areaId]
|
||||
@ -176,7 +177,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
protected setupOptions(
|
||||
chart: Chart,
|
||||
options: ChoroplethOptions,
|
||||
...extra: any[]
|
||||
context: Record<string, any>
|
||||
): ChoroplethOptions {
|
||||
return flow(
|
||||
this.configEmptyDataStrategy,
|
||||
@ -185,6 +186,6 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
this.configTooltip,
|
||||
this.configBasicStyle,
|
||||
this.configLegend
|
||||
)(chart, options, extra)
|
||||
)(chart, options, context)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export const CHART_MIX_EDITOR_PROPERTY: EditorProperty[] = [
|
||||
export const CHART_MIX_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
'label-selector': ['fontSize', 'color'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'],
|
||||
'basic-style-selector': [
|
||||
'colors',
|
||||
'alpha',
|
||||
|
@ -24,7 +24,7 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
||||
'background-overall-component': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha'],
|
||||
'label-selector': ['fontSize', 'color', 'hPosition', 'labelFormatter'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'title-selector': [
|
||||
'show',
|
||||
'title',
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { merge } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -28,7 +29,7 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
]
|
||||
propertyInner: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'gaugeStyle', 'gradient'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'gradient', 'gaugeAxisLine', 'gaugePercentLabel'],
|
||||
'label-selector': ['fontSize', 'color', 'labelFormatter'],
|
||||
'title-selector': [
|
||||
'title',
|
||||
@ -77,10 +78,6 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
label: {
|
||||
style: {
|
||||
fontSize: getScaleValue(12, scale) // 刻度值字体大小
|
||||
},
|
||||
formatter: function (v) {
|
||||
const r = parseFloat(v)
|
||||
return v === '0' || !r ? v : r * 100 + '%'
|
||||
}
|
||||
},
|
||||
tickLine: {
|
||||
@ -98,11 +95,15 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
}
|
||||
}
|
||||
}
|
||||
const options = this.setupOptions(chart, initOptions, scale)
|
||||
const options = this.setupOptions(chart, initOptions, { scale })
|
||||
return new G2Gauge(container, options)
|
||||
}
|
||||
|
||||
protected configMisc(chart: Chart, options: GaugeOptions): GaugeOptions {
|
||||
protected configMisc(
|
||||
chart: Chart,
|
||||
options: GaugeOptions,
|
||||
context: Record<string, any>
|
||||
): GaugeOptions {
|
||||
const customAttr = parseJson(chart.customAttr)
|
||||
const data = chart.data.series[0].data[0]
|
||||
let min, max, startAngle, endAngle
|
||||
@ -123,6 +124,8 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
}
|
||||
startAngle = (misc.gaugeStartAngle * Math.PI) / 180
|
||||
endAngle = (misc.gaugeEndAngle * Math.PI) / 180
|
||||
context.min = min
|
||||
context.max = max
|
||||
}
|
||||
const percent = (parseFloat(data) - parseFloat(min)) / (parseFloat(max) - parseFloat(min))
|
||||
const tmp = {
|
||||
@ -133,8 +136,12 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
return { ...options, ...tmp }
|
||||
}
|
||||
|
||||
private configRange(chart: Chart, options: GaugeOptions, extra: any[]): GaugeOptions {
|
||||
const [scale] = extra
|
||||
private configRange(
|
||||
chart: Chart,
|
||||
options: GaugeOptions,
|
||||
context: Record<string, any>
|
||||
): GaugeOptions {
|
||||
const { scale } = context
|
||||
const range = [0]
|
||||
let index = 0
|
||||
let flag = false
|
||||
@ -216,36 +223,55 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
return { ...options, ...rangOptions }
|
||||
}
|
||||
|
||||
protected configLabel(chart: Chart, options: GaugeOptions): GaugeOptions {
|
||||
protected configLabel(
|
||||
chart: Chart,
|
||||
options: GaugeOptions,
|
||||
context?: Record<string, any>
|
||||
): GaugeOptions {
|
||||
const customAttr = parseJson(chart.customAttr)
|
||||
const data = chart.data.series[0].data[0]
|
||||
let labelContent
|
||||
if (customAttr.label) {
|
||||
const label = customAttr.label
|
||||
const labelFormatter = label.labelFormatter ?? DEFAULT_LABEL.labelFormatter
|
||||
if (label.show) {
|
||||
labelContent = {
|
||||
style: () => ({
|
||||
fontSize: label.fontSize,
|
||||
color: label.color
|
||||
}),
|
||||
formatter: function () {
|
||||
let value
|
||||
if (labelFormatter.type === 'percent') {
|
||||
value = options.percent
|
||||
} else {
|
||||
value = data
|
||||
}
|
||||
return valueFormatter(value, labelFormatter)
|
||||
let labelContent: GaugeOptions['statistic']['content'] = false
|
||||
const label = customAttr.label
|
||||
const labelFormatter = label.labelFormatter ?? DEFAULT_LABEL.labelFormatter
|
||||
if (label.show) {
|
||||
labelContent = {
|
||||
style: {
|
||||
fontSize: `${label.fontSize}`,
|
||||
color: label.color
|
||||
},
|
||||
formatter: function () {
|
||||
let value
|
||||
if (labelFormatter.type === 'percent') {
|
||||
value = options.percent
|
||||
} else {
|
||||
value = data
|
||||
}
|
||||
return valueFormatter(value, labelFormatter)
|
||||
}
|
||||
} else {
|
||||
labelContent = false
|
||||
}
|
||||
} as GaugeOptions['statistic']['content']
|
||||
}
|
||||
const statistic = {
|
||||
content: labelContent
|
||||
}
|
||||
const { gaugeAxisLine, gaugePercentLabel } = customAttr.basicStyle
|
||||
const { min, max } = context
|
||||
const tmp = {
|
||||
axis: {
|
||||
label: {
|
||||
formatter: v => {
|
||||
if (gaugeAxisLine === false) {
|
||||
return ''
|
||||
}
|
||||
if (gaugePercentLabel === false) {
|
||||
const val = v === '0' ? min : v === '1' ? max : min + (max - min) * v
|
||||
return valueFormatter(val, labelFormatter)
|
||||
}
|
||||
return v === '0' ? v : v * 100 + '%'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options = merge(options, tmp)
|
||||
return { ...options, statistic }
|
||||
}
|
||||
|
||||
@ -263,13 +289,17 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
||||
return chart
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: GaugeOptions, ...extra: any[]): GaugeOptions {
|
||||
protected setupOptions(
|
||||
chart: Chart,
|
||||
options: GaugeOptions,
|
||||
context: Record<string, any>
|
||||
): GaugeOptions {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
this.configMisc,
|
||||
this.configLabel,
|
||||
this.configRange
|
||||
)(chart, options, extra)
|
||||
)(chart, options, context)
|
||||
}
|
||||
constructor() {
|
||||
super('gauge', DEFAULT_DATA)
|
||||
|
@ -30,7 +30,7 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
propertyInner: EditorPropertyInner = {
|
||||
'basic-style-selector': ['colors', 'alpha', 'scatterSymbol', 'scatterSymbolSize'],
|
||||
'label-selector': ['fontSize', 'color'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'x-axis-selector': [
|
||||
'position',
|
||||
'name',
|
||||
|
@ -24,7 +24,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
|
||||
propertyInner: EditorPropertyInner = {
|
||||
'basic-style-selector': ['colors', 'alpha', 'radarShape'],
|
||||
'label-selector': ['seriesLabelFormatter'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'misc-style-selector': ['showName', 'color', 'fontSize', 'axisColor'],
|
||||
'title-selector': [
|
||||
'show',
|
||||
@ -42,6 +42,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
|
||||
'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition']
|
||||
}
|
||||
selectorSpec: EditorSelectorSpec = {
|
||||
...this['selectorSpec'],
|
||||
'misc-style-selector': {
|
||||
title: `${t('chart.tooltip_axis')}`
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ export class RangeBar extends G2PlotChartView<SankeyOptions, Sankey> {
|
||||
propertyInner = {
|
||||
...SANKEY_EDITOR_PROPERTY_INNER,
|
||||
'label-selector': ['color', 'fontSize'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter']
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
|
||||
}
|
||||
axis: AxisType[] = [...SANKEY_AXIS_TYPE]
|
||||
protected baseOptions: SankeyOptions = {
|
||||
|
@ -29,7 +29,7 @@ export class Scatter extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
propertyInner: EditorPropertyInner = {
|
||||
'basic-style-selector': ['colors', 'alpha', 'scatterSymbol', 'scatterSymbolSize'],
|
||||
'label-selector': ['fontSize', 'color', 'labelFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'x-axis-selector': [
|
||||
'position',
|
||||
'name',
|
||||
|
@ -29,7 +29,7 @@ export class Treemap extends G2PlotChartView<TreemapOptions, G2Treemap> {
|
||||
'basic-style-selector': ['colors', 'alpha'],
|
||||
'label-selector': ['fontSize', 'color', 'showDimension', 'showQuota', 'showProportion'],
|
||||
'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'title-selector': [
|
||||
'title',
|
||||
'fontSize',
|
||||
|
@ -41,7 +41,7 @@ export class WordCloud extends G2PlotChartView<WordCloudOptions, G2WordCloud> {
|
||||
'fontShadow'
|
||||
],
|
||||
'misc-selector': ['wordSizeRange', 'wordSpacing'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter']
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show']
|
||||
}
|
||||
axis: AxisType[] = ['xAxis', 'yAxis', 'filter']
|
||||
axisConfig: AxisConfig = {
|
||||
|
@ -22,7 +22,7 @@ export const PIE_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'showQuota',
|
||||
'showProportion'
|
||||
],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'radius'],
|
||||
'title-selector': [
|
||||
'title',
|
||||
|
@ -4,6 +4,7 @@ export const TABLE_EDITOR_PROPERTY: EditorProperty[] = [
|
||||
'table-header-selector',
|
||||
'table-cell-selector',
|
||||
'title-selector',
|
||||
'tooltip-selector',
|
||||
'function-cfg',
|
||||
'threshold',
|
||||
'scroll-cfg',
|
||||
@ -45,6 +46,7 @@ export const TABLE_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'letterSpace',
|
||||
'fontShadow'
|
||||
],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'],
|
||||
'function-cfg': ['emptyDataStrategy'],
|
||||
threshold: ['tableThreshold']
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { S2ChartView, S2DrawOptions } from '../../types/impl/s2'
|
||||
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { isNumber } from 'lodash-es'
|
||||
import { copyContent } from '@/views/chart/components/js/panel/common/common_table'
|
||||
import { copyContent, SortTooltip } from '@/views/chart/components/js/panel/common/common_table'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -18,7 +18,8 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
...TABLE_EDITOR_PROPERTY_INNER,
|
||||
'table-header-selector': [
|
||||
...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'],
|
||||
'tableHeaderSort'
|
||||
'tableHeaderSort',
|
||||
'showTableHeader'
|
||||
],
|
||||
'basic-style-selector': [
|
||||
'tableColumnMode',
|
||||
@ -107,7 +108,8 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
style: this.configStyle(chart),
|
||||
conditions: this.configConditions(chart),
|
||||
tooltip: {
|
||||
getContainer: () => containerDom
|
||||
getContainer: () => containerDom,
|
||||
renderTooltip: sheet => new SortTooltip(sheet)
|
||||
}
|
||||
}
|
||||
// 开启序号之后,第一列就是序号列,修改 label 即可
|
||||
@ -134,9 +136,23 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
}
|
||||
}
|
||||
// tooltip
|
||||
this.configTooltip(s2Options)
|
||||
// header interaction
|
||||
this.configHeaderInteraction(chart, s2Options)
|
||||
this.configTooltip(chart, s2Options)
|
||||
// 隐藏表头,保留顶部的分割线, 禁用表头横向 resize
|
||||
if (customAttr.tableHeader.showTableHeader === false) {
|
||||
s2Options.style.colCfg.height = 1
|
||||
s2Options.interaction = {
|
||||
resize: {
|
||||
colCellVertical: false
|
||||
}
|
||||
}
|
||||
s2Options.colCell = (node, sheet, config) => {
|
||||
node.label = ' '
|
||||
return new TableColCell(node, sheet, config)
|
||||
}
|
||||
} else {
|
||||
// header interaction
|
||||
this.configHeaderInteraction(chart, s2Options)
|
||||
}
|
||||
// 开始渲染
|
||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||
|
||||
@ -168,14 +184,10 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
}
|
||||
action(param)
|
||||
})
|
||||
|
||||
// hover
|
||||
const { showColTooltip } = customAttr.tableHeader
|
||||
if (showColTooltip) {
|
||||
// tooltip
|
||||
const { show } = customAttr.tooltip
|
||||
if (show) {
|
||||
newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||
}
|
||||
const { showTooltip } = customAttr.tableCell
|
||||
if (showTooltip) {
|
||||
newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||
}
|
||||
// header resize
|
||||
|
@ -2,7 +2,11 @@ import { S2ChartView, S2DrawOptions } from '@/views/chart/components/js/panel/ty
|
||||
import { S2Event, S2Options, TableSheet, TableColCell, ViewMeta, TableDataCell } from '@antv/s2'
|
||||
import { parseJson } from '@/views/chart/components/js/util'
|
||||
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { copyContent, getCurrentField } from '@/views/chart/components/js/panel/common/common_table'
|
||||
import {
|
||||
copyContent,
|
||||
getCurrentField,
|
||||
SortTooltip
|
||||
} from '@/views/chart/components/js/panel/common/common_table'
|
||||
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { isNumber } from 'lodash-es'
|
||||
@ -17,7 +21,8 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
...TABLE_EDITOR_PROPERTY_INNER,
|
||||
'table-header-selector': [
|
||||
...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'],
|
||||
'tableHeaderSort'
|
||||
'tableHeaderSort',
|
||||
'showTableHeader'
|
||||
]
|
||||
}
|
||||
axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter']
|
||||
@ -110,7 +115,8 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
style: this.configStyle(chart),
|
||||
conditions: this.configConditions(chart),
|
||||
tooltip: {
|
||||
getContainer: () => containerDom
|
||||
getContainer: () => containerDom,
|
||||
renderTooltip: sheet => new SortTooltip(sheet)
|
||||
}
|
||||
}
|
||||
// 开启序号之后,第一列就是序号列,修改 label 即可
|
||||
@ -133,9 +139,23 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
}
|
||||
}
|
||||
// tooltip
|
||||
this.configTooltip(s2Options)
|
||||
// header interaction
|
||||
this.configHeaderInteraction(chart, s2Options)
|
||||
this.configTooltip(chart, s2Options)
|
||||
// 隐藏表头,保留顶部的分割线, 禁用表头横向 resize
|
||||
if (customAttr.tableHeader.showTableHeader === false) {
|
||||
s2Options.style.colCfg.height = 1
|
||||
s2Options.interaction = {
|
||||
resize: {
|
||||
colCellVertical: false
|
||||
}
|
||||
}
|
||||
s2Options.colCell = (node, sheet, config) => {
|
||||
node.label = ' '
|
||||
return new TableColCell(node, sheet, config)
|
||||
}
|
||||
} else {
|
||||
// header interaction
|
||||
this.configHeaderInteraction(chart, s2Options)
|
||||
}
|
||||
// 开始渲染
|
||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||
|
||||
@ -167,13 +187,10 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
}
|
||||
action(param)
|
||||
})
|
||||
// hover
|
||||
const { showColTooltip } = customAttr.tableHeader
|
||||
if (showColTooltip) {
|
||||
// tooltip
|
||||
const { show } = customAttr.tooltip
|
||||
if (show) {
|
||||
newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||
}
|
||||
const { showTooltip } = customAttr.tableCell
|
||||
if (showTooltip) {
|
||||
newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||
}
|
||||
// header resize
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user