diff --git a/README.md b/README.md index ccdc83186e..0fa9021e03 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ License: GPL v3 Codacy Stars - FOSSA Status

|说明| @@ -16,9 +15,7 @@ DataEase 是开源的数据可视化分析工具,帮助用户快速分析数据并洞察业务趋势,从而实现业务的改进与优化。DataEase 支持丰富的数据源连接,能够通过拖拉拽方式快速制作图表,并可以方便的与他人分享。 -**DataEase 的工作原理:** - -![image](https://github.com/dataease/dataease/assets/41712985/68d46fac-985e-4d1d-8548-2baadf9cd2e8) +![DataEase 概览图](https://github.com/dataease/dataease/assets/41712985/ef020c86-68e0-43a3-8054-f51463eae361) **DataEase 的优势:** @@ -55,10 +52,11 @@ DataEase 是开源的数据可视化分析工具,帮助用户快速分析数 ## DataEase 快速入门 -- 安装部署教程 -- 快速入门视频 -- 完整在线文档 -- 中文论坛支持 +- [安装部署教程](https://dataease.io/docs/installation/installation_mode/) +- [快速入门视频](https://www.bilibili.com/video/BV1qG4y1F7uc/) +- [完整在线文档](https://dataease.io/docs/) +- [中文社区论坛](https://bbs.fit2cloud.com/c/de/6) +- [模板应用市场](https://dataease.io/templates/) ## License diff --git a/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java b/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java index b0c2eba9d0..a4ca90c54a 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java +++ b/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java @@ -1106,11 +1106,11 @@ public class ChartDataBuild { break; } if (originStr.length() >= columnPermissionItem.getDesensitizationRule().getM() && originStr.length() >= columnPermissionItem.getDesensitizationRule().getN()) { - desensitizationStr = StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, columnPermissionItem.getDesensitizationRule().getN()) + "***"; + desensitizationStr = "***" + StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, columnPermissionItem.getDesensitizationRule().getN()) + "***"; break; } if (originStr.length() >= columnPermissionItem.getDesensitizationRule().getM() && originStr.length() < columnPermissionItem.getDesensitizationRule().getN()) { - desensitizationStr = StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, originStr.length()) + "***"; + desensitizationStr = "***" + StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, originStr.length()); } break; default: diff --git a/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java b/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java index a53682a812..b4c3059602 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java @@ -34,7 +34,7 @@ import java.util.stream.Collectors; public class ExcelUtils { - + public static final String UFEFF = "\uFEFF"; private static String path = "/opt/dataease/data/excel/"; private static ObjectMapper objectMapper = new ObjectMapper(); @@ -450,6 +450,9 @@ public class ExcelUtils { if(StringUtils.isEmpty(filedName)){ DEException.throwException("首行行中不允许有空单元格!"); } + if (filedName.startsWith(UFEFF)) { + filedName = filedName.replace(UFEFF, ""); + } TableField tableFiled = new TableField(); tableFiled.setName(filedName); tableFiled.setOriginName(filedName); 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 ec90781cfc..e7373c95a3 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 @@ -19,8 +19,6 @@ import io.dataease.api.permissions.user.vo.UserFormVO; import io.dataease.commons.constants.TaskStatus; import io.dataease.commons.utils.CommonThreadPool; import io.dataease.constant.DataSourceType; -import io.dataease.dataset.dao.auto.entity.CoreDatasetTable; -import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper; import io.dataease.dataset.dto.DatasourceSchemaDTO; import io.dataease.dataset.manage.DatasetDataManage; import io.dataease.dataset.utils.TableUtils; @@ -109,6 +107,14 @@ public class DatasourceServer implements DatasourceApi { private boolean isUpdatingStatus = false; + private void getParents(Long pid, List ids) { + CoreDatasource parent = datasourceMapper.selectById(pid);// 查找父级folder + ids.add(parent.getId()); + if (parent.getPid() != null && parent.getPid() != 0) { + getParents(parent.getPid(), ids); + } + } + public void move(DatasourceDTO dataSourceDTO) throws DEException { switch (dataSourceDTO.getAction()) { case "move" -> { @@ -116,7 +122,12 @@ public class DatasourceServer implements DatasourceApi { DEException.throwException("目录必选!"); } if (Objects.equals(dataSourceDTO.getId(), dataSourceDTO.getPid())) { - DEException.throwException("pid can not equal to id."); + DEException.throwException(Translator.get("i18n_pid_not_eq_id")); + } + List ids = new ArrayList<>(); + getParents(dataSourceDTO.getPid(), ids); + if (ids.contains(dataSourceDTO.getId())) { + DEException.throwException(Translator.get("i18n_pid_not_eq_id")); } dataSourceManage.move(dataSourceDTO); } @@ -144,8 +155,10 @@ public class DatasourceServer implements DatasourceApi { private void filterDs(List busiNodeVOS, List ids, String type, Long id) { for (BusiNodeVO busiNodeVO : busiNodeVOS) { if (busiNodeVO.getType() != null && busiNodeVO.getType().equalsIgnoreCase(type)) { - if (id != null && !busiNodeVO.getId().equals(id)) { - ids.add(busiNodeVO.getId()); + if (id != null) { + if (!busiNodeVO.getId().equals(id)) { + ids.add(busiNodeVO.getId()); + } } else { ids.add(busiNodeVO.getId()); } @@ -166,7 +179,7 @@ public class DatasourceServer implements DatasourceApi { List ids = new ArrayList<>(); filterDs(busiNodeVOS, ids, dataSourceDTO.getType(), dataSourceDTO.getId()); - if(CollectionUtil.isEmpty(ids)){ + if (CollectionUtil.isEmpty(ids)) { return false; } QueryWrapper wrapper = new QueryWrapper<>(); @@ -181,7 +194,7 @@ public class DatasourceServer implements DatasourceApi { boolean hasRepeat = false; for (CoreDatasource datasource : datasources) { if (Arrays.asList("API", "Excel", "folder").contains(datasource.getType())) { - continue; + continue; } DatasourceConfiguration compare = JsonUtil.parseObject(datasource.getConfiguration(), DatasourceConfiguration.class); switch (dataSourceDTO.getType()) { diff --git a/core/core-backend/src/main/java/io/dataease/visualization/manage/CoreVisualizationManage.java b/core/core-backend/src/main/java/io/dataease/visualization/manage/CoreVisualizationManage.java index 57b28b2f71..d4979bc207 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/manage/CoreVisualizationManage.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/manage/CoreVisualizationManage.java @@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.dataease.api.visualization.request.DataVisualizationBaseRequest; import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest; import io.dataease.api.visualization.vo.VisualizationResourceVO; -import io.dataease.api.visualization.vo.VisualizationStoreVO; import io.dataease.commons.constants.DataVisualizationConstants; import io.dataease.commons.constants.OptConstants; import io.dataease.constant.BusiResourceEnum; @@ -21,7 +20,6 @@ import io.dataease.visualization.dao.auto.entity.DataVisualizationInfo; import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper; import io.dataease.visualization.dao.ext.mapper.CoreVisualiationExtMapper; import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper; -import io.dataease.visualization.dao.ext.po.StorePO; import io.dataease.visualization.dao.ext.po.VisualizationNodePO; import io.dataease.visualization.dao.ext.po.VisualizationResourcePO; import io.dataease.visualization.dto.VisualizationNodeBO; @@ -30,7 +28,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.RequestBody; import java.util.*; @@ -84,30 +81,34 @@ public class CoreVisualizationManage { delIds.add(tempPid); List childrenIdList = extMapper.queryChildrenId(tempPid); if (CollectionUtil.isNotEmpty(childrenIdList)) { - stack.addAll(childrenIdList); + childrenIdList.forEach(kid -> { + if (!delIds.contains(kid)) { + stack.add(kid); + } + }); } } extMapper.batchDel(delIds, System.currentTimeMillis(), AuthUtils.getUser().getUserId()); - coreOptRecentManage.saveOpt(id, OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION,OptConstants.OPT_TYPE.DELETE); + coreOptRecentManage.saveOpt(id, OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION, OptConstants.OPT_TYPE.DELETE); } @XpackInteract(value = "visualizationResourceTree", before = false) public void move(DataVisualizationBaseRequest request) { - if(!request.getMoveFromUpdate()){ + if (!request.getMoveFromUpdate()) { DataVisualizationInfo visualizationInfo = new DataVisualizationInfo(); BeanUtils.copyBean(visualizationInfo, request); if (ObjectUtils.isEmpty(visualizationInfo.getId())) { DEException.throwException("resource not exist"); } visualizationInfo.setUpdateTime(System.currentTimeMillis()); - coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION,OptConstants.OPT_TYPE.UPDATE); + coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION, OptConstants.OPT_TYPE.UPDATE); mapper.updateById(visualizationInfo); } } @XpackInteract(value = "visualizationResourceTree", before = false) public Long innerSave(DataVisualizationInfo visualizationInfo) { - if(visualizationInfo.getId() == null){ + if (visualizationInfo.getId() == null) { Long id = IDUtils.snowID(); visualizationInfo.setId(id); } @@ -118,7 +119,7 @@ public class CoreVisualizationManage { visualizationInfo.setUpdateTime(System.currentTimeMillis()); visualizationInfo.setOrgId(AuthUtils.getUser().getDefaultOid()); mapper.insert(visualizationInfo); - coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION,OptConstants.OPT_TYPE.NEW); + coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION, OptConstants.OPT_TYPE.NEW); return visualizationInfo.getId(); } @@ -127,7 +128,7 @@ public class CoreVisualizationManage { visualizationInfo.setUpdateTime(System.currentTimeMillis()); visualizationInfo.setUpdateBy(AuthUtils.getUser().getUserId().toString()); mapper.updateById(visualizationInfo); - coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION,OptConstants.OPT_TYPE.UPDATE); + coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION, OptConstants.OPT_TYPE.UPDATE); } private boolean isTopNode(Long pid) { @@ -162,15 +163,15 @@ public class CoreVisualizationManage { return iPage; } - List formatResult(List pos){ - if (CollectionUtil.isEmpty(pos)){ + List formatResult(List pos) { + if (CollectionUtil.isEmpty(pos)) { return new ArrayList<>(); } return pos.stream().map(po -> new VisualizationResourceVO( po.getId(), po.getResourceId(), po.getName(), - po.getType(), String.valueOf(po.getCreator()),String.valueOf(po.getLastEditor()), po.getLastEditTime(), - po.getFavorite(),9)).toList(); + po.getType(), String.valueOf(po.getCreator()), String.valueOf(po.getLastEditor()), po.getLastEditTime(), + po.getFavorite(), 9)).toList(); } public IPage queryVisualizationPage(int goPage, int pageSize, VisualizationWorkbranchQueryRequest request) { @@ -188,6 +189,6 @@ public class CoreVisualizationManage { } queryWrapper.orderBy(true, request.isAsc(), "core_opt_recent.time"); Page page = new Page<>(goPage, pageSize); - return extDataVisualizationMapper.findRecent(page,uid, queryWrapper); + return extDataVisualizationMapper.findRecent(page, uid, queryWrapper); } } diff --git a/core/core-frontend/src/components/collapse-switch-item/src/CollapseSwitchItem.vue b/core/core-frontend/src/components/collapse-switch-item/src/CollapseSwitchItem.vue index c9ab2a9d91..4476ca562f 100644 --- a/core/core-frontend/src/components/collapse-switch-item/src/CollapseSwitchItem.vue +++ b/core/core-frontend/src/components/collapse-switch-item/src/CollapseSwitchItem.vue @@ -49,7 +49,7 @@ const switchValue = computed({ :effect="themes" size="small" v-model="switchValue" - @click.stop="e => onSwitchChange(e)" + @click.stop="onSwitchChange" /> @@ -63,5 +63,18 @@ const switchValue = computed({ align-items: center; padding-right: 8px; flex-grow: 1; + :deep(.ed-switch.is-checked .ed-switch__core > .ed-switch__action) { + left: calc(100% - 12px); + } + :deep(span.ed-switch__core) { + min-width: 24px; + border: none; + height: 6px; + border-radius: 3px; + .ed-switch__action { + left: 0; + box-shadow: 0 2px 4px rgba(31, 35, 41, 0.12); + } + } } diff --git a/core/core-frontend/src/components/data-visualization/RealTimeComponentList.vue b/core/core-frontend/src/components/data-visualization/RealTimeComponentList.vue index 7d87a48331..e4033579da 100644 --- a/core/core-frontend/src/components/data-visualization/RealTimeComponentList.vue +++ b/core/core-frontend/src/components/data-visualization/RealTimeComponentList.vue @@ -93,7 +93,9 @@ let nameEdit = ref(false) let editComponentId = ref('') let inputName = ref('') let nameInput = ref(null) +let curEditComponent = null const editComponentName = item => { + curEditComponent = curComponent.value editComponentId.value = `#component-label-${item.id}` nameEdit.value = true inputName.value = item.name @@ -106,11 +108,12 @@ const closeEditComponentName = () => { if (!inputName.value || !inputName.value.trim()) { return } - if (inputName.value.trim() === curComponent.value.name) { + if (inputName.value.trim() === curEditComponent.name) { return } - curComponent.value.name = inputName.value + curEditComponent.name = inputName.value inputName.value = '' + curEditComponent = null } const lock = () => { @@ -221,12 +224,15 @@ const handleContextMenu = e => { areaData.components.includes(getComponent(index)) }" @click="onClick($event, transformIndex(index))" - @dblclick="editComponentName(getComponent(index))" > - + {{ getComponent(index)?.name }}
{ } // 如果没有选中组件 在画布上点击时需要调用 e.preventDefault() 防止触发 drop 事件 if (!curComponent.value || isPreventDrop(curComponent.value.component)) { - e.preventDefault() + // e.preventDefault() } hideArea() const rectInfo = editorMap.value[canvasId.value].getBoundingClientRect() 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 1de352f086..bf14b0aa42 100644 --- a/core/core-frontend/src/components/data-visualization/canvas/Shape.vue +++ b/core/core-frontend/src/components/data-visualization/canvas/Shape.vue @@ -385,9 +385,9 @@ const handleMouseDownOnShape = e => { nextTick(() => eventBus.emit('componentClick')) dvMainStore.setInEditorStatus(true) dvMainStore.setClickComponentStatus(true) - if (isPreventDrop(element.value.component)) { - e.preventDefault() - } + // if (isPreventDrop(element.value.component)) { + // e.preventDefault() + // } e.stopPropagation() if (element.value['isLock'] || !isEditMode.value) return diff --git a/core/core-frontend/src/custom-component/component-list.ts b/core/core-frontend/src/custom-component/component-list.ts index 330e3bd9f1..78f0ed76ae 100644 --- a/core/core-frontend/src/custom-component/component-list.ts +++ b/core/core-frontend/src/custom-component/component-list.ts @@ -211,6 +211,7 @@ for (let i = 0, len = list.length; i < len; i++) { const item = list[i] item.style = { ...commonStyle, ...item.style } item['commonBackground'] = deepCopy(COMMON_COMPONENT_BACKGROUND_BASE) + item['state'] = 'prepare' list[i] = { ...commonAttr, ...item } } diff --git a/core/core-frontend/src/permission.ts b/core/core-frontend/src/permission.ts index a6226384bf..550d8bf2a1 100644 --- a/core/core-frontend/src/permission.ts +++ b/core/core-frontend/src/permission.ts @@ -49,6 +49,11 @@ router.beforeEach(async (to, from, next) => { return pre }, {}) } + if (!pathValid(to.path) && to.path !== '/404' && !to.path.startsWith('/de-link')) { + const firstPath = getFirstAuthMenu() + next({ path: firstPath || '/404' }) + return + } next() return } diff --git a/core/core-frontend/src/store/modules/data-visualization/copy.ts b/core/core-frontend/src/store/modules/data-visualization/copy.ts index 1e3b468234..7bf6d6f98e 100644 --- a/core/core-frontend/src/store/modules/data-visualization/copy.ts +++ b/core/core-frontend/src/store/modules/data-visualization/copy.ts @@ -107,8 +107,10 @@ export const copyStore = defineStore('copy', { eventBus.emit('addDashboardItem-' + newComponent.canvasId, newComponent) } }) - //占位优化 整合定位 - eventBus.emit('doCanvasInit-canvas-main') + if (dvInfo.value.type === 'dashboard') { + //占位优化 整合定位 + eventBus.emit('doCanvasInit-canvas-main') + } snapshotStore.recordSnapshotCache() }, cut() { diff --git a/core/core-frontend/src/store/modules/data-visualization/dvMain.ts b/core/core-frontend/src/store/modules/data-visualization/dvMain.ts index 88148d13b7..1ac36ccf3c 100644 --- a/core/core-frontend/src/store/modules/data-visualization/dvMain.ts +++ b/core/core-frontend/src/store/modules/data-visualization/dvMain.ts @@ -577,7 +577,11 @@ export const dvMainStore = defineStore('dataVisualization', { } else { viewInfo[propertyInfo.custom][propertyInfo.property] = propertyInfo.value } - useEmitt().emitter.emit('renderChart-' + viewId, viewInfo) + if (['tablePageMode', 'tablePageSize'].includes(propertyInfo.subProp)) { + useEmitt().emitter.emit('calcData-' + viewId, viewInfo) + } else { + useEmitt().emitter.emit('renderChart-' + viewId, viewInfo) + } }) } else { this.componentData.forEach(component => { diff --git a/core/core-frontend/src/store/modules/data-visualization/layer.ts b/core/core-frontend/src/store/modules/data-visualization/layer.ts index e44927cbcc..f373e10c8f 100644 --- a/core/core-frontend/src/store/modules/data-visualization/layer.ts +++ b/core/core-frontend/src/store/modules/data-visualization/layer.ts @@ -2,6 +2,7 @@ import { defineStore, storeToRefs } from 'pinia' import { store } from '../../index' import { dvMainStoreWithOut } from './dvMain' import { swap } from '@/utils/utils' +import { useEmitt } from '@/hooks/web/useEmitt' const dvMainStore = dvMainStoreWithOut() const { componentData, curComponentIndex, curComponent } = storeToRefs(dvMainStore) @@ -52,6 +53,11 @@ export const layerStore = defineStore('layer', { // 显示 if (curComponent && curComponent.value) { curComponent.value.isShow = true + if (curComponent.value.innerType.indexOf('table') !== -1) { + setTimeout(() => { + useEmitt().emitter.emit('renderChart-' + curComponent.value.id) + }, 400) + } } } } diff --git a/core/core-frontend/src/utils/DeShortcutKey.ts b/core/core-frontend/src/utils/DeShortcutKey.ts index 119103a51b..3f264b426b 100644 --- a/core/core-frontend/src/utils/DeShortcutKey.ts +++ b/core/core-frontend/src/utils/DeShortcutKey.ts @@ -83,6 +83,11 @@ const checkDialog = () => { haveDialog = true } }) + document.querySelectorAll('.ed-popover').forEach(element => { + if (window.getComputedStyle(element).getPropertyValue('display') != 'none') { + haveDialog = true + } + }) // 富文本单框 if (document.querySelector('.tox-dialog-wrap')) { haveDialog = true @@ -92,19 +97,24 @@ const checkDialog = () => { } let isCtrlOrCommandDown = false +let isShiftDown = false // 全局监听按键操作并执行相应命令 export function listenGlobalKeyDown() { window.onkeydown = e => { + console.log('e.keyCode-down=' + e.keyCode) if (!isInEditor || checkDialog()) return const { keyCode } = e if (positionMoveKey[keyCode] && curComponent.value) { positionMoveKey[keyCode](keyCode) e.preventDefault() } else if (keyCode === shiftKey) { + isShiftDown = true composeStore.setIsShiftDownStatus(true) + releaseKeyCheck() } else if (keyCode === ctrlKey || keyCode === commandKey) { isCtrlOrCommandDown = true composeStore.setIsCtrlOrCmdDownStatus(true) + releaseKeyCheck() } else if ((keyCode == deleteKey || keyCode == macDeleteKey) && curComponent.value) { deleteComponent() } else if (isCtrlOrCommandDown) { @@ -119,10 +129,12 @@ export function listenGlobalKeyDown() { } window.onkeyup = e => { + console.log('e.keyCode=' + e.keyCode) if (e.keyCode === ctrlKey || e.keyCode === commandKey) { isCtrlOrCommandDown = false composeStore.setIsCtrlOrCmdDownStatus(false) } else if (e.keyCode === shiftKey) { + isShiftDown = true composeStore.setIsShiftDownStatus(false) } } @@ -132,6 +144,16 @@ export function listenGlobalKeyDown() { } } +//当前不支持同时ctrl + shift操作 +function releaseKeyCheck() { + if (isCtrlOrCommandDown && isShiftDown) { + isCtrlOrCommandDown = false + composeStore.setIsCtrlOrCmdDownStatus(false) + isShiftDown = true + composeStore.setIsShiftDownStatus(false) + } +} + function copy() { copyStore.copy() } diff --git a/core/core-frontend/src/views/chart/components/editor/index.vue b/core/core-frontend/src/views/chart/components/editor/index.vue index 71bc3bacd8..fc5b4ba265 100644 --- a/core/core-frontend/src/views/chart/components/editor/index.vue +++ b/core/core-frontend/src/views/chart/components/editor/index.vue @@ -521,6 +521,11 @@ const calcData = (view, resetDrill = false, updateQuery = '') => { } } +const updateChartData = view => { + curComponent.value['state'] = 'ready' + calcData(view, true, 'updateQuery') +} + const renderChart = view => { useEmitt().emitter.emit('renderChart-' + view.id, view) snapshotStore.recordSnapshotCache('renderChart', view.id) @@ -1607,7 +1612,7 @@ const onRefreshChange = val => { {{ t('chart.update_chart_data') }} diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts index 4e43f0b772..600b280ebb 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts @@ -5,7 +5,7 @@ import { import { Line as G2Line, LineOptions } from '@antv/g2plot/esm/plots/line' import { getPadding } from '../../common/common_antv' import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util' -import { cloneDeep } from 'lodash-es' +import { cloneDeep, isEmpty } from 'lodash-es' import { valueFormatter } from '@/views/chart/components/js/formatter' import { LINE_AXIS_TYPE, @@ -214,11 +214,67 @@ export class Line extends G2PlotChartView { return tmpOptions } + protected configTooltip(chart: Chart, options: LineOptions): LineOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const xAxisExt = chart.xAxisExt + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: LineOptions['tooltip'] = { + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const head = originalItems[0] + // 非原始数据 + if (!head.data.quotaList) { + return originalItems + } + const result = [] + originalItems + .filter(item => formatterMap[item.data.quotaList[0].id]) + .forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + let name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + if (xAxisExt?.length > 0) { + name = item.data.category + } + result.push({ ...item, name, value }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + return result + } + } + return { + ...options, + tooltip + } + } + protected setupOptions(chart: Chart, options: LineOptions): LineOptions { return flow( this.configTheme, this.configLabel, - this.configMultiSeriesTooltip, + this.configTooltip, this.configBasicStyle, this.configCustomColors, this.configLegend, diff --git a/core/core-frontend/src/views/chart/components/views/components/ChartComponentS2.vue b/core/core-frontend/src/views/chart/components/views/components/ChartComponentS2.vue index 74d072a1bc..6e0093baf9 100644 --- a/core/core-frontend/src/views/chart/components/views/components/ChartComponentS2.vue +++ b/core/core-frontend/src/views/chart/components/views/components/ChartComponentS2.vue @@ -108,18 +108,21 @@ const renderChartFromDialog = (viewInfo: Chart, chartDataInfo) => { chartData.value = chartDataInfo renderChart(viewInfo, false) } -const renderChart = (view: Chart, resetPageInfo: boolean) => { - if (!view) { +const renderChart = (viewInfo: Chart, resetPageInfo: boolean) => { + if (!viewInfo) { return } // view 为引用对象 需要存库 view.data 直接赋值会导致保存不必要的数据 const chart = { - ...defaultsDeep(view, cloneDeep(BASE_VIEW_CONFIG)), + ...defaultsDeep(viewInfo, cloneDeep(BASE_VIEW_CONFIG)), data: chartData.value } as ChartObj setupPage(chart, resetPageInfo) myChart?.destroy() - const chartView = chartViewManager.getChartView(view.render, view.type) as S2ChartView + const chartView = chartViewManager.getChartView( + viewInfo.render, + viewInfo.type + ) as S2ChartView myChart = chartView.drawChart({ container: containerId, chart: toRaw(chart), diff --git a/core/core-frontend/src/views/chart/components/views/index.vue b/core/core-frontend/src/views/chart/components/views/index.vue index 11f71432c9..7a46020a24 100644 --- a/core/core-frontend/src/views/chart/components/views/index.vue +++ b/core/core-frontend/src/views/chart/components/views/index.vue @@ -434,7 +434,7 @@ onMounted(() => { } }) useEmitt({ - name: 'calcData-' + view.value.id, + name: 'calc-data-' + view.value.id, callback: function (val) { if (!state.initReady) { return @@ -453,8 +453,9 @@ onMounted(() => { return } initTitle() + const viewInfo = val ? val : view.value nextTick(() => { - chartComponent?.value?.renderChart(val) + chartComponent?.value?.renderChart(viewInfo) }) } }) @@ -497,7 +498,8 @@ const loadingFlag = computed(() => { const chartAreaShow = computed(() => { return ( - view.value.tableId || + (view.value.tableId && + (element.value['state'] === undefined || element.value['state'] === 'ready')) || view.value.type === 'rich-text' || (view.value.type === 'map' && view.value.customAttr.map.id) ) diff --git a/core/core-frontend/src/views/data-visualization/index.vue b/core/core-frontend/src/views/data-visualization/index.vue index 92c1a4eb0c..d908c04e90 100644 --- a/core/core-frontend/src/views/data-visualization/index.vue +++ b/core/core-frontend/src/views/data-visualization/index.vue @@ -113,7 +113,7 @@ const handleDragOver = e => { } const handleMouseDown = e => { - e.stopPropagation() + // e.stopPropagation() dvMainStore.setClickComponentStatus(false) // 点击画布的空区域 提前清空curComponent 防止右击菜单内容抖动 dvMainStore.setCurComponent({ component: null, index: null }) diff --git a/core/core-frontend/src/views/visualized/data/datasource/form/option.ts b/core/core-frontend/src/views/visualized/data/datasource/form/option.ts index 47854cd4e0..9bbcd6cdeb 100644 --- a/core/core-frontend/src/views/visualized/data/datasource/form/option.ts +++ b/core/core-frontend/src/views/visualized/data/datasource/form/option.ts @@ -85,12 +85,6 @@ export const dsTypes = [ catalog: 'OLAP', extraParams: '' }, - { - type: 'db2', - name: 'Db2', - catalog: 'OLTP', - extraParams: '' - }, { type: 'redshift', name: 'AWS Redshift', diff --git a/de-xpack b/de-xpack index 24cd326ab7..0a8337cd2b 160000 --- a/de-xpack +++ b/de-xpack @@ -1 +1 @@ -Subproject commit 24cd326ab7961272b7b39595af475bbd76a55233 +Subproject commit 0a8337cd2b6ea435977c22614c2a24bc9460c6c9