Compare commits

..

1 Commits

Author SHA1 Message Date
taojinlong
9d15e0106f fix: 【数据源】存量数据源连接信息AES加密存储 2024-11-28 16:01:09 +08:00
83 changed files with 711 additions and 1313 deletions

View File

@ -17,10 +17,9 @@ import io.dataease.license.config.XpackInteract;
import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeRequest;
import io.dataease.model.BusiNodeVO; import io.dataease.model.BusiNodeVO;
import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.operation.manage.CoreOptRecentManage;
import io.dataease.utils.AuthUtils; import io.dataease.system.dao.auto.entity.CoreSysSetting;
import io.dataease.utils.BeanUtils; import io.dataease.system.manage.SysParameterManage;
import io.dataease.utils.CommunityUtils; import io.dataease.utils.*;
import io.dataease.utils.TreeUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
@ -43,6 +42,9 @@ public class DataSourceManage {
@Resource @Resource
private CoreOptRecentManage coreOptRecentManage; private CoreOptRecentManage coreOptRecentManage;
@Resource
private SysParameterManage sysParameterManage;
private DatasourceNodeBO rootNode() { private DatasourceNodeBO rootNode() {
return new DatasourceNodeBO(0L, "root", false, 7, -1L, 0, "mysql"); return new DatasourceNodeBO(0L, "root", false, 7, -1L, 0, "mysql");
} }
@ -157,10 +159,20 @@ public class DataSourceManage {
} }
public void encryptDsConfig(){ public void encryptDsConfig() {
coreDatasourceMapper.selectList(null).forEach(dataSource -> { List<CoreSysSetting> coreSysSettings = sysParameterManage.groupList("datasource.encrypt");
coreDatasourceMapper.updateById(dataSource); if (CollectionUtils.isEmpty(coreSysSettings)) {
}); coreDatasourceMapper.selectList(null).forEach(dataSource -> {
coreDatasourceMapper.updateById(dataSource);
});
CoreSysSetting coreSysSetting = new CoreSysSetting();
coreSysSetting.setId(IDUtils.snowID());
coreSysSetting.setPkey("datasource.encrypt");
coreSysSetting.setPval("true");
coreSysSetting.setType("text");
coreSysSetting.setSort(1);
sysParameterManage.insert(coreSysSetting);
}
} }
public DatasourceDTO getDs(Long id) { public DatasourceDTO getDs(Long id) {

View File

@ -0,0 +1,12 @@
package io.dataease.rmonitor.bo;
import lombok.Data;
import java.io.Serializable;
@Data
public class PerMonitorCheckBO implements Serializable {
private boolean valid;
private boolean emptyPermission;
}

View File

@ -0,0 +1,24 @@
package io.dataease.rmonitor.bo;
import io.dataease.model.TreeBaseModel;
import io.dataease.model.TreeResultModel;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class PerMonitorNodeBO implements TreeBaseModel<PerMonitorNodeBO>, TreeResultModel<PerMonitorNodeBO>, Serializable {
private Long id;
private String name;
private Long pid;
private boolean leaf;
private int extraFlag;
private List<PerMonitorNodeBO> children;
}

View File

@ -0,0 +1,120 @@
package io.dataease.rmonitor.manage;
import io.dataease.constant.DataSourceType;
import io.dataease.exception.DEException;
import io.dataease.rmonitor.bo.PerMonitorCheckBO;
import io.dataease.rmonitor.bo.PerMonitorNodeBO;
import io.dataease.rmonitor.mapper.ResourceMonitorMapper;
import io.dataease.rmonitor.mapper.entity.DatasetFreeResource;
import io.dataease.rmonitor.mapper.entity.DsFreeResource;
import io.dataease.rmonitor.mapper.entity.VisualFreeResource;
import io.dataease.utils.BeanUtils;
import io.dataease.utils.TreeUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component("resourceMonitorManage")
public class ResourceMonitorManage {
@Resource(name = "resourceMonitorSyncManage")
private ResourceMonitorSyncManage resourceMonitorSyncManage;
@Resource
private ResourceMonitorMapper resourceMonitorMapper;
private boolean existFreeResource() {
int rCount = resourceMonitorMapper.dsCount() + resourceMonitorMapper.datasetCount() + resourceMonitorMapper.vCount();
return rCount > 0;
}
private Map<String, List<PerMonitorNodeBO>> freeResource() {
Map<String, List<PerMonitorNodeBO>> result = new HashMap<>();
List<DsFreeResource> dsFreeResources = resourceMonitorMapper.queryFreeDs();
if (CollectionUtils.isNotEmpty(dsFreeResources)) {
List<PerMonitorNodeBO> dsBos = dsFreeResources.stream().map(node -> {
PerMonitorNodeBO bo = BeanUtils.copyBean(new PerMonitorNodeBO(), node);
bo.setLeaf(!StringUtils.equals("folder", node.getType()));
bo.setExtraFlag(DataSourceType.valueOf(node.getType()).getFlag());
return bo;
}).collect(Collectors.toList());
List<PerMonitorNodeBO> dsTree = TreeUtils.mergeTree(dsBos, PerMonitorNodeBO.class, false);
result.put("datasource", dsTree);
}
List<DatasetFreeResource> datasetFreeResources = resourceMonitorMapper.queryFreeDataset();
if (CollectionUtils.isNotEmpty(datasetFreeResources)) {
List<PerMonitorNodeBO> datasetBos = datasetFreeResources.stream().map(node -> {
PerMonitorNodeBO bo = BeanUtils.copyBean(new PerMonitorNodeBO(), node);
bo.setLeaf(!StringUtils.equals("folder", node.getNodeType()));
return bo;
}).collect(Collectors.toList());
List<PerMonitorNodeBO> datasetTree = TreeUtils.mergeTree(datasetBos, PerMonitorNodeBO.class, false);
result.put("dataset", datasetTree);
}
List<VisualFreeResource> visualFreeResources = resourceMonitorMapper.queryFreeVusial();
if (CollectionUtils.isNotEmpty(visualFreeResources)) {
Map<String, List<VisualFreeResource>> baseMap = visualFreeResources.stream().collect(Collectors.groupingBy(VisualFreeResource::getType));
for (Map.Entry<String, List<VisualFreeResource>> entry : baseMap.entrySet()) {
List<VisualFreeResource> freeResource = entry.getValue();
List<PerMonitorNodeBO> visualBos = freeResource.stream().map(node -> {
PerMonitorNodeBO bo = BeanUtils.copyBean(new PerMonitorNodeBO(), node);
bo.setLeaf(!StringUtils.equals("folder", node.getNodeType()));
return bo;
}).collect(Collectors.toList());
result.put(convertBusiFlag(entry.getKey()), TreeUtils.mergeTree(visualBos, PerMonitorNodeBO.class, false));
}
}
return result;
}
private String convertBusiFlag(String key) {
if (StringUtils.equals("dashboard", key)) {
return "panel";
} else if (StringUtils.equals("dataV", key)) {
return "screen";
} else return key;
}
public boolean check() {
PerMonitorCheckBO checkBO = resourceMonitorSyncManage.checkXpackResource();
return checkBO.isValid() && checkBO.isEmptyPermission() && existFreeResource();
}
@Transactional
public void delete() {
boolean existFree = existFreeResource();
if (!existFree) DEException.throwException("无未同步资源!");
resourceMonitorMapper.delFreeDs();
resourceMonitorMapper.delFreeDataset();
resourceMonitorMapper.delFreeVisual();
}
public void sync() {
//1从xpack获取资源 如果xpack不存在 或者资源不为空 则直接返回 并且抛出异常仅支持首次导入lic同步
//2从core获取资源
//3根据类型分组 并组织成树形结构
//4分别遍历每一棵树 从上到下 同步到权限体系 给默认组织
PerMonitorCheckBO checkBO = resourceMonitorSyncManage.checkXpackResource();
if (!checkBO.isValid()) DEException.throwException("缺少许可证");
if (!checkBO.isEmptyPermission()) DEException.throwException("仅支持license首次导入同步");
Map<String, List<PerMonitorNodeBO>> freeResourceMap = freeResource();
if (MapUtils.isEmpty(freeResourceMap)) DEException.throwException("无未同步资源!");
for (Map.Entry<String, List<PerMonitorNodeBO>> entry : freeResourceMap.entrySet()) {
resourceMonitorSyncManage.sync(entry.getKey(), entry.getValue());
}
}
}

View File

@ -0,0 +1,28 @@
package io.dataease.rmonitor.manage;
import io.dataease.exception.DEException;
import io.dataease.license.config.XpackInteract;
import io.dataease.rmonitor.bo.PerMonitorCheckBO;
import io.dataease.rmonitor.bo.PerMonitorNodeBO;
import io.dataease.rmonitor.mapper.ResourceMonitorMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
@Component("resourceMonitorSyncManage")
public class ResourceMonitorSyncManage {
@Resource(name = "resourceMonitorMapper")
private ResourceMonitorMapper resourceMonitorMapper;
@XpackInteract(value = "resourceMonitorSyncManage", replace = true)
public void sync(String flag, List<PerMonitorNodeBO> treeNodes) {
DEException.throwException("缺失许可证");
}
@XpackInteract(value = "resourceMonitorSyncManage", replace = true)
public PerMonitorCheckBO checkXpackResource() {
return new PerMonitorCheckBO();
}
}

View File

@ -0,0 +1,41 @@
package io.dataease.rmonitor.mapper;
import io.dataease.rmonitor.mapper.entity.DatasetFreeResource;
import io.dataease.rmonitor.mapper.entity.DsFreeResource;
import io.dataease.rmonitor.mapper.entity.VisualFreeResource;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface ResourceMonitorMapper {
@Select("select count(id) from core_datasource")
int dsCount();
@Select("select count(id) from core_dataset_group")
int datasetCount();
@Select("select count(id) from data_visualization_info where delete_flag = 0 and pid != -1")
int vCount();
@Select("select id, name, pid, type, status from core_datasource")
List<DsFreeResource> queryFreeDs();
@Select("select id, name, pid, node_type from core_dataset_group")
List<DatasetFreeResource> queryFreeDataset();
@Select("select id, name, pid, node_type, type from data_visualization_info where delete_flag = 0 and pid != -1")
List<VisualFreeResource> queryFreeVusial();
@Delete("delete from core_datasource")
void delFreeDs();
@Delete("delete from core_dataset_group")
void delFreeDataset();
@Delete("delete from data_visualization_info")
void delFreeVisual();
}

View File

@ -0,0 +1,15 @@
package io.dataease.rmonitor.mapper.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class BaseFreeResource implements Serializable {
private Long id;
private String name;
private Long pid;
}

View File

@ -0,0 +1,13 @@
package io.dataease.rmonitor.mapper.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
@EqualsAndHashCode(callSuper = true)
@Data
public class DatasetFreeResource extends BaseFreeResource implements Serializable {
private String nodeType;
}

View File

@ -0,0 +1,16 @@
package io.dataease.rmonitor.mapper.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
@EqualsAndHashCode(callSuper = true)
@Data
public class DsFreeResource extends BaseFreeResource implements Serializable {
private String type;
private String status;
}

View File

@ -0,0 +1,15 @@
package io.dataease.rmonitor.mapper.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
@EqualsAndHashCode(callSuper = true)
@Data
public class VisualFreeResource extends BaseFreeResource implements Serializable {
private String nodeType;
private String type;
}

View File

@ -0,0 +1,30 @@
package io.dataease.rmonitor.server;
import io.dataease.api.rmonitor.ResourceMonitorApi;
import io.dataease.rmonitor.manage.ResourceMonitorManage;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/rmonitor")
public class ResourceMonitorServer implements ResourceMonitorApi {
@Resource(name = "resourceMonitorManage")
private ResourceMonitorManage resourceMonitorManage;
@Override
public boolean existFree() {
return resourceMonitorManage.check();
}
@Override
public void delete() {
resourceMonitorManage.delete();
}
@Override
public void sync() {
resourceMonitorManage.sync();
}
}

View File

@ -172,4 +172,9 @@ public class SysParameterManage {
} }
return vo; return vo;
} }
public void insert(CoreSysSetting coreSysSetting) {
coreSysSettingMapper.insert(coreSysSetting);
}
} }

View File

@ -52,6 +52,3 @@ create table core_custom_geo_sub_area
) )
comment '自定义地理区域分区详情'; comment '自定义地理区域分区详情';
UPDATE `core_sys_setting` SET `sort` = 11 WHERE `pkey` = 'basic.dsIntervalTime';

View File

@ -3,3 +3,7 @@ import request from '@/config/axios'
export const validateApi = data => request.post({ url: '/license/validate', data }) export const validateApi = data => request.post({ url: '/license/validate', data })
export const buildVersionApi = () => request.get({ url: '/license/version' }) export const buildVersionApi = () => request.get({ url: '/license/version' })
export const updateInfoApi = data => request.post({ url: '/license/update', data }) export const updateInfoApi = data => request.post({ url: '/license/update', data })
export const checkFreeApi = () => request.get({ url: '/rmonitor/existFree' })
export const syncFreeApi = () => request.post({ url: '/rmonitor/sync' })
export const delFreeApi = () => request.post({ url: '/rmonitor/delete' })

View File

@ -139,7 +139,8 @@ const previewOuter = () => {
} }
canvasSave(() => { canvasSave(() => {
const url = '#/preview?dvId=' + dvInfo.value.id + '&ignoreParams=true' const url = '#/preview?dvId=' + dvInfo.value.id + '&ignoreParams=true'
const newWindow = window.open(url, '_blank') const openType = wsCache.get('open-backend') === '1' ? '_self' : '_blank'
const newWindow = window.open(url, openType)
initOpenHandler(newWindow) initOpenHandler(newWindow)
}) })
} }

View File

@ -195,11 +195,7 @@
:disabled="canvasStyleData.dashboard.resultMode === 'all'" :disabled="canvasStyleData.dashboard.resultMode === 'all'"
/> />
</el-form-item> </el-form-item>
<el-form-item <el-form-item style="margin-top: 16px; margin-bottom: 8px" :class="'form-item-' + themes">
v-show="dvInfo.type === 'dashboard'"
style="margin-top: 16px; margin-bottom: 8px"
:class="'form-item-' + themes"
>
<el-checkbox <el-checkbox
:effect="themes" :effect="themes"
size="small" size="small"
@ -210,7 +206,7 @@
<span style="margin-right: 4px"> {{ t('visualization.button_tips') }}</span> <span style="margin-right: 4px"> {{ t('visualization.button_tips') }}</span>
<el-tooltip class="item" :effect="toolTip" placement="bottom"> <el-tooltip class="item" :effect="toolTip" placement="bottom">
<template #content> <template #content>
<div>{{ t('visualization.effective_during_link') }}</div> <div>{{ t('visualization.effective_during_preview') }}</div>
</template> </template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }"> <el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon> <Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
@ -219,11 +215,7 @@
</span> </span>
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-form-item <el-form-item class="form-item" :class="'form-item-' + themes">
v-show="dvInfo.type === 'dashboard'"
class="form-item"
:class="'form-item-' + themes"
>
<el-checkbox <el-checkbox
:effect="themes" :effect="themes"
size="small" size="small"
@ -249,7 +241,7 @@ import {
LIGHT_THEME_DASHBOARD_BACKGROUND LIGHT_THEME_DASHBOARD_BACKGROUND
} from '@/utils/canvasStyle' } from '@/utils/canvasStyle'
import { import {
CHART_FONT_FAMILY_ORIGIN, CHART_FONT_FAMILY,
DEFAULT_COLOR_CASE_DARK, DEFAULT_COLOR_CASE_DARK,
DEFAULT_COLOR_CASE_LIGHT, DEFAULT_COLOR_CASE_LIGHT,
DEFAULT_TAB_COLOR_CASE_DARK, DEFAULT_TAB_COLOR_CASE_DARK,
@ -282,7 +274,7 @@ const props = defineProps({
default: 'light' default: 'light'
} }
}) })
const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat( const fontFamily = CHART_FONT_FAMILY.concat(
appearanceStore.fontList.map(ele => ({ appearanceStore.fontList.map(ele => ({
name: ele.name, name: ele.name,
value: ele.name value: ele.name

View File

@ -13,7 +13,7 @@
<el-color-picker <el-color-picker
:effect="themes" :effect="themes"
v-model="seniorStyleSetting.linkageIconColor" v-model="seniorStyleSetting.linkageIconColor"
:trigger-width="100" :trigger-width="197"
is-custom is-custom
:predefine="state.predefineColors" :predefine="state.predefineColors"
@change="themeChange" @change="themeChange"
@ -30,7 +30,7 @@
<el-color-picker <el-color-picker
v-model="seniorStyleSetting.drillLayerColor" v-model="seniorStyleSetting.drillLayerColor"
:effect="themes" :effect="themes"
:trigger-width="100" :trigger-width="197"
is-custom is-custom
:predefine="state.predefineColors" :predefine="state.predefineColors"
@change="themeChange" @change="themeChange"

View File

@ -10,7 +10,7 @@
<path <path
:d="smallGridPathD" :d="smallGridPathD"
fill="none" fill="none"
stroke="rgba(207, 207, 207, 0.4)" stroke="rgba(207, 207, 207, 0.3)"
stroke-width="0.8" stroke-width="0.8"
/> />
</pattern> </pattern>
@ -21,11 +21,11 @@
patternUnits="userSpaceOnUse" patternUnits="userSpaceOnUse"
> >
<rect :width="middleGridW" :height="middleGridH" fill="url(#smallGrid)" /> <rect :width="middleGridW" :height="middleGridH" fill="url(#smallGrid)" />
<path :d="middleGridPathD" fill="none" stroke="rgba(207, 207, 207, 0.4)" stroke-width="1" /> <path :d="middleGridPathD" fill="none" stroke="rgba(207, 207, 207, 0.3)" stroke-width="1" />
</pattern> </pattern>
<pattern id="grid" :width="gridW" :height="gridH" patternUnits="userSpaceOnUse"> <pattern id="grid" :width="gridW" :height="gridH" patternUnits="userSpaceOnUse">
<rect :width="gridW" :height="gridH" fill="url(#middleGrid)" /> <rect :width="gridW" :height="gridH" fill="url(#middleGrid)" />
<path :d="pathD" fill="none" stroke="rgba(207, 207, 207, 0.4)" stroke-width="1.2" /> <path :d="pathD" fill="none" stroke="rgba(207, 207, 207, 0.3)" stroke-width="1.2" />
</pattern> </pattern>
</defs> </defs>
<rect width="100%" height="100%" fill="url(#grid)" /> <rect width="100%" height="100%" fill="url(#grid)" />

View File

@ -3,7 +3,7 @@
<defs> <defs>
<pattern id="grid" :width="gridW" :height="gridH" patternUnits="userSpaceOnUse"> <pattern id="grid" :width="gridW" :height="gridH" patternUnits="userSpaceOnUse">
<rect :width="gridW" :height="gridH" fill="url(#middleGrid)" /> <rect :width="gridW" :height="gridH" fill="url(#middleGrid)" />
<path :d="pathD" fill="none" stroke="rgba(207, 207, 207, 0.4)" stroke-width="0.7" /> <path :d="pathD" fill="none" stroke="rgba(207, 207, 207, 0.2)" stroke-width="0.5" />
</pattern> </pattern>
<pattern <pattern
id="middleGrid" id="middleGrid"
@ -15,7 +15,7 @@
<path <path
:d="middleGridPathD" :d="middleGridPathD"
fill="none" fill="none"
stroke="rgba(207, 207, 207, 0.4)" stroke="rgba(207, 207, 207, 0.2)"
stroke-width="0.3" stroke-width="0.3"
/> />
</pattern> </pattern>

View File

@ -74,6 +74,14 @@ const closeEditComponentName = () => {
const dragOnEnd = ({ oldIndex, newIndex }) => { const dragOnEnd = ({ oldIndex, newIndex }) => {
const source = componentData.value[newIndex] const source = componentData.value[newIndex]
const comLength = componentData.value.length
//
componentData.value.splice(newIndex, 1)
componentData.value.splice(oldIndex, 0, source)
const target = componentData.value[comLength - 1 - oldIndex]
//
componentData.value.splice(comLength - 1 - oldIndex, 1)
componentData.value.splice(comLength - 1 - newIndex, 0, target)
dvMainStore.setCurTabName(source.title) dvMainStore.setCurTabName(source.title)
eventBus.emit('onTabSortChange-' + tabElement.value?.id) eventBus.emit('onTabSortChange-' + tabElement.value?.id)
snapshotStore.recordSnapshotCache() snapshotStore.recordSnapshotCache()

View File

@ -25,7 +25,7 @@
<div class="bar-content"> <div class="bar-content">
<div class="bar-diver" /> <div class="bar-diver" />
<div v-show="fromLink" class="link-icon-active"> <div v-show="fromLink" class="link-icon-active">
<el-tooltip :content="t('visualization.back_parent')"> <el-tooltip content="返回上一级">
<el-icon style="width: 16px; height: 16px" @click="back2Last"> <el-icon style="width: 16px; height: 16px" @click="back2Last">
<Icon name="icon_left_outlined"> <Icon name="icon_left_outlined">
<icon_left_outlined class="svg-icon" /> <icon_left_outlined class="svg-icon" />
@ -34,7 +34,7 @@
</el-tooltip> </el-tooltip>
</div> </div>
<div class="link-icon-active"> <div class="link-icon-active">
<el-tooltip :content="t('visualization.export_pdf')"> <el-tooltip content="导出PDF">
<el-icon style="width: 16px; height: 16px" @click="exportPDF"> <el-icon style="width: 16px; height: 16px" @click="exportPDF">
<Icon name="icon_download_outlined"> <Icon name="icon_download_outlined">
<icon_download_outlined class="svg-icon" /> <icon_download_outlined class="svg-icon" />
@ -43,11 +43,7 @@
</el-tooltip> </el-tooltip>
</div> </div>
<div id="fullscreenElement" class="link-icon-active" style="padding-right: 4px"> <div id="fullscreenElement" class="link-icon-active" style="padding-right: 4px">
<el-tooltip <el-tooltip :content="fullscreenFlag ? '退出全屏' : '全屏'">
:content="
fullscreenFlag ? t('visualization.ext_fullscreen') : t('visualization.fullscreen')
"
>
<el-icon style="width: 16px; height: 16px" @click="toggleFullscreen"> <el-icon style="width: 16px; height: 16px" @click="toggleFullscreen">
<Icon name="icon_minify_outlined" v-if="fullscreenFlag"> <Icon name="icon_minify_outlined" v-if="fullscreenFlag">
<icon_minify_outlined class="svg-icon" /> <icon_minify_outlined class="svg-icon" />
@ -76,7 +72,6 @@ import icon_magnify_outlined from '@/assets/svg/icon_magnify_outlined.svg'
import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/hooks/web/useEmitt'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useI18n } from '@/hooks/web/useI18n'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const props = defineProps({ const props = defineProps({
canvasStyleData: { canvasStyleData: {
@ -87,7 +82,6 @@ const props = defineProps({
const { canvasStyleData } = toRefs(props) const { canvasStyleData } = toRefs(props)
const { fullscreenFlag } = storeToRefs(dvMainStore) const { fullscreenFlag } = storeToRefs(dvMainStore)
const { t } = useI18n()
const state = reactive({ const state = reactive({
fullscreenElement: null, fullscreenElement: null,
@ -128,7 +122,7 @@ const back2Last = () => {
window.location.reload() window.location.reload()
} }
const exportPDF = () => { const exportPDF = () => {
useEmitt().emitter.emit('canvasDownload', 'pdf') useEmitt().emitter.emit('canvasDownload')
} }
</script> </script>

View File

@ -33,7 +33,7 @@
</el-form-item> </el-form-item>
<el-form-item :label="t('visualization.description')" prop="description"> <el-form-item :label="t('visualization.description')" prop="description">
<el-input <el-input
:placeholder="t('commons.input_content')" :placeholder="t('visualization.input_content')"
show-word-limit show-word-limit
v-model="state.form.description" v-model="state.form.description"
type="textarea" type="textarea"
@ -44,7 +44,7 @@
<template #footer> <template #footer>
<div class="apply" style="width: 100%"> <div class="apply" style="width: 100%">
<el-button secondary @click="close">{{ t('commons.cancel') }} </el-button> <el-button secondary @click="close">{{ t('commons.cancel') }} </el-button>
<el-button type="primary" @click="downloadApp">{{ t('chart.export') }}</el-button> <el-button type="primary" @click="downloadApp">{{ t('visualization.export') }}</el-button>
</div> </div>
</template> </template>
</el-drawer> </el-drawer>

View File

@ -3,7 +3,6 @@ import noLic from './nolic.vue'
import { ref, useAttrs, onMounted } from 'vue' import { ref, useAttrs, onMounted } from 'vue'
import { execute, randomKey, formatArray } from './convert' import { execute, randomKey, formatArray } from './convert'
import { load, loadDistributed, xpackModelApi } from '@/api/plugin' import { load, loadDistributed, xpackModelApi } from '@/api/plugin'
import configGlobal from '@/components/config-global/src/ConfigGlobal.vue'
import { useCache } from '@/hooks/web/useCache' import { useCache } from '@/hooks/web/useCache'
import { i18n } from '@/plugins/vue-i18n' import { i18n } from '@/plugins/vue-i18n'
import * as Vue from 'vue' import * as Vue from 'vue'
@ -153,13 +152,13 @@ onMounted(async () => {
</script> </script>
<template> <template>
<configGlobal> <component
<component :key="attrs.jsname"
:key="attrs.jsname" ref="pluginProxy"
ref="pluginProxy" :is="plugin"
:is="plugin" v-loading="loading"
v-loading="loading" v-bind="attrs"
v-bind="attrs" ></component>
></component>
</configGlobal>
</template> </template>
<style lang="less" scoped></style>

View File

@ -52,7 +52,7 @@
<span style="margin-right: 4px">{{ t('visualization.show_zoom_button') }}</span> <span style="margin-right: 4px">{{ t('visualization.show_zoom_button') }}</span>
<el-tooltip class="item" :effect="themes" placement="bottom"> <el-tooltip class="item" :effect="themes" placement="bottom">
<template #content> <template #content>
<div>{{ t('visualization.effective_during_link') }}</div> <div>{{ t('visualization.effective_during_preview') }}</div>
</template> </template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }"> <el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon> <Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
@ -83,7 +83,7 @@ import { storeToRefs } from 'pinia'
import { ElFormItem, ElIcon } from 'element-plus-secondary' import { ElFormItem, ElIcon } from 'element-plus-secondary'
import Icon from '../icon-custom/src/Icon.vue' import Icon from '../icon-custom/src/Icon.vue'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance' import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { CHART_FONT_FAMILY_ORIGIN } from '@/views/chart/components/editor/util/chart' import { CHART_FONT_FAMILY } from '@/views/chart/components/editor/util/chart'
import { adaptTitleFontFamilyAll } from '@/utils/canvasStyle' import { adaptTitleFontFamilyAll } from '@/utils/canvasStyle'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
@ -91,7 +91,7 @@ const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { canvasStyleData } = storeToRefs(dvMainStore) const { canvasStyleData } = storeToRefs(dvMainStore)
const appearanceStore = useAppearanceStoreWithOut() const appearanceStore = useAppearanceStoreWithOut()
const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat( const fontFamily = CHART_FONT_FAMILY.concat(
appearanceStore.fontList.map(ele => ({ appearanceStore.fontList.map(ele => ({
name: ele.name, name: ele.name,
value: ele.name value: ele.name

View File

@ -13,7 +13,7 @@
<el-tooltip <el-tooltip
effect="dark" effect="dark"
placement="top" placement="top"
:content="t('visualization.sort')" :content="'排序'"
v-if="element.component === 'DeTabs' && showPosition === 'canvas'" v-if="element.component === 'DeTabs' && showPosition === 'canvas'"
> >
<el-icon class="bar-base-icon" @click="tabSort"> <el-icon class="bar-base-icon" @click="tabSort">
@ -21,12 +21,12 @@
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
<template v-if="element.component === 'VQuery' && showPosition === 'canvas'"> <template v-if="element.component === 'VQuery' && showPosition === 'canvas'">
<span :title="t('visualization.add_query_filter')"> <span title="添加查询条件">
<el-icon class="bar-base-icon" @click="addQueryCriteria"> <el-icon class="bar-base-icon" @click="addQueryCriteria">
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon
></el-icon> ></el-icon>
</span> </span>
<span :title="t('visualization.edit_query_filter')"> <span title="编辑查询条件">
<el-icon class="bar-base-icon" @click="editQueryCriteria"> <el-icon class="bar-base-icon" @click="editQueryCriteria">
<Icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></Icon <Icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></Icon
></el-icon> ></el-icon>
@ -47,7 +47,7 @@
<el-tooltip <el-tooltip
effect="dark" effect="dark"
:placement="showBarTooltipPosition" :placement="showBarTooltipPosition"
:content="t('visualization.show_data')" content="查看数据"
v-if="!['picture-group', 'rich-text'].includes(element.innerType) && barShowCheck('details')" v-if="!['picture-group', 'rich-text'].includes(element.innerType) && barShowCheck('details')"
> >
<span> <span>
@ -59,7 +59,7 @@
<el-tooltip <el-tooltip
effect="dark" effect="dark"
placement="top" placement="top"
:content="t('visualization.input_calc_data')" content="输入计算数据"
v-if="barShowCheck('datasetParams') && datasetParamsSetShow" v-if="barShowCheck('datasetParams') && datasetParamsSetShow"
> >
<span> <span>
@ -102,14 +102,14 @@
</el-icon> </el-icon>
<template #dropdown> <template #dropdown>
<el-dropdown-menu style="width: 158px"> <el-dropdown-menu style="width: 158px">
<el-dropdown-item @click="copyComponent" v-if="barShowCheck('copy')">{{ <el-dropdown-item @click="copyComponent" v-if="barShowCheck('copy')"
t('visualization.copy') >复制</el-dropdown-item
}}</el-dropdown-item> >
<template v-if="element.innerType !== 'rich-text' && barShowCheck('enlarge')"> <template v-if="element.innerType !== 'rich-text' && barShowCheck('enlarge')">
<el-dropdown-item <el-dropdown-item
:divided="showPosition === 'canvas'" :divided="showPosition === 'canvas'"
@click="userViewEnlargeOpen($event, 'enlarge')" @click="userViewEnlargeOpen($event, 'enlarge')"
>{{ t('visualization.enlarge') }}</el-dropdown-item >放大</el-dropdown-item
> >
<el-dropdown-item <el-dropdown-item
@click="userViewEnlargeOpen($event, 'details')" @click="userViewEnlargeOpen($event, 'details')"
@ -117,7 +117,7 @@
!['picture-group', 'rich-text'].includes(element.innerType) && !['picture-group', 'rich-text'].includes(element.innerType) &&
barShowCheck('details') barShowCheck('details')
" "
>{{ t('visualization.show_data') }}</el-dropdown-item >查看数据</el-dropdown-item
> >
<el-dropdown-item <el-dropdown-item
style="padding: 0" style="padding: 0"
@ -134,7 +134,7 @@
class="flex-align-center" class="flex-align-center"
style="width: 100%; padding: 5px 6px 5px 16px; line-height: 24px" style="width: 100%; padding: 5px 6px 5px 16px; line-height: 24px"
> >
{{ t('visualization.export_as') }} 导出为
<el-icon size="16px" style="margin-left: auto"><ArrowRight /></el-icon> <el-icon size="16px" style="margin-left: auto"><ArrowRight /></el-icon>
</div> </div>
<template #dropdown> <template #dropdown>
@ -146,11 +146,11 @@
v-if="exportPermissions[1] && element.innerType === 'table-pivot'" v-if="exportPermissions[1] && element.innerType === 'table-pivot'"
@click="exportAsFormattedExcel" @click="exportAsFormattedExcel"
> >
<span>{{ t('visualization.excel_with_format') }}</span> <span>Excel(带格式)</span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-if="exportPermissions[0]" @click="exportAsImage">{{ <el-dropdown-item v-if="exportPermissions[0]" @click="exportAsImage"
t('visualization.image') >图片</el-dropdown-item
}}</el-dropdown-item> >
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@ -161,9 +161,9 @@
jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9FZGl0QmFySGFuZGxlcg==" jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9FZGl0QmFySGFuZGxlcg=="
@close-item="closeItem" @close-item="closeItem"
/> />
<el-dropdown-item divided @click="deleteComponent" v-if="barShowCheck('delete')">{{ <el-dropdown-item divided @click="deleteComponent" v-if="barShowCheck('delete')"
t('visualization.delete') >删除</el-dropdown-item
}}</el-dropdown-item> >
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@ -191,11 +191,11 @@
v-if="exportPermissions[1] && element.innerType === 'table-pivot'" v-if="exportPermissions[1] && element.innerType === 'table-pivot'"
@click="exportAsFormattedExcel" @click="exportAsFormattedExcel"
> >
<span>{{ t('visualization.excel_with_format') }}</span> <span>Excel(带格式)</span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-if="exportPermissions[0]" @click="exportAsImage">{{ <el-dropdown-item v-if="exportPermissions[0]" @click="exportAsImage"
t('visualization.image') >图片</el-dropdown-item
}}</el-dropdown-item> >
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>

View File

@ -15,7 +15,7 @@ import { useLinkStoreWithOut } from '@/store/modules/link'
import { config } from './config' import { config } from './config'
import { configHandler } from './refresh' import { configHandler } from './refresh'
import { isMobile } from '@/utils/utils' import { isMobile } from '@/utils/utils'
import { useRequestStoreWithOut } from '@/store/modules/request'
type AxiosErrorWidthLoading<T> = T & { type AxiosErrorWidthLoading<T> = T & {
config: { config: {
loading?: boolean loading?: boolean
@ -31,11 +31,8 @@ import router from '@/router'
const { result_code } = config const { result_code } = config
import { useCache } from '@/hooks/web/useCache' import { useCache } from '@/hooks/web/useCache'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const { wsCache } = useCache() const { wsCache } = useCache()
const requestStore = useRequestStoreWithOut()
const embeddedStore = useEmbedded() const embeddedStore = useEmbedded()
const basePath = import.meta.env.VITE_API_BASEPATH const basePath = import.meta.env.VITE_API_BASEPATH
@ -206,15 +203,6 @@ service.interceptors.response.use(
} }
}, },
(error: AxiosErrorWidthLoading<AxiosError>) => { (error: AxiosErrorWidthLoading<AxiosError>) => {
if (error.message?.includes('timeout of')) {
requestStore.resetLoadingMap()
ElMessage({
type: 'error',
message: '请求超时请稍后再试',
showClose: true
})
}
if (!error?.response) { if (!error?.response) {
return Promise.reject(error) return Promise.reject(error)
} }

View File

@ -40,7 +40,7 @@ const handleDragEnd = e => {
<drag-component <drag-component
:themes="themes" :themes="themes"
:icon="dbMoreWeb" :icon="dbMoreWeb"
:label="$t('visualization.web')" label="网页"
drag-info="DeFrame&DeFrame" drag-info="DeFrame&DeFrame"
></drag-component> ></drag-component>
</div> </div>

View File

@ -580,7 +580,8 @@ const list = [
color: '', color: '',
padding: 4, padding: 4,
verticalAlign: 'middle', verticalAlign: 'middle',
scrollSpeed: 0 scrollSpeed: 0,
fontFamily: 'Microsoft YaHei'
} }
} }
] ]

View File

@ -1,14 +1,16 @@
<template> <template>
<div class="pic-main"> <div class="pic-main">
<chart-error v-if="isError" :err-msg="errMsg" />
<img <img
draggable="false" draggable="false"
v-else-if="state.showUrl" v-if="state.showUrl"
:style="imageAdapter" :style="imageAdapter"
:src="imgUrlTrans(state.showUrl)" :src="imgUrlTrans(state.showUrl)"
/> />
<template v-else> <template v-else>
<chart-empty-info :view-icon="view.type"></chart-empty-info> <chart-empty-info
:themes="canvasStyleData.dashboard.themeColor"
:view-icon="view.type"
></chart-empty-info>
</template> </template>
</div> </div>
</template> </template>
@ -33,7 +35,6 @@ import { parseJson } from '@/views/chart/components/js/util'
import { mappingColor } from '@/views/chart/components/js/panel/common/common_table' import { mappingColor } from '@/views/chart/components/js/panel/common/common_table'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import ChartEmptyInfo from '@/views/chart/components/views/components/ChartEmptyInfo.vue' import ChartEmptyInfo from '@/views/chart/components/views/components/ChartEmptyInfo.vue'
import ChartError from '@/views/chart/components/views/components/ChartError.vue'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { canvasViewInfo, editMode, mobileInPc, canvasStyleData } = storeToRefs(dvMainStore) const { canvasViewInfo, editMode, mobileInPc, canvasStyleData } = storeToRefs(dvMainStore)
const state = reactive({ const state = reactive({
@ -201,17 +202,12 @@ const calcData = (viewCalc: Chart, callback) => {
} }
if (viewCalc.tableId || viewCalc['dataFrom'] === 'template') { if (viewCalc.tableId || viewCalc['dataFrom'] === 'template') {
const v = JSON.parse(JSON.stringify(viewCalc)) const v = JSON.parse(JSON.stringify(viewCalc))
v.type = 'table-info'
v.render = 'antv'
v.resultCount = 1
getData(v) getData(v)
.then(res => { .then(res => {
if (res.code && res.code !== 0) { if (res.code && res.code !== 0) {
isError.value = true isError.value = true
errMsg.value = res.msg errMsg.value = res.msg
} else { } else {
res.type = 'picture-group'
res.render = 'custom'
state.data = res?.data state.data = res?.data
state.viewDataInfo = res state.viewDataInfo = res
state.totalItems = res?.totalItems state.totalItems = res?.totalItems

View File

@ -62,7 +62,7 @@ import { useEmitt } from '@/hooks/web/useEmitt'
import { valueFormatter } from '@/views/chart/components/js/formatter' import { valueFormatter } from '@/views/chart/components/js/formatter'
import { parseJson } from '@/views/chart/components/js/util' import { parseJson } from '@/views/chart/components/js/util'
import { mappingColor } from '@/views/chart/components/js/panel/common/common_table' import { mappingColor } from '@/views/chart/components/js/panel/common/common_table'
import { CHART_FONT_FAMILY_ORIGIN } from '@/views/chart/components/editor/util/chart' import { CHART_FONT_FAMILY } from '@/views/chart/components/editor/util/chart'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance' import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const errMsg = ref('') const errMsg = ref('')
@ -137,7 +137,7 @@ const myValue = ref('')
const systemFontFamily = appearanceStore.fontList.map(item => item.name) const systemFontFamily = appearanceStore.fontList.map(item => item.name)
const curFontFamily = () => { const curFontFamily = () => {
let result = '' let result = ''
CHART_FONT_FAMILY_ORIGIN.concat( CHART_FONT_FAMILY.concat(
appearanceStore.fontList.map(ele => ({ appearanceStore.fontList.map(ele => ({
name: ele.name, name: ele.name,
value: ele.name value: ele.name
@ -225,7 +225,7 @@ const init = ref({
// //
originalHandle.style.display = '' originalHandle.style.display = ''
if (cloneHandle) { if (cloneHandle) {
cloneHandle.parentNode?.removeChild(cloneHandle) // cloneHandle.parentNode.removeChild(cloneHandle) //
} }
cloneHandle = null cloneHandle = null
originalHandle = null originalHandle = null
@ -539,9 +539,6 @@ const calcData = (view: Chart, callback) => {
updateEmptyValue(view) updateEmptyValue(view)
if (view.tableId || view['dataFrom'] === 'template') { if (view.tableId || view['dataFrom'] === 'template') {
const v = JSON.parse(JSON.stringify(view)) const v = JSON.parse(JSON.stringify(view))
v.type = 'table-info'
v.render = 'antv'
v.resultCount = 1
getData(v) getData(v)
.then(res => { .then(res => {
if (res.code && res.code !== 0) { if (res.code && res.code !== 0) {
@ -549,8 +546,6 @@ const calcData = (view: Chart, callback) => {
errMsg.value = res.msg errMsg.value = res.msg
} else { } else {
state.data = res?.data state.data = res?.data
res.type = 'rich-text'
res.render = 'custom'
state.viewDataInfo = res state.viewDataInfo = res
state.totalItems = res?.totalItems state.totalItems = res?.totalItems
const curViewInfo = canvasViewInfo.value[element.value.id] const curViewInfo = canvasViewInfo.value[element.value.id]

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, toRefs, PropType } from 'vue' import { computed, toRefs, PropType, CSSProperties } from 'vue'
import Chart from '@/views/chart/components/views/index.vue' import Chart from '@/views/chart/components/views/index.vue'
const props = defineProps({ const props = defineProps({

View File

@ -268,13 +268,7 @@ const disabledDate = val => {
.startOf(queryTimeType.value) .startOf(queryTimeType.value)
.valueOf() - .valueOf() -
1000 < 1000 <
timeStamp || timeStamp
dayjs(startWindowTime.value)
.subtract(maximumSingleQuery, queryTimeType.value)
.startOf(queryTimeType.value)
.valueOf() +
1000 >
timeStamp
} }
if (intervalType === 'none') { if (intervalType === 'none') {
if (dynamicWindow) return isDynamicWindowTime if (dynamicWindow) return isDynamicWindowTime

View File

@ -1,117 +1,21 @@
<script lang="ts" setup> <script lang="ts" setup>
import iconSetting from '@/assets/svg/icon-setting.svg' import iconSetting from '@/assets/svg/icon-setting.svg'
import TopDocCard from '@/layout/components/TopDocCard.vue'
import copilot from '@/assets/svg/copilot.svg'
import LangSelector from '@/layout/components/LangSelector.vue'
import topEnterpriseTrial from '@/assets/svg/top-enterprise-trial.svg'
import topHelpDoc from '@/assets/svg/top-help-doc.svg'
import topProductBbs from '@/assets/svg/top-product-bbs.svg'
import topTechnology from '@/assets/svg/top-technology.svg'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import TopDesktopCard from './TopDesktopCard.vue'
import icon_right_outlined from '@/assets/svg/icon_right_outlined.svg'
import dvAi from '@/assets/svg/dv-ai.svg'
import AiComponent from '@/layout/components/AiComponent.vue'
import dvPreviewDownload from '@/assets/svg/dv-preview-download.svg'
import ToolboxCfg from './ToolboxCfg.vue'
import { findBaseParams } from '@/api/aiComponent'
import icon_more_outlined from '@/assets/svg/icon_more_outlined.svg'
import msgNotice from '@/assets/svg/msg-notice.svg'
import { usePermissionStore } from '@/store/modules/permission'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance' import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { msgCountApi } from '@/api/msg' import { computed } from 'vue'
import { computed, ref, onMounted } from 'vue'
import { useEmitt } from '@/hooks/web/useEmitt'
const aiBaseUrl = ref('https://maxkb.fit2cloud.com/ui/chat/2ddd8b594ce09dbb?mode=embed')
const showToolbox = ref(false)
const badgeCount = ref('0')
const permissionStore = usePermissionStore()
const appearanceStore = useAppearanceStoreWithOut() const appearanceStore = useAppearanceStoreWithOut()
const navigateBg = computed(() => appearanceStore.getNavigateBg) const navigateBg = computed(() => appearanceStore.getNavigateBg)
const help = computed(() => appearanceStore.getHelp)
const cardInfoList = [
{ name: '帮助文档', url: help.value || 'https://dataease.io/docs/v2/', icon: topHelpDoc },
{ name: '产品论坛', url: 'https://bbs.fit2cloud.com/c/de/6', icon: topProductBbs },
{
name: '技术博客',
url: 'https://blog.fit2cloud.com/categories/dataease',
icon: topTechnology
},
{ name: '企业版试用', url: 'https://jinshuju.net/f/TK5TTd', icon: topEnterpriseTrial }
]
const { push, resolve } = useRouter() const { push, resolve } = useRouter()
const redirectUser = () => { const redirectUser = () => {
const sysMenu = resolve('/sys-setting') const sysMenu = resolve('/sys-setting')
const kidPath = sysMenu.matched[0].children[0].path const kidPath = sysMenu.matched[0].children[0].path
push(`${sysMenu.path}/${kidPath}`) push(`${sysMenu.path}/${kidPath}`)
} }
const msgNoticePush = () => {
push('/msg/msg-fill')
}
const initShowToolbox = () => {
showToolbox.value = permissionStore.getRouters.some(route => route.path === '/toolbox')
}
const downloadClick = params => {
useEmitt().emitter.emit('data-export-center', params)
}
const initAiBase = async () => {
await findBaseParams().then(rsp => {
const params = rsp.data
if (params && params['ai.baseUrl']) {
aiBaseUrl.value = params['ai.baseUrl']
} else {
aiBaseUrl.value = null
}
})
}
const handleCopilotClick = () => {
push('/copilot/index')
}
const handleAiClick = () => {
useEmitt().emitter.emit('aiComponentChange')
}
onMounted(() => {
initShowToolbox()
initAiBase()
msgCountApi().then(res => {
badgeCount.value = (res?.data > 99 ? '99+' : res?.data) || '0'
})
})
</script> </script>
<template> <template>
<ToolboxCfg v-if="showToolbox" /> <el-tooltip class="box-item" effect="dark" content="系统设置" placement="top">
<el-tooltip effect="dark" :content="$t('data_export.export_center')" placement="bottom">
<el-icon
style="margin-left: 10px"
class="preview-download_icon"
:class="navigateBg === 'light' && 'is-light-setting'"
>
<Icon><dvPreviewDownload @click="downloadClick" class="svg-icon" /></Icon>
</el-icon>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('v_query.msg_center')" placement="bottom">
<el-badge
style="margin-left: 10px"
:hidden="[0, '0'].includes(badgeCount)"
:value="badgeCount"
class="ed-badge_custom"
>
<el-icon class="preview-download_icon" :class="navigateBg === 'light' && 'is-light-setting'">
<Icon><msgNotice @click="msgNoticePush" class="svg-icon" /></Icon>
</el-icon>
</el-badge>
</el-tooltip>
<el-tooltip
class="box-item"
effect="dark"
:content="$t('commons.system_setting')"
placement="top"
>
<div <div
class="sys-setting in-iframe-setting" class="sys-setting in-iframe-setting"
:class="{ :class="{
@ -119,90 +23,12 @@ onMounted(() => {
}" }"
> >
<el-icon @click="redirectUser"> <el-icon @click="redirectUser">
<Icon><iconSetting class="svg-icon icon-setting" /></Icon> <Icon class="icon-setting" name="icon-setting"
><iconSetting class="svg-icon icon-setting"
/></Icon>
</el-icon> </el-icon>
</div> </div>
</el-tooltip> </el-tooltip>
<el-popover
popper-class="popper-class_ai-copilot"
placement="bottom-end"
:width="224"
trigger="hover"
>
<template #default>
<div>
<div class="card-content_desk">
<TopDesktopCard
v-if="aiBaseUrl && appearanceStore.getShowAi"
@openBlank="handleAiClick"
:cardInfo="{
icon: dvAi,
name: $t('commons.assistant')
}"
></TopDesktopCard>
<TopDesktopCard
v-if="appearanceStore.getShowCopilot"
@openBlank="handleCopilotClick"
:cardInfo="{
icon: copilot,
name: 'Copilot'
}"
></TopDesktopCard>
</div>
<div class="border-top">
<el-popover
:teleported="false"
popper-class="popper-class_ai-copilot"
placement="left-start"
:width="224"
trigger="click"
><template #default>
<div style="display: flex; padding: 8px; flex-wrap: wrap">
<top-doc-card
:span="12"
v-for="(item, index) in cardInfoList"
:key="index"
:card-info="item"
></top-doc-card>
</div>
</template>
<template #reference
><div class="item-select_info">
{{ $t('commons.help_center') }}
<el-icon style="font-size: 16px">
<Icon><icon_right_outlined></icon_right_outlined></Icon>
</el-icon></div></template
></el-popover>
<el-popover
:teleported="false"
popper-class="popper-class_ai-copilot"
placement="left-start"
:width="224"
trigger="click"
><template #default>
<div style="padding: 8px 0">
<LangSelector />
</div>
</template>
<template #reference>
<div class="item-select_info">
{{ $t('commons.language') }}
<el-icon style="font-size: 16px">
<Icon><icon_right_outlined></icon_right_outlined></Icon>
</el-icon>
</div> </template
></el-popover>
</div>
</div>
</template>
<template #reference>
<el-icon class="preview-download_icon" :class="navigateBg === 'light' && 'is-light-setting'">
<Icon><icon_more_outlined class="svg-icon" /></Icon>
</el-icon>
</template>
</el-popover>
<ai-component v-if="aiBaseUrl && appearanceStore.getShowAi" :base-url="aiBaseUrl"></ai-component>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
@ -226,52 +52,4 @@ onMounted(() => {
background-color: #1f23291a !important; background-color: #1f23291a !important;
} }
} }
.preview-download_icon {
padding: 5px;
height: 28px;
width: 28px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
&:hover {
background-color: #1e2738;
}
&.is-light-setting {
&:hover {
background-color: var(--ed-menu-hover-bg-color) !important;
}
}
}
</style>
<style lang="less">
.popper-class_ai-copilot {
padding: 0 !important;
.card-content_desk {
display: flex;
justify-content: space-between;
padding: 12px 12px 8px;
}
.border-top {
border-top: 1px solid #1f232926;
padding-top: 4px;
padding-bottom: 8px;
}
.item-select_info {
cursor: pointer;
height: 40px;
padding: 9px 11px;
display: flex;
align-items: center;
justify-content: space-between;
color: #1f2329;
.ed-icon {
color: #8f959e;
}
&:hover {
background: #1f23291a;
}
}
}
</style> </style>

View File

@ -62,7 +62,7 @@ const routers: any[] = formatRoute(permissionStore.getRoutersNotHidden as AppCus
const showSystem = ref(false) const showSystem = ref(false)
const showToolbox = ref(false) const showToolbox = ref(false)
const showOverlay = ref(false) const showOverlay = ref(false)
const showOverlayCopilot = ref(false) const showOverlayCopilot = ref(true)
const handleSelect = (index: string) => { const handleSelect = (index: string) => {
// //
if (isExternal(index)) { if (isExternal(index)) {
@ -100,11 +100,11 @@ const initAiBase = async () => {
const initCopilotBase = async () => { const initCopilotBase = async () => {
const aiCopilotCheck = wsCache.get('DE-COPILOT-TIPS-CHECK') const aiCopilotCheck = wsCache.get('DE-COPILOT-TIPS-CHECK')
// if (aiCopilotCheck === 'CHECKED') { if (aiCopilotCheck === 'CHECKED') {
// showOverlayCopilot.value = false showOverlayCopilot.value = false
// } else { } else {
// showOverlayCopilot.value = true showOverlayCopilot.value = true
// } }
} }
const aiTipsConfirm = () => { const aiTipsConfirm = () => {

View File

@ -1,56 +0,0 @@
<script lang="ts" setup>
defineProps({
cardInfo: {
type: Object,
default() {
return {
name: '',
icon: ''
}
}
}
})
const emits = defineEmits(['openBlank'])
const openBlank = () => {
emits('openBlank')
}
</script>
<template>
<div class="doc-card" @click="openBlank">
<div class="base-show">
<Icon><component class="svg-icon item-top-icon" :is="cardInfo.icon"></component></Icon>
</div>
<div class="base-show show-content">{{ cardInfo.name }}</div>
</div>
</template>
<style lang="less" scoped>
.doc-card {
padding: 8px 0;
width: 96px;
height: 66px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
&:hover,
&:active {
background-color: #1f23291a;
border-radius: 4px;
}
}
.show-content {
font-size: 14px;
color: #1f2329;
line-height: 22px;
font-weight: 400;
margin-top: 4px;
}
.item-top-icon {
width: 24px;
height: 24px;
}
</style>

View File

@ -863,7 +863,7 @@ export default {
'Please fill in one per line, up to 500 items can be added. Duplicate options and already added options will be automatically filtered out when identifying input', 'Please fill in one per line, up to 500 items can be added. Duplicate options and already added options will be automatically filtered out when identifying input',
close: 'Close', close: 'Close',
add: 'Add', add: 'Add',
sure: 'Confirm', sure: 'Confirm',
uncommitted_tips: 'There are uncommitted permission changes, do you want to submit? ', uncommitted_tips: 'There are uncommitted permission changes, do you want to submit? ',
use: 'Use', use: 'Use',
check: 'View', check: 'View',
@ -1234,8 +1234,8 @@ export default {
text_pos_right: 'right', text_pos_right: 'right',
text_pos_top: 'top', text_pos_top: 'top',
text_pos_bottom: 'bottom', text_pos_bottom: 'bottom',
text_italic: 'font italic', text_italic: 'font tilt',
italic: 'italic', italic: 'tilt',
orient: 'direction', orient: 'direction',
horizontal: 'horizontal', horizontal: 'horizontal',
vertical: 'vertical', vertical: 'vertical',
@ -1850,14 +1850,7 @@ Scatter chart (bubble) chart: {a} (series name), {b} (data name), {c} (value arr
full_display: 'full display', full_display: 'full display',
show_hover_style: 'show mouse hover style', show_hover_style: 'show mouse hover style',
merge_cells: 'merge cells', merge_cells: 'merge cells',
length_limit: 'length limit', length_limit: 'length limit'
radar_point: 'enable auxiliary points',
radar_point_size: 'size',
radar_area_color: 'enable area',
table_freeze_tip: 'after merging cells, column and row freezing is not supported',
merge_cells_tips:
'after merging cells, freezing rows and columns and automatic line wrapping will become invalid',
merge_cells_break_line_tip: 'after merging cells, automatic line wrapping is not supported'
}, },
dataset: { dataset: {
scope_edit: 'only effective when editing', scope_edit: 'only effective when editing',
@ -2272,9 +2265,6 @@ Scatter chart (bubble) chart: {a} (series name), {b} (data name), {c} (value arr
day_limit: 'Days cannot be less than 1 and greater than 31' day_limit: 'Days cannot be less than 1 and greater than 31'
}, },
commons: { commons: {
language: 'language',
help_center: 'Help Center',
assistant: 'Assistant',
test_connect: 'Test connection', test_connect: 'Test connection',
consanguinity: 'blood relationship', consanguinity: 'blood relationship',
collapse_navigation: 'Collapse navigation', collapse_navigation: 'Collapse navigation',
@ -2657,36 +2647,6 @@ Scatter chart (bubble) chart: {a} (series name), {b} (data name), {c} (value arr
column_name: 'Field name' column_name: 'Field name'
}, },
visualization: { visualization: {
effective_during_link: 'Public link active',
condition_style_set: 'Condition Style Settings',
cell_merge_tips:
'After merging cells, row/column freezing and automatic line wrapping will be disabled.',
image: 'Image',
jump_set_tips: 'Drill-down has been set',
input_calc_data: 'Enter calculation data',
excel_with_format: 'Excel (with format)',
show_data: 'View Data',
sort: 'Sort',
add_query_filter: 'Add Query Condition',
edit_query_filter: 'Edit Query Condition',
jump_set_tips: 'Redirection has been set',
tips_world: 'Tip Words',
query_name_space2: 'Spacing between name and selection box',
button_color: 'Button Color',
button_text: 'Button Text',
font_size: 'Font Size',
show_button: 'Show Button',
query_tips:
'If the query button is displayed, the chart query will be triggered only after clicking the button. If not displayed, the query is triggered immediately after selecting the query conditions.',
custom_query_bg_color: 'Custom Query Background Color',
query_condition_space: 'Query Condition Spacing',
query_condition_name: 'Query Condition Name',
condition_left: 'Left Side',
condition_top: 'Top Side',
custom_bg_color: 'Custom Component Background',
background_img: 'Background Image',
back_parent: 'Back to Parent',
ext_fullscreen: 'Exit Fullscreen',
no_edit_auth: 'No edit permissions for the target resource, please contact the administrator!', no_edit_auth: 'No edit permissions for the target resource, please contact the administrator!',
select_target_dashboard_tips: 'Please select the target dashboard', select_target_dashboard_tips: 'Please select the target dashboard',
select_target_screen_tips: 'Please select the target data screen', select_target_screen_tips: 'Please select the target data screen',
@ -2981,7 +2941,7 @@ Scatter chart (bubble) chart: {a} (series name), {b} (data name), {c} (value arr
panel_background: 'Dashboard Background', panel_background: 'Dashboard Background',
component_color: 'Component Color', component_color: 'Component Color',
chart_title: 'Chart Title', chart_title: 'Chart Title',
filter_component: 'Query', filter_component: 'Filter Component',
enable_refresh_view: 'Enable Refresh', enable_refresh_view: 'Enable Refresh',
enable_view_loading: 'Chart Loading Prompt', enable_view_loading: 'Chart Loading Prompt',
image_size_tips: 'Please ensure images are no larger than 15MB', image_size_tips: 'Please ensure images are no larger than 15MB',

View File

@ -608,7 +608,6 @@ export default {
secret_length: '密鑰長度' secret_length: '密鑰長度'
}, },
components: { components: {
effective_during_link: '公共連結生效',
dashboard_style: '儀表板風格', dashboard_style: '儀表板風格',
overall_configuration: '整體配置', overall_configuration: '整體配置',
dashboard_background: '儀表板背景', dashboard_background: '儀表板背景',
@ -1811,13 +1810,7 @@ export default {
full_display: '全量顯示', full_display: '全量顯示',
show_hover_style: '顯示滑鼠懸浮樣式', show_hover_style: '顯示滑鼠懸浮樣式',
merge_cells: '合併儲存格', merge_cells: '合併儲存格',
length_limit: '長度限制', length_limit: '長度限制'
radar_point: '開啟輔助點',
radar_point_size: '輔助點大小',
radar_area_color: '開啟面積',
table_freeze_tip: '合併儲存格後不支持行列凍結',
merge_cells_tips: '合併儲存格後行列凍結自動換行會失效',
merge_cells_break_line_tip: '合併儲存格後不支持自動換行'
}, },
dataset: { dataset: {
scope_edit: '僅編輯時生效', scope_edit: '僅編輯時生效',
@ -2221,9 +2214,6 @@ export default {
day_limit: '天不能小於1大於31' day_limit: '天不能小於1大於31'
}, },
commons: { commons: {
language: '語言',
help_center: '幫助中心',
assistant: '小助手',
test_connect: '測試連線', test_connect: '測試連線',
consanguinity: '血緣關係', consanguinity: '血緣關係',
collapse_navigation: '收起導航', collapse_navigation: '收起導航',
@ -2595,34 +2585,6 @@ export default {
column_name: '欄位名稱' column_name: '欄位名稱'
}, },
visualization: { visualization: {
condition_style_set: '條件樣式設定',
cell_merge_tips: '合併單元格後行列凍結自動換行將失效',
image: '圖片',
jump_set_tips: '已設定下鑽',
input_calc_data: '輸入計算數據',
excel_with_format: 'Excel(帶格式)',
show_data: '查看數據',
sort: '排序',
add_query_filter: '添加查詢條件',
edit_query_filter: '編輯查詢條件',
jump_set_tips: '已設定跳轉',
tips_world: '提示詞',
query_name_space2: '名稱與選框間距',
button_color: '按鈕顏色',
button_text: '按鈕文字',
font_size: '字號',
show_button: '展示按鈕',
query_tips:
'如果展示查詢按鈕需要點擊該按鈕後才能觸發圖表查詢如果不展示查詢按鈕選擇完查詢條件後立即觸發圖表查詢',
custom_query_bg_color: '自定義查詢條件背景',
query_condition_space: '查詢條件間距',
query_condition_name: '查詢條件名稱',
condition_left: '左側',
condition_top: '上側',
custom_bg_color: '自定義組件背景',
background_img: '背景圖片',
back_parent: '返回上一級',
ext_fullscreen: '退出全屏',
no_edit_auth: '目標資源沒有編輯權限請聯繫管理員', no_edit_auth: '目標資源沒有編輯權限請聯繫管理員',
select_target_dashboard_tips: '請選擇目標儀表板', select_target_dashboard_tips: '請選擇目標儀表板',
select_target_screen_tips: '請選擇目標數據大屏', select_target_screen_tips: '請選擇目標數據大屏',

View File

@ -1,6 +1,5 @@
export default { export default {
common: { common: {
timeout_tips: '请求超时请稍后再试',
component: { component: {
input: '单行输入', input: '单行输入',
textarea: '多行输入', textarea: '多行输入',
@ -1813,13 +1812,7 @@ export default {
full_display: '全量显示', full_display: '全量显示',
show_hover_style: '显示鼠标悬浮样式', show_hover_style: '显示鼠标悬浮样式',
merge_cells: '合并单元格', merge_cells: '合并单元格',
length_limit: '长度限制', length_limit: '长度限制'
radar_point: '开启辅助点',
radar_point_size: '辅助点大小',
radar_area_color: '开启面积',
table_freeze_tip: '合并单元格后不支持行列冻结',
merge_cells_tips: '合并单元格后行列冻结自动换行会失效',
merge_cells_break_line_tip: '合并单元格后不支持自动换行'
}, },
dataset: { dataset: {
scope_edit: '仅编辑时生效', scope_edit: '仅编辑时生效',
@ -2223,9 +2216,6 @@ export default {
day_limit: '天不能小于1大于31' day_limit: '天不能小于1大于31'
}, },
commons: { commons: {
language: '语言',
help_center: '帮助中心',
assistant: '小助手',
test_connect: '测试连接', test_connect: '测试连接',
consanguinity: '血缘关系', consanguinity: '血缘关系',
collapse_navigation: '收起导航', collapse_navigation: '收起导航',
@ -2597,35 +2587,6 @@ export default {
column_name: '字段名称' column_name: '字段名称'
}, },
visualization: { visualization: {
effective_during_link: '公共链接生效',
condition_style_set: '条件样式设置',
cell_merge_tips: '合并单元格后行列冻结自动换行会失效',
image: '图片',
jump_set_tips: '已设置下钻',
input_calc_data: '输入计算数据',
excel_with_format: 'Excel(带格式)',
show_data: '查看数据',
sort: '排序',
add_query_filter: '添加查询条件',
edit_query_filter: '编辑查询条件',
jump_set_tips: '已设置跳转',
tips_world: '提示词',
query_name_space2: '名称与选框间距',
button_color: '按钮颜色',
button_text: '按钮文字',
font_size: '字号',
show_button: '展示按钮',
query_tips:
'如果展示查询按钮需要点击该按钮后才能触发图表查询如果不展示查询按钮选择完查询条件后立即触发图表查询',
custom_query_bg_color: '自定义查询条件背景',
query_condition_space: '查询条件间距',
query_condition_name: '查询条件名称',
condition_left: '左侧',
condition_top: '上侧',
custom_bg_color: '自定义组件背景',
background_img: '背景图片',
back_parent: '返回上一级',
ext_fullscreen: '退出全屏',
no_edit_auth: '目标资源没有编辑权限请联系管理员', no_edit_auth: '目标资源没有编辑权限请联系管理员',
select_target_dashboard_tips: '请选择目标仪表板', select_target_dashboard_tips: '请选择目标仪表板',
select_target_screen_tips: '请选择目标数据大屏', select_target_screen_tips: '请选择目标数据大屏',

View File

@ -334,18 +334,6 @@ declare interface ChartBasicStyle {
* 最大行数 * 最大行数
*/ */
maxLines?: number maxLines?: number
/**
* 雷达图辅助点
*/
radarShowPoint: boolean
/**
* 雷达图辅助点大小
*/
radarPointSize: number
/**
* 雷达图面积颜色开关
*/
radarAreaColor: boolean
} }
/** /**
* 表头属性 * 表头属性

View File

@ -474,7 +474,7 @@ export const dvMainStore = defineStore('dataVisualization', {
const newView = { const newView = {
...JSON.parse(JSON.stringify(BASE_VIEW_CONFIG)), ...JSON.parse(JSON.stringify(BASE_VIEW_CONFIG)),
id: component.id, id: component.id,
title: t('visualization.query_component'), title: '查询组件',
type: component.innerType, type: component.innerType,
customStyle: { customStyle: {
component: { component: {

View File

@ -24,11 +24,6 @@ export const useRequestStore = defineStore('request', {
setLoadingMap(value: object) { setLoadingMap(value: object) {
this.loadingMap = value this.loadingMap = value
}, },
resetLoadingMap() {
for (const key in this.loadingMap) {
this.loadingMap[key] = 0
}
},
addLoading(key: string) { addLoading(key: string) {
if (Object.prototype.hasOwnProperty.call(this.loadingMap, key)) { if (Object.prototype.hasOwnProperty.call(this.loadingMap, key)) {
const map = this.loadingMap const map = this.loadingMap

View File

@ -187,16 +187,16 @@ function move(keyCode) {
const scale = dvMainStore.canvasStyleData.scale / 100 const scale = dvMainStore.canvasStyleData.scale / 100
if (keyCode === leftKey) { if (keyCode === leftKey) {
curComponent.value.style.left = curComponent.value.style.left - scale curComponent.value.style.left = curComponent.value.style.left - scale
groupAreaAdaptor(-scale, 0) groupAreaAdaptor(-1, 0)
} else if (keyCode === rightKey) { } else if (keyCode === rightKey) {
curComponent.value.style.left = curComponent.value.style.left + scale curComponent.value.style.left = curComponent.value.style.left + scale
groupAreaAdaptor(scale, 0) groupAreaAdaptor(1, 0)
} else if (keyCode === upKey) { } else if (keyCode === upKey) {
curComponent.value.style.top = curComponent.value.style.top - scale curComponent.value.style.top = curComponent.value.style.top - scale
groupAreaAdaptor(0, -scale) groupAreaAdaptor(0, -1)
} else if (keyCode === downKey) { } else if (keyCode === downKey) {
curComponent.value.style.top = curComponent.value.style.top + scale curComponent.value.style.top = curComponent.value.style.top + scale
groupAreaAdaptor(0, scale) groupAreaAdaptor(0, 1)
} }
snapshotStore.recordSnapshotCache('key-move') snapshotStore.recordSnapshotCache('key-move')
} }
@ -212,11 +212,6 @@ function groupAreaAdaptor(leftOffset = 0, topOffset = 0) {
width: parentNode.offsetWidth, width: parentNode.offsetWidth,
height: parentNode.offsetHeight height: parentNode.offsetHeight
}) })
} else if (curComponent.value.component === 'GroupArea' && areaData.value.components.length > 0) {
areaData.value.components.forEach(component => {
component.style.top = component.style.top + topOffset
component.style.left = component.style.left + leftOffset
})
} }
} }

View File

@ -1,15 +1,12 @@
import { cos, sin } from '@/utils/translate' import { cos, sin } from '@/utils/translate'
import { import {
CHART_FONT_FAMILY_MAP,
CHART_FONT_FAMILY_MAP_TRANS,
DEFAULT_COLOR_CASE, DEFAULT_COLOR_CASE,
DEFAULT_COLOR_CASE_DARK, DEFAULT_COLOR_CASE_DARK
DEFAULT_INDICATOR_STYLE
} from '@/views/chart/components/editor/util/chart' } from '@/views/chart/components/editor/util/chart'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/hooks/web/useEmitt'
import { defaultTo, merge } from 'lodash-es' import { merge } from 'lodash-es'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
export const LIGHT_THEME_COLOR_MAIN = '#000000' export const LIGHT_THEME_COLOR_MAIN = '#000000'
@ -116,7 +113,7 @@ export function colorRgb(color, opacity) {
} }
export const customAttrTrans = { export const customAttrTrans = {
basicStyle: ['barWidth', 'lineWidth', 'lineSymbolSize', 'tableColumnWidth'], basicStyle: ['barWidth', 'lineWidth', 'lineSymbolSize'],
tableHeader: ['tableTitleFontSize', 'tableTitleHeight'], tableHeader: ['tableTitleFontSize', 'tableTitleHeight'],
tableCell: ['tableItemFontSize', 'tableItemHeight'], tableCell: ['tableItemFontSize', 'tableItemHeight'],
misc: [ misc: [
@ -427,10 +424,7 @@ export function adaptCurTheme(customStyle, customAttr) {
export function adaptTitleFontFamily(fontFamily, viewInfo) { export function adaptTitleFontFamily(fontFamily, viewInfo) {
if (viewInfo) { if (viewInfo) {
viewInfo.customStyle['text']['fontFamily'] = defaultTo( viewInfo.customStyle['text']['fontFamily'] = fontFamily
CHART_FONT_FAMILY_MAP_TRANS[fontFamily],
fontFamily
)
} }
} }

View File

@ -1,11 +1,18 @@
<script lang="ts" setup> <script lang="ts" setup>
import logo from '@/assets/svg/logo.svg' import logo from '@/assets/svg/logo.svg'
import aboutBg from '@/assets/img/about-bg.png' import aboutBg from '@/assets/img/about-bg.png'
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted, h } from 'vue'
import { useUserStoreWithOut } from '@/store/modules/user' import { useUserStoreWithOut } from '@/store/modules/user'
import { F2CLicense } from './index' import { F2CLicense } from './index'
import { validateApi, buildVersionApi, updateInfoApi } from '@/api/about' import {
import { ElMessage } from 'element-plus-secondary' validateApi,
buildVersionApi,
updateInfoApi,
checkFreeApi,
syncFreeApi,
delFreeApi
} from '@/api/about'
import { ElMessage, ElMessageBox, Action } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/hooks/web/useEmitt'
import { useCache } from '@/hooks/web/useCache' import { useCache } from '@/hooks/web/useCache'
@ -122,11 +129,65 @@ const update = (licKey: string) => {
ElMessage.success(t('about.update_success')) ElMessage.success(t('about.update_success'))
const info = getLicense(response.data) const info = getLicense(response.data)
setLicense(info) setLicense(info)
checkFree()
} else { } else {
ElMessage.warning(response.data.message) ElMessage.warning(response.data.message)
} }
}) })
} }
const autoSync = ref(true)
const checkFree = () => {
checkFreeApi().then(res => {
if (res.data) {
if (autoSync.value) {
syncFree()
return
}
// do something
const title = '存在未同步的资源数据,请谨慎操作!'
const childrenDomList = [h('strong', null, title)]
ElMessageBox.confirm('', {
confirmButtonType: 'primary',
type: 'warning',
autofocus: false,
dangerouslyUseHTMLString: true,
message: h('div', { class: 'free-sync-tip-box' }, childrenDomList),
showClose: false,
cancelButtonText: '删除',
cancelButtonClass: 'free-cancel-bt',
showCancelButton: false,
preButtonType: 'danger',
preButtonText: '删除',
showPreButton: true,
confirmButtonText: '同步',
callback: (action: Action) => {
if (action === 'confirm') {
syncFree()
} else {
delFree
}
}
})
}
})
}
const delFree = () => {
delFreeApi().then(res => {
if (!res.code && !res.msg) {
ElMessage.success(t('common.delete_success'))
}
})
}
const syncFree = () => {
syncFreeApi().then(res => {
if (!res.code && !res.msg) {
ElMessage.success('同步成功')
}
})
}
</script> </script>
<template> <template>

View File

@ -3,7 +3,6 @@ import { computed, nextTick, onMounted, PropType, reactive, ref, watch } from 'v
import { getGeoJsonFile, parseJson } from '../../../js/util' import { getGeoJsonFile, parseJson } from '../../../js/util'
import { forEach, debounce } from 'lodash-es' import { forEach, debounce } from 'lodash-es'
import { toRefs } from 'vue' import { toRefs } from 'vue'
import { getCustomGeoArea } from '@/api/map'
const props = defineProps({ const props = defineProps({
chart: { chart: {
@ -71,11 +70,7 @@ const getAreaMapping = async areaId => {
return {} return {}
} }
if (areaId.startsWith('custom_')) { if (areaId.startsWith('custom_')) {
const areaList = (await getCustomGeoArea(areaId)).data areaId = '156'
return areaList.reduce((p, n) => {
p[n.name] = n.name
return p
}, {})
} }
const geoJson = await getGeoJsonFile(areaId) const geoJson = await getGeoJsonFile(areaId)
return geoJson.features.reduce((p, n) => { return geoJson.features.reduce((p, n) => {

View File

@ -496,9 +496,7 @@ init()
<el-col v-if="props.chart.type && props.chart.type === 'indicator'"> <el-col v-if="props.chart.type && props.chart.type === 'indicator'">
<el-col> <el-col>
<div class="inner-container"> <div class="inner-container">
<span class="label" :class="'label-' + props.themes">{{ <span class="label" :class="'label-' + props.themes">条件样式设置</span>
$t('visualization.condition_style_set')
}}</span>
<span class="right-btns"> <span class="right-btns">
<span <span
class="set-text-info" class="set-text-info"
@ -596,9 +594,7 @@ init()
<el-col v-show="showProperty('tableThreshold')"> <el-col v-show="showProperty('tableThreshold')">
<el-col> <el-col>
<div class="inner-container"> <div class="inner-container">
<span class="label" :class="'label-' + props.themes">{{ <span class="label" :class="'label-' + props.themes">条件样式设置</span>
$t('visualization.condition_style_set')
}}</span>
<span class="right-btns"> <span class="right-btns">
<span <span
class="set-text-info" class="set-text-info"
@ -796,16 +792,14 @@ init()
<el-col v-show="showProperty('lineThreshold')"> <el-col v-show="showProperty('lineThreshold')">
<el-col> <el-col>
<div class="inner-container"> <div class="inner-container">
<span class="label" :class="'label-' + props.themes">{{ <span class="label" :class="'label-' + props.themes">条件样式设置</span>
$t('visualization.condition_style_set')
}}</span>
<span class="right-btns"> <span class="right-btns">
<span <span
class="set-text-info" class="set-text-info"
:class="{ 'set-text-info-dark': themes === 'dark' }" :class="{ 'set-text-info-dark': themes === 'dark' }"
v-if="state.thresholdForm?.tableThreshold?.length > 0" v-if="state.thresholdForm?.tableThreshold?.length > 0"
> >
$t('visualization.already_setting') 已设置
</span> </span>
<el-button <el-button
:title="t('chart.edit')" :title="t('chart.edit')"

View File

@ -283,7 +283,7 @@ initParams()
/> />
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="t('components.title_color')" label="标题颜色"
class="form-item" class="form-item"
style="padding-left: 20px" style="padding-left: 20px"
:class="'form-item-' + themes" :class="'form-item-' + themes"
@ -330,7 +330,7 @@ initParams()
size="small" size="small"
v-model="commonBackgroundPop.backgroundColorSelect" v-model="commonBackgroundPop.backgroundColorSelect"
> >
{{ t('visualization.custom_bg_color') }} 自定义组件背景
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-row style="padding-left: 20px" :gutter="8"> <el-row style="padding-left: 20px" :gutter="8">
@ -389,14 +389,10 @@ initParams()
label="innerImage" label="innerImage"
:effect="themes" :effect="themes"
> >
{{ t('visualization.background_color') }} 背景颜色
</el-radio>
<el-radio key="color" v-else label="color" :effect="themes">
{{ t('visualization.background_color') }}
</el-radio>
<el-radio label="outerImage" :effect="themes">
{{ t('visualization.background_img') }}
</el-radio> </el-radio>
<el-radio key="color" v-else label="color" :effect="themes"> 背景颜色 </el-radio>
<el-radio label="outerImage" :effect="themes"> 背景图片 </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -434,7 +430,7 @@ initParams()
class="image-hint" class="image-hint"
:class="`image-hint_${themes}`" :class="`image-hint_${themes}`"
> >
{{ t('visualization.pic_import_tips') }} 支持JPGPNGGIFSVG
</span> </span>
<el-button <el-button
@ -469,7 +465,7 @@ initParams()
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-collapse-item> </el-collapse-item>
<el-collapse-item :effect="themes" name="addition" :title="t('v_query.query_condition')"> <el-collapse-item :effect="themes" name="addition" title="查询条件">
<el-form @keydown.stop.prevent.enter label-position="top"> <el-form @keydown.stop.prevent.enter label-position="top">
<el-form-item class="form-item margin-bottom-8" :class="'form-item-' + themes"> <el-form-item class="form-item margin-bottom-8" :class="'form-item-' + themes">
<el-checkbox <el-checkbox
@ -505,7 +501,7 @@ initParams()
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="t('visualization.text_html')" label="文本"
class="form-item" class="form-item"
style="padding-left: 20px" style="padding-left: 20px"
:class="'form-item-' + themes" :class="'form-item-' + themes"
@ -548,7 +544,7 @@ initParams()
</div> </div>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="t('visualization.tips_world')" label="提示词"
class="form-item" class="form-item"
style="padding-left: 20px" style="padding-left: 20px"
:class="'form-item-' + themes" :class="'form-item-' + themes"
@ -580,7 +576,7 @@ initParams()
size="small" size="small"
v-model="chart.customStyle.component.bgColorShow" v-model="chart.customStyle.component.bgColorShow"
> >
{{ t('visualization.custom_query_bg_color') }} 自定义查询条件背景
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -600,7 +596,7 @@ initParams()
<el-form-item <el-form-item
:effect="themes" :effect="themes"
class="form-item" class="form-item"
:label="t('visualization.query_condition_space')" label="查询条件间距"
:class="'form-item-' + themes" :class="'form-item-' + themes"
> >
<el-input-number <el-input-number
@ -616,7 +612,7 @@ initParams()
:themes="themes" :themes="themes"
v-model="chart.customStyle.component.labelShow" v-model="chart.customStyle.component.labelShow"
name="legend" name="legend"
:title="t('visualization.query_condition_name')" title="查询条件名称"
> >
<el-form <el-form
:class="!chart.customStyle.component.labelShow && 'is-disabled'" :class="!chart.customStyle.component.labelShow && 'is-disabled'"
@ -630,12 +626,8 @@ initParams()
:class="'form-item-' + themes" :class="'form-item-' + themes"
> >
<el-radio-group :effect="themes" v-model="chart.customStyle.component.layout"> <el-radio-group :effect="themes" v-model="chart.customStyle.component.layout">
<el-radio label="vertical" :effect="themes"> <el-radio label="vertical" :effect="themes"> 上侧 </el-radio>
{{ t('visualization.condition_top') }} <el-radio label="horizontal" :effect="themes"> 左侧 </el-radio>
</el-radio>
<el-radio label="horizontal" :effect="themes">
{{ t('visualization.condition_left') }}
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -648,11 +640,7 @@ initParams()
is-custom is-custom
v-model="chart.customStyle.component.labelColor" v-model="chart.customStyle.component.labelColor"
:predefine="predefineColors" :predefine="predefineColors"
/><el-tooltip /><el-tooltip content="" :effect="toolTip" placement="top">
:content="t('visualization.font_size')"
:effect="toolTip"
placement="top"
>
<el-select <el-select
style="width: 80px; margin: 0 8px" style="width: 80px; margin: 0 8px"
:effect="themes" :effect="themes"
@ -710,7 +698,7 @@ initParams()
<el-form-item <el-form-item
:effect="themes" :effect="themes"
class="form-item" class="form-item"
:label="t('visualization.query_name_space2')" label="名称与选框间距"
:class="'form-item-' + themes" :class="'form-item-' + themes"
> >
<el-input-number <el-input-number
@ -728,7 +716,7 @@ initParams()
<el-form-item <el-form-item
:effect="themes" :effect="themes"
class="form-item" class="form-item"
:label="t('visualization.show_button')" label="展示按钮"
:class="'form-item-' + themes" :class="'form-item-' + themes"
> >
<el-checkbox-group :effect="themes" v-model="chart.customStyle.component.btnList"> <el-checkbox-group :effect="themes" v-model="chart.customStyle.component.btnList">
@ -736,7 +724,7 @@ initParams()
{{ t('commons.adv_search.search') }} {{ t('commons.adv_search.search') }}
<el-tooltip <el-tooltip
:effect="toolTip" :effect="toolTip"
:content="t('visualization.query_tips')" content="如果展示查询按钮,需要点击该按钮后才能触发图表查询;如果不展示查询按钮,选择完查询条件后立即触发图表查询"
placement="top" placement="top"
> >
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }"> <el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
@ -753,11 +741,7 @@ initParams()
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item class="form-item" label="按钮颜色" :class="'form-item-' + themes">
class="form-item"
:label="t('visualization.button_color')"
:class="'form-item-' + themes"
>
<el-color-picker <el-color-picker
:effect="themes" :effect="themes"
:trigger-width="108" :trigger-width="108"
@ -767,7 +751,7 @@ initParams()
/> />
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="t('visualization.button_text')" label="按钮文字"
class="form-item margin-bottom-8" class="form-item margin-bottom-8"
:class="'form-item-' + themes" :class="'form-item-' + themes"
> >
@ -776,11 +760,7 @@ initParams()
is-custom is-custom
v-model="chart.customStyle.component.labelColorBtn" v-model="chart.customStyle.component.labelColorBtn"
:predefine="predefineColors" :predefine="predefineColors"
/><el-tooltip /><el-tooltip content="" :effect="toolTip" placement="top">
:content="t('visualization.font_size')"
:effect="toolTip"
placement="top"
>
<el-select <el-select
style="width: 80px; margin: 0 8px" style="width: 80px; margin: 0 8px"
:effect="themes" :effect="themes"

View File

@ -320,17 +320,6 @@ const mapCustomRangeValidate = prop => {
} }
changeBasicStyle(prop) changeBasicStyle(prop)
} }
/**
* 表格是否合并单元格
*/
const mergeCell = computed(() => {
if (COLUMN_WIDTH_TYPE.includes(props.chart.type)) {
let { customAttr } = JSON.parse(JSON.stringify(props.chart))
const { tableCell } = customAttr
return tableCell.mergeCells
}
return false
})
onMounted(() => { onMounted(() => {
init() init()
}) })
@ -1068,21 +1057,12 @@ onMounted(() => {
<el-checkbox <el-checkbox
size="small" size="small"
:effect="themes" :effect="themes"
:disabled="mergeCell"
v-model="state.basicStyleForm.autoWrap" v-model="state.basicStyleForm.autoWrap"
@change="changeBasicStyle('autoWrap')" @change="changeBasicStyle('autoWrap')"
> >
<span class="data-area-label"> <span class="data-area-label">
<span style="margin-right: 4px">{{ t('chart.table_auto_break_line') }}</span> <span style="margin-right: 4px">{{ t('chart.table_auto_break_line') }}</span>
<el-tooltip class="item" effect="dark" placement="bottom" v-if="mergeCell"> <el-tooltip class="item" effect="dark" placement="bottom">
<template #content>
<div>{{ t('chart.merge_cells_break_line_tip') }}</div>
</template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
</el-icon>
</el-tooltip>
<el-tooltip class="item" effect="dark" placement="bottom" v-else>
<template #content> <template #content>
<div>{{ t('chart.table_break_line_tip') }}</div> <div>{{ t('chart.table_break_line_tip') }}</div>
</template> </template>
@ -1106,7 +1086,6 @@ onMounted(() => {
:show-input-controls="false" :show-input-controls="false"
:min="1" :min="1"
:step="1" :step="1"
:disabled="mergeCell"
@change="changeBasicStyle('maxLines')" @change="changeBasicStyle('maxLines')"
/> />
</el-form-item> </el-form-item>
@ -1299,53 +1278,6 @@ onMounted(() => {
<el-radio :effect="themes" label="circle">{{ t('chart.circle') }}</el-radio> <el-radio :effect="themes" label="circle">{{ t('chart.circle') }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item
class="form-item margin-bottom-8"
:class="'form-item-' + themes"
v-if="showProperty('radarShowPoint')"
>
<el-checkbox
size="small"
:effect="themes"
v-model="state.basicStyleForm.radarShowPoint"
@change="changeBasicStyle('radarShowPoint')"
>
{{ $t('chart.radar_point') }}
</el-checkbox>
</el-form-item>
<el-form-item
style="padding-left: 20px"
class="form-item margin-bottom-8"
:class="'form-item-' + themes"
:label="t('chart.radar_point_size')"
v-if="showProperty('radarPointSize')"
>
<el-input-number
style="width: 100%"
:effect="themes"
controls-position="right"
size="middle"
:min="0"
:max="30"
:disabled="!state.basicStyleForm.radarShowPoint"
v-model="state.basicStyleForm.radarPointSize"
@change="changeBasicStyle('radarPointSize')"
/>
</el-form-item>
<el-form-item
class="form-item margin-bottom-8"
:class="'form-item-' + themes"
v-if="showProperty('radarAreaColor')"
>
<el-checkbox
size="small"
:effect="themes"
v-model="state.basicStyleForm.radarAreaColor"
@change="changeBasicStyle('radarAreaColor')"
>
{{ $t('chart.radar_area_color') }}
</el-checkbox>
</el-form-item>
<!--radar end--> <!--radar end-->
<!--scatter start--> <!--scatter start-->
<el-form-item <el-form-item

View File

@ -282,7 +282,8 @@ onMounted(() => {
:deep(.ed-tabs__content) { :deep(.ed-tabs__content) {
height: calc(100% - 35px); height: calc(100% - 35px);
overflow: hidden; overflow-y: auto;
overflow-x: hidden;
} }
} }
.padding-tab { .padding-tab {

View File

@ -473,9 +473,6 @@ const noFullDisplay = computed(() => {
const isGauge = computed(() => { const isGauge = computed(() => {
return props.chart.type === 'gauge' return props.chart.type === 'gauge'
}) })
const isProgressBar = computed(() => {
return props.chart.type === 'progress-bar'
})
</script> </script>
<template> <template>
@ -943,7 +940,7 @@ const isProgressBar = computed(() => {
<el-checkbox <el-checkbox
v-model="state.labelForm.showQuota" v-model="state.labelForm.showQuota"
:effect="themes" :effect="themes"
:disabled="isProgressBar ? false : checkLabelContent('showQuota')" :disabled="checkLabelContent('showQuota')"
size="small" size="small"
label="quota" label="quota"
@change="changeLabelAttr('showQuota')" @change="changeLabelAttr('showQuota')"
@ -1063,12 +1060,12 @@ const isProgressBar = computed(() => {
<el-checkbox <el-checkbox
v-model="state.labelForm.showProportion" v-model="state.labelForm.showProportion"
:effect="themes" :effect="themes"
:disabled="isProgressBar ? false : checkLabelContent('showProportion')" :disabled="checkLabelContent('showProportion')"
size="small" size="small"
label="proportion" label="proportion"
@change="changeLabelAttr('showProportion')" @change="changeLabelAttr('showProportion')"
> >
{{ isProgressBar ? t('chart.value_formatter_percent') : t('chart.proportion') }} {{ t('chart.proportion') }}
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<div style="padding-left: 22px"> <div style="padding-left: 22px">

View File

@ -332,22 +332,7 @@ onMounted(() => {
v-model="state.tableCellForm.tableFreeze" v-model="state.tableCellForm.tableFreeze"
@change="changeTableCell('tableFreeze')" @change="changeTableCell('tableFreeze')"
> >
<span class="data-area-label"> {{ t('chart.table_freeze') }}
<span style="margin-right: 4px">{{ t('chart.table_freeze') }}</span>
<el-tooltip
class="item"
effect="dark"
placement="bottom"
v-if="state.tableCellForm.mergeCells"
>
<template #content>
<div>{{ t('chart.table_freeze_tip') }}</div>
</template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
</el-icon>
</el-tooltip>
</span>
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-row :gutter="8" v-if="showProperty('tableFreeze')"> <el-row :gutter="8" v-if="showProperty('tableFreeze')">
@ -409,7 +394,7 @@ onMounted(() => {
<span style="margin-right: 4px">{{ t('chart.merge_cells') }}</span> <span style="margin-right: 4px">{{ t('chart.merge_cells') }}</span>
<el-tooltip class="item" effect="dark" placement="bottom"> <el-tooltip class="item" effect="dark" placement="bottom">
<template #content> <template #content>
<div>{{ t('chart.merge_cells_tips') }}</div> <div>合并单元格后行列冻结自动换行会失效</div>
</template> </template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }"> <el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon> <Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>

View File

@ -84,7 +84,7 @@ defineExpose({
<el-dialog <el-dialog
width="896px" width="896px"
append-to-body append-to-body
:title="$t('chart.add_filter')" title="添加过滤"
destroy-on-close destroy-on-close
class="de-dialog-form filter-tree-cont" class="de-dialog-form filter-tree-cont"
v-model="dialogVisible" v-model="dialogVisible"

View File

@ -1102,19 +1102,13 @@ const onFunctionCfgChange = val => {
} }
const onBackgroundChange = val => { const onBackgroundChange = val => {
// #13299 curComponent.value.commonBackground = val
if (curComponent.value.id === view.value?.id) { if (mobileInPc.value) {
curComponent.value.commonBackground = val //
if (mobileInPc.value) { useEmitt().emitter.emit('onMobileStatusChange', {
// type: 'componentStyleChange',
useEmitt().emitter.emit('onMobileStatusChange', { value: { type: 'commonBackground', component: JSON.parse(JSON.stringify(curComponent.value)) }
type: 'componentStyleChange', })
value: {
type: 'commonBackground',
component: JSON.parse(JSON.stringify(curComponent.value))
}
})
}
} }
} }
@ -3280,11 +3274,7 @@ const deleteChartFieldItem = id => {
@add-ds-window="addDsWindow" @add-ds-window="addDsWindow"
@on-dataset-change="recordSnapshotInfo('calcData')" @on-dataset-change="recordSnapshotInfo('calcData')"
/> />
<el-tooltip <el-tooltip :effect="toolTip" content="编辑数据集" placement="top">
:effect="toolTip"
:content="$t('deDataset.edit_dataset')"
placement="top"
>
<el-icon <el-icon
v-if="curDatasetWeight >= 7 && !isDataEaseBi" v-if="curDatasetWeight >= 7 && !isDataEaseBi"
class="field-search-icon-btn" class="field-search-icon-btn"

View File

@ -1112,20 +1112,6 @@ export const BASE_ECHARTS_SELECT = {
} }
} }
export const CHART_FONT_FAMILY_ORIGIN = [
{ name: '微软雅黑', value: 'Microsoft YaHei' },
{ name: '宋体', value: 'SimSun, "Songti SC", STSong' },
{ name: '黑体', value: 'SimHei, Helvetica' },
{ name: '楷体', value: 'KaiTi, "Kaiti SC", STKaiti' }
]
export const CHART_FONT_FAMILY_MAP_TRANS = {
'Microsoft YaHei': 'Microsoft YaHei',
'SimSun, "Songti SC", STSong': 'SimSun',
'SimHei, Helvetica': 'SimHei',
'KaiTi, "Kaiti SC", STKaiti': 'KaiTi'
}
export const CHART_FONT_FAMILY = [ export const CHART_FONT_FAMILY = [
{ name: '微软雅黑', value: 'Microsoft YaHei' }, { name: '微软雅黑', value: 'Microsoft YaHei' },
{ name: '宋体', value: 'SimSun' }, { name: '宋体', value: 'SimSun' },
@ -1560,7 +1546,7 @@ export const CHART_TYPE_CONFIGS = [
export const DEFAULT_BASIC_STYLE: ChartBasicStyle = { export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
alpha: 100, alpha: 100,
tableBorderColor: '#CCCCCC', tableBorderColor: '#CCCCCC',
tableScrollBarColor: '#1f23294d', tableScrollBarColor: 'rgba(0, 0, 0, 0.15)',
tableColumnMode: 'adapt', tableColumnMode: 'adapt',
tableColumnWidth: 100, tableColumnWidth: 100,
tableFieldWidth: [], tableFieldWidth: [],
@ -1633,10 +1619,7 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
customIcon: '', customIcon: '',
showHoverStyle: true, showHoverStyle: true,
autoWrap: false, autoWrap: false,
maxLines: 3, maxLines: 3
radarShowPoint: true,
radarPointSize: 4,
radarAreaColor: true
} }
export const BASE_VIEW_CONFIG = { export const BASE_VIEW_CONFIG = {

View File

@ -55,7 +55,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
'background-overall-component': ['all'], 'background-overall-component': ['all'],
'border-style': ['all'], 'border-style': ['all'],
'basic-style-selector': ['colors', 'alpha', 'gradient', 'radiusColumnBar'], 'basic-style-selector': ['colors', 'alpha', 'gradient', 'radiusColumnBar'],
'label-selector': ['hPosition', 'color', 'fontSize', 'showQuota', 'showProportion'], 'label-selector': ['hPosition', 'color', 'fontSize'],
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'], 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'],
'y-axis-selector': [ 'y-axis-selector': [
'name', 'name',
@ -249,30 +249,27 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
protected configLabel(chart: Chart, options: BarOptions): BarOptions { protected configLabel(chart: Chart, options: BarOptions): BarOptions {
const baseOptions = super.configLabel(chart, options) const baseOptions = super.configLabel(chart, options)
if (!baseOptions.label) return baseOptions if (!baseOptions.label) {
if (!baseOptions.label.layout?.[0]) { return baseOptions
baseOptions.label.layout = [{ type: 'limit-in-canvas' }]
} }
const { label: labelAttr } = parseJson(chart.customAttr) const { label: labelAttr } = parseJson(chart.customAttr)
baseOptions.label.style.fill = labelAttr.color baseOptions.label.style.fill = labelAttr.color
const label = { const label = {
...baseOptions.label, ...baseOptions.label,
content: item => { content: item => {
if (item.type === 'target') return '' if (item.type === 'target') {
let text = '' return ''
if (labelAttr.showQuota) text += valueFormatter(item.value, labelAttr.quotaLabelFormatter)
if (labelAttr.showProportion) {
let proportion = item.originalProgress.toFixed(labelAttr.reserveDecimalCount) + '%'
if (labelAttr.showQuota) {
proportion = ` (${proportion}) `
}
text += proportion
} }
return text return item.originalProgress.toFixed(2) + '%'
} }
} }
if (label.position === 'top') label.position = 'right' if (label.position === 'top') {
return { ...baseOptions, label } label.position = 'right'
}
return {
...baseOptions,
label
}
} }
protected configYAxis(chart: Chart, options: BarOptions): BarOptions { protected configYAxis(chart: Chart, options: BarOptions): BarOptions {
const baseOption = super.configYAxis(chart, options) const baseOption = super.configYAxis(chart, options)
@ -303,8 +300,6 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
chart.customStyle.legend.show = false chart.customStyle.legend.show = false
chart.customAttr.label.show = true chart.customAttr.label.show = true
chart.customAttr.label.position = 'right' chart.customAttr.label.position = 'right'
chart.customAttr.label.showQuota = false
chart.customAttr.label.showProportion = true
return chart return chart
} }

View File

@ -12,7 +12,7 @@ import {
MapMouseEvent MapMouseEvent
} from '@/views/chart/components/js/panel/charts/map/common' } from '@/views/chart/components/js/panel/charts/map/common'
import { flow, getGeoJsonFile, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util' import { flow, getGeoJsonFile, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { cloneDeep, isEmpty } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import { import {
handleGeoJson, handleGeoJson,
@ -22,9 +22,6 @@ import {
import { valueFormatter } from '@/views/chart/components/js/formatter' import { valueFormatter } from '@/views/chart/components/js/formatter'
import { deepCopy } from '@/utils/utils' import { deepCopy } from '@/utils/utils'
import { configCarouselTooltip } from '@/views/chart/components/js/panel/charts/map/tooltip-carousel' import { configCarouselTooltip } from '@/views/chart/components/js/panel/charts/map/tooltip-carousel'
import { getCustomGeoArea } from '@/api/map'
import { TextLayer } from '@antv/l7plot/dist/esm'
import { centroid } from '@turf/centroid'
const { t } = useI18n() const { t } = useI18n()
@ -56,23 +53,12 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
} }
async drawChart(drawOption: L7PlotDrawOptions<Choropleth>): Promise<Choropleth> { async drawChart(drawOption: L7PlotDrawOptions<Choropleth>): Promise<Choropleth> {
const { chart, level, areaId, container, action, scope } = drawOption const { chart, level, areaId, container, action } = drawOption
if (!areaId) { if (!areaId) {
return return
} }
chart.container = container chart.container = container
let geoJson = {} as FeatureCollection const geoJson = cloneDeep(await getGeoJsonFile(areaId))
let customSubArea: CustomGeoSubArea[] = []
if (areaId.startsWith('custom_') || scope) {
customSubArea = (await getCustomGeoArea(areaId)).data || []
customSubArea.forEach(a => (a.scopeArr = a.scope?.split(',') || []))
geoJson = cloneDeep(await getGeoJsonFile('156'))
if (scope) {
geoJson.features = geoJson.features.filter(f => scope.includes('156' + f.properties.adcode))
}
} else {
geoJson = cloneDeep(await getGeoJsonFile(areaId))
}
let options: ChoroplethOptions = { let options: ChoroplethOptions = {
preserveDrawingBuffer: true, preserveDrawingBuffer: true,
map: { map: {
@ -115,27 +101,19 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
// 禁用线上地图数据 // 禁用线上地图数据
customFetchGeoData: () => null customFetchGeoData: () => null
} }
const context: Record<string, any> = { drawOption, geoJson, customSubArea } const context = { drawOption, geoJson }
options = this.setupOptions(chart, options, context) options = this.setupOptions(chart, options, context)
const tooltip = deepCopy(options.tooltip) const tooltip = deepCopy(options.tooltip)
options = { ...options, tooltip: { ...tooltip, showComponent: false } } options = { ...options, tooltip: { ...tooltip, showComponent: false } }
const view = new Choropleth(container, options) const view = new Choropleth(container, options)
const dotLayer = this.getDotLayer(chart, geoJson, drawOption, customSubArea) const dotLayer = this.getDotLayer(chart, geoJson, drawOption)
if (!areaId.startsWith('custom_')) { dotLayer.options = { ...dotLayer.options, tooltip }
dotLayer.options = { ...dotLayer.options, tooltip }
}
this.configZoomButton(chart, view) this.configZoomButton(chart, view)
mapRendering(container) mapRendering(container)
view.once('loaded', () => { view.once('loaded', () => {
// 修改地图鼠标样式为默认 // 修改地图鼠标样式为默认
view.scene.map._canvasContainer.lastElementChild.style.cursor = 'default' view.scene.map._canvasContainer.lastElementChild.style.cursor = 'default'
const { layers } = context
if (layers) {
layers.forEach(l => {
view.addLayer(l)
})
}
dotLayer.addToScene(view.scene) dotLayer.addToScene(view.scene)
dotLayer.once('add', () => { dotLayer.once('add', () => {
mapRendered(container) mapRendered(container)
@ -143,22 +121,15 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
view.scene.map['keyboard'].disable() view.scene.map['keyboard'].disable()
dotLayer.on('dotLayer:click', (ev: MapMouseEvent) => { dotLayer.on('dotLayer:click', (ev: MapMouseEvent) => {
const data = ev.feature.properties const data = ev.feature.properties
let adcode, scope const adcode = view.currentDistrictData.features.find(
if (areaId.startsWith('custom_')) { i => i.properties.name === ev.feature.properties.name
adcode = '156' )?.properties.adcode
const area = customSubArea.find(a => a.name === data.name)
scope = area?.scopeArr
} else {
adcode = view.currentDistrictData.features.find(
i => i.properties.name === ev.feature.properties.name
)?.properties.adcode
}
action({ action({
x: ev.x, x: ev.x,
y: ev.y, y: ev.y,
data: { data: {
data, data,
extra: { adcode, scope } extra: { adcode: adcode }
} }
}) })
}) })
@ -173,14 +144,28 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
private getDotLayer( private getDotLayer(
chart: Chart, chart: Chart,
geoJson: FeatureCollection, geoJson: FeatureCollection,
drawOption: L7PlotDrawOptions<Choropleth>, drawOption: L7PlotDrawOptions<Choropleth>
customSubArea: CustomGeoSubArea[]
): IPlotLayer { ): IPlotLayer {
const { areaId } = drawOption const areaMap = chart.data?.data?.reduce((obj, value) => {
const { basicStyle, tooltip } = parseJson(chart.customAttr) obj[value['field']] = { value: value.value, data: value }
return obj
}, {})
const dotData = []
geoJson.features.forEach(item => {
const name = item.properties['name']
if (areaMap?.[name]?.value) {
dotData.push({
x: item.properties['centroid'][0],
y: item.properties['centroid'][1],
size: areaMap[name].value,
properties: areaMap[name].data,
name: name
})
}
})
const { basicStyle } = parseJson(chart.customAttr)
const { bubbleCfg } = parseJson(chart.senior) const { bubbleCfg } = parseJson(chart.senior)
const { offsetHeight, offsetWidth } = document.getElementById(drawOption.container) const { offsetHeight, offsetWidth } = document.getElementById(drawOption.container)
const dotData = []
const options: DotOptions = { const options: DotOptions = {
source: { source: {
data: dotData, data: dotData,
@ -205,120 +190,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
state: { state: {
active: { color: 'rgba(30,90,255,1)' } active: { color: 'rgba(30,90,255,1)' }
}, },
tooltip: { tooltip: {}
showComponent: tooltip.show
}
}
if (areaId.startsWith('custom_')) {
const geoJsonMap = geoJson.features.reduce((p, n) => {
if (n.properties['adcode']) {
p['156' + n.properties['adcode']] = n
}
return p
}, {})
const { areaMapping } = parseJson(chart.senior)
const customAreaMap = customSubArea.reduce((p, n) => {
const mappedName = areaMapping?.[areaId]?.[n.name]
if (mappedName) {
n.name = mappedName
}
p[n.name] = n
return p
}, {})
chart.data?.data?.forEach(d => {
const area = customAreaMap[d.name]
if (area) {
const areaJsonArr = []
area.scopeArr?.forEach(adcode => {
const json = geoJsonMap[adcode]
json && areaJsonArr.push(json)
})
if (areaJsonArr.length) {
const areaJson: FeatureCollection = {
type: 'FeatureCollection',
features: areaJsonArr
}
const center = centroid(areaJson)
dotData.push({
name: area.name,
size: d.value,
properties: d,
x: center.geometry.coordinates[0],
y: center.geometry.coordinates[1]
})
}
}
})
if (options.tooltip && options.tooltip.showComponent) {
options.tooltip.items = ['name', 'adcode', 'value']
options.tooltip.customTitle = ({ name }) => {
return name
}
const formatterMap = tooltip.seriesTooltipFormatter
?.filter(i => i.show)
.reduce((pre, next) => {
pre[next.id] = next
return pre
}, {}) as Record<string, SeriesFormatter>
options.tooltip.customItems = originalItem => {
const result = []
if (isEmpty(formatterMap)) {
return result
}
const head = originalItem.properties
const formatter = formatterMap[head.quotaList?.[0]?.id]
if (!isEmpty(formatter)) {
const originValue = parseFloat(head.value as string)
const value = valueFormatter(originValue, formatter.formatterCfg)
const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName
result.push({ ...head, name, value: `${value ?? ''}` })
}
head.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: `${value ?? ''}` })
}
})
return result
}
options.tooltip.domStyles = {
'l7plot-tooltip': {
'background-color': tooltip.backgroundColor,
'font-size': `${tooltip.fontSize}px`,
'line-height': 1.6
},
'l7plot-tooltip__name': {
color: tooltip.color
},
'l7plot-tooltip__value': {
color: tooltip.color
},
'l7plot-tooltip__title': {
color: tooltip.color
}
}
}
} else {
const areaMap = chart.data?.data?.reduce((obj, value) => {
obj[value['field']] = { value: value.value, data: value }
return obj
}, {})
geoJson.features.forEach(item => {
const name = item.properties['name']
if (areaMap?.[name]?.value) {
dotData.push({
x: item.properties['centroid'][0],
y: item.properties['centroid'][1],
size: areaMap[name].value,
properties: areaMap[name].data,
name: name
})
}
})
} }
if (bubbleCfg && bubbleCfg.enable) { if (bubbleCfg && bubbleCfg.enable) {
return new Dot({ return new Dot({
@ -375,91 +247,6 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
return options return options
} }
protected configCustomArea(
chart: Chart,
options: ChoroplethOptions,
context: Record<string, any>
): ChoroplethOptions {
const { drawOption, customSubArea, geoJson } = context
if (!drawOption.areaId.startsWith('custom_')) {
return options
}
const customAttr = parseJson(chart.customAttr)
const { label } = customAttr
const data = chart.data?.data
const areaMap = data?.reduce((obj, value) => {
obj[value['field']] = value
return obj
}, {})
//处理label
options.label = false
if (label.show) {
const geoJsonMap = geoJson.features.reduce((p, n) => {
if (n.properties['adcode']) {
p['156' + n.properties['adcode']] = n
}
return p
}, {})
const { areaMapping } = parseJson(chart.senior)
const labelLocation = []
customSubArea.forEach(area => {
const areaJsonArr = []
area.scopeArr?.forEach(adcode => {
const json = geoJsonMap[adcode]
json && areaJsonArr.push(json)
})
if (areaJsonArr.length) {
const areaJson: FeatureCollection = {
type: 'FeatureCollection',
features: areaJsonArr
}
const content = []
if (label.showDimension) {
const mappedName = areaMapping?.[drawOption.areaId]?.[area.name]
if (mappedName) {
area.name = mappedName
}
content.push(area.name)
}
if (label.showQuota) {
areaMap[area.name] &&
content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter))
}
const center = centroid(areaJson)
labelLocation.push({
name: content.join('\n\n'),
x: center.geometry.coordinates[0],
y: center.geometry.coordinates[1]
})
}
})
const areaLabelLayer = new TextLayer({
name: 'areaLabelLayer',
source: {
data: labelLocation,
parser: {
type: 'json',
x: 'x',
y: 'y'
}
},
field: 'name',
zIndex: 0.06,
style: {
fill: label.color,
fontSize: label.fontSize,
opacity: 1,
fontWeight: 'bold',
textAnchor: 'center',
textAllowOverlap: label.fullDisplay,
padding: !label.fullDisplay ? [2, 2] : undefined
}
})
context.layers = [areaLabelLayer]
}
return options
}
protected setupOptions( protected setupOptions(
chart: Chart, chart: Chart,
options: ChoroplethOptions, options: ChoroplethOptions,
@ -470,8 +257,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
this.configLabel, this.configLabel,
this.configStyle, this.configStyle,
this.configTooltip, this.configTooltip,
this.configBasicStyle, this.configBasicStyle
this.configCustomArea )(chart, options, context)
)(chart, options, context, this)
} }
} }

View File

@ -99,12 +99,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
p['156' + n.properties.adcode] = n.properties.name p['156' + n.properties.adcode] = n.properties.name
return p return p
}, {}) }, {})
const { areaMapping } = parseJson(chart.senior)
const areaMap = customSubArea.reduce((p, n) => { const areaMap = customSubArea.reduce((p, n) => {
const mappedName = areaMapping?.[areaId]?.[n.name]
if (mappedName) {
n.name = mappedName
}
p[n.name] = n p[n.name] = n
n.scopeArr = n.scope?.split(',') || [] n.scopeArr = n.scope?.split(',') || []
return p return p

View File

@ -1,7 +1,7 @@
import type { RadarOptions, Radar as G2Radar } from '@antv/g2plot/esm/plots/radar' import type { RadarOptions, Radar as G2Radar } from '@antv/g2plot/esm/plots/radar'
import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot' import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
import { flow, parseJson } from '../../../util' import { flow, parseJson } from '../../../util'
import { configPlotTooltipEvent } from '../../common/common_antv' import { configPlotTooltipEvent, getPadding } from '../../common/common_antv'
import { valueFormatter } from '../../../formatter' import { valueFormatter } from '../../../formatter'
import type { Datum } from '@antv/g2plot/esm/types/common' import type { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
@ -25,15 +25,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
'linkage' 'linkage'
] ]
propertyInner: EditorPropertyInner = { propertyInner: EditorPropertyInner = {
'basic-style-selector': [ 'basic-style-selector': ['colors', 'alpha', 'radarShape', 'seriesColor'],
'colors',
'alpha',
'radarShape',
'seriesColor',
'radarShowPoint',
'radarPointSize',
'radarAreaColor'
],
'label-selector': ['seriesLabelFormatter'], 'label-selector': ['seriesLabelFormatter'],
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'], 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
'misc-style-selector': ['showName', 'color', 'fontSize', 'axisColor', 'axisValue'], 'misc-style-selector': ['showName', 'color', 'fontSize', 'axisColor', 'axisValue'],
@ -82,6 +74,13 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
yField: 'value', yField: 'value',
seriesField: 'category', seriesField: 'category',
appendPadding: [10, 10, 10, 10], appendPadding: [10, 10, 10, 10],
point: {
size: 4,
shape: 'circle',
style: {
fill: null
}
},
interactions: [ interactions: [
{ {
type: 'legend-active', type: 'legend-active',
@ -123,22 +122,6 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
return newChart return newChart
} }
protected configBasicStyle(chart: Chart, options: RadarOptions): RadarOptions {
const { radarShowPoint, radarPointSize, radarAreaColor } = parseJson(
chart.customAttr
).basicStyle
const tempOptions: RadarOptions = {}
if (radarShowPoint) {
tempOptions['point'] = { shape: 'circle', size: radarPointSize, style: { fill: null } }
}
if (radarAreaColor) {
tempOptions['area'] = {}
}
return { ...options, ...tempOptions }
}
protected configLabel(chart: Chart, options: RadarOptions): RadarOptions { protected configLabel(chart: Chart, options: RadarOptions): RadarOptions {
const tmpOptions = super.configLabel(chart, options) const tmpOptions = super.configLabel(chart, options)
if (!tmpOptions.label) { if (!tmpOptions.label) {
@ -283,8 +266,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
this.configLabel, this.configLabel,
this.configLegend, this.configLegend,
this.configMultiSeriesTooltip, this.configMultiSeriesTooltip,
this.configAxis, this.configAxis
this.configBasicStyle
)(chart, options) )(chart, options)
} }

View File

@ -4,7 +4,6 @@ import {
S2Event, S2Event,
S2Options, S2Options,
S2Theme, S2Theme,
ScrollbarPositionType,
TableColCell, TableColCell,
TableSheet, TableSheet,
ViewMeta ViewMeta
@ -23,8 +22,7 @@ import {
calculateHeaderHeight, calculateHeaderHeight,
SortTooltip, SortTooltip,
configSummaryRow, configSummaryRow,
summaryRowStyle, summaryRowStyle
configEmptyDataStyle
} from '@/views/chart/components/js/panel/common/common_table' } from '@/views/chart/components/js/panel/common/common_table'
const { t } = useI18n() const { t } = useI18n()
@ -169,10 +167,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
renderTooltip: sheet => new SortTooltip(sheet) renderTooltip: sheet => new SortTooltip(sheet)
}, },
interaction: { interaction: {
hoverHighlight: !(basicStyle.showHoverStyle === false), hoverHighlight: !(basicStyle.showHoverStyle === false)
scrollbarPosition: newData.length
? ScrollbarPositionType.CONTENT
: ScrollbarPositionType.CANVAS
} }
} }
s2Options.style = this.configStyle(chart, s2DataConfig) s2Options.style = this.configStyle(chart, s2DataConfig)
@ -186,7 +181,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
return p return p
}, {}) }, {})
} }
if (tableCell.tableFreeze && !tableCell.mergeCells) { if (tableCell.tableFreeze) {
s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0 s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0
s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0 s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0
} }
@ -217,7 +212,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
} }
} }
// 配置文本自动换行参数 // 配置文本自动换行参数
viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap viewMeta.autoWrap = basicStyle.autoWrap
viewMeta.maxLines = basicStyle.maxLines viewMeta.maxLines = basicStyle.maxLines
return new CustomDataCell(viewMeta, viewMeta?.spreadsheet) return new CustomDataCell(viewMeta, viewMeta?.spreadsheet)
} }
@ -244,7 +239,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
this.configHeaderInteraction(chart, s2Options) this.configHeaderInteraction(chart, s2Options)
s2Options.colCell = (node, sheet, config) => { s2Options.colCell = (node, sheet, config) => {
// 配置文本自动换行参数 // 配置文本自动换行参数
node.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap node.autoWrap = basicStyle.autoWrap
node.maxLines = basicStyle.maxLines node.maxLines = basicStyle.maxLines
return new CustomTableColCell(node, sheet, config) return new CustomTableColCell(node, sheet, config)
} }
@ -256,7 +251,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
// 总计紧贴在单元格后面 // 总计紧贴在单元格后面
summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
// 开启自动换行 // 开启自动换行
if (basicStyle.autoWrap && !tableCell.mergeCells) { if (basicStyle.autoWrap) {
// 调整表头宽度时计算表头高度 // 调整表头宽度时计算表头高度
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, info => { newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, info => {
calculateHeaderHeight(info, newChart, tableHeader, basicStyle, null) calculateHeaderHeight(info, newChart, tableHeader, basicStyle, null)
@ -340,8 +335,6 @@ export class TableInfo extends S2ChartView<TableSheet> {
ev.colsHierarchy.width = containerWidth ev.colsHierarchy.width = containerWidth
}) })
} }
// 空数据时表格样式
configEmptyDataStyle(newChart, basicStyle, newData, container)
// click // click
newChart.on(S2Event.DATA_CELL_CLICK, ev => { newChart.on(S2Event.DATA_CELL_CLICK, ev => {
const cell = newChart.getCell(ev.target) const cell = newChart.getCell(ev.target)

View File

@ -1,7 +1,6 @@
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter' import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
import { import {
configEmptyDataStyle,
configSummaryRow, configSummaryRow,
copyContent, copyContent,
SortTooltip, SortTooltip,
@ -14,7 +13,6 @@ import {
S2DataConfig, S2DataConfig,
S2Event, S2Event,
S2Options, S2Options,
ScrollbarPositionType,
TableColCell, TableColCell,
TableSheet, TableSheet,
ViewMeta ViewMeta
@ -147,10 +145,7 @@ export class TableNormal extends S2ChartView<TableSheet> {
renderTooltip: sheet => new SortTooltip(sheet) renderTooltip: sheet => new SortTooltip(sheet)
}, },
interaction: { interaction: {
hoverHighlight: !(basicStyle.showHoverStyle === false), hoverHighlight: !(basicStyle.showHoverStyle === false)
scrollbarPosition: newData.length
? ScrollbarPositionType.CONTENT
: ScrollbarPositionType.CANVAS
} }
} }
// 列宽设置 // 列宽设置
@ -247,7 +242,6 @@ export class TableNormal extends S2ChartView<TableSheet> {
ev.colsHierarchy.width = containerWidth ev.colsHierarchy.width = containerWidth
}) })
} }
configEmptyDataStyle(newChart, basicStyle, newData, container)
// click // click
newChart.on(S2Event.DATA_CELL_CLICK, ev => { newChart.on(S2Event.DATA_CELL_CLICK, ev => {
const cell = newChart.getCell(ev.target) const cell = newChart.getCell(ev.target)

View File

@ -176,10 +176,6 @@ export function getLabel(chart: Chart) {
) { ) {
layout.push({ type: 'limit-in-canvas' }) layout.push({ type: 'limit-in-canvas' })
layout.push({ type: 'hide-overlap' }) layout.push({ type: 'hide-overlap' })
} else if (chart.type.includes('chart-mix')) {
layout.push({ type: 'limit-in-canvas' })
layout.push({ type: 'limit-in-plot' })
layout.push({ type: 'hide-overlap' })
} else { } else {
layout.push({ type: 'limit-in-plot' }) layout.push({ type: 'limit-in-plot' })
layout.push({ type: 'fixed-overlap' }) layout.push({ type: 'fixed-overlap' })
@ -560,8 +556,7 @@ export function getYAxis(chart: Chart) {
grid, grid,
label, label,
line, line,
tickLine, tickLine
nice: true
} }
return axis return axis
} }
@ -654,8 +649,7 @@ export function getYAxisExt(chart: Chart) {
grid, grid,
label, label,
line, line,
tickLine, tickLine
nice: true
} }
return axis return axis
} }

View File

@ -1671,7 +1671,6 @@ const drawTextShape = (cell, isHeader) => {
* @param layoutResult * @param layoutResult
*/ */
export const calculateHeaderHeight = (info, newChart, tableHeader, basicStyle, layoutResult) => { export const calculateHeaderHeight = (info, newChart, tableHeader, basicStyle, layoutResult) => {
if (tableHeader.showTableHeader === false ) return
const ev = layoutResult || newChart.facet.layoutResult const ev = layoutResult || newChart.facet.layoutResult
const maxLines = basicStyle.maxLines ?? 1 const maxLines = basicStyle.maxLines ?? 1
const textStyle = { ...newChart.theme.cornerCell.text } const textStyle = { ...newChart.theme.cornerCell.text }
@ -1764,7 +1763,7 @@ const getWrapTextHeight = (wrapText, textStyle, spreadsheet, maxLines) => {
* @param showSummary * @param showSummary
*/ */
export const configSummaryRow = (chart, s2Options, newData, tableHeader, basicStyle, showSummary) =>{ export const configSummaryRow = (chart, s2Options, newData, tableHeader, basicStyle, showSummary) =>{
if (!showSummary || !newData.length) return if (!showSummary) return
// 设置汇总行高度和表头一致 // 设置汇总行高度和表头一致
const heightByField = {} const heightByField = {}
heightByField[newData.length] = tableHeader.tableTitleHeight heightByField[newData.length] = tableHeader.tableTitleHeight
@ -1822,13 +1821,10 @@ export const configSummaryRow = (chart, s2Options, newData, tableHeader, basicSt
* @param showSummary * @param showSummary
*/ */
export const summaryRowStyle = (newChart, newData, tableCell, tableHeader, showSummary) => { export const summaryRowStyle = (newChart, newData, tableCell, tableHeader, showSummary) => {
if (!showSummary || !newData.length) return if (!showSummary) return
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => { newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
const showHeader = tableHeader.showTableHeader === true
// 不显示表头时减少一个表头的高度
const headerAndSummaryHeight = showHeader ? 2 : 1
const totalHeight = const totalHeight =
tableHeader.tableTitleHeight * headerAndSummaryHeight + tableCell.tableItemHeight * (newData.length - 1) tableHeader.tableTitleHeight * 2 + tableCell.tableItemHeight * (newData.length - 1)
if (totalHeight < newChart.options.height) { if (totalHeight < newChart.options.height) {
// 6 是阴影高度 // 6 是阴影高度
newChart.options.height = newChart.options.height =
@ -1848,41 +1844,3 @@ export class SummaryCell extends CustomDataCell {
return { backgroundColor, backgroundColorOpacity } return { backgroundColor, backgroundColorOpacity }
} }
} }
/**
* 配置空数据样式
* @param newChart
* @param basicStyle
* @param newData
* @param container
*/
export const configEmptyDataStyle = (newChart, basicStyle, newData, container) => {
/**
* 辅助函数移除空数据dom
*/
const removeEmptyDom = () => {
const emptyElement = document.getElementById(container + '_empty')
if (emptyElement) {
emptyElement.parentElement.removeChild(emptyElement)
}
}
removeEmptyDom()
if (newData.length) return
newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev) => {
removeEmptyDom()
if (!newData.length) {
const emptyDom = document.createElement('div')
const left = Math.min(newChart.options.width, ev.colsHierarchy.width) / 2 - 32
emptyDom.id = container + '_empty'
emptyDom.textContent = t('data_set.no_data')
emptyDom.setAttribute(
'style',
`position: absolute;
left: ${left}px;
top: 50%;`
)
const parent = document.getElementById(container)
parent.insertBefore(emptyDom, parent.firstChild)
}
})
}

View File

@ -183,7 +183,6 @@ const calcData = async (view, callback) => {
emit('onDrillFilters', res?.drillFilters) emit('onDrillFilters', res?.drillFilters)
if (!res?.drillFilters?.length) { if (!res?.drillFilters?.length) {
dynamicAreaId.value = '' dynamicAreaId.value = ''
scope = null
} else { } else {
const extra = view.chartExtRequest?.drill?.[res?.drillFilters?.length - 1].extra const extra = view.chartExtRequest?.drill?.[res?.drillFilters?.length - 1].extra
dynamicAreaId.value = extra?.adcode + '' dynamicAreaId.value = extra?.adcode + ''

View File

@ -22,7 +22,7 @@ import { storeToRefs } from 'pinia'
import { S2ChartView } from '@/views/chart/components/js/panel/types/impl/s2' import { S2ChartView } from '@/views/chart/components/js/panel/types/impl/s2'
import { ElPagination } from 'element-plus-secondary' import { ElPagination } from 'element-plus-secondary'
import ChartError from '@/views/chart/components/views/components/ChartError.vue' import ChartError from '@/views/chart/components/views/components/ChartError.vue'
import { defaultsDeep, cloneDeep, debounce } from 'lodash-es' import { defaultsDeep, cloneDeep } from 'lodash-es'
import { BASE_VIEW_CONFIG } from '../../editor/util/chart' import { BASE_VIEW_CONFIG } from '../../editor/util/chart'
import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/canvasStyle' import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/canvasStyle'
import { deepCopy } from '@/utils/utils' import { deepCopy } from '@/utils/utils'
@ -193,31 +193,29 @@ const renderChart = (viewInfo: Chart, resetPageInfo: boolean) => {
recursionTransObj(customAttrTrans, actualChart.customAttr, scale.value, terminal.value) recursionTransObj(customAttrTrans, actualChart.customAttr, scale.value, terminal.value)
recursionTransObj(customStyleTrans, actualChart.customStyle, scale.value, terminal.value) recursionTransObj(customStyleTrans, actualChart.customStyle, scale.value, terminal.value)
setupPage(actualChart, resetPageInfo)
nextTick(() => debounceRender(resetPageInfo))
}
const debounceRender = debounce(resetPageInfo => {
myChart?.facet?.timer?.stop() myChart?.facet?.timer?.stop()
myChart?.facet?.cancelScrollFrame() myChart?.facet?.cancelScrollFrame()
myChart?.destroy() myChart?.destroy()
myChart?.getCanvasElement()?.remove() myChart = null
setupPage(actualChart, resetPageInfo)
const chartView = chartViewManager.getChartView( const chartView = chartViewManager.getChartView(
actualChart.render, viewInfo.render,
actualChart.type viewInfo.type
) as S2ChartView<any> ) as S2ChartView<any>
myChart = chartView.drawChart({ timer = setTimeout(() => {
container: containerId, myChart = chartView.drawChart({
chart: toRaw(actualChart), container: containerId,
chartObj: myChart, chart: toRaw(actualChart),
pageInfo: state.pageInfo, chartObj: myChart,
action, pageInfo: state.pageInfo,
resizeAction action,
}) resizeAction
myChart?.render() })
dvMainStore.setViewInstanceInfo(actualChart.id, myChart) myChart?.render()
initScroll() dvMainStore.setViewInstanceInfo(viewInfo.id, myChart)
}, 500) initScroll()
}, 500)
}
const setupPage = (chart: ChartObj, resetPageInfo?: boolean) => { const setupPage = (chart: ChartObj, resetPageInfo?: boolean) => {
const customAttr = chart.customAttr const customAttr = chart.customAttr
@ -583,12 +581,24 @@ const resize = (width, height) => {
} }
timer = setTimeout(() => { timer = setTimeout(() => {
if (!myChart?.facet) { if (!myChart?.facet) {
debounceRender(false) const chartView = chartViewManager.getChartView(
actualChart.render,
actualChart.type
) as S2ChartView<any>
myChart = chartView.drawChart({
container: containerId,
chart: toRaw(actualChart),
chartObj: myChart,
pageInfo: state.pageInfo,
action,
resizeAction
})
dvMainStore.setViewInstanceInfo(actualChart.id, myChart)
} else { } else {
myChart?.facet?.timer?.stop() myChart?.facet?.timer?.stop()
myChart?.changeSheetSize(width, height) myChart?.changeSheetSize(width, height)
myChart?.render()
} }
myChart?.render()
initScroll() initScroll()
}, 500) }, 500)
} }
@ -610,7 +620,7 @@ onMounted(() => {
} }
preSize[0] = size.inlineSize preSize[0] = size.inlineSize
preSize[1] = size.blockSize preSize[1] = size.blockSize
resize(size.inlineSize, Math.round(size.blockSize)) resize(size.inlineSize, Math.ceil(size.blockSize))
}) })
resizeObserver.observe(document.getElementById(containerId)) resizeObserver.observe(document.getElementById(containerId))

View File

@ -67,15 +67,10 @@ const loadThemeStyle = () => {
} }
} }
} }
const drillPathVar = computed(() => [{ '--drill-color': textColor.value }])
</script> </script>
<template> <template>
<div <div v-if="props.drillFilters && props.drillFilters.length > 0" class="drill">
v-if="props.drillFilters && props.drillFilters.length > 0"
class="drill"
:style="drillPathVar"
>
<el-breadcrumb :separator-icon="ArrowRight" class="drill-style"> <el-breadcrumb :separator-icon="ArrowRight" class="drill-style">
<el-breadcrumb-item class="drill-item" @click="drillJump(0)"> <el-breadcrumb-item class="drill-item" @click="drillJump(0)">
<span :style="{ color: textColor }">{{ t('commons.all') }}</span> <span :style="{ color: textColor }">{{ t('commons.all') }}</span>
@ -115,8 +110,5 @@ const drillPathVar = computed(() => [{ '--drill-color': textColor.value }])
z-index: 1; z-index: 1;
height: 20px; height: 20px;
padding: 0 16px; padding: 0 16px;
::v-deep(.ed-icon) {
color: var(--drill-color) !important;
}
} }
</style> </style>

View File

@ -1067,24 +1067,14 @@ const titleTooltipWidth = computed(() => {
/></Icon> /></Icon>
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip :effect="toolTip" placement="top" content="已设置跳转" v-if="hasJumpIcon">
:effect="toolTip"
placement="top"
:content="t('visualization.jump_set_tips')"
v-if="hasJumpIcon"
>
<el-icon :size="iconSize" class="inner-icon"> <el-icon :size="iconSize" class="inner-icon">
<Icon name="icon_viewinchat_outlined" <Icon name="icon_viewinchat_outlined"
><icon_viewinchat_outlined class="svg-icon" ><icon_viewinchat_outlined class="svg-icon"
/></Icon> /></Icon>
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip :effect="toolTip" placement="top" content="已设置下钻" v-if="hasDrillIcon">
:effect="toolTip"
placement="top"
:content="t('visualization.drill_set_tips')"
v-if="hasDrillIcon"
>
<el-icon :size="iconSize" class="inner-icon"> <el-icon :size="iconSize" class="inner-icon">
<Icon name="icon_drilling_outlined"><icon_drilling_outlined class="svg-icon" /></Icon> <Icon name="icon_drilling_outlined"><icon_drilling_outlined class="svg-icon" /></Icon>
</el-icon> </el-icon>

View File

@ -141,8 +141,8 @@ const optInit = (type, data: BusiTreeNode, exec, parentSelect = false) => {
const placeholderLabel = const placeholderLabel =
data.leaf || type === 'leaf' data.leaf || type === 'leaf'
? props.curCanvasType === 'dataV' ? props.curCanvasType === 'dataV'
? t('work_branch.screen') ? t('visualization.screen')
: t('work_branch.dashboard') : t('visualization.dashboard')
: t('visualization.folder') : t('visualization.folder')
placeholder.value = t('visualization.input_name_tips', [placeholderLabel]) placeholder.value = t('visualization.input_name_tips', [placeholderLabel])
filterText.value = '' filterText.value = ''

View File

@ -321,7 +321,7 @@ const save = () => {
<el-tab-pane :label="t('visualization.visualization_component')" name="com"> </el-tab-pane> <el-tab-pane :label="t('visualization.visualization_component')" name="com"> </el-tab-pane>
<el-tab-pane :label="t('visualization.component_style')" name="componentStyle"> <el-tab-pane :label="t('visualization.component_style')" name="componentStyle">
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="t('visualization.whole_style')" name="style"> </el-tab-pane> <el-tab-pane label="t('visualization.whole_style')" name="style"> </el-tab-pane>
</el-tabs> </el-tabs>
<template v-if="!mobileLoading"> <template v-if="!mobileLoading">
<div class="config-mobile-tab" v-show="activeCollapse === 'style'"> <div class="config-mobile-tab" v-show="activeCollapse === 'style'">

View File

@ -168,8 +168,8 @@ const XpackLoaded = () => p(true)
onMounted(async () => { onMounted(async () => {
useEmitt({ useEmitt({
name: 'canvasDownload', name: 'canvasDownload',
callback: function (type = 'img') { callback: function () {
downloadH2(type) downloadH2('img')
} }
}) })
await new Promise(r => (p = r)) await new Promise(r => (p = r))

View File

@ -34,7 +34,7 @@ const favorited = ref(false)
const preview = () => { const preview = () => {
const baseUrl = isDataEaseBi.value ? embeddedStore.baseUrl : '' const baseUrl = isDataEaseBi.value ? embeddedStore.baseUrl : ''
const url = baseUrl + '#/preview?dvId=' + dvInfo.value.id + '&ignoreParams=true' const url = baseUrl + '#/preview?dvId=' + dvInfo.value.id + '&ignoreParams=true'
const newWindow = window.open(url, '_blank') const newWindow = window.open(url, openType)
initOpenHandler(newWindow) initOpenHandler(newWindow)
} }
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi) const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)

View File

@ -342,7 +342,6 @@ const newWindowFromDiv = ref(false)
let p = null let p = null
const XpackLoaded = () => p(true) const XpackLoaded = () => p(true)
onMounted(async () => { onMounted(async () => {
snapshotStore.initSnapShot()
if (window.location.hash.includes('#/dvCanvas')) { if (window.location.hash.includes('#/dvCanvas')) {
newWindowFromDiv.value = true newWindowFromDiv.value = true
} }
@ -429,8 +428,6 @@ onMounted(async () => {
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('storage', eventCheck) window.removeEventListener('storage', eventCheck)
window.removeEventListener('blur', releaseAttachKey) window.removeEventListener('blur', releaseAttachKey)
eventBus.off('handleNew', handleNew)
eventBus.off('tabSort', tabSort)
}) })
const previewStatus = computed(() => editMode.value === 'preview') const previewStatus = computed(() => editMode.value === 'preview')

View File

@ -147,7 +147,7 @@
</div> </div>
<div class="ticket-btn"> <div class="ticket-btn">
<el-button type="primary" @click.stop="finish"> {{ $t('components.complete') }} </el-button> <el-button type="primary" @click.stop="finish"> 完成 </el-button>
</div> </div>
</div> </div>
</template> </template>

View File

@ -1,19 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, PropType } from 'vue' import { ref, reactive } from 'vue'
import { ElMessage, ElLoading } from 'element-plus-secondary' import { ElMessage, ElLoading } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import type { FormInstance, FormRules } from 'element-plus-secondary' import type { FormInstance, FormRules } from 'element-plus-secondary'
import request from '@/config/axios' import request from '@/config/axios'
import dvInfo from '@/assets/svg/dv-info.svg'
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({
labelTooltips: {
type: Array as PropType<any[]>,
default: () => []
}
})
const dialogVisible = ref(false) const dialogVisible = ref(false)
const loadingInstance = ref(null) const loadingInstance = ref(null)
const basicForm = ref<FormInstance>() const basicForm = ref<FormInstance>()
@ -57,14 +48,6 @@ const state = reactive({
] ]
}) })
const tooltipItem = ref({})
const formatLabel = () => {
props.labelTooltips?.length &&
props.labelTooltips.forEach(tooltip => {
tooltipItem.value[tooltip.key] = tooltip.val
})
}
const rule = reactive<FormRules>({ const rule = reactive<FormRules>({
dsIntervalTime: [ dsIntervalTime: [
{ {
@ -246,7 +229,6 @@ const oidChange = () => {
state.form['platformRid'] = [] state.form['platformRid'] = []
loadRoleOptions() loadRoleOptions()
} }
formatLabel()
defineExpose({ defineExpose({
edit edit
}) })
@ -273,22 +255,8 @@ defineExpose({
:key="item.pkey" :key="item.pkey"
:prop="item.pkey" :prop="item.pkey"
:class="{ 'setting-hidden-item': item.pkey === 'dsExecuteTime' }" :class="{ 'setting-hidden-item': item.pkey === 'dsExecuteTime' }"
:label="t(item.label)"
> >
<template v-slot:label>
<div class="basic-form-info-tips">
<span class="custom-form-item__label">{{ t(item.label) }}</span>
<el-tooltip
v-if="tooltipItem[`setting_basic.${item.pkey}`]"
effect="dark"
:content="tooltipItem[`setting_basic.${item.pkey}`]"
placement="top"
>
<el-icon
><Icon name="dv-info"><dvInfo class="svg-icon" /></Icon
></el-icon>
</el-tooltip>
</div>
</template>
<el-switch <el-switch
class="de-basic-switch" class="de-basic-switch"
v-if=" v-if="
@ -451,32 +419,6 @@ defineExpose({
.ed-form-item__label { .ed-form-item__label {
line-height: 22px !important; line-height: 22px !important;
height: 22px !important; height: 22px !important;
.basic-form-info-tips {
width: fit-content;
display: inline-flex;
align-items: center;
column-gap: 4px;
}
}
.ed-form-item {
&.is-required.asterisk-right {
.ed-form-item__label:after {
display: none;
}
.basic-form-info-tips {
.custom-form-item__label:after {
content: '*';
color: var(--ed-color-danger);
margin-left: 2px;
font-family: var(--de-custom_font, 'PingFang');
font-size: 14px;
font-style: normal;
font-weight: 400;
}
}
}
} }
.ed-radio__label { .ed-radio__label {
font-weight: 400; font-weight: 400;

View File

@ -13,7 +13,6 @@
" "
/> />
<InfoTemplate <InfoTemplate
v-if="loginInoSettings?.length"
ref="loginTemplate" ref="loginTemplate"
class="login-setting-template" class="login-setting-template"
:label-tooltips="tooltips" :label-tooltips="tooltips"
@ -29,7 +28,6 @@
/> />
<InfoTemplate <InfoTemplate
v-if="thirdInfoSettings?.length"
ref="thirdTemplate" ref="thirdTemplate"
class="login-setting-template" class="login-setting-template"
:label-tooltips="tooltips" :label-tooltips="tooltips"
@ -43,7 +41,7 @@
) )
" "
/> />
<basic-edit ref="editor" :label-tooltips="tooltips" @saved="refresh" /> <basic-edit ref="editor" @saved="refresh" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -251,9 +249,9 @@ const search = cb => {
const refresh = () => { const refresh = () => {
search(() => { search(() => {
nextTick(() => { nextTick(() => {
infoTemplate?.value?.init() infoTemplate?.value.init()
loginTemplate?.value?.init() loginTemplate?.value.init()
thirdTemplate?.value?.init() thirdTemplate?.value.init()
}) })
}) })
} }

View File

@ -150,8 +150,8 @@
</div> </div>
<div class="sub-area-view" v-else> <div class="sub-area-view" v-else>
<div id="map-container" class="map-container"></div> <div id="map-container" class="map-container"></div>
<el-divider />
<div class="sub-area-editor"> <div class="sub-area-editor">
<el-divider />
<span class="header"> <span class="header">
<span class="label"> <span class="label">
<span>自定义区域</span> <span>自定义区域</span>
@ -164,7 +164,7 @@
<span>添加区域</span> <span>添加区域</span>
</span> </span>
</span> </span>
<el-table :data="subAreaList" stripe style="width: 100%" :height="300"> <el-table :data="subAreaList" stripe style="width: 100%">
<el-table-column prop="name" label="区域名称"> <el-table-column prop="name" label="区域名称">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<span <span
@ -593,7 +593,13 @@ const mapOption: ChoroplethOptions = {
lineWidth: 0.6, lineWidth: 0.6,
lineOpacity: 1 lineOpacity: 1
}, },
label: false, label: {
field: 'name',
style: {
fill: 'black',
textAnchor: 'center'
}
},
state: { state: {
active: { stroke: 'green', lineWidth: 1 } active: { stroke: 'green', lineWidth: 1 }
}, },
@ -650,8 +656,7 @@ const renderMap = async () => {
fontSize: 20, fontSize: 20,
opacity: 1, opacity: 1,
fontWeight: 'bold', fontWeight: 'bold',
textAnchor: 'center', textAnchor: 'center'
textAllowOverlap: true
} }
}) })
if (mapInstance) { if (mapInstance) {
@ -667,7 +672,7 @@ const renderMap = async () => {
value: area => { value: area => {
let color = 'white' let color = 'white'
subAreaList.value?.forEach((subArea, i) => { subAreaList.value?.forEach((subArea, i) => {
if (subArea.scopeArr?.includes('156' + area.adcode)) { if (subArea.scope?.includes(area.adcode)) {
color = AREA_COLOR[i % AREA_COLOR.length] color = AREA_COLOR[i % AREA_COLOR.length]
} }
}) })
@ -840,17 +845,16 @@ onBeforeMount(() => {
.sub-area-view { .sub-area-view {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; width: 100;
width: 100%;
height: 100%; height: 100%;
.map-container { .map-container {
flex: 1; flex: 7;
} }
.ed-divider { .ed-divider {
margin: 10px 0; margin: 10px 0;
} }
.sub-area-editor { .sub-area-editor {
height: 350px; flex: 3;
.header { .header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

@ -1 +1 @@
Subproject commit 13ecdfab148086cf6e66fed2bcb41d88fdd5efab Subproject commit fd3d8b68af7560e817c7043933320289f79b0175

View File

@ -371,7 +371,6 @@ function restore() {
mkdir -p $DE_RUNNING_BASE mkdir -p $DE_RUNNING_BASE
fi fi
echo "恢复备份 $target" echo "恢复备份 $target"
rm -rf $DE_RUNNING_BASE/data/mysql/*
tar -zxf $target --directory=$DE_RUNNING_BASE tar -zxf $target --directory=$DE_RUNNING_BASE
service dataease start service dataease start
else else

View File

@ -19,7 +19,7 @@
</parent> </parent>
<properties> <properties>
<dataease.version>2.10.3</dataease.version> <dataease.version>2.10.2</dataease.version>
<java.version>21</java.version> <java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version> <spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>

View File

@ -0,0 +1,16 @@
package io.dataease.api.rmonitor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
public interface ResourceMonitorApi {
@GetMapping("/existFree")
boolean existFree();
@PostMapping("/delete")
void delete();
@PostMapping("/sync")
void sync();
}

View File

@ -3,7 +3,10 @@ package io.dataease.api.permissions.auth.api;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.api.permissions.auth.dto.*; import io.dataease.api.permissions.auth.dto.BusiPerCheckDTO;
import io.dataease.api.permissions.auth.dto.BusiResourceCreator;
import io.dataease.api.permissions.auth.dto.BusiResourceEditor;
import io.dataease.api.permissions.auth.dto.BusiResourceMover;
import io.dataease.api.permissions.auth.vo.PermissionValVO; import io.dataease.api.permissions.auth.vo.PermissionValVO;
import io.dataease.api.permissions.auth.vo.ResourceNodeVO; import io.dataease.api.permissions.auth.vo.ResourceNodeVO;
import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeRequest;
@ -86,7 +89,4 @@ public interface InteractiveAuthApi {
String OrgNameForResource(ExportTaskDTO exportTaskDTO); String OrgNameForResource(ExportTaskDTO exportTaskDTO);
void editResourceExtraFlag(BusiResourceEditor editor); void editResourceExtraFlag(BusiResourceEditor editor);
@PostMapping("/batchAuthorize")
void batchAuthorize(@RequestBody BusiBatchAuthorizeRequest request);
} }

View File

@ -1,17 +0,0 @@
package io.dataease.api.permissions.auth.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
public class BusiBatchAuthorizeNode implements Serializable {
@Serial
private static final long serialVersionUID = 5804450226135199435L;
private List<Long> idList;
private int flag;
}

View File

@ -1,17 +0,0 @@
package io.dataease.api.permissions.auth.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
public class BusiBatchAuthorizeRequest implements Serializable {
@Serial
private static final long serialVersionUID = -5219199153835271350L;
private List<BusiBatchAuthorizeNode> nodeList;
private Long oid;
}

View File

@ -15,9 +15,6 @@ import java.util.List;
@Configuration @Configuration
public class CorsConfig implements WebMvcConfigurer { public class CorsConfig implements WebMvcConfigurer {
@Value("${dataease.cors-strict:false}")
private boolean corsStrict;
@Value("#{'${dataease.origin-list:http://127.0.0.1:8100}'.split(',')}") @Value("#{'${dataease.origin-list:http://127.0.0.1:8100}'.split(',')}")
private List<String> originList; private List<String> originList;
@ -32,19 +29,15 @@ public class CorsConfig implements WebMvcConfigurer {
@Override @Override
public void addCorsMappings(CorsRegistry registry) { public void addCorsMappings(CorsRegistry registry) {
operateCorsRegistration = registry.addMapping("/**") operateCorsRegistration = registry.addMapping("/**")
.allowCredentials(false) .allowCredentials(true)
.allowedOrigins(originList.toArray(new String[0]))
.allowedHeaders("*") .allowedHeaders("*")
.maxAge(3600) .maxAge(3600)
.allowedMethods("GET", "POST", "DELETE"); .allowedMethods("GET", "POST", "DELETE");
if (corsStrict) {
operateCorsRegistration.allowedOrigins(originList.toArray(new String[0]));
return;
}
operateCorsRegistration.allowedOrigins("*");
} }
public void addAllowedOrigins(List<String> origins) { public void addAllowedOrigins(List<String> origins) {
if (!corsStrict || CollectionUtils.isEmpty(origins)) { if (CollectionUtils.isEmpty(origins)) {
return; return;
} }
origins.addAll(originList); origins.addAll(originList);