mirror of
https://github.com/dataease/dataease.git
synced 2025-02-24 19:42:56 +08:00
Merge pull request #9891 from dataease/pr@dev-v2_export_data
Pr@dev v2 export data
This commit is contained in:
commit
6e6df50914
@ -1,6 +1,6 @@
|
||||
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/
|
||||
|
@ -83,6 +83,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);
|
||||
|
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> {
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
@ -41,6 +42,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 +50,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 +63,8 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
|
||||
@Resource
|
||||
private ChartViewManege chartViewManege;
|
||||
@Resource
|
||||
private CoreChartViewMapper coreChartViewMapper;
|
||||
|
||||
@Resource
|
||||
private ExtDataVisualizationMapper extDataVisualizationMapper;
|
||||
@ -391,4 +392,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.entity.WsMessage;
|
||||
import io.dataease.websocket.service.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,21 @@
|
||||
package io.dataease.websocket.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WsMessage<T> implements Serializable {
|
||||
private Long userId;
|
||||
|
||||
private String topic;
|
||||
|
||||
private T data;
|
||||
|
||||
|
||||
}
|
||||
|
@ -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,11 @@
|
||||
package io.dataease.websocket.service;
|
||||
|
||||
import io.dataease.websocket.entity.WsMessage;
|
||||
|
||||
|
||||
public interface WsService {
|
||||
|
||||
void releaseMessage(WsMessage wsMessage);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.dataease.websocket.service.impl;
|
||||
|
||||
import io.dataease.websocket.entity.WsMessage;
|
||||
import io.dataease.websocket.service.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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -250,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
core/core-frontend/src/assets/svg/de-refresh.svg
Normal file
1
core/core-frontend/src/assets/svg/de-refresh.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="1716540076970" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7068" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M912 480c-17.7 0-32 14.3-32 32 0 25-2.5 50-7.5 74.2-4.8 23.6-12 46.8-21.4 69-9.2 21.8-20.6 42.8-33.9 62.5-13.2 19.5-28.3 37.8-45 54.5s-35 31.8-54.5 45c-19.7 13.3-40.7 24.7-62.5 33.9-22.2 9.4-45.4 16.6-69 21.4-48.5 9.9-99.9 9.9-148.4 0-23.6-4.8-46.8-12-69-21.4-21.8-9.2-42.8-20.6-62.5-33.9-19.5-13.2-37.8-28.3-54.5-45s-31.8-35-45-54.5c-13.3-19.7-24.7-40.7-33.9-62.5-9.4-22.2-16.6-45.4-21.4-69-5-24.2-7.5-49.2-7.5-74.2s2.5-50 7.5-74.2c4.8-23.6 12-46.8 21.4-69 9.2-21.8 20.6-42.8 33.9-62.5 13.2-19.5 28.3-37.8 45-54.5s35-31.8 54.5-45c19.7-13.3 40.7-24.7 62.5-33.9 22.2-9.4 45.4-16.6 69-21.4 48.5-9.9 99.9-9.9 148.4 0 23.6 4.8 46.8 12 69 21.4 21.8 9.2 42.8 20.6 62.5 33.9 19.5 13.2 37.8 28.3 54.5 45 1.4 1.4 2.8 2.8 4.1 4.2H688c-17.7 0-32 14.3-32 32s14.3 32 32 32h160c17.7 0 32-14.3 32-32V128c0-17.7-14.3-32-32-32s-32 14.3-32 32v77.1c-19.2-19-40.1-36.2-62.4-51.3-23.1-15.6-47.8-29-73.4-39.8-26.1-11-53.4-19.5-81.1-25.2-56.9-11.6-117.1-11.6-174.1 0-27.8 5.7-55.1 14.2-81.1 25.2-25.6 10.8-50.3 24.2-73.4 39.8-22.9 15.4-44.4 33.2-63.9 52.7s-37.3 41-52.7 63.9c-15.6 23.1-29 47.8-39.8 73.4-11 26.1-19.5 53.4-25.2 81.1C83 453.4 80 482.7 80 512s3 58.6 8.8 87c5.7 27.8 14.2 55 25.2 81.1 10.8 25.6 24.2 50.3 39.8 73.4 15.4 22.9 33.2 44.4 52.7 63.9s41 37.3 63.9 52.7c23.1 15.6 47.8 29 73.4 39.8 26.1 11 53.4 19.5 81.1 25.2 28.5 5.8 57.7 8.8 87 8.8s58.6-3 87-8.8c27.8-5.7 55-14.2 81.1-25.2 25.6-10.8 50.3-24.2 73.4-39.8 22.9-15.5 44.4-33.2 63.9-52.7s37.3-41 52.7-63.9c15.6-23.1 29-47.8 39.8-73.4 11-26.1 19.5-53.4 25.2-81.1 5.8-28.5 8.8-57.7 8.8-87 0.2-17.7-14.1-32-31.8-32z" fill="#1875F0" p-id="7069"></path></svg>
|
After Width: | Height: | Size: 1.9 KiB |
@ -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 { ElMessage, ElTooltip } from 'element-plus-secondary'
|
||||
import { Button } from 'vant'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const copyStore = copyStoreWithOut()
|
||||
@ -312,12 +313,48 @@ 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(
|
||||
Button,
|
||||
{
|
||||
props: {
|
||||
type: 'text',
|
||||
size: 'mini'
|
||||
},
|
||||
class: 'btn-text',
|
||||
on: {
|
||||
click: () => {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
},
|
||||
'数据导出中心'
|
||||
),
|
||||
'查看进度,进行下载'
|
||||
]),
|
||||
iconClass,
|
||||
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'
|
||||
@ -81,6 +81,8 @@ import { exportExcelDownload } from '@/views/chart/components/js/util'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { assign } from 'lodash-es'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { Button } from 'vant'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
const downLoading = ref(false)
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const dialogShow = ref(false)
|
||||
@ -201,10 +203,45 @@ const downloadViewDetails = () => {
|
||||
}
|
||||
exportLoading.value = true
|
||||
exportExcelDownload(chart, () => {
|
||||
console.log('aa')
|
||||
openMessageLoading(exportData)
|
||||
exportLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const exportData = () => {
|
||||
// bus.$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(
|
||||
Button,
|
||||
{
|
||||
props: {
|
||||
type: 'text',
|
||||
size: 'mini'
|
||||
},
|
||||
class: 'btn-text',
|
||||
on: {
|
||||
click: () => {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
},
|
||||
'数据导出中心'
|
||||
),
|
||||
'查看进度,进行下载'
|
||||
]),
|
||||
iconClass,
|
||||
showClose: true,
|
||||
customClass
|
||||
})
|
||||
}
|
||||
const htmlToImage = () => {
|
||||
downLoading.value = true
|
||||
useEmitt().emitter.emit('renderChart-' + viewInfo.value.id)
|
||||
|
@ -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: '登录',
|
||||
|
@ -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')
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import { PickOptions } from '@antv/g2plot/esm/core/plot'
|
||||
import { innerExportDetails } from '@/api/chart'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useLinkStoreWithOut } from '@/store/modules/link'
|
||||
const { t } = useI18n()
|
||||
// 同时支持将hex和rgb,转换成rgba
|
||||
export function hexColorToRGBA(hex, alpha) {
|
||||
@ -460,18 +461,24 @@ export const exportExcelDownload = (chart, callBack?) => {
|
||||
viewInfo: chart,
|
||||
detailFields
|
||||
}
|
||||
const linkStore = useLinkStoreWithOut()
|
||||
|
||||
const method = innerExportDetails
|
||||
method(request)
|
||||
.then(res => {
|
||||
const blob = new Blob([res.data], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = excelName + '.xlsx' // 下载的文件名
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
callBack('success')
|
||||
if (linkStore.getLinkToken) {
|
||||
const blob = new Blob([res.data], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = excelName + '.xlsx' // 下载的文件名
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
callBack('success')
|
||||
} else {
|
||||
callBack && callBack(res)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Excel download error')
|
||||
|
@ -0,0 +1,530 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, h, onUnmounted, onMounted } from 'vue'
|
||||
import { EmptyBackground } from '@/components/empty-background'
|
||||
import { ElButton, ElMessage, ElMessageBox, ElTabPane, ElTabs } from 'element-plus-secondary'
|
||||
import { RefreshLeft } from '@element-plus/icons-vue'
|
||||
import eventBus from '@/utils/eventBus'
|
||||
import {
|
||||
exportTasks,
|
||||
exportRetry,
|
||||
downloadFile,
|
||||
exportDelete,
|
||||
exportDeleteAll,
|
||||
exportDeletePost
|
||||
} from '@/api/dataset'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import Icon from '@/components/icon-custom/src/Icon.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const tableData = ref([])
|
||||
const drawerLoading = ref(false)
|
||||
const drawer = ref(false)
|
||||
const exportDatasetLoading = ref(false)
|
||||
const activeName = ref('ALL')
|
||||
const multipleSelection = ref([])
|
||||
const description = ref('暂无任务')
|
||||
const tabList = ref([
|
||||
{
|
||||
label: '导出中(0)',
|
||||
name: 'IN_PROGRESS'
|
||||
},
|
||||
{
|
||||
label: '成功(0)',
|
||||
name: 'SUCCESS'
|
||||
},
|
||||
{
|
||||
label: '失败(0)',
|
||||
name: 'FAILED'
|
||||
},
|
||||
{
|
||||
label: '等待中(0)',
|
||||
name: 'PENDING'
|
||||
},
|
||||
{
|
||||
label: '全部(0)',
|
||||
name: 'ALL'
|
||||
}
|
||||
])
|
||||
let timer
|
||||
const handleClose = () => {
|
||||
drawer.value = false
|
||||
clearInterval(timer)
|
||||
}
|
||||
onMounted(() => {
|
||||
eventBus.on('task-export-topic-call', taskExportTopicCall)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(timer)
|
||||
})
|
||||
const handleClick = tab => {
|
||||
if (tab) {
|
||||
activeName.value = tab.paneName
|
||||
}
|
||||
if (activeName.value === 'ALL') {
|
||||
description.value = t('data_export.no_file')
|
||||
} else if (activeName.value === 'FAILED') {
|
||||
description.value = t('data_export.no_failed_file')
|
||||
} else {
|
||||
description.value = t('data_export.no_task')
|
||||
}
|
||||
|
||||
tableData.value = []
|
||||
drawerLoading.value = true
|
||||
exportTasks(activeName.value)
|
||||
.then(res => {
|
||||
tabList.value.forEach(item => {
|
||||
if (item.name === 'ALL') {
|
||||
item.label = '全部' + '(' + res.data.length + ')'
|
||||
}
|
||||
if (item.name === 'IN_PROGRESS') {
|
||||
item.label =
|
||||
'导出中' +
|
||||
'(' +
|
||||
res.data.filter(task => task.exportStatus === 'IN_PROGRESS').length +
|
||||
')'
|
||||
}
|
||||
if (item.name === 'SUCCESS') {
|
||||
item.label =
|
||||
'成功' + '(' + res.data.filter(task => task.exportStatus === 'SUCCESS').length + ')'
|
||||
}
|
||||
if (item.name === 'FAILED') {
|
||||
item.label =
|
||||
'失败' + '(' + res.data.filter(task => task.exportStatus === 'FAILED').length + ')'
|
||||
}
|
||||
if (item.name === 'PENDING') {
|
||||
item.label =
|
||||
'等待中' + '(' + res.data.filter(task => task.exportStatus === 'PENDING').length + ')'
|
||||
}
|
||||
})
|
||||
if (activeName.value === 'ALL') {
|
||||
tableData.value = res.data
|
||||
} else {
|
||||
tableData.value = res.data.filter(task => task.exportStatus === activeName.value)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
drawerLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const init = () => {
|
||||
drawer.value = true
|
||||
handleClick()
|
||||
timer = setInterval(() => {
|
||||
if (activeName.value === 'IN_PROGRESS') {
|
||||
exportTasks(activeName.value).then(res => {
|
||||
tabList.value.forEach(item => {
|
||||
if (item.name === 'ALL') {
|
||||
item.label = '全部' + '(' + res.data.length + ')'
|
||||
}
|
||||
if (item.name === 'IN_PROGRESS') {
|
||||
item.label =
|
||||
'导出中' +
|
||||
'(' +
|
||||
res.data.filter(task => task.exportStatus === 'IN_PROGRESS').length +
|
||||
')'
|
||||
}
|
||||
if (item.name === 'SUCCESS') {
|
||||
item.label =
|
||||
'成功' + '(' + res.data.filter(task => task.exportStatus === 'SUCCESS').length + ')'
|
||||
}
|
||||
if (item.name === 'FAILED') {
|
||||
item.label =
|
||||
'失败' + '(' + res.data.filter(task => task.exportStatus === 'FAILED').length + ')'
|
||||
}
|
||||
if (item.name === 'PENDING') {
|
||||
item.label =
|
||||
'等待中' + '(' + res.data.filter(task => task.exportStatus === 'PENDING').length + ')'
|
||||
}
|
||||
})
|
||||
if (activeName.value === 'ALL') {
|
||||
tableData.value = res.data
|
||||
} else {
|
||||
tableData.value = res.data.filter(task => task.exportStatus === activeName.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
const taskExportTopicCall = task => {
|
||||
if (JSON.parse(task).exportStatus === 'SUCCESS') {
|
||||
openMessageLoading(
|
||||
JSON.parse(task).exportFromName + ' 导出成功,前往',
|
||||
'success',
|
||||
callbackExport
|
||||
)
|
||||
}
|
||||
if (JSON.parse(task).exportStatus === 'FAILED') {
|
||||
openMessageLoading(JSON.parse(task).exportFromName + ' 导出失败,前往', 'error', callbackExport)
|
||||
}
|
||||
}
|
||||
|
||||
const openMessageLoading = (text, type = 'success', cb) => {
|
||||
// success error loading
|
||||
const customClass = `de-message-${type || 'success'} de-message-export`
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
t(text),
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'mini',
|
||||
class: 'btn-text',
|
||||
onClick: () => {
|
||||
cb()
|
||||
}
|
||||
},
|
||||
t('data_export.export_center')
|
||||
)
|
||||
]),
|
||||
icon: type === 'loading' ? h(RefreshLeft) : '',
|
||||
duration: 0,
|
||||
type,
|
||||
showClose: true,
|
||||
customClass
|
||||
})
|
||||
}
|
||||
|
||||
const callbackExport = () => {
|
||||
useEmitt().emitter.emit('data-export-center')
|
||||
}
|
||||
|
||||
const downLoadAll = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
tableData.value.forEach(item => {
|
||||
downloadFile(item.id)
|
||||
.then(res => {
|
||||
const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = item.fileName // 下载的文件名
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
.finally(() => {
|
||||
exportDatasetLoading.value = false
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
multipleSelection.value.map(ele => {
|
||||
downloadFile(ele.id)
|
||||
.then(res => {
|
||||
const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = ele.fileName // 下载的文件名
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
.finally(() => {
|
||||
exportDatasetLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
const timestampFormatDate = value => {
|
||||
if (!value) {
|
||||
return '-'
|
||||
}
|
||||
return new Date(value).toLocaleString()
|
||||
}
|
||||
const downloadClick = item => {
|
||||
downloadFile(item.id)
|
||||
.then(res => {
|
||||
const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = item.fileName // 下载的文件名
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
.finally(() => {
|
||||
exportDatasetLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const retry = item => {
|
||||
exportRetry(item.id).then(() => {
|
||||
handleClick()
|
||||
})
|
||||
}
|
||||
|
||||
const deleteField = item => {
|
||||
ElMessageBox.confirm(t('data_export.sure_del'), {
|
||||
confirmButtonType: 'danger',
|
||||
type: 'warning',
|
||||
autofocus: false,
|
||||
showClose: false
|
||||
})
|
||||
.then(() => {
|
||||
exportDelete(item.id).then(() => {
|
||||
ElMessage.success(t('commons.delete_success'))
|
||||
handleClick()
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
// info(t('commons.delete_cancel'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleSelectionChange = val => {
|
||||
multipleSelection.value = val
|
||||
}
|
||||
|
||||
const confirmDelete = () => {
|
||||
const options = {
|
||||
title: '确定删除该任务吗?',
|
||||
type: 'primary',
|
||||
cb: deleteField
|
||||
}
|
||||
// handlerConfirm(options)
|
||||
}
|
||||
|
||||
const delAll = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
ElMessageBox.confirm(t('data_export.sure_del_all'), {
|
||||
confirmButtonType: 'danger',
|
||||
type: 'warning',
|
||||
autofocus: false,
|
||||
showClose: false
|
||||
})
|
||||
.then(() => {
|
||||
exportDeleteAll(
|
||||
activeName.value,
|
||||
multipleSelection.value.map(ele => ele.id)
|
||||
).then(() => {
|
||||
ElMessage.success(t('commons.delete_success'))
|
||||
handleClick()
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
// info(t('commons.delete_cancel'))
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(t('data_export.sure_del'), {
|
||||
confirmButtonType: 'danger',
|
||||
type: 'warning',
|
||||
autofocus: false,
|
||||
showClose: false
|
||||
})
|
||||
.then(() => {
|
||||
exportDeletePost(multipleSelection.value.map(ele => ele.id)).then(() => {
|
||||
ElMessage.success(t('commons.delete_success'))
|
||||
handleClick()
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
// info(t('commons.delete_cancel'))
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
init
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
v-loading="drawerLoading"
|
||||
custom-class="de-export-excel"
|
||||
:title="$t('data_export.export_center')"
|
||||
v-model="drawer"
|
||||
direction="rtl"
|
||||
size="1000px"
|
||||
append-to-body
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane v-for="tab in tabList" :key="tab.name" :label="tab.label" :name="tab.name" />
|
||||
</el-tabs>
|
||||
<el-button
|
||||
v-show="activeName === 'SUCCESS' && multipleSelection.length === 0"
|
||||
secondary
|
||||
@click="downLoadAll"
|
||||
>
|
||||
<template #icon>
|
||||
<Icon name="de-delete"></Icon>
|
||||
</template>
|
||||
{{ $t('data_export.download_all') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-show="activeName === 'SUCCESS' && multipleSelection.length !== 0"
|
||||
secondary
|
||||
@click="downLoadAll"
|
||||
><template #icon> <Icon name="de-delete"></Icon> </template>{{ $t('data_export.download') }}
|
||||
</el-button>
|
||||
<el-button v-show="multipleSelection.length === 0" secondary @click="delAll"
|
||||
><template #icon> <Icon name="de-delete"></Icon> </template>{{ $t('data_export.del_all') }}
|
||||
</el-button>
|
||||
<el-button v-show="multipleSelection.length !== 0" secondary @click="delAll"
|
||||
><template #icon> <Icon name="de-delete"></Icon> </template>{{ $t('commons.delete') }}
|
||||
</el-button>
|
||||
<div class="table-container" :class="!tableData.length && 'hidden-bottom'">
|
||||
<el-table
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column prop="fileName" :label="$t('driver.file_name')" width="332">
|
||||
<template #default="scope">
|
||||
<div class="name-excel">
|
||||
<el-icon>
|
||||
<Icon name="file-excel_colorful"></Icon>
|
||||
</el-icon>
|
||||
<div class="name-content">
|
||||
<div class="fileName">{{ scope.row.fileName }}</div>
|
||||
<div v-if="scope.row.exportStatus === 'FAILED'" class="failed">
|
||||
{{ $t('data_export.export_failed') }}
|
||||
</div>
|
||||
<div v-if="scope.row.exportStatus === 'SUCCESS'" class="success">
|
||||
{{ scope.row.fileSize }}{{ scope.row.fileSizeUnit }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="scope.row.exportStatus === 'FAILED'" class="red-line" />
|
||||
<el-progress
|
||||
v-if="scope.row.exportStatus === 'IN_PROGRESS'"
|
||||
:percentage="+scope.row.exportPogress"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="exportFromName" :label="$t('data_export.export_obj')" width="200" />
|
||||
<el-table-column prop="exportFromType" width="120" :label="$t('data_export.export_from')">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.exportFromType === 'dataset'">数据集</span>
|
||||
<span v-if="scope.row.exportFromType === 'chart'">视图</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="exportTime" width="180" :label="$t('data_export.export_time')">
|
||||
<template #default="scope">
|
||||
<span>{{ timestampFormatDate(scope.row.exportTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" prop="operate" width="150" :label="$t('commons.operating')">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.exportStatus === 'SUCCESS'"
|
||||
type="text"
|
||||
@click="downloadClick(scope.row)"
|
||||
>
|
||||
<div class="download-export">
|
||||
<el-icon>
|
||||
<Icon name="dv-preview-download"></Icon>
|
||||
</el-icon>
|
||||
</div>
|
||||
</el-button>
|
||||
<el-button type="text" @click="retry(scope.row)">
|
||||
<template #icon>
|
||||
<Icon name="de-refresh"></Icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button type="text" @click="deleteField(scope.row)">
|
||||
<template #icon>
|
||||
<Icon name="de-delete"></Icon>
|
||||
</template>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<empty-background :description="description" img-type="noneWhite" />
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.de-export-excel {
|
||||
.ed-drawer__header {
|
||||
border-bottom: none;
|
||||
}
|
||||
.ed-tabs {
|
||||
margin-top: -25px;
|
||||
.ed-tabs__header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.download-export {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-top: 16px;
|
||||
|
||||
.ed-table .cell {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
&.hidden-bottom {
|
||||
.ed-table::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.name-excel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.name-content {
|
||||
max-width: 280px;
|
||||
margin-left: 4px;
|
||||
.fileName {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.failed {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: #f54a45;
|
||||
}
|
||||
|
||||
.success {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: #8f959e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ed-table__header {
|
||||
border-top: 1px solid #1f232926;
|
||||
}
|
||||
|
||||
th.ed-table__cell.is-leaf {
|
||||
border-color: #1f232926;
|
||||
}
|
||||
|
||||
.red-line {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: #f54a45;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
35
core/core-frontend/src/websocket/index.ts
Normal file
35
core/core-frontend/src/websocket/index.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import SockJS from 'sockjs-client/dist/sockjs.min.js'
|
||||
import Stomp from 'stompjs'
|
||||
import eventBus from '@/utils/eventBus'
|
||||
let stompClient: Stomp.Client
|
||||
|
||||
export default {
|
||||
install() {
|
||||
const channels = [
|
||||
{
|
||||
topic: '/task-export-topic',
|
||||
event: 'task-export-topic-call'
|
||||
}
|
||||
]
|
||||
|
||||
const socket = new SockJS('http://localhost:8100' + '/websocket' + '?userId=1')
|
||||
stompClient = Stomp.over(socket)
|
||||
const heads = {
|
||||
userId: 1
|
||||
}
|
||||
stompClient.connect(
|
||||
heads,
|
||||
res => {
|
||||
console.log('连接成功: ' + res)
|
||||
channels.forEach(channel => {
|
||||
stompClient.subscribe('/user/' + 1 + channel.topic, res => {
|
||||
res && res.body && eventBus.emit(channel.event, res.body)
|
||||
})
|
||||
})
|
||||
},
|
||||
error => {
|
||||
console.log('连接失败: ' + error)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ services:
|
||||
- ${DE_BASE}/dataease2.0/cache:/opt/dataease2.0/cache
|
||||
- ${DE_BASE}/dataease2.0/data/geo:/opt/dataease2.0/data/geo
|
||||
- ${DE_BASE}/dataease2.0/data/appearance:/opt/dataease2.0/data/appearance
|
||||
- ${DE_BASE}/dataease2.0/data/exportData:/opt/dataease2.0/data/exportData
|
||||
depends_on:
|
||||
DE_MYSQL_HOST:
|
||||
condition: service_healthy
|
||||
|
@ -27,7 +27,7 @@ function prop {
|
||||
|
||||
function check_and_prepare_env_params() {
|
||||
log "当前时间 : $(date)"
|
||||
log_title "检查安装环境并初始化环境变量"
|
||||
log_title "检查安装环境并初始化环境变量"
|
||||
|
||||
cd ${CURRENT_DIR}
|
||||
if [ -f /usr/bin/dectl ]; then
|
||||
@ -39,10 +39,10 @@ function check_and_prepare_env_params() {
|
||||
log_content "停止 DataEase 服务"
|
||||
if [[ -f /etc/systemd/system/dataease.service ]];then
|
||||
systemctl stop dataease
|
||||
else
|
||||
else
|
||||
dectl stop
|
||||
fi
|
||||
|
||||
|
||||
INSTALL_TYPE='upgrade'
|
||||
|
||||
v2_version=$(dectl version | head -n 2 | grep "v2.")
|
||||
@ -99,7 +99,7 @@ function prepare_de_run_base() {
|
||||
env | grep DE_ >.env
|
||||
|
||||
mkdir -p ${DE_RUN_BASE}/{cache,logs,conf}
|
||||
mkdir -p ${DE_RUN_BASE}/data/{mysql,static-resource,map,etcd_data,geo,appearance}
|
||||
mkdir -p ${DE_RUN_BASE}/data/{mysql,static-resource,map,etcd_data,geo,appearance,exportData}
|
||||
mkdir -p ${DE_RUN_BASE}/apisix/logs
|
||||
mkdir -p ${DE_RUN_BASE}/task/logs
|
||||
chmod 777 ${DE_RUN_BASE}/apisix/logs ${DE_RUN_BASE}/data/etcd_data ${DE_RUN_BASE}/task/logs
|
||||
@ -132,7 +132,7 @@ function update_dectl() {
|
||||
\cp dectl /usr/local/bin && chmod +x /usr/local/bin/dectl
|
||||
if [ ! -f /usr/bin/dectl ]; then
|
||||
ln -s /usr/local/bin/dectl /usr/bin/dectl 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function prepare_system_settings() {
|
||||
@ -312,4 +312,4 @@ function main() {
|
||||
start_de_service
|
||||
}
|
||||
|
||||
main
|
||||
main
|
||||
|
7
pom.xml
7
pom.xml
@ -75,6 +75,13 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
|
@ -0,0 +1,41 @@
|
||||
package io.dataease.api.exportCenter;
|
||||
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.dataease.api.exportCenter.vo.ExportTaskDTO;
|
||||
import io.dataease.auth.DeApiPath;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.dataease.constant.AuthResourceEnum.DATASOURCE;
|
||||
|
||||
@Tag(name = "数据导出中心")
|
||||
@ApiSupport(order = 971)
|
||||
@DeApiPath(value = "/exportCenter", rt = DATASOURCE)
|
||||
public interface ExportCenterApi {
|
||||
|
||||
|
||||
@PostMapping("/exportTasks/{status}")
|
||||
public List<ExportTaskDTO> exportTasks(@PathVariable String status) ;
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
public void delete(@PathVariable String id);
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody List<String> ids);
|
||||
|
||||
@PostMapping("/deleteAll/{type}")
|
||||
public void deleteAll(@PathVariable String type);
|
||||
|
||||
@GetMapping("/download/{id}")
|
||||
public void download(@PathVariable String id, HttpServletResponse response) throws Exception ;
|
||||
|
||||
@PostMapping("/retry/{id}")
|
||||
public void retry(@PathVariable String id);
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.dataease.api.exportCenter.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ExportTaskDTO {
|
||||
@JsonSerialize(using= ToStringSerializer.class)
|
||||
private String id;
|
||||
@JsonSerialize(using= ToStringSerializer.class)
|
||||
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 exportFromName;
|
||||
}
|
@ -269,4 +269,24 @@ public class FileUtils {
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
public static boolean deleteDirectoryRecursively(String directoryPath) {
|
||||
File directory = new File(directoryPath);
|
||||
if (!directory.exists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
File[] files = directory.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
deleteDirectoryRecursively(file.getAbsolutePath());
|
||||
} else {
|
||||
boolean deletionSuccess = file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
return directory.delete();
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ public class WhitelistUtils {
|
||||
|| StringUtils.startsWithAny(requestURI, "/share/proxyInfo")
|
||||
|| StringUtils.startsWithAny(requestURI, "/xpackComponent/content/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/geo/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/websocket")
|
||||
|| StringUtils.startsWithAny(requestURI, "/map/");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user