diff --git a/backend/src/main/java/io/dataease/commons/constants/StaticResourceConstants.java b/backend/src/main/java/io/dataease/commons/constants/StaticResourceConstants.java new file mode 100644 index 0000000000..86750b99df --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/constants/StaticResourceConstants.java @@ -0,0 +1,32 @@ +package io.dataease.commons.constants; + +import java.io.File; + +import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix; + +/** + * Author: wangjiahao + * Date: 2022/4/28 + * Description: + */ +public class StaticResourceConstants { + + public static final String FILE_PROTOCOL = "file://"; + + public static final String FILE_SEPARATOR = File.separator; + + public static final String USER_HOME = "/opt/dataease/data"; + + public static String WORK_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "static-resource" + FILE_SEPARATOR; + + /** + * Upload prefix. + */ + public final static String UPLOAD_URL_PREFIX = "static-resource"; + + /** + * url separator. + */ + public static final String URL_SEPARATOR = "/"; + +} diff --git a/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java b/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java index cd644a98a0..bce0fb98b3 100644 --- a/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java @@ -1,8 +1,14 @@ package io.dataease.commons.utils; +import static io.dataease.commons.constants.StaticResourceConstants.*; import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.util.Assert; +import sun.misc.BASE64Encoder; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; /** * Author: wangjiahao @@ -10,9 +16,8 @@ import org.springframework.util.Assert; * Description: */ public class StaticResourceUtils { - public static final String URL_SEPARATOR = "/"; - private static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + private final static String FILE_BASE_PATH = USER_HOME+ FILE_SEPARATOR+UPLOAD_URL_PREFIX; public static String ensureBoth(@NonNull String string, @NonNull String bothfix) { return ensureBoth(string, bothfix, bothfix); @@ -51,4 +56,45 @@ public class StaticResourceUtils { return StringUtils.removeEnd(string, suffix) + suffix; } + + /** + * + * @param imgFile local storage path + * @return + */ + public static String getImgFileToBase64(String imgFile) { + //Convert the picture file into byte array and encode it with Base64 + InputStream inputStream = null; + byte[] buffer = null; + //Read picture byte array + try { + inputStream = new FileInputStream(FILE_BASE_PATH+FILE_SEPARATOR+imgFile); + int count = 0; + while (count == 0) { + count = inputStream.available(); + } + buffer = new byte[count]; + inputStream.read(buffer); + } catch (IOException e) { + LogUtil.error(e); + }catch (Exception e){ + LogUtil.error(e); + }finally { + if (inputStream != null) { + try { + // Close InputStream + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + // Encode byte array as Base64 + if(buffer!=null){ + return new BASE64Encoder().encode(buffer); + }else{ + return null; + } + } + } diff --git a/backend/src/main/java/io/dataease/config/DeMvcConfig.java b/backend/src/main/java/io/dataease/config/DeMvcConfig.java index 04f73c5217..5c56212de1 100644 --- a/backend/src/main/java/io/dataease/config/DeMvcConfig.java +++ b/backend/src/main/java/io/dataease/config/DeMvcConfig.java @@ -1,13 +1,9 @@ package io.dataease.config; +import static io.dataease.commons.constants.StaticResourceConstants.*; import org.springframework.context.annotation.Configuration; -import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.io.File; -import java.util.concurrent.TimeUnit; - import static io.dataease.commons.utils.StaticResourceUtils.ensureBoth; import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix; @@ -18,24 +14,6 @@ import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix; */ @Configuration public class DeMvcConfig implements WebMvcConfigurer { - private static final String FILE_PROTOCOL = "file://"; - public static final String FILE_SEPARATOR = File.separator; - public static final String USER_HOME = "/opt/dataease/data"; - - private static String WORK_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "static-resource" + FILE_SEPARATOR; - - - /** - * Upload prefix. - */ - private final static String UPLOAD_URL_PREFIX = "static-resource"; - - - /** - * url separator. - */ - public static final String URL_SEPARATOR = "/"; - /** * Configuring static resource path * diff --git a/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java b/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java index aa5dbf9003..2e5e9d0955 100644 --- a/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java +++ b/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java @@ -23,7 +23,8 @@ public class PanelGroupRequest extends PanelGroupDTO { private String dynamicData; @ApiModelProperty("内部模板ID") private String templateId; - + @ApiModelProperty("静态文件") + private String staticResource; public PanelGroupRequest() { } diff --git a/backend/src/main/java/io/dataease/controller/request/panel/PanelShareRemoveRequest.java b/backend/src/main/java/io/dataease/controller/request/panel/PanelShareRemoveRequest.java index 595b194ec2..302115956c 100644 --- a/backend/src/main/java/io/dataease/controller/request/panel/PanelShareRemoveRequest.java +++ b/backend/src/main/java/io/dataease/controller/request/panel/PanelShareRemoveRequest.java @@ -15,4 +15,10 @@ public class PanelShareRemoveRequest implements Serializable { @ApiModelProperty("分享ID") private String shareId; + + @ApiModelProperty("分享类型{0:用户,1:角色,2:组织}") + private Integer type; + + @ApiModelProperty("目标ID") + private Long targetId; } diff --git a/backend/src/main/java/io/dataease/controller/request/resource/StaticResourceRequest.java b/backend/src/main/java/io/dataease/controller/request/resource/StaticResourceRequest.java new file mode 100644 index 0000000000..13b6ca831d --- /dev/null +++ b/backend/src/main/java/io/dataease/controller/request/resource/StaticResourceRequest.java @@ -0,0 +1,17 @@ +package io.dataease.controller.request.resource; + +import lombok.Data; + +import java.util.List; + +/** + * Author: wangjiahao + * Date: 2022/4/28 + * Description: + */ +@Data +public class StaticResourceRequest { + + private List resourcePathList; + +} diff --git a/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java index 8f4297289f..277552ecc3 100644 --- a/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java +++ b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java @@ -1,5 +1,6 @@ package io.dataease.controller.staticResource; +import io.dataease.controller.request.resource.StaticResourceRequest; import io.dataease.service.staticResource.StaticResourceService; import io.swagger.annotations.ApiOperation; import org.pentaho.ui.xul.stereotype.Controller; @@ -7,6 +8,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.util.Map; /** * Author: wangjiahao @@ -21,8 +23,14 @@ public class StaticResourceController { StaticResourceService staticResourceService; @PostMapping("upload/{fileId}") - @ApiOperation("Uploads static file") + @ApiOperation("上传静态文件") public void upload(@PathVariable("fileId") String fileId, @RequestPart("file") MultipartFile file) { staticResourceService.upload(fileId,file); } + + @PostMapping("findResourceAsBase64") + @ApiOperation("查找静态文件并转为Base64") + public Map findResourceAsBase64(@RequestBody StaticResourceRequest resourceRequest){ + return staticResourceService.findResourceAsBase64(resourceRequest); + } } diff --git a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java index 8022c7749f..d657c78556 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java @@ -8,7 +8,6 @@ import io.dataease.commons.utils.LogUtil; import io.dataease.commons.utils.TreeUtils; import io.dataease.controller.request.authModel.VAuthModelRequest; import io.dataease.controller.request.dataset.DataSetTableRequest; -import io.dataease.controller.request.panel.PanelGroupQueryRequest; import io.dataease.controller.request.panel.PanelGroupRequest; import io.dataease.controller.request.panel.PanelViewDetailsRequest; import io.dataease.dto.PanelGroupExtendDataDTO; @@ -17,7 +16,6 @@ import io.dataease.dto.chart.ChartViewDTO; import io.dataease.dto.dataset.DataSetTableDTO; import io.dataease.dto.panel.PanelGroupDTO; import io.dataease.dto.panel.po.PanelViewInsertDTO; -import io.dataease.excel.utils.EasyExcelExporter; import io.dataease.exception.DataEaseException; import io.dataease.ext.*; import io.dataease.i18n.Translator; @@ -26,6 +24,7 @@ import io.dataease.plugins.common.base.domain.*; import io.dataease.plugins.common.base.mapper.*; import io.dataease.service.chart.ChartViewService; import io.dataease.service.dataset.DataSetTableService; +import io.dataease.service.staticResource.StaticResourceService; import io.dataease.service.sys.SysAuthService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -39,13 +38,9 @@ import org.springframework.util.Assert; import org.springframework.util.Base64Utils; import javax.annotation.Resource; -import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URL; import java.util.*; import java.util.stream.Collectors; @@ -100,6 +95,8 @@ public class PanelGroupService { private PanelTemplateMapper templateMapper; @Resource private ExtPanelGroupExtendDataMapper extPanelGroupExtendDataMapper; + @Resource + private StaticResourceService staticResourceService; public List tree(PanelGroupRequest panelGroupRequest) { String userId = String.valueOf(AuthUtils.getUser().getUserId()); @@ -117,7 +114,6 @@ public class PanelGroupService { @DeCleaner(DePermissionType.PANEL) public PanelGroup saveOrUpdate(PanelGroupRequest request) { - String userName = AuthUtils.getUser().getUsername(); String panelId = request.getId(); if (StringUtils.isNotEmpty(panelId)) { panelViewService.syncPanelViews(request); @@ -223,12 +219,12 @@ public class PanelGroupService { /** - * @Description 查询仪表板信息 * @param panelId * @return + * @Description 查询仪表板信息 */ public PanelGroupDTO findOne(String panelId) { - Assert.notNull(panelId,"Method findOne panelId can not be null"); + Assert.notNull(panelId, "Method findOne panelId can not be null"); PanelGroupDTO panelGroup = extPanelGroupMapper.findOneWithPrivileges(panelId, String.valueOf(AuthUtils.getUser().getUserId())); // 默认仪表板取源仪表板样式 if (panelGroup != null && StringUtils.isNotEmpty(panelGroup.getSource())) { @@ -331,8 +327,9 @@ public class PanelGroupService { String templateStyle = null; String templateData = null; String dynamicData = null; + String staticResource = null; if (PanelConstants.NEW_PANEL_FROM.NEW.equals(newFrom)) { - + // do nothing } else { //内部模板新建 if (PanelConstants.NEW_PANEL_FROM.NEW_INNER_TEMPLATE.equals(newFrom)) { @@ -344,6 +341,7 @@ public class PanelGroupService { templateStyle = request.getPanelStyle(); templateData = request.getPanelData(); dynamicData = request.getDynamicData(); + staticResource = request.getStaticResource(); } Map dynamicDataMap = JSON.parseObject(dynamicData, Map.class); List panelViews = new ArrayList<>(); @@ -370,6 +368,8 @@ public class PanelGroupService { } request.setPanelData(templateData); request.setPanelStyle(templateStyle); + //Store static resource into the server + staticResourceService.saveFilesToServe(staticResource); } request.setId(newPanelId); request.setCreateTime(System.currentTimeMillis()); @@ -467,7 +467,7 @@ public class PanelGroupService { try { String snapshot = request.getSnapshot(); List details = request.getDetails(); - details.add(0,request.getHeader()); + details.add(0, request.getHeader()); HSSFWorkbook wb = new HSSFWorkbook(); //明细sheet HSSFSheet detailsSheet = wb.createSheet("数据"); @@ -494,28 +494,28 @@ public class PanelGroupService { for (int j = 0; j < rowData.length; j++) { HSSFCell cell = row.createCell(j); cell.setCellValue(rowData[j]); - if(i==0){// 头部 + if (i == 0) {// 头部 cell.setCellStyle(cellStyle); //设置列的宽度 - detailsSheet.setColumnWidth(j, 255*20); + detailsSheet.setColumnWidth(j, 255 * 20); } } } } } - if(StringUtils.isNotEmpty(snapshot)){ + if (StringUtils.isNotEmpty(snapshot)) { //截图sheet 1px ≈ 2.33dx ≈ 0.48 dy 8*24 个单元格 HSSFSheet snapshotSheet = wb.createSheet("图表"); - short reDefaultRowHeight = (short)Math.round(request.getSnapshotHeight()*3.5/8); - int reDefaultColumnWidth = (int)Math.round(request.getSnapshotWidth()*0.25/24); + short reDefaultRowHeight = (short) Math.round(request.getSnapshotHeight() * 3.5 / 8); + int reDefaultColumnWidth = (int) Math.round(request.getSnapshotWidth() * 0.25 / 24); snapshotSheet.setDefaultColumnWidth(reDefaultColumnWidth); snapshotSheet.setDefaultRowHeight(reDefaultRowHeight); //画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)i HSSFPatriarch patriarch = snapshotSheet.createDrawingPatriarch(); - HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, reDefaultColumnWidth, reDefaultColumnWidth,(short) 0, 0, (short)8, 24); + HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, reDefaultColumnWidth, reDefaultColumnWidth, (short) 0, 0, (short) 8, 24); anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_DO_RESIZE); - patriarch.createPicture(anchor, wb.addPicture(Base64Utils.decodeFromString(snapshot.replace(DATA_URL_TITLE,"")), HSSFWorkbook.PICTURE_TYPE_JPEG)); + patriarch.createPicture(anchor, wb.addPicture(Base64Utils.decodeFromString(snapshot.replace(DATA_URL_TITLE, "")), HSSFWorkbook.PICTURE_TYPE_JPEG)); } response.setContentType("application/vnd.ms-excel"); //文件名称 diff --git a/backend/src/main/java/io/dataease/service/panel/ShareService.java b/backend/src/main/java/io/dataease/service/panel/ShareService.java index 0501d52ea6..4155a4bf7f 100644 --- a/backend/src/main/java/io/dataease/service/panel/ShareService.java +++ b/backend/src/main/java/io/dataease/service/panel/ShareService.java @@ -92,9 +92,9 @@ public class ShareService { } else { shareNodes = typeSharedMap.get(key); } - - if (null != authURDMap.get(key)) { - Map dataMap = filterData(authURDMap.get(key), shareNodes); + List value = entry.getValue(); + if (null != value) { + Map dataMap = filterData(value, shareNodes); List newIds = (List) dataMap.get("add"); for (int i = 0; i < newIds.size(); i++) { Long id = newIds.get(i); @@ -340,8 +340,29 @@ public class ShareService { .collect(Collectors.toList()); } + @Transactional public void removeShares(PanelShareRemoveRequest removeRequest) { + String panelId = removeRequest.getPanelId(); extPanelShareMapper.removeShares(removeRequest); + AuthURD sharedAuthURD = new AuthURD(); + List removeIds = new ArrayList(){{add(removeRequest.getTargetId());}}; + buildRedAuthURD(removeRequest.getType(), removeIds, sharedAuthURD); + CurrentUserDto user = AuthUtils.getUser(); + Gson gson = new Gson(); + PanelGroup panel = panelGroupMapper.selectByPrimaryKey(panelId); + + String msg = panel.getName(); + + List msgParam = new ArrayList<>(); + msgParam.add(panelId); + Set redIds = AuthUtils.userIdsByURD(sharedAuthURD); + redIds.forEach(userId -> { + if (!user.getUserId().equals(userId)) { + DeMsgutil.sendMsg(userId, 3L, user.getNickName() + " 取消分享了仪表板【" + msg + "】,请查收!", + gson.toJson(msgParam)); + } + }); + } } diff --git a/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java index 61cc19bacd..175f5c7572 100644 --- a/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java +++ b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java @@ -1,21 +1,27 @@ package io.dataease.service.staticResource; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSON; import io.dataease.commons.utils.FileUtils; import io.dataease.commons.utils.LogUtil; +import io.dataease.commons.utils.StaticResourceUtils; +import io.dataease.controller.request.resource.StaticResourceRequest; import io.dataease.exception.DataEaseException; -import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.util.Base64Utils; +import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; import java.io.IOException; -import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; /** * Author: wangjiahao @@ -45,4 +51,38 @@ public class StaticResourceService { DataEaseException.throwException(e); } } + + public void saveFilesToServe(String staticResource){ + if(StringUtils.isNotEmpty(staticResource)){ + Map resource = JSON.parseObject(staticResource,Map.class); + for(Map.Entry entry:resource.entrySet()){ + String path = entry.getKey(); + Path uploadPath = Paths.get(staticDir.toString(), path.substring(path.lastIndexOf("/")+1,path.length())); + try{ + if (uploadPath.toFile().exists()) { + LogUtil.info("file exists"); + }else{ + String content = entry.getValue(); + if(StringUtils.isNotEmpty(content)){ + Files.createFile(uploadPath); + FileCopyUtils.copy(new BASE64Decoder().decodeBuffer(content),Files.newOutputStream(uploadPath)); + } + } + }catch (Exception e){ + LogUtil.error("template static resource save error"+e.getMessage()); + } + } + } + } + + public Map findResourceAsBase64(StaticResourceRequest resourceRequest){ + Map result = new HashMap<>(); + if(CollectionUtil.isNotEmpty(resourceRequest.getResourcePathList())){ + for(String path :resourceRequest.getResourcePathList()){ + String value = StaticResourceUtils.getImgFileToBase64(path.substring(path.lastIndexOf("/")+1,path.length())); + result.put(path,value); + } + } + return result; + } } diff --git a/frontend/src/api/staticResource/staticResource.js b/frontend/src/api/staticResource/staticResource.js index de424b0680..40ee10055e 100644 --- a/frontend/src/api/staticResource/staticResource.js +++ b/frontend/src/api/staticResource/staticResource.js @@ -24,3 +24,12 @@ export function uploadFileResult(file, callback) { }) } +export function findResourceAsBase64(params) { + return request({ + url: '/static/resource/findResourceAsBase64', + method: 'post', + data: params, + loading: false + }) +} + diff --git a/frontend/src/components/DeDrag/index.vue b/frontend/src/components/DeDrag/index.vue index 5ffc167358..92d86c0959 100644 --- a/frontend/src/components/DeDrag/index.vue +++ b/frontend/src/components/DeDrag/index.vue @@ -542,9 +542,9 @@ export default { style['padding'] = (this.element.commonBackground.innerPadding || 0) + 'px' style['border-radius'] = (this.element.commonBackground.borderRadius || 0) + 'px' if (this.element.commonBackground.enable) { - if (this.element.commonBackground.backgroundType === 'innerImage') { + if (this.element.commonBackground.backgroundType === 'innerImage' && this.element.commonBackground.innerImage) { style['background'] = `url(${this.element.commonBackground.innerImage}) no-repeat` - } else if (this.element.commonBackground.backgroundType === 'outerImage') { + } else if (this.element.commonBackground.backgroundType === 'outerImage' && this.element.commonBackground.outerImage) { style['background'] = `url(${this.element.commonBackground.outerImage}) no-repeat` } else if (this.element.commonBackground.backgroundType === 'color') { style['background-color'] = hexColorToRGBA(this.element.commonBackground.color, this.element.commonBackground.alpha) diff --git a/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue b/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue index 166baa82ac..a192165007 100644 --- a/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue +++ b/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue @@ -28,6 +28,7 @@ :style="getComponentStyleDefault(config.style)" :prop-value="config.propValue" :is-edit="false" + :in-screen="inScreen" :active="componentActiveFlag" :element="config" :search-count="searchCount" @@ -104,13 +105,13 @@ export default { style['padding'] = (this.config.commonBackground.innerPadding || 0) + 'px' style['border-radius'] = (this.config.commonBackground.borderRadius || 0) + 'px' if (this.config.commonBackground.enable) { - if (this.config.commonBackground.backgroundType === 'innerImage') { + if (this.config.commonBackground.backgroundType === 'innerImage' && this.config.commonBackground.innerImage) { let innerImage = this.config.commonBackground.innerImage if (this.screenShot) { innerImage = innerImage.replace('svg', 'png') } style['background'] = `url(${innerImage}) no-repeat` - } else if (this.config.commonBackground.backgroundType === 'outerImage') { + } else if (this.config.commonBackground.backgroundType === 'outerImage' && this.config.commonBackground.outerImage) { style['background'] = `url(${this.config.commonBackground.outerImage}) no-repeat` } else if (this.config.commonBackground.backgroundType === 'color') { style['background-color'] = hexColorToRGBA(this.config.commonBackground.color, this.config.commonBackground.alpha) diff --git a/frontend/src/components/canvas/custom-component/DeStreamMedia.vue b/frontend/src/components/canvas/custom-component/DeStreamMedia.vue index f541f7b468..d6242c99f7 100644 --- a/frontend/src/components/canvas/custom-component/DeStreamMedia.vue +++ b/frontend/src/components/canvas/custom-component/DeStreamMedia.vue @@ -1,9 +1,9 @@