Merge branch 'dev-v2' into dual-axis

# Conflicts:
#	core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java
#	core/core-frontend/src/components/visualization/UserViewEnlarge.vue
This commit is contained in:
ulleo 2024-06-06 18:17:18 +08:00
commit 4565e65ae1
39 changed files with 990 additions and 337 deletions

View File

@ -835,6 +835,8 @@ public class ChartDataManage {
mapChart = ChartDataBuild.transMixChartDataAntV(xAxis, yAxis, view, data, isDrill);
} else if (StringUtils.equalsIgnoreCase(view.getType(), "bar-range")) {
mapChart = ChartDataBuild.transBarRangeDataAntV(skipBarRange, barRangeDate, xAxisBase, xAxis, yAxis, view, data, isDrill);
} else if(StringUtils.equalsIgnoreCase(view.getType(), "heat-map")){
mapChart = ChartDataBuild.transHeatMapChartDataAntV(xAxisBase, xAxis, yAxis, view, data, isDrill);
} else {
mapChart = ChartDataBuild.transChartDataAntV(xAxis, yAxis, view, data, isDrill);
}

View File

@ -4,8 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.dataease.api.chart.dto.*;
import io.dataease.api.chart.vo.ViewSelectorVO;
import io.dataease.api.chart.filter.FilterTreeObj;
import io.dataease.api.chart.vo.ViewSelectorVO;
import io.dataease.api.dataset.union.model.SQLObj;
import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
@ -20,6 +20,7 @@ import io.dataease.engine.utils.Utils;
import io.dataease.exception.DEException;
import io.dataease.i18n.Translator;
import io.dataease.utils.BeanUtils;
import io.dataease.utils.IDUtils;
import io.dataease.utils.JsonUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
@ -120,6 +121,7 @@ public class ChartViewManege {
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
wrapper.eq("dataset_group_id", id);
wrapper.eq("checked", true);
wrapper.isNull("chart_id");
List<CoreDatasetTableField> fields = coreDatasetTableFieldMapper.selectList(wrapper);
List<DatasetTableFieldDTO> collect = fields.stream().map(ele -> {
@ -173,6 +175,36 @@ public class ChartViewManege {
return map;
}
public void copyField(Long id, Long chartId) {
CoreDatasetTableField coreDatasetTableField = coreDatasetTableFieldMapper.selectById(id);
QueryWrapper<CoreDatasetTableField> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("dataset_group_id", coreDatasetTableField.getDatasetGroupId());
List<CoreDatasetTableField> coreDatasetTableFields = coreDatasetTableFieldMapper.selectList(queryWrapper);
HashMap<String, String> map = new HashMap<>();
for (CoreDatasetTableField ele : coreDatasetTableFields) {
map.put(ele.getName(), ele.getName());
}
newName(map, coreDatasetTableField, coreDatasetTableField.getName());
coreDatasetTableField.setChartId(chartId);
coreDatasetTableField.setExtField(2);
coreDatasetTableField.setOriginName("[" + id + "]");
coreDatasetTableField.setId(IDUtils.snowID());
coreDatasetTableFieldMapper.insert(coreDatasetTableField);
}
private void newName(HashMap<String, String> map, CoreDatasetTableField coreDatasetTableField, String name) {
name = name + "_copy";
if (map.containsKey(name)) {
newName(map, coreDatasetTableField, name);
} else {
coreDatasetTableField.setName(name);
}
}
public void deleteField(Long id) {
coreDatasetTableFieldMapper.deleteById(id);
}
public DatasetTableFieldDTO createCountField(Long id) {
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
dto.setId(-1L);

View File

@ -5,6 +5,7 @@ import io.dataease.api.chart.dto.ChartViewDTO;
import io.dataease.api.chart.dto.ViewDetailField;
import io.dataease.api.chart.request.ChartExcelRequest;
import io.dataease.api.chart.request.ChartExcelRequestInner;
import io.dataease.chart.constant.ChartConstants;
import io.dataease.chart.manage.ChartDataManage;
import io.dataease.constant.AuthConstant;
import io.dataease.constant.CommonConstants;
@ -69,7 +70,12 @@ public class ChartDataServer implements ChartDataApi {
try {
ChartViewDTO viewDTO = request.getViewInfo();
viewDTO.setIsExcelExport(true);
viewDTO.setResultCount(limit);
if(ChartConstants.VIEW_RESULT_MODE.CUSTOM.equals(viewDTO.getResultMode())){
Integer limitCount = viewDTO.getResultCount();
viewDTO.setResultCount(limitCount>limit?limit:limitCount);
}else{
viewDTO.setResultCount(limit);
}
ChartViewDTO chartViewInfo = getData(viewDTO);
List<Object[]> tableRow = (List) chartViewInfo.getData().get("sourceData");
request.setDetails(tableRow);

View File

@ -57,4 +57,14 @@ public class ChartViewServer implements ChartViewApi {
public List<ViewSelectorVO> viewOption(Long resourceId) {
return chartViewManege.viewOption(resourceId);
}
@Override
public void copyField(Long id, Long chartId) {
chartViewManege.copyField(id, chartId);
}
@Override
public void deleteField(Long id) {
chartViewManege.deleteField(id);
}
}

View File

@ -4,6 +4,7 @@ import io.dataease.api.chart.dto.*;
import io.dataease.i18n.Lang;
import io.dataease.i18n.Translator;
import io.dataease.utils.IDUtils;
import io.dataease.utils.JsonUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
@ -113,6 +114,77 @@ public class ChartDataBuild {
return map;
}
public static Map<String, Object> transHeatMapChartDataAntV(List<ChartViewFieldDTO> xAxisBase, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
Map<String, Object> map = new HashMap<>();
List<Map<String, Object>> dataList = new ArrayList<>();
if (xAxisBase.size() != 2) {
map.put("data", dataList);
return map;
}
for (int i1 = 0; i1 < data.size(); i1++) {
String[] row = data.get(i1);
StringBuilder a = new StringBuilder();
if (isDrill) {
a.append(row[xAxis.size() - 1]);
} else {
for (int i = 0; i < xAxis.size(); i++) {
if (i == xAxis.size() - 1) {
a.append(row[i]);
} else {
a.append(row[i]).append("\n");
}
}
}
// yAxis最后的数据对应extLabel和extTooltip将他们从yAxis中去掉同时转换成动态值
int size = xAxis.size() + yAxis.size();
int extSize = view.getExtLabel().size() + view.getExtTooltip().size();
for (int i = xAxis.size(); i < size - extSize; i++) {
AxisChartDataAntVDTO axisChartDataDTO = new AxisChartDataAntVDTO();
axisChartDataDTO.setField(a.toString());
axisChartDataDTO.setName(a.toString());
List<ChartDimensionDTO> dimensionList = new ArrayList<>();
List<ChartQuotaDTO> quotaList = new ArrayList<>();
for (int j = 0; j < xAxis.size(); j++) {
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
chartDimensionDTO.setId(xAxis.get(j).getId());
chartDimensionDTO.setValue(row[j]);
dimensionList.add(chartDimensionDTO);
}
axisChartDataDTO.setDimensionList(dimensionList);
int j = i - xAxis.size();
ChartQuotaDTO chartQuotaDTO = new ChartQuotaDTO();
chartQuotaDTO.setId(yAxis.get(j).getId());
quotaList.add(chartQuotaDTO);
axisChartDataDTO.setQuotaList(quotaList);
try {
axisChartDataDTO.setValue(StringUtils.isEmpty(row[i]) ? null : new BigDecimal(row[i]));
} catch (Exception e) {
axisChartDataDTO.setValue(new BigDecimal(0));
}
axisChartDataDTO.setCategory(StringUtils.defaultIfBlank(yAxis.get(j).getChartShowName(), yAxis.get(j).getName()));
buildDynamicValue(view, axisChartDataDTO, row, size, extSize);
Map<String, Object> object = JsonUtil.parse((String) JsonUtil.toJSONString(axisChartDataDTO) , HashMap.class);
object.put("x", new BigDecimal(row[0]));
object.put("y", new BigDecimal(row[1]));
dataList.add(object);
}
}
map.put("data", dataList);
return map;
}
public static Map<String, Object> transBaseGroupDataAntV(List<ChartViewFieldDTO> xAxisBase, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> xAxisExt, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
Map<String, Object> map = new HashMap<>();

View File

@ -341,6 +341,70 @@ public class CalciteProvider {
}
}
break;
case pg:
configuration = JsonUtil.parseObject(datasourceDTO.getConfiguration(), Pg.class);
if (StringUtils.isNotEmpty(configuration.getUrlType()) && configuration.getUrlType().equalsIgnoreCase("jdbcUrl")) {
if (configuration.getJdbcUrl().contains("password=")) {
String[] params = configuration.getJdbcUrl().split("\\?")[1].split("&");
String pd = "";
for (int i = 0; i < params.length; i++) {
if (params[i].contains("password=")) {
pd = params[i];
}
}
configuration.setJdbcUrl(configuration.getJdbcUrl().replace(pd, "password=******"));
datasourceDTO.setConfiguration(JsonUtil.toJSONString(configuration).toString());
}
}
break;
case redshift:
configuration = JsonUtil.parseObject(datasourceDTO.getConfiguration(), Redshift.class);
if (StringUtils.isNotEmpty(configuration.getUrlType()) && configuration.getUrlType().equalsIgnoreCase("jdbcUrl")) {
if (configuration.getJdbcUrl().contains("password=")) {
String[] params = configuration.getJdbcUrl().split("\\?")[1].split("&");
String pd = "";
for (int i = 0; i < params.length; i++) {
if (params[i].contains("password=")) {
pd = params[i];
}
}
configuration.setJdbcUrl(configuration.getJdbcUrl().replace(pd, "password=******"));
datasourceDTO.setConfiguration(JsonUtil.toJSONString(configuration).toString());
}
}
break;
case ck:
configuration = JsonUtil.parseObject(datasourceDTO.getConfiguration(), CK.class);
if (StringUtils.isNotEmpty(configuration.getUrlType()) && configuration.getUrlType().equalsIgnoreCase("jdbcUrl")) {
if (configuration.getJdbcUrl().contains("password=")) {
String[] params = configuration.getJdbcUrl().split("\\?")[1].split("&");
String pd = "";
for (int i = 0; i < params.length; i++) {
if (params[i].contains("password=")) {
pd = params[i];
}
}
configuration.setJdbcUrl(configuration.getJdbcUrl().replace(pd, "password=******"));
datasourceDTO.setConfiguration(JsonUtil.toJSONString(configuration).toString());
}
}
break;
case impala:
configuration = JsonUtil.parseObject(datasourceDTO.getConfiguration(), Impala.class);
if (StringUtils.isNotEmpty(configuration.getUrlType()) && configuration.getUrlType().equalsIgnoreCase("jdbcUrl")) {
if (configuration.getJdbcUrl().contains("password=")) {
String[] params = configuration.getJdbcUrl().split(";")[1].split("&");
String pd = "";
for (int i = 0; i < params.length; i++) {
if (params[i].contains("password=")) {
pd = params[i];
}
}
configuration.setJdbcUrl(configuration.getJdbcUrl().replace(pd, "password=******"));
datasourceDTO.setConfiguration(JsonUtil.toJSONString(configuration).toString());
}
}
break;
default:
break;
}

View File

@ -15,22 +15,22 @@ INSERT INTO `core_sys_startup_job` VALUES ('chartFilterMerge', 'chartFilterMerge
COMMIT;
DROP TABLE IF EXISTS "core_export_task";
CREATE TABLE "core_export_task"
DROP TABLE IF EXISTS `core_export_task`;
CREATE TABLE `core_export_task`
(
"id" VARCHAR(255) NOT NULL,
"user_id" BIGINT(20) NOT NULL,
"file_name" VARCHAR(2048) DEFAULT NULL,
"file_size" DOUBLE DEFAULT NULL,
"file_size_unit" VARCHAR(255) DEFAULT NULL,
"export_from" VARCHAR(255) DEFAULT NULL,
"export_status" VARCHAR(255) DEFAULT NULL,
"export_from_type" VARCHAR(255) DEFAULT NULL,
"export_time" BIGINT(20) DEFAULT NULL,
"export_progress" VARCHAR(255) DEFAULT NULL,
"export_machine_name" VARCHAR(512) DEFAULT NULL,
"params" CLOB NOT NULL COMMENT '过滤参数',
PRIMARY KEY ("id")
`id` VARCHAR(255) NOT NULL,
`user_id` BIGINT(20) NOT NULL,
`file_name` VARCHAR(2048) DEFAULT NULL,
`file_size` DOUBLE DEFAULT NULL,
`file_size_unit` VARCHAR(255) DEFAULT NULL,
`export_from` VARCHAR(255) DEFAULT NULL,
`export_status` VARCHAR(255) DEFAULT NULL,
`export_from_type` VARCHAR(255) DEFAULT NULL,
`export_time` BIGINT(20) DEFAULT NULL,
`export_progress` VARCHAR(255) DEFAULT NULL,
`export_machine_name` VARCHAR(512) DEFAULT NULL,
`params` longtext NOT NULL COMMENT '过滤参数',
PRIMARY KEY (`id`)
) COMMENT='导出任务表';
UPDATE `QRTZ_JOB_DETAILS` SET `JOB_CLASS_NAME` = 'io.dataease.job.schedule.CheckDsStatusJob' WHERE (`SCHED_NAME` = 'deSyncJob') and (`JOB_NAME` = 'Datasource') and (`JOB_GROUP` = 'check_status');

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import noLic from './nolic.vue'
import { ref, useAttrs, onMounted, watch } from 'vue'
import { ref, useAttrs, onMounted } from 'vue'
import { execute, randomKey, formatArray } from './convert'
import { load, loadDistributed, xpackModelApi } from '@/api/plugin'
import { useCache } from '@/hooks/web/useCache'
@ -81,7 +81,11 @@ const storeCacheProxy = byteArray => {
}
const pluginProxy = ref(null)
const invokeMethod = param => {
pluginProxy.value['invokeMethod'](param)
if (pluginProxy.value['invokeMethod']) {
pluginProxy.value['invokeMethod'](param)
} else {
pluginProxy.value[param.methodName](param.args)
}
}
onMounted(async () => {
@ -95,16 +99,16 @@ onMounted(async () => {
distributed = wsCache.get(key)
}
if (distributed) {
window['Vue'] = Vue
window['Axios'] = axios
window['Pinia'] = Pinia
window['vueRouter'] = vueRouter
window['MittAll'] = useEmitt().emitter.all
window['I18n'] = i18n
if (window['DEXPack']) {
const xpack = await window['DEXPack'].mapping[attrs.jsname]
plugin.value = xpack.default
} else {
window['Vue'] = Vue
window['Axios'] = axios
window['Pinia'] = Pinia
window['vueRouter'] = vueRouter
window['MittAll'] = useEmitt().emitter.all
window['I18n'] = i18n
loadDistributed().then(async res => {
new Function(res.data)()
const xpack = await window['DEXPack'].mapping[attrs.jsname]
@ -116,16 +120,6 @@ onMounted(async () => {
}
})
watch(
() => attrs.jsname,
() => {
if (window['DEXPack']) {
const xpack = window['DEXPack'].mapping[attrs.jsname]
plugin.value = xpack.default
}
}
)
const emits = defineEmits(['loadFail'])
defineExpose({
invokeMethod
@ -134,7 +128,7 @@ defineExpose({
<template>
<component
:class="attrs.jsname"
:key="attrs.jsname"
ref="pluginProxy"
:is="plugin"
v-loading="loading"

View File

@ -8,7 +8,12 @@
trigger="click"
>
<div class="export-button">
<el-select v-if="optType === 'enlarge'" v-model="pixel" class="pixel-select" size="small">
<el-select
v-if="optType === 'enlarge' && authShow"
v-model="pixel"
class="pixel-select"
size="small"
>
<el-option-group v-for="group in pixelOptions" :key="group.label" :label="group.label">
<el-option
v-for="item in group.options"
@ -21,7 +26,7 @@
<el-button
class="m-button"
v-if="optType === 'enlarge'"
v-if="optType === 'enlarge' && authShow"
link
icon="Download"
size="middle"
@ -31,7 +36,7 @@
</el-button>
<el-button
class="m-button"
v-if="optType === 'details'"
v-if="optType === 'details' && authShow"
link
icon="Download"
size="middle"
@ -40,7 +45,7 @@
>
导出Excel
</el-button>
<el-divider class="close-divider" direction="vertical" />
<el-divider class="close-divider" direction="vertical" v-if="authShow" />
</div>
<div
v-loading="downLoading"
@ -112,7 +117,7 @@ const { t } = useI18n()
const optType = ref(null)
const chartComponentDetails = ref(null)
const chartComponentDetails2 = ref(null)
const { dvInfo } = storeToRefs(dvMainStore)
const { dvInfo, editMode } = storeToRefs(dvMainStore)
const exportLoading = ref(false)
const sourceViewType = ref()
const activeName = ref('left')
@ -131,10 +136,15 @@ const DETAIL_TABLE_ATTR: DeepPartial<ChartObj> = {
tableItemBgColor: '#FFFFFF',
tableFontColor: '#7C7E81',
enableTableCrossBG: false
},
tooltip: {
show: false
}
}
}
const authShow = computed(() => editMode.value === 'edit' || dvInfo.value.weight > 3)
const customExport = computed(() => {
if (downLoading.value) {
const bashStyle = pixel.value.split(' * ')

View File

@ -21,7 +21,7 @@
<script lang="ts" setup>
import flvjs from 'flv.js'
import '@/style/custom-theme.css'
import { onMounted, reactive, toRefs, getCurrentInstance, watch, nextTick } from 'vue'
import { onMounted, reactive, toRefs, getCurrentInstance, nextTick, onBeforeUnmount } from 'vue'
import { useEmitt } from '@/hooks/web/useEmitt'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
@ -109,6 +109,10 @@ const destroyPlayer = () => {
state.flvPlayer = null
}
}
onBeforeUnmount(() => {
destroyPlayer()
})
</script>
<style lang="less" scoped>

View File

@ -1,11 +1,11 @@
<script lang="ts" setup>
import { ElMain } from 'element-plus-secondary'
import { useRoute } from 'vue-router'
const route = useRoute()
</script>
<template>
<el-main>
<RouterView />
<RouterView :key="route.path" />
</el-main>
</template>
<style lang="less" scoped></style>

View File

@ -481,6 +481,7 @@ export default {
condition_style: '标记样式',
longitude: '经度',
latitude: '纬度',
longitude_and_latitude: '经度纬度',
gradient: '渐变',
layer_controller: '指标切换',
show_zoom: '显示缩放按钮',
@ -938,6 +939,9 @@ export default {
table_align_center: '居中',
table_align_right: '右对齐',
table_scroll_bar_color: '滚动条颜色',
table_pager_style: '分页器风格',
page_pager_simple: '精简',
page_pager_general: '常规',
draw_back: '收回',
senior: '高级',
senior_cfg: '高级设置',
@ -1093,6 +1097,7 @@ export default {
step: '步长(px)',
no_function: '函数尚未支持直接引用请在字段表达式中手动输入',
chart_flow_map: '流向地图',
chart_heat_map: '热力地图',
start_point: '起点经纬度',
end_point: '终点经纬度',
line: '线条',
@ -1111,10 +1116,15 @@ export default {
map_style_darkblue: '极夜蓝',
map_style_wine: '酱籽',
map_line_type: '类型',
type: '类型',
map_line_width: '线条宽度',
map_line_height: '线条高度',
map_line_linear: '渐变',
map_line_animate: '动画',
heatmap_classics: '经典热力图',
heatmap3D: '3D热力图',
heatMapIntensity: '热力强度',
heatMapRadius: '热力点半径',
map_line_animate_duration: '动画间隔',
map_line_animate_interval: '轨迹间隔',
map_line_animate_trail_length: '轨迹长度',
@ -1159,6 +1169,9 @@ export default {
font_size: '字号',
word_size_range: '字号区间',
word_spacing: '文字间隔',
radiusColumnBar: '柱形',
rightAngle: '直角',
roundAngle: '圆角',
table_layout_mode: '展示形式',
table_layout_grid: '平铺展示',
table_layout_tree: '树形展示',

View File

@ -92,6 +92,10 @@ declare interface ChartBasicStyle {
* 表格分页模式
*/
tablePageMode: 'page' | 'pull'
/**
* 表格分页器风格
*/
tablePageStyle: 'simple' | 'general'
/**
* 表格分页大小
*/
@ -148,6 +152,14 @@ declare interface ChartBasicStyle {
* 柱宽
*/
barWidth: number
/**
* 柱子形状直角圆角
*/
radiusColumnBar?: 'rightAngle' | 'roundAngle'
/**
* 圆角柱倒角
*/
columnBarRightAngleRadius: number
/**
* 柱间距
*/
@ -176,6 +188,9 @@ declare interface ChartBasicStyle {
* 地图主题风格
*/
mapStyle: string
heatMapType?: string
heatMapIntensity?: number
heatMapRadius?: number
/**
* 地图边线颜色
*/

View File

@ -187,6 +187,10 @@ const mapStyleOptions = [
{ name: t('chart.map_style_blue'), value: 'blue' },
{ name: t('chart.map_style_wine'), value: 'wine' }
]
const heatMapTypeOptions = [
{ name: t('chart.heatmap_classics'), value: 'heatmap' },
{ name: t('chart.heatmap3D'), value: 'heatmap3D' }
]
const flowLineTypeOptions = [
{ name: t('chart.map_line_type_line'), value: 'line' },
@ -269,6 +273,23 @@ onMounted(() => {
</el-row>
</div>
<el-form-item
class="form-item"
v-if="showProperty('radiusColumnBar')"
:label="t('chart.radiusColumnBar')"
:class="'form-item-' + themes"
>
<el-radio-group
size="small"
:effect="themes"
v-model="state.basicStyleForm.radiusColumnBar"
@change="changeBasicStyle('radiusColumnBar')"
>
<el-radio label="rightAngle" :effect="themes">{{ t('chart.rightAngle') }}</el-radio>
<el-radio label="roundAngle" :effect="themes">{{ t('chart.roundAngle') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="t('chart.orient')"
class="form-item"
@ -286,233 +307,286 @@ onMounted(() => {
</el-radio-group>
</el-form-item>
<!--flow map begin-->
<div class="map-setting" v-if="showProperty('mapStyle')">
<div class="map-style">
<el-form-item
v-if="showProperty('heatMapStyle')"
:label="t('chart.type')"
class="form-item"
:class="'form-item-' + themes"
>
<el-select
:effect="themes"
v-model="state.basicStyleForm.heatMapType"
@change="changeBasicStyle('heatMapType')"
>
<el-option
v-for="item in heatMapTypeOptions"
:key="item.name"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<div class="map-style" v-if="showProperty('mapStyle') || showProperty('heatMapStyle')">
<el-row style="flex: 1">
<el-col>
<el-form-item
:label="t('chart.chart_map') + t('chart.map_style')"
class="form-item"
:class="'form-item-' + themes"
>
<el-select
:effect="themes"
v-model="state.basicStyleForm.mapStyle"
@change="changeBasicStyle('mapStyle')"
>
<el-option
v-for="item in mapStyleOptions"
:key="item.name"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<div class="alpha-setting">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.chart_map') + t('chart.map_pitch') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="0"
:max="90"
v-model="state.miscForm.mapPitch"
@change="changeMisc('mapPitch')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<div class="map-flow-style" v-if="showProperty('mapStyle')">
<el-row style="flex: 1">
<el-col>
<el-form-item
:label="t('chart.line') + t('chart.map_line_type')"
class="form-item"
:class="'form-item-' + themes"
>
<el-select
:effect="themes"
v-model="state.miscForm.mapLineType"
@change="changeMisc('mapLineType')"
>
<el-option
v-for="item in flowLineTypeOptions"
:key="item.name"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<div class="alpha-setting">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.map_line_width') }}
</label>
<el-row style="flex: 1">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="1"
:max="10"
v-model="state.miscForm.mapLineWidth"
@change="changeMisc('mapLineWidth')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<el-row style="flex: 1">
<el-col>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
size="small"
:effect="themes"
v-model="state.miscForm.mapLineGradient"
:predefine="predefineColors"
@change="changeMisc('mapLineGradient')"
>
{{ t('chart.line') + t('chart.map_line_linear') }}
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<div v-if="state.miscForm.mapLineGradient">
<el-row style="flex: 1" :gutter="8">
<el-col :span="13">
<el-form-item
:label="t('chart.chart_map') + t('chart.map_style')"
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.map_line_color_source_color')"
>
<el-select
<el-color-picker
is-custom
class="color-picker-style"
v-model="state.miscForm.mapLineSourceColor"
:persistent="false"
:effect="themes"
v-model="state.basicStyleForm.mapStyle"
@change="changeBasicStyle('mapStyle')"
>
<el-option
v-for="item in mapStyleOptions"
:key="item.name"
:label="item.name"
:value="item.value"
/>
</el-select>
:trigger-width="108"
:predefine="predefineColors"
@change="changeMisc('mapLineSourceColor')"
/>
</el-form-item>
</el-col>
</el-row>
<div class="alpha-setting">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.chart_map') + t('chart.map_pitch') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="0"
:max="90"
v-model="state.miscForm.mapPitch"
@change="changeMisc('mapPitch')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<div class="map-flow-style">
<el-row style="flex: 1">
<el-col>
<el-col :span="13">
<el-form-item
:label="t('chart.line') + t('chart.map_line_type')"
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.map_line_color_target_color')"
>
<el-select
<el-color-picker
is-custom
class="color-picker-style"
v-model="state.miscForm.mapLineTargetColor"
:persistent="false"
:effect="themes"
v-model="state.miscForm.mapLineType"
@change="changeMisc('mapLineType')"
>
<el-option
v-for="item in flowLineTypeOptions"
:key="item.name"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<div class="alpha-setting">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.map_line_width') }}
</label>
<el-row style="flex: 1">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="1"
:max="10"
v-model="state.miscForm.mapLineWidth"
@change="changeMisc('mapLineWidth')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<el-row style="flex: 1">
<el-col>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
size="small"
:effect="themes"
v-model="state.miscForm.mapLineGradient"
:trigger-width="108"
:predefine="predefineColors"
@change="changeMisc('mapLineGradient')"
>
{{ t('chart.line') + t('chart.map_line_linear') }}
</el-checkbox>
@change="changeMisc('mapLineTargetColor')"
/>
</el-form-item>
</el-col>
</el-row>
<div v-if="state.miscForm.mapLineGradient">
<el-row style="flex: 1" :gutter="8">
<el-col :span="13">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.map_line_color_source_color')"
>
<el-color-picker
is-custom
class="color-picker-style"
v-model="state.miscForm.mapLineSourceColor"
:persistent="false"
:effect="themes"
:trigger-width="108"
:predefine="predefineColors"
@change="changeMisc('mapLineSourceColor')"
/>
</el-form-item>
</el-col>
<el-col :span="13">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.map_line_color_target_color')"
>
<el-color-picker
is-custom
class="color-picker-style"
v-model="state.miscForm.mapLineTargetColor"
:persistent="false"
:effect="themes"
:trigger-width="108"
:predefine="predefineColors"
@change="changeMisc('mapLineTargetColor')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<div v-if="!state.miscForm.mapLineGradient">
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.color')"
>
<el-color-picker
is-custom
class="color-picker-style"
v-model="state.miscForm.mapLineSourceColor"
:persistent="false"
:effect="themes"
:trigger-width="108"
:predefine="predefineColors"
@change="changeMisc('mapLineSourceColor')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="alpha-setting">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.not_alpha') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col :span="13">
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
v-model="state.basicStyleForm.alpha"
@change="changeBasicStyle('alpha')"
/>
</el-form-item>
</el-col>
<el-col :span="11" style="padding-top: 2px">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-input
type="number"
:effect="themes"
v-model="state.basicStyleForm.alpha"
:min="0"
:max="100"
class="basic-input-number"
:controls="false"
@change="changeBasicStyle('alpha')"
>
<template #suffix> % </template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</div>
<el-row style="flex: 1">
<el-col>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
size="small"
:effect="themes"
v-model="state.miscForm.mapLineAnimate"
:predefine="predefineColors"
@change="changeMisc('mapLineAnimate')"
>
{{ t('chart.line') + t('chart.map_line_animate') }}
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<div class="alpha-setting" v-if="state.miscForm.mapLineAnimate">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.map_line_animate_duration') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="0"
:max="20"
v-model="state.miscForm.mapLineAnimateDuration"
@change="changeMisc('mapLineAnimateDuration')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<div v-if="!state.miscForm.mapLineGradient">
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.color')"
>
<el-color-picker
is-custom
class="color-picker-style"
v-model="state.miscForm.mapLineSourceColor"
:persistent="false"
:effect="themes"
:trigger-width="108"
:predefine="predefineColors"
@change="changeMisc('mapLineSourceColor')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="alpha-setting">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.not_alpha') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col :span="13">
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
v-model="state.basicStyleForm.alpha"
@change="changeBasicStyle('alpha')"
/>
</el-form-item>
</el-col>
<el-col :span="11" style="padding-top: 2px">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-input
type="number"
:effect="themes"
v-model="state.basicStyleForm.alpha"
:min="0"
:max="100"
class="basic-input-number"
:controls="false"
@change="changeBasicStyle('alpha')"
>
<template #suffix> % </template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</div>
<el-row style="flex: 1">
<el-col>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
size="small"
:effect="themes"
v-model="state.miscForm.mapLineAnimate"
:predefine="predefineColors"
@change="changeMisc('mapLineAnimate')"
>
{{ t('chart.line') + t('chart.map_line_animate') }}
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<div class="alpha-setting" v-if="state.miscForm.mapLineAnimate">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.map_line_animate_duration') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="0"
:max="20"
v-model="state.miscForm.mapLineAnimateDuration"
@change="changeMisc('mapLineAnimateDuration')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<div class="alpha-setting" v-if="showProperty('heatMapStyle')">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.heatMapIntensity') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="1"
:max="20"
v-model="state.basicStyleForm.heatMapIntensity"
@change="changeBasicStyle('heatMapIntensity')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="alpha-setting" v-if="showProperty('heatMapStyle')">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.heatMapRadius') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col>
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
:min="1"
:max="40"
v-model="state.basicStyleForm.heatMapRadius"
@change="changeBasicStyle('heatMapRadius')"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!--flow map end-->
<!--map start-->
@ -644,49 +718,61 @@ onMounted(() => {
</el-col>
</el-row>
<el-row :gutter="8">
<el-col :span="12" v-if="showProperty('tablePageMode')">
<el-form-item
:label="t('chart.table_page_mode')"
class="form-item"
:class="'form-item-' + themes"
>
<el-select
:effect="themes"
v-model="state.basicStyleForm.tablePageMode"
:placeholder="t('chart.table_page_mode')"
@change="changeBasicStyle('tablePageMode', true)"
>
<el-option :label="t('chart.page_mode_page')" value="page" />
<el-option :label="t('chart.page_mode_pull')" value="pull" />
</el-select>
</el-form-item>
</el-col>
<el-col
:span="12"
v-if="showProperty('tablePageMode') && state.basicStyleForm.tablePageMode === 'page'"
<el-form-item
v-if="showProperty('tablePageMode')"
:label="t('chart.table_page_mode')"
class="form-item"
:class="'form-item-' + themes"
>
<el-radio-group
:effect="themes"
v-model="state.basicStyleForm.tablePageMode"
@change="changeBasicStyle('tablePageMode', true)"
>
<el-form-item
:label="t('chart.table_page_size')"
class="form-item"
:class="'form-item-' + themes"
>
<el-select
:effect="themes"
v-model="state.basicStyleForm.tablePageSize"
:placeholder="t('chart.table_page_size')"
@change="changeBasicStyle('tablePageSize', true)"
>
<el-option
v-for="item in pageSizeOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-radio :effect="themes" label="page">{{ t('chart.page_mode_page') }}</el-radio>
<el-radio :effect="themes" label="pull">{{ t('chart.page_mode_pull') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="showProperty('tablePageMode')"
:label="t('chart.table_pager_style')"
class="form-item"
:class="'form-item-' + themes"
>
<el-radio-group
:effect="themes"
v-model="state.basicStyleForm.tablePageStyle"
@change="changeBasicStyle('tablePageStyle', true)"
>
<el-radio :effect="themes" label="simple">{{ t('chart.page_pager_simple') }}</el-radio>
<el-radio :effect="themes" label="general">{{ t('chart.page_pager_general') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="
showProperty('tablePageMode') &&
state.basicStyleForm.tablePageMode === 'page' &&
state.basicStyleForm.tablePageStyle === 'simple'
"
:label="t('chart.table_page_size')"
class="form-item"
:class="'form-item-' + themes"
>
<el-select
:effect="themes"
v-model="state.basicStyleForm.tablePageSize"
:placeholder="t('chart.table_page_size')"
@change="changeBasicStyle('tablePageSize', true)"
>
<el-option
v-for="item in pageSizeOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<!--table end-->
<!--table2 start-->

View File

@ -101,6 +101,7 @@ onMounted(() => {
:themes="themes"
type="left"
:chart-type="chart.type"
:layout="chart.customAttr.basicStyle.layout"
@on-change-y-axis-form="changeAxisStyle"
/>
</el-tab-pane>
@ -120,6 +121,7 @@ onMounted(() => {
:themes="themes"
type="right"
:chart-type="chart.type"
:layout="chart.customAttr.basicStyle.layout"
@on-change-y-axis-form="changeSubAxisStyle"
/>
</el-tab-pane>

View File

@ -14,6 +14,7 @@ const props = withDefaults(
propertyInner?: Array<string>
type?: 'left' | 'right'
chartType?: string
layout?: string
}>(),
{
themes: 'dark',
@ -75,6 +76,14 @@ const init = () => {
const showProperty = prop => props.propertyInner?.includes(prop)
const isBidirectionalBar = computed(() => {
return props.chartType === 'bidirectional-bar'
})
const isVerticalLayout = computed(() => {
return props.layout === 'vertical'
})
onMounted(() => {
init()
})
@ -99,9 +108,19 @@ onMounted(() => {
size="small"
@change="changeAxisStyle('position')"
>
<div v-if="chartType === 'bidirectional-bar'">
<el-radio :effect="props.themes" label="right">{{ t('chart.text_pos_top') }}</el-radio>
<el-radio :effect="props.themes" label="left">{{ t('chart.text_pos_bottom') }}</el-radio>
<div v-if="isBidirectionalBar">
<div v-if="isVerticalLayout">
<el-radio :effect="props.themes" label="left">{{ t('chart.text_pos_left') }}</el-radio>
<el-radio :effect="props.themes" label="right">{{
t('chart.text_pos_right')
}}</el-radio>
</div>
<div v-else>
<el-radio :effect="props.themes" label="right">{{ t('chart.text_pos_top') }}</el-radio>
<el-radio :effect="props.themes" label="left">{{
t('chart.text_pos_bottom')
}}</el-radio>
</div>
</div>
<div v-else>
<el-radio :effect="props.themes" label="left">{{ t('chart.text_pos_left') }}</el-radio>

View File

@ -100,6 +100,14 @@ const init = () => {
const showProperty = prop => props.propertyInner?.includes(prop)
const isBidirectionalBar = computed(() => {
return props.chart.type === 'bidirectional-bar'
})
const isHorizontalLayout = computed(() => {
return props.chart.customAttr.basicStyle.layout === 'horizontal'
})
onMounted(() => {
init()
})
@ -124,8 +132,10 @@ onMounted(() => {
size="small"
@change="changeAxisStyle('position')"
>
<div v-if="chart.type === 'bidirectional-bar'">
<el-radio :effect="props.themes" label="top">{{ t('chart.text_pos_left') }}</el-radio>
<div v-if="isBidirectionalBar">
<el-radio :effect="props.themes" label="top">{{
isHorizontalLayout ? t('chart.text_pos_left') : t('chart.text_pos_top')
}}</el-radio>
<el-radio :effect="props.themes" label="bottom">{{
t('chart.text_pos_center')
}}</el-radio>

View File

@ -1318,6 +1318,13 @@ export const CHART_TYPE_CONFIGS = [
value: 'flow-map',
title: t('chart.chart_flow_map'),
icon: 'flow-map'
},
{
render: 'antv',
category: 'map',
value: 'heat-map',
title: t('chart.chart_heat_map'),
icon: 'heat-map'
}
]
},
@ -1394,6 +1401,7 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
tableColumnWidth: 100,
tableFieldWidth: [],
tablePageMode: 'page',
tablePageStyle: 'simple',
tablePageSize: 20,
gaugeStyle: 'default',
colorScheme: 'default',
@ -1415,6 +1423,8 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
lineSymbolSize: 4,
lineSmooth: true,
barDefault: true,
radiusColumnBar: 'rightAngle',
columnBarRightAngleRadius: 20,
barWidth: 40,
barGap: 0.4,
lineType: 'solid',
@ -1422,6 +1432,9 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
scatterSymbolSize: 8,
radarShape: 'polygon',
mapStyle: 'normal',
heatMapType: 'heatmap',
heatMapIntensity: 2,
heatMapRadius: 20,
areaBorderColor: '#EBEEF5',
areaBaseColor: '#ffffff',
mapSymbolOpacity: 0.7,
@ -1449,7 +1462,7 @@ export const BASE_VIEW_CONFIG = {
type: 'bar',
render: 'antv',
resultCount: 1000,
resultMode: 'all',
resultMode: 'custom',
refreshViewEnable: false,
refreshTime: 5,
refreshUnit: 'minute',

View File

@ -173,6 +173,20 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
color
}
}
if (basicStyle.radiusColumnBar === 'roundAngle') {
const columnStyle = {
radius: [
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius
]
}
options = {
...options,
columnStyle
}
}
return options
}

View File

@ -198,6 +198,20 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
...options,
layout: basicStyle.layout
}
if (basicStyle.radiusColumnBar === 'roundAngle') {
const barStyle = {
radius: [
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius
]
}
options = {
...options,
barStyle
}
}
return options
}
@ -325,8 +339,9 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
valueExt: undefined
}
}
const layoutHorizontal = options.layout === 'horizontal'
// 处理横轴标题方向不对
if (yAxis && yAxis['title']) {
if (yAxis && yAxis['title'] && layoutHorizontal) {
yAxis['title'].autoRotate = false
}
const yAxisTmp = parseJson(chart.customStyle).yAxis

View File

@ -28,7 +28,7 @@ export const BAR_RANGE_EDITOR_PROPERTY: EditorProperty[] = [
export const BAR_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
'background-overall-component': ['all'],
'basic-style-selector': ['colors', 'alpha', 'gradient'],
'basic-style-selector': ['colors', 'alpha', 'gradient', 'radiusColumnBar'],
'label-selector': ['fontSize', 'color', 'labelFormatter'],
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show'],
'x-axis-selector': [

View File

@ -161,6 +161,20 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
color
}
}
if (basicStyle.radiusColumnBar === 'roundAngle') {
const barStyle = {
radius: [
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius
]
}
options = {
...options,
barStyle
}
}
return options
}

View File

@ -163,6 +163,20 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
}
}
}
if (basicStyle.radiusColumnBar === 'roundAngle') {
const barStyle = {
radius: [
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius
]
}
options = {
...options,
barStyle
}
}
return options
}
protected configTooltip(chart: Chart, options: BarOptions): BarOptions {

View File

@ -292,6 +292,20 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
}
}
}
if (basicStyle.radiusColumnBar === 'roundAngle') {
const barStyle = {
radius: [
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius,
basicStyle.columnBarRightAngleRadius
]
}
options = {
...options,
barStyle
}
}
return options
}

View File

@ -86,24 +86,25 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
drawChart(drawOptions: G2PlotDrawOptions<G2Area>): G2Area {
const { chart, container, action } = drawOptions
if (chart?.data) {
// data
const data = cloneDeep(chart.data.data)
const initOptions: AreaOptions = {
...this.baseOptions,
data,
appendPadding: getPadding(chart)
}
// options
const options = this.setupOptions(chart, initOptions)
// 开始渲染
const newChart = new G2Area(container, options)
newChart.on('point:click', action)
return newChart
if (!chart.data.data?.length) {
return
}
// data
const data = cloneDeep(chart.data.data)
const initOptions: AreaOptions = {
...this.baseOptions,
data,
appendPadding: getPadding(chart)
}
// options
const options = this.setupOptions(chart, initOptions)
// 开始渲染
const newChart = new G2Area(container, options)
newChart.on('point:click', action)
return newChart
}
protected configLabel(chart: Chart, options: AreaOptions): AreaOptions {
@ -177,8 +178,12 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
let areaStyle
if (customAttr.basicStyle.gradient) {
const colorMap = new Map()
const yAxis = parseJson(chart.customStyle).yAxis
const axisValue = yAxis.axisValue
const start =
!axisValue?.auto && axisValue.min && axisValue.max ? axisValue.min / axisValue.max : 0
areaStyle = item => {
let ele
let ele: string
const key = `${item.field}-${item.category}`
if (colorMap.has(key)) {
ele = colorMap.get(key)
@ -188,9 +193,12 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
}
if (ele) {
return {
fill: setGradientColor(hexColorToRGBA(ele, alpha), true, 270)
fill: setGradientColor(hexColorToRGBA(ele, alpha), true, 270, start)
}
}
return {
fill: 'rgba(255,255,255,0)'
}
}
}
return {

View File

@ -0,0 +1,120 @@
import { useI18n } from '@/hooks/web/useI18n'
import {
L7ChartView,
L7Config,
L7DrawConfig,
L7Wrapper
} from '@/views/chart/components/js/panel/types/impl/l7'
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
import { flow, parseJson } from '@/views/chart/components/js/util'
import { deepCopy } from '@/utils/utils'
import { GaodeMap } from '@antv/l7-maps'
import { Scene } from '@antv/l7-scene'
import { HeatmapLayer } from '@antv/l7-layers'
import { queryMapKeyApi } from '@/api/setting/sysParameter'
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
const { t } = useI18n()
/**
* 流向地图
*/
export class HeatMap extends L7ChartView<Scene, L7Config> {
properties: EditorProperty[] = [
'background-overall-component',
'basic-style-selector',
'title-selector'
]
propertyInner: EditorPropertyInner = {
...MAP_EDITOR_PROPERTY_INNER,
'basic-style-selector': ['colors', 'heatMapStyle', 'zoom']
}
axis: AxisType[] = ['xAxis', 'yAxis', 'filter']
axisConfig: AxisConfig = {
xAxis: {
name: `${t('chart.longitude_and_latitude')} / ${t('chart.dimension')}`,
type: 'd',
limit: 2
},
yAxis: {
name: `${t('chart.chart_data')} / ${t('chart.quota')}`,
type: 'q',
limit: 1
}
}
constructor() {
super('heat-map', [])
}
async drawChart(drawOption: L7DrawConfig<L7Config>) {
const { chart, container } = drawOption
const xAxis = deepCopy(chart.xAxis)
const yAxis = deepCopy(chart.yAxis)
let basicStyle
let miscStyle
if (chart.customAttr) {
basicStyle = parseJson(chart.customAttr).basicStyle
miscStyle = parseJson(chart.customAttr).misc
}
console.log(basicStyle)
const mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
const key = await this.getMapKey()
// 底层
const scene = new Scene({
id: container,
logoVisible: false,
map: new GaodeMap({
token: key ?? undefined,
style: mapStyle,
pitch: miscStyle.mapPitch,
zoom: 2.5
})
})
if (xAxis?.length < 2 || yAxis?.length < 1) {
return new L7Wrapper(scene, undefined)
}
console.log(chart.data?.data)
const config: L7Config = new HeatmapLayer({
name: 'line',
blend: 'normal',
autoFit: true
})
.source(chart.data?.data, {
parser: {
type: 'json',
x: 'x',
y: 'y'
}
})
.size('value', [0, 1.0]) // weight映射通道
.shape(basicStyle.heatMapType ?? DEFAULT_BASIC_STYLE.heatMapType)
config.style({
intensity: basicStyle.heatMapIntensity ?? DEFAULT_BASIC_STYLE.heatMapIntensity,
radius: basicStyle.heatMapRadius ?? DEFAULT_BASIC_STYLE.heatMapRadius,
rampColors: {
colors: basicStyle.colors.reverse(),
positions: [0, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66, 0.77, 0.88, 1.0]
}
})
this.configZoomButton(chart, scene)
return new L7Wrapper(scene, config)
}
getMapKey = async () => {
const key = 'online-map-key'
if (!localStorage.getItem(key)) {
await queryMapKeyApi().then(res => localStorage.setItem(key, res.data))
}
return localStorage.getItem(key)
}
setupDefaultOptions(chart: ChartObj): ChartObj {
chart.customAttr.misc.mapLineAnimate = true
return chart
}
protected setupOptions(chart: Chart, config: L7Config): L7Config {
return flow(this.configEmptyDataStrategy)(chart, config)
}
}

View File

@ -23,7 +23,8 @@ export const CHART_MIX_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
'lineWidth',
'lineSymbol',
'lineSymbolSize',
'lineSmooth'
'lineSmooth',
'radiusColumnBar'
],
'x-axis-selector': [
'name',

View File

@ -227,7 +227,21 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
tempOption.geometryOptions[1].smooth = smooth
tempOption.geometryOptions[1].point = point
tempOption.geometryOptions[1].lineStyle = lineStyle
if (s.radiusColumnBar === 'roundAngle') {
const columnStyle = {
radius: [
s.columnBarRightAngleRadius,
s.columnBarRightAngleRadius,
s.columnBarRightAngleRadius,
s.columnBarRightAngleRadius
]
}
tempOption.geometryOptions[0].columnStyle = columnStyle
tempOption.geometryOptions[1].columnStyle = columnStyle
}
}
return tempOption
}

View File

@ -800,11 +800,20 @@ export function getLineDash(type) {
* @param rawColor 原始 RGBA 颜色
* @param show
* @param angle 渐变角度
* @param start 起始值
*/
export function setGradientColor(rawColor: string, show = false, angle = 0) {
export function setGradientColor(rawColor: string, show = false, angle = 0, start = 0) {
const item = rawColor.split(',')
item.splice(3, 1, '0.3)')
return show ? `l(${angle}) 0:${item.join(',')} 1:${rawColor}` : rawColor
let color: string
if (start == 0) {
color = `l(${angle}) 0:${item.join(',')} 1:${rawColor}`
} else if (start > 0) {
color = `l(${angle}) 0:rgba(255,255,255,0) ${start}:${item.join(',')} 1:${rawColor}`
} else {
color = `l(${angle}) 0:rgba(255,255,255,0) 0.1:${item.join(',')} 1:${rawColor}`
}
return show ? color : rawColor
}
export function transAxisPosition(position: string): string {

View File

@ -261,6 +261,29 @@ const trackClick = trackAction => {
if (state.pointParam.data.dimensionList.length > 1) {
checkName = state.pointParam.data.dimensionList[0].id
}
//
let jumpName = state.pointParam.data.name
if (state.pointParam.data.dimensionList.length > 1) {
const fieldIds = []
//
if (curView.drill) {
const curFiled = curView.drillFields[curView.drillFilters.length]
fieldIds.push(curFiled.id)
}
chartData.value?.fields.forEach(field => {
if (!fieldIds.includes(field.id)) {
fieldIds.push(field.id)
}
})
for (let i = 0; i < fieldIds.length; i++) {
const id = fieldIds[i]
const sourceInfo = view.value.id + '#' + id
if (nowPanelJumpInfo.value[sourceInfo]) {
jumpName = id
break
}
}
}
let quotaList = state.pointParam.data.quotaList
if (curView.type === 'bar-range') {
quotaList = state.pointParam.data.dimensionList
@ -276,7 +299,7 @@ const trackClick = trackAction => {
}
const jumpParam = {
option: 'jump',
name: checkName,
name: jumpName,
viewId: view.value.id,
dimensionList: state.pointParam.data.dimensionList,
quotaList: quotaList

View File

@ -90,7 +90,9 @@ const state = reactive({
currentPage: 1
},
totalItems: 0,
showPage: false
showPage: false,
pageStyle: 'simple',
currentPageSize: 0
})
//
let chartData = shallowRef<Partial<Chart['data']>>({
@ -182,6 +184,12 @@ const setupPage = (chart: ChartObj, resetPageInfo?: boolean) => {
if (resetPageInfo) {
state.pageInfo.currentPage = 1
}
state.pageStyle = customAttr.basicStyle.tablePageStyle
if (state.pageStyle === 'general') {
if (state.currentPageSize == 0) {
state.currentPageSize = pageInfo.pageSize
}
}
}
const initScroll = () => {
@ -242,6 +250,16 @@ const handleCurrentChange = pageNum => {
const chart = { ...view.value, chartExtRequest: extReq }
calcData(chart, null, false)
}
const handlePageSizeChange = pageSize => {
let extReq = { pageSize: pageSize }
if (chartExtRequest.value) {
extReq = { ...extReq, ...chartExtRequest.value }
}
const chart = { ...view.value, chartExtRequest: extReq }
calcData(chart, null, false)
}
const pointClickTrans = () => {
if (embeddedCallBack.value === 'yes') {
trackClick('pointClick')
@ -457,6 +475,7 @@ const tabStyle = computed(() => [
<div class="table-page-info" :style="tabStyle">
<div>{{ state.pageInfo.total }}</div>
<el-pagination
v-if="state.pageStyle !== 'general'"
class="table-page-content"
layout="prev, pager, next"
v-model:page-size="state.pageInfo.pageSize"
@ -465,6 +484,17 @@ const tabStyle = computed(() => [
:total="state.pageInfo.total"
@update:current-page="handleCurrentChange"
/>
<el-pagination
v-else
class="table-page-content"
layout="prev, pager, next, sizes, jumper"
v-model:page-size="state.currentPageSize"
v-model:current-page="state.pageInfo.currentPage"
:pager-count="5"
:total="state.pageInfo.total"
@update:current-page="handleCurrentChange"
@update:page-size="handlePageSizeChange"
/>
</div>
</el-row>
<chart-error v-if="isError" :err-msg="errMsg" />

View File

@ -356,9 +356,6 @@ const windowsJump = (url, jumpType) => {
try {
const newWindow = window.open(url, jumpType)
initOpenHandler(newWindow)
if (jumpType === '_self') {
location.reload()
}
} catch (e) {
ElMessage.error(t('visualization.url_check_error') + ':' + url)
}
@ -414,6 +411,10 @@ const jumpClick = param => {
const url = `${embeddedBaseUrl}#/preview?dvId=${
jumpInfo.targetDvId
}&jumpInfoParam=${encodeURIComponent(Base64.encode(JSON.stringify(param)))}`
if (isIframe.value || isDataEaseBi.value) {
embeddedStore.clearState()
}
if (divSelf) {
embeddedStore.setDvId(jumpInfo.targetDvId)
embeddedStore.setJumpInfoParam(encodeURIComponent(Base64.encode(JSON.stringify(param))))
@ -434,11 +435,16 @@ const jumpClick = param => {
const colList = [...param.dimensionList, ...param.quotaList]
let url = setIdValueTrans('id', 'value', jumpInfo.content, colList)
url = checkAddHttp(url)
if (isIframe.value || isDataEaseBi.value) {
embeddedStore.clearState()
}
if (divSelf) {
embeddedStore.setOuterUrl(url)
divEmbedded('Iframe')
return
}
windowsJump(url, jumpInfo.jumpType)
}
} else {

View File

@ -279,7 +279,11 @@ const save = () => {
:scale="80"
/>
</div>
<div class="mobile-com-mask" @click="addToMobile(item)"></div>
<div class="mobile-com-mask" @click="addToMobile(item)">
<span v-show="item.component === 'DeStreamMedia'" style="color: #909399"
>IOS可能无法显示</span
>
</div>
<div class="pc-select-to-mobile" @click="addToMobile(item)" v-if="!mobileLoading"></div>
</div>
</template>
@ -511,6 +515,9 @@ const save = () => {
left: 0;
z-index: 10;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.pc-select-to-mobile {

View File

@ -73,7 +73,6 @@ const loadCanvasDataAsync = async (dvId, dvType) => {
ElMessage.error(t('visualization.outer_param_decode_error'))
}
}
initCanvasData(
dvId,
dvType,

View File

@ -117,8 +117,12 @@ const handleLogin = () => {
if (!xpackLoadFail.value && xpackInvalidPwd.value?.invokeMethod) {
const param = {
methodName: 'init',
args: () => {
duringLogin.value = false
args: r => {
duringLogin.value = !!r
if (r) {
const queryRedirectPath = getCurLocation()
router.push({ path: queryRedirectPath })
}
}
}
xpackInvalidPwd?.value.invokeMethod(param)

@ -1 +1 @@
Subproject commit ff5fe709c3cdb815c70d2b90a89c5b4fc3b105e3
Subproject commit a12eea394d8d5edf2941988819b08676e512a11e

View File

@ -138,6 +138,7 @@ curl http://127.0.0.1:9180/apisix/admin/routes -X POST -H "X-API-KEY: $DE_APISIX
]
],
"upstream_id": "1",
"enable_websocket": true,
"status": 1
}'
@ -173,4 +174,4 @@ curl http://127.0.0.1:9180/apisix/admin/routes -X POST -H "X-API-KEY: $DE_APISIX
],
"service_id": "10",
"status": 1
}'
}'

View File

@ -53,6 +53,7 @@ function check_and_prepare_env_params() {
fi
set -a
source ${CURRENT_DIR}/install.conf
if [[ -d $DE_BASE ]] && [[ -f $DE_BASE/dataease2.0/.env ]]; then
source $DE_BASE/dataease2.0/.env
INSTALL_TYPE='upgrade'
@ -64,7 +65,6 @@ function check_and_prepare_env_params() {
fi
log_content "升级安装"
else
source ${CURRENT_DIR}/install.conf
INSTALL_TYPE='install'
mkdir -p ${DE_BASE}
log_content "全新安装"

View File

@ -43,4 +43,12 @@ public interface ChartViewApi {
@Operation(summary = "查询仪表板下视图项")
@GetMapping("/viewOption/{resourceId}")
List<ViewSelectorVO> viewOption(@PathVariable("resourceId") Long resourceId);
@Operation(summary = "视图复制字段")
@PostMapping("copyField/{id}/{chartId}")
void copyField(@PathVariable Long id, @PathVariable Long chartId);
@Operation(summary = "视图删除字段")
@PostMapping("deleteField/{id}")
void deleteField(@PathVariable Long id);
}