diff --git a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java index 024d821ff2..683cb561a6 100644 --- a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java +++ b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import io.dataease.api.dataset.union.DatasetGroupInfoDTO; import io.dataease.api.dataset.union.UnionDTO; import io.dataease.api.dataset.vo.DataSetBarVO; +import io.dataease.api.permissions.relation.api.RelationApi; import io.dataease.commons.constants.OptConstants; import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup; import io.dataease.dataset.dao.auto.entity.CoreDatasetTable; @@ -35,6 +36,7 @@ import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -43,6 +45,8 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; +import static io.dataease.result.ResultCode.DV_RESOURCE_UNCHECKED; + /** * @Author Junjun */ @@ -75,6 +79,9 @@ public class DatasetGroupManage { @Resource private CoreOptRecentManage coreOptRecentManage; + @Autowired(required = false) + private RelationApi relationManage; + private static final String leafType = "dataset"; private Lock lock = new ReentrantLock(); @@ -176,6 +183,21 @@ public class DatasetGroupManage { return datasetGroupInfoDTO; } + public boolean perDelete(Long id) { + if (LicenseUtil.licenseValid()) { + try { + relationManage.checkAuth(); + } catch (Exception e) { + return false; + } + Long count = relationManage.getDatasetResource(id); + if (count > 0) { + return true; + } + } + return false; + } + @XpackInteract(value = "authResourceTree", before = false) public void delete(Long id) { CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id); diff --git a/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetTreeServer.java b/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetTreeServer.java index 05815fd531..3e0f9e8aa9 100644 --- a/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetTreeServer.java +++ b/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetTreeServer.java @@ -49,6 +49,11 @@ public class DatasetTreeServer implements DatasetTreeApi { return datasetGroupManage.move(dto); } + @Override + public boolean perDelete(Long id) { + return datasetGroupManage.perDelete(id); + } + @DeLog(id = "#p0", ot = LogOT.DELETE, st = LogST.DATASET) @Override public void delete(Long id) { diff --git a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java index 101a58d36e..0b4d40699b 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java @@ -13,6 +13,7 @@ import io.dataease.api.ds.vo.ApiDefinition; import io.dataease.api.ds.vo.CoreDatasourceTaskLogDTO; import io.dataease.api.ds.vo.ExcelFileData; import io.dataease.api.ds.vo.ExcelSheetData; +import io.dataease.api.permissions.relation.api.RelationApi; import io.dataease.commons.constants.TaskStatus; import io.dataease.constant.LogOT; import io.dataease.constant.LogST; @@ -69,6 +70,7 @@ import java.util.stream.Collectors; import static io.dataease.datasource.server.DatasourceTaskServer.ScheduleType.MANUAL; import static io.dataease.datasource.server.DatasourceTaskServer.ScheduleType.RIGHTNOW; +import static io.dataease.result.ResultCode.DS_RESOURCE_UNCHECKED; @RestController @@ -106,6 +108,8 @@ public class DatasourceServer implements DatasourceApi { @Autowired(required = false) private PluginManageApi pluginManage; + @Autowired(required = false) + private RelationApi relationManage; @Override public List query(String keyWord) { @@ -627,6 +631,22 @@ public class DatasourceServer implements DatasourceApi { return datasourceDTO; } + @Override + public boolean perDelete(Long id) { + if (LicenseUtil.licenseValid()) { + try { + relationManage.checkAuth(); + } catch (Exception e) { + return false; + } + Long count = relationManage.getDsResource(id); + if (count > 0) { + return true; + } + } + return false; + } + @Transactional @DeLog(id = "#p0", ot = LogOT.DELETE, st = LogST.DATASOURCE) @Override diff --git a/core/core-backend/src/main/java/io/dataease/engine/constant/SQLConstants.java b/core/core-backend/src/main/java/io/dataease/engine/constant/SQLConstants.java index 28d6395879..e1aa7542dc 100644 --- a/core/core-backend/src/main/java/io/dataease/engine/constant/SQLConstants.java +++ b/core/core-backend/src/main/java/io/dataease/engine/constant/SQLConstants.java @@ -94,4 +94,6 @@ public class SQLConstants { public static final String QUARTER = "QUARTER(%s)"; public static final String EMPTY_SIGN = "_empty_$"; + + public static final String CONCAT = "CONCAT(%s, %s)"; } diff --git a/core/core-frontend/public/svg/icon_app_outlined.svg b/core/core-frontend/public/svg/icon_app_outlined.svg new file mode 100644 index 0000000000..3548abb421 --- /dev/null +++ b/core/core-frontend/public/svg/icon_app_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/core-frontend/public/svg/icon_dashboard_outlined.svg b/core/core-frontend/public/svg/icon_dashboard_outlined.svg new file mode 100644 index 0000000000..3435cd2ce5 --- /dev/null +++ b/core/core-frontend/public/svg/icon_dashboard_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/core-frontend/public/svg/icon_database_outlined.svg b/core/core-frontend/public/svg/icon_database_outlined.svg new file mode 100644 index 0000000000..b19453c41c --- /dev/null +++ b/core/core-frontend/public/svg/icon_database_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/core-frontend/public/svg/icon_operation-analysis_outlined.svg b/core/core-frontend/public/svg/icon_operation-analysis_outlined.svg new file mode 100644 index 0000000000..6a792ff4a3 --- /dev/null +++ b/core/core-frontend/public/svg/icon_operation-analysis_outlined.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/core/core-frontend/src/components/data-visualization/DvToolbar.vue b/core/core-frontend/src/components/data-visualization/DvToolbar.vue index c594b1ad20..7bbbba187c 100644 --- a/core/core-frontend/src/components/data-visualization/DvToolbar.vue +++ b/core/core-frontend/src/components/data-visualization/DvToolbar.vue @@ -28,6 +28,7 @@ import DeFullscreen from '@/components/visualization/common/DeFullscreen.vue' import DeAppApply from '@/views/common/DeAppApply.vue' import { useEmitt } from '@/hooks/web/useEmitt' import { useUserStoreWithOut } from '@/store/modules/user' +import TabsGroup from '@/custom-component/component-group/TabsGroup.vue' let nameEdit = ref(false) let inputName = ref('') let nameInput = ref(null) @@ -332,6 +333,9 @@ const fullScreenPreview = () => { > + + + diff --git a/core/core-frontend/src/components/data-visualization/canvas/CanvasCore.vue b/core/core-frontend/src/components/data-visualization/canvas/CanvasCore.vue index 51e56d9970..bd402be76a 100644 --- a/core/core-frontend/src/components/data-visualization/canvas/CanvasCore.vue +++ b/core/core-frontend/src/components/data-visualization/canvas/CanvasCore.vue @@ -576,7 +576,7 @@ const editStyle = computed(() => { } } else { const result = { - ...getCanvasStyle(canvasStyleData.value), + ...getCanvasStyle(canvasStyleData.value, canvasId.value), width: changeStyleWithScale(canvasStyleData.value.width) + 'px', height: changeStyleWithScale(canvasStyleData.value.height) + 'px' } diff --git a/core/core-frontend/src/components/data-visualization/canvas/Shape.vue b/core/core-frontend/src/components/data-visualization/canvas/Shape.vue index ebbcd7115f..f63d1656f3 100644 --- a/core/core-frontend/src/components/data-visualization/canvas/Shape.vue +++ b/core/core-frontend/src/components/data-visualization/canvas/Shape.vue @@ -530,7 +530,7 @@ const handleMouseDownOnShape = e => { contentDisplay.value = true } // 仪表板进行Tab碰撞检查 - dashboardActive.value && tabMoveInCheck() + tabMoveInCheck() // 仪表板模式 会造成移动现象 当检测组件正在碰撞有效区内或者移入有效区内 则周边组件不进行移动 if ( dashboardActive.value && diff --git a/core/core-frontend/src/custom-component/de-tabs/Component.vue b/core/core-frontend/src/custom-component/de-tabs/Component.vue index 7d9a1d425a..22b5523ee9 100644 --- a/core/core-frontend/src/custom-component/de-tabs/Component.vue +++ b/core/core-frontend/src/custom-component/de-tabs/Component.vue @@ -2,7 +2,7 @@
@@ -26,6 +26,7 @@ {{ tabItem.title }} editMode.value === 'edit' && isEdit.value && !mobileInPc.value) - +const curThemes = isDashboard() ? 'light' : 'dark' const calcTabLength = () => { setTimeout(() => { if (element.value.propValue.length > 1) { @@ -456,9 +457,20 @@ onBeforeMount(() => { :deep(.ed-tabs__content) { height: calc(100% - 46px) !important; } -:deep(.ed-tabs__new-tab) { - margin-right: 25px; - background-color: #fff; +.ed-tabs-dark { + :deep(.ed-tabs__new-tab) { + margin-right: 25px; + color: #fff; + } + :deep(.el-dropdown-link) { + color: #fff; + } +} +.ed-tabs-light { + :deep(.ed-tabs__new-tab) { + margin-right: 25px; + background-color: #fff; + } } .el-tab-pane-custom { width: 100%; diff --git a/core/core-frontend/src/utils/style.ts b/core/core-frontend/src/utils/style.ts index 9480be52e2..c311ed2de1 100644 --- a/core/core-frontend/src/utils/style.ts +++ b/core/core-frontend/src/utils/style.ts @@ -2,6 +2,7 @@ import { sin, cos } from '@/utils/translate' import { imgUrlTrans } from '@/utils/imgUtils' import { hexColorToRGBA } from '@/views/chart/components/js/util' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' +import { isMainCanvas } from '@/utils/canvasUtils' const dvMainStore = dvMainStoreWithOut() export function getShapeStyle(style) { const result = {} @@ -181,7 +182,7 @@ export function getComponentRotatedStyle(style) { return style } -export function getCanvasStyle(canvasStyleData) { +export function getCanvasStyle(canvasStyleData, canvasId = 'canvasMain') { const { backgroundColorSelect, background, @@ -191,27 +192,30 @@ export function getCanvasStyle(canvasStyleData) { mobileSetting } = canvasStyleData const style = { fontSize: fontSize + 'px', color: canvasStyleData.color } - // 仪表板默认色#f5f6f7 大屏默认配色 #1a1a1a - let colorRGBA = dvMainStore.dvInfo.type === 'dashboard' ? '#f5f6f7' : '#1a1a1a' - if (backgroundColorSelect && backgroundColor) { - colorRGBA = backgroundColor - } - if (backgroundImageEnable) { - style['background'] = `url(${imgUrlTrans(background)}) no-repeat ${colorRGBA}` - } else { - style['background-color'] = colorRGBA - } + if (isMainCanvas(canvasId)) { + // 仪表板默认色#f5f6f7 大屏默认配色 #1a1a1a + let colorRGBA = dvMainStore.dvInfo.type === 'dashboard' ? '#f5f6f7' : '#1a1a1a' + if (backgroundColorSelect && backgroundColor) { + colorRGBA = backgroundColor + } + if (backgroundImageEnable) { + style['background'] = `url(${imgUrlTrans(background)}) no-repeat ${colorRGBA}` + } else { + style['background-color'] = colorRGBA + } - if (dvMainStore.mobileInPc && mobileSetting?.customSetting) { - const { backgroundColorSelect, color, backgroundImageEnable, background } = mobileSetting - if (backgroundColorSelect && backgroundImageEnable && typeof background === 'string') { - style['background'] = `url(${imgUrlTrans(background)}) no-repeat ${color}` - } else if (backgroundColorSelect) { - style['background-color'] = color - } else if (backgroundImageEnable) { - style['background'] = `url(${imgUrlTrans(background)}) no-repeat` + if (dvMainStore.mobileInPc && mobileSetting?.customSetting) { + const { backgroundColorSelect, color, backgroundImageEnable, background } = mobileSetting + if (backgroundColorSelect && backgroundImageEnable && typeof background === 'string') { + style['background'] = `url(${imgUrlTrans(background)}) no-repeat ${color}` + } else if (backgroundColorSelect) { + style['background-color'] = color + } else if (backgroundImageEnable) { + style['background'] = `url(${imgUrlTrans(background)}) no-repeat` + } } } + return style } diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix-common.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix-common.ts index e881172469..5358081ab4 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix-common.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix-common.ts @@ -29,7 +29,8 @@ export const CHART_MIX_EDITOR_PROPERTY_INNER: EditorPropertyInner = { 'lineSymbolSize', 'lineSmooth', 'radiusColumnBar', - 'subSeriesColor' + 'subSeriesColor', + 'seriesColor' ], 'x-axis-selector': [ 'name', diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts index cbffc6fee8..a5ff2ac46b 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts @@ -279,6 +279,25 @@ export class ColumnLineMix extends G2PlotChartView { ...options } const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle + + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis } = chart + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } //左轴 const color = basicStyle.colors.map(ele => { const tmp = hexColorToRGBA(ele, basicStyle.alpha) @@ -568,10 +587,6 @@ export class GroupColumnLineMix extends ColumnLineMix { axis: AxisType[] = [...this['axis'], 'xAxisExt'] propertyInner = { ...CHART_MIX_EDITOR_PROPERTY_INNER, - 'dual-basic-style-selector': [ - ...CHART_MIX_EDITOR_PROPERTY_INNER['dual-basic-style-selector'], - 'seriesColor' - ], 'label-selector': ['vPosition', 'seriesLabelFormatter'], 'tooltip-selector': [ ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], @@ -683,10 +698,6 @@ export class StackColumnLineMix extends ColumnLineMix { axis: AxisType[] = [...this['axis'], 'extStack'] propertyInner = { ...CHART_MIX_EDITOR_PROPERTY_INNER, - 'dual-basic-style-selector': [ - ...CHART_MIX_EDITOR_PROPERTY_INNER['dual-basic-style-selector'], - 'seriesColor' - ], 'label-selector': ['vPosition', 'seriesLabelFormatter'], 'tooltip-selector': [ ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/dataset/DatasetTreeApi.java b/sdk/api/api-base/src/main/java/io/dataease/api/dataset/DatasetTreeApi.java index 2d4f746357..ccafd39c93 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/dataset/DatasetTreeApi.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/dataset/DatasetTreeApi.java @@ -60,6 +60,10 @@ public interface DatasetTreeApi { @PostMapping("move") DatasetNodeDTO move(@RequestBody DatasetGroupInfoDTO dto) throws Exception; + @DePermit({"#p0+':manage'"}) + @PostMapping("perDelete/{id}") + boolean perDelete(@PathVariable("id") Long id); + @Operation(summary = "删除数据集") @DePermit({"#p0+':manage'"}) @PostMapping("delete/{id}") diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/ds/DatasourceApi.java b/sdk/api/api-base/src/main/java/io/dataease/api/ds/DatasourceApi.java index d4dfb17142..b7d5d3a88d 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/ds/DatasourceApi.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/ds/DatasourceApi.java @@ -66,6 +66,10 @@ public interface DatasourceApi { @GetMapping("/validate/{datasourceId}") DatasourceDTO validate(@PathVariable("datasourceId") Long datasourceId) throws DEException; + @DePermit({"#p0+':manage'"}) + @PostMapping("/perDelete/{datasourceId}") + boolean perDelete(@PathVariable("datasourceId") Long datasourceId); + @DePermit({"#p0+':manage'"}) @GetMapping("/delete/{datasourceId}") void delete(@PathVariable("datasourceId") Long datasourceId) throws DEException; diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/api/RelationApi.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/api/RelationApi.java new file mode 100644 index 0000000000..dd437695f6 --- /dev/null +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/api/RelationApi.java @@ -0,0 +1,14 @@ +package io.dataease.api.permissions.relation.api; + +import io.dataease.exception.DEException; + +/** + * @Author Junjun + */ +public interface RelationApi { + Long getDsResource(Long id); + + Long getDatasetResource(Long id); + + void checkAuth() throws DEException; +} diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/dto/RelationDTO.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/dto/RelationDTO.java new file mode 100644 index 0000000000..53a993c734 --- /dev/null +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/dto/RelationDTO.java @@ -0,0 +1,22 @@ +package io.dataease.api.permissions.relation.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.util.List; + +/** + * @Author Junjun + */ +@Data +public class RelationDTO { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + private String name; + private String auths; + private String type; + private String creator; + private Long updateTime; + private List subRelation; +} diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/dto/RelationListDTO.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/dto/RelationListDTO.java new file mode 100644 index 0000000000..e36b2238f7 --- /dev/null +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/relation/dto/RelationListDTO.java @@ -0,0 +1,31 @@ +package io.dataease.api.permissions.relation.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @Author Junjun + */ +@Data +public class RelationListDTO implements Serializable { + private Long dsId; + private String dsName; + private String dsCreator; + private Long dsUpdateTime; + + private Long datasetId; + private String datasetName; + private String datasetCreator; + private Long datasetUpdateTime; + + private Long dashboardId; + private String dashboardName; + private String dashboardCreator; + private Long dashboardUpdateTime; + + private Long dvId; + private String dvName; + private String dvCreator; + private Long dvUpdateTime; +} diff --git a/sdk/common/src/main/java/io/dataease/result/ResultCode.java b/sdk/common/src/main/java/io/dataease/result/ResultCode.java index 86ad357993..55e5849b3e 100644 --- a/sdk/common/src/main/java/io/dataease/result/ResultCode.java +++ b/sdk/common/src/main/java/io/dataease/result/ResultCode.java @@ -27,6 +27,9 @@ public enum ResultCode { RESULE_DATA_NONE(50001, "数据未找到"), DATA_IS_WRONG(50002, "数据有误"), DATA_ALREADY_EXISTED(50003, "数据已存在"), + DS_RESOURCE_UNCHECKED(50004, "%s个数据集正在使用此数据源,无法删除"), + + DV_RESOURCE_UNCHECKED(50004, "%s个仪表板或数据大屏正在使用此数据集,无法删除"), /* 接口错误:60001-69999 */ INTERFACE_INNER_INVOKE_ERROR(60001, "内部系统接口调用异常"),