mirror of
https://github.com/dataease/dataease.git
synced 2026-06-10 05:36:54 +08:00
Merge branch 'dev-v2' into v2.10
This commit is contained in:
@@ -4,11 +4,14 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.dataease.api.chart.dto.PageInfo;
|
||||
import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||
import io.dataease.chart.charts.impl.DefaultChartHandler;
|
||||
import io.dataease.constant.DeTypeConstants;
|
||||
import io.dataease.engine.constant.ExtFieldConstant;
|
||||
import io.dataease.engine.sql.SQLProvider;
|
||||
import io.dataease.engine.trans.Dimension2SQLObj;
|
||||
import io.dataease.engine.trans.ExtWhere2Str;
|
||||
import io.dataease.engine.trans.Quota2SQLObj;
|
||||
import io.dataease.engine.utils.Utils;
|
||||
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||
@@ -16,14 +19,18 @@ import io.dataease.extensions.datasource.provider.Provider;
|
||||
import io.dataease.extensions.view.dto.*;
|
||||
import io.dataease.extensions.view.util.ChartDataUtil;
|
||||
import io.dataease.extensions.view.util.FieldUtil;
|
||||
import io.dataease.utils.IDUtils;
|
||||
import io.dataease.utils.JsonUtil;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author jianneng
|
||||
@@ -110,7 +117,7 @@ public class TableNormalHandler extends DefaultChartHandler {
|
||||
|
||||
var tablePageMode = (String) filterResult.getContext().get("tablePageMode");
|
||||
var totalPageSql = "SELECT COUNT(*) FROM (" + SQLProvider.createQuerySQLNoSort(sqlMeta, true, view) + ") COUNT_TEMP";
|
||||
if (StringUtils.isNotEmpty(totalPageSql) && StringUtils.equalsIgnoreCase(tablePageMode, "page")) {
|
||||
if (StringUtils.equalsIgnoreCase(tablePageMode, "page")) {
|
||||
totalPageSql = provider.rebuildSQL(totalPageSql, sqlMeta, crossDs, dsMap);
|
||||
datasourceRequest.setQuery(totalPageSql);
|
||||
datasourceRequest.setTotalPageFlag(true);
|
||||
@@ -131,7 +138,6 @@ public class TableNormalHandler extends DefaultChartHandler {
|
||||
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||
//自定义排序
|
||||
data = ChartDataUtil.resultCustomSort(xAxis, yAxis, view.getSortPriority(), data);
|
||||
|
||||
var yoyFiltered = filterResult.getContext().get("yoyFiltered") != null;
|
||||
if (yoyFiltered) {
|
||||
// 这里没加分页,因为加了分页参数可能会把原始数据挤出去
|
||||
@@ -208,6 +214,64 @@ public class TableNormalHandler extends DefaultChartHandler {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 自定义汇总
|
||||
var basicStyle = (Map<String, Object>) view.getCustomAttr().get("basicStyle");
|
||||
var showSummary = BooleanUtils.isTrue((Boolean) basicStyle.get("showSummary"));
|
||||
if (showSummary) {
|
||||
var fieldList = (List) basicStyle.get("seriesSummary");
|
||||
if (CollectionUtils.isNotEmpty(fieldList)) {
|
||||
var customCalcFields = new ArrayList<ChartViewFieldDTO>();
|
||||
var seriesList = JsonUtil.parseList(JsonUtil.toJSONString(fieldList).toString(), new TypeReference<List<ChartViewFieldDTO>>(){});
|
||||
var quotaIds = allFields.stream().map(DatasetTableFieldDTO::getDataeaseName).collect(Collectors.toSet());
|
||||
seriesList.forEach(field -> {
|
||||
if (!BooleanUtils.isTrue(field.getShow()) || !"custom".equalsIgnoreCase(field.getSummary())) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(field.getOriginName())) {
|
||||
return;
|
||||
}
|
||||
if (!quotaIds.contains(field.getField())) {
|
||||
return;
|
||||
}
|
||||
field.setSummary("");
|
||||
field.setDeType(DeTypeConstants.DE_FLOAT);
|
||||
field.setId(IDUtils.snowID());
|
||||
field.setExtField(ExtFieldConstant.EXT_CALC);
|
||||
customCalcFields.add(field);
|
||||
});
|
||||
if (!customCalcFields.isEmpty()) {
|
||||
var xFields = sqlMeta.getXFields();
|
||||
// 清空维度值,获取完结果再设置回去
|
||||
sqlMeta.setXFields(Collections.emptyList());
|
||||
List<DatasetTableFieldDTO> tmpList = FieldUtil.transFields(allFields);
|
||||
tmpList.addAll(customCalcFields);
|
||||
Quota2SQLObj.quota2sqlObj(sqlMeta, customCalcFields, tmpList, crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||
String customSumSql = SQLProvider.createQuerySQL(sqlMeta, false, !StringUtils.equalsIgnoreCase(dsMap.values().iterator().next().getType(), "es"), view);
|
||||
customSumSql = provider.rebuildSQL(customSumSql, sqlMeta, crossDs, dsMap);
|
||||
var customSumReq = new DatasourceRequest();
|
||||
customSumReq.setIsCross(crossDs);
|
||||
customSumReq.setDsList(dsMap);
|
||||
customSumReq.setQuery(customSumSql);
|
||||
var customSumData = (List<String[]>) provider.fetchResultField(customSumReq).get("data");
|
||||
if (CollectionUtils.isNotEmpty(customSumData)) {
|
||||
var customSumResult = new HashMap<String, BigDecimal>();
|
||||
// 只取第一行结果
|
||||
var customSumArr = customSumData.get(0);
|
||||
for (int i = 0; i < customSumArr.length; i++) {
|
||||
if (customCalcFields.get(i) != null && customSumArr[i] != null) {
|
||||
try {
|
||||
customSumResult.put(customCalcFields.get(i).getField(), new BigDecimal(customSumArr[i]));
|
||||
} catch (Exception e) {
|
||||
customSumResult.put(customCalcFields.get(i).getField(), new BigDecimal(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
result.put("customSumResult", customSumResult);
|
||||
}
|
||||
sqlMeta.setXFields(xFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
return calcResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,8 +511,7 @@ const dataVPreview = computed(
|
||||
const linkOptBarShow = computed(() => {
|
||||
return Boolean(
|
||||
canvasStyleData.value.suspensionButtonAvailable &&
|
||||
!inMobile.value &&
|
||||
!mobileInPc.value &&
|
||||
((!inMobile.value && !mobileInPc.value) || !isDashboard()) &&
|
||||
showPopBar.value &&
|
||||
!isDesktopFlag
|
||||
)
|
||||
|
||||
@@ -255,6 +255,7 @@ const showSuffix = ref<boolean>(DEFAULT_INDICATOR_STYLE.suffixEnable)
|
||||
const suffixContent = ref('')
|
||||
|
||||
const indicatorNameShow = ref(false)
|
||||
const indicatorNamePositionBottom = ref(true)
|
||||
|
||||
const indicatorNameWrapperStyle = reactive<CSSProperties>({
|
||||
'margin-top': DEFAULT_INDICATOR_NAME_STYLE.nameValueSpacing + 'px'
|
||||
@@ -369,8 +370,10 @@ const renderChart = async view => {
|
||||
}
|
||||
indicatorNameWrapperStyle['margin-top'] =
|
||||
(indicatorName.nameValueSpacing ?? DEFAULT_INDICATOR_NAME_STYLE.nameValueSpacing) + 'px'
|
||||
indicatorNamePositionBottom.value = indicatorName.namePosition !== 'top'
|
||||
} else {
|
||||
indicatorNameShow.value = false
|
||||
indicatorNamePositionBottom.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -595,11 +598,16 @@ defineExpose({
|
||||
@trackClick="trackClick"
|
||||
:is-data-v-mobile="dataVMobile"
|
||||
/>
|
||||
<div v-if="indicatorNameShow && !indicatorNamePositionBottom">
|
||||
<span :style="indicatorNameClass">{{ resultName }}</span>
|
||||
<div :style="indicatorNameWrapperStyle"></div>
|
||||
</div>
|
||||
<div>
|
||||
<span :style="indicatorClass">{{ formattedResult }}</span>
|
||||
<span :style="indicatorSuffixClass" v-if="showSuffix">{{ suffixContent }}</span>
|
||||
</div>
|
||||
<div :style="indicatorNameWrapperStyle" v-if="indicatorNameShow">
|
||||
<div v-if="indicatorNameShow && indicatorNamePositionBottom">
|
||||
<div :style="indicatorNameWrapperStyle"></div>
|
||||
<span :style="indicatorNameClass">{{ resultName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -348,6 +348,11 @@ const handleFieldIdChange = (val: EnumValue) => {
|
||||
}
|
||||
})
|
||||
customSort()
|
||||
if (!res?.length) {
|
||||
options.value = []
|
||||
selectValue.value = config.value.multiple ? [] : undefined
|
||||
config.value.defaultValue = selectValue.value
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
|
||||
@@ -1821,6 +1821,9 @@ export default {
|
||||
dimension_text_style: 'Name style',
|
||||
dimension_letter_space: 'Name letter spacing',
|
||||
name_value_spacing: 'Name/value spacing',
|
||||
name_position: 'Position',
|
||||
name_position_top: 'Top',
|
||||
name_position_bottom: 'Bottom',
|
||||
font_family: 'Font',
|
||||
letter_space: 'Letter spacing',
|
||||
font_shadow: 'Font shadow',
|
||||
@@ -2117,7 +2120,10 @@ export default {
|
||||
table_field_total_label: 'Field Alias',
|
||||
table_row_header_freeze: 'Row Header Freeze',
|
||||
value_formatter_total_out_percent: 'Show percentage',
|
||||
enable_slider_tip: 'After enabling the slider, the carousel prompt will be disabled.'
|
||||
enable_slider_tip: 'After enabling the slider, the carousel prompt will be disabled.',
|
||||
liquid_show_border: 'Show Border',
|
||||
liquid_border_width: 'Border Width',
|
||||
liquid_border_distance: 'Border Distance'
|
||||
},
|
||||
dataset: {
|
||||
field_value: 'Field Value',
|
||||
|
||||
@@ -1777,6 +1777,9 @@ export default {
|
||||
dimension_text_style: '名稱樣式',
|
||||
dimension_letter_space: '名稱字間距',
|
||||
name_value_spacing: '名稱/值間距',
|
||||
name_position: '位置',
|
||||
name_position_top: '上方',
|
||||
name_position_bottom: '下方',
|
||||
font_family: '字體',
|
||||
letter_space: '字間距',
|
||||
font_shadow: '字體陰影',
|
||||
@@ -2058,7 +2061,10 @@ export default {
|
||||
table_field_total_label: '字段別名',
|
||||
table_row_header_freeze: '行頭凍結',
|
||||
value_formatter_total_out_percent: '顯示佔比',
|
||||
enable_slider_tip: '開啟縮略軸後,輪播提示將會失效'
|
||||
enable_slider_tip: '開啟縮略軸後,輪播提示將會失效',
|
||||
liquid_show_border: '顯示邊框',
|
||||
liquid_border_width: '邊框寬度',
|
||||
liquid_border_distance: '邊框間距'
|
||||
},
|
||||
dataset: {
|
||||
field_value: '欄位值',
|
||||
|
||||
@@ -1785,6 +1785,9 @@ export default {
|
||||
dimension_text_style: '名称样式',
|
||||
dimension_letter_space: '名称字间距',
|
||||
name_value_spacing: '名称/值间距',
|
||||
name_position: '位置',
|
||||
name_position_top: '上方',
|
||||
name_position_bottom: '下方',
|
||||
font_family: '字体',
|
||||
letter_space: '字间距',
|
||||
font_shadow: '字体阴影',
|
||||
@@ -2067,7 +2070,10 @@ export default {
|
||||
table_field_total_label: '字段别名',
|
||||
table_row_header_freeze: '行头冻结',
|
||||
value_formatter_total_out_percent: '显示占比',
|
||||
enable_slider_tip: '开启缩略轴后,轮播提示将会失效'
|
||||
enable_slider_tip: '开启缩略轴后,轮播提示将会失效',
|
||||
liquid_show_border: '显示边框',
|
||||
liquid_border_width: '边框宽度',
|
||||
liquid_border_distance: '边框间距'
|
||||
},
|
||||
dataset: {
|
||||
field_value: '字段值',
|
||||
|
||||
@@ -306,6 +306,7 @@ declare interface ChartBasicStyle {
|
||||
show: boolean
|
||||
field: string
|
||||
summary: string
|
||||
originName?: string
|
||||
}>
|
||||
/**
|
||||
* 符号地图符号大小最小值
|
||||
@@ -729,6 +730,18 @@ declare interface ChartMiscAttr {
|
||||
* 水波图形状
|
||||
*/
|
||||
liquidShape: string
|
||||
/**
|
||||
* 水波图边框显示
|
||||
*/
|
||||
liquidShowBorder: boolean
|
||||
/**
|
||||
* 水波图边框宽度
|
||||
*/
|
||||
liquidBorderWidth: number
|
||||
/**
|
||||
* 水波图边框距离
|
||||
*/
|
||||
liquidBorderDistance: number
|
||||
/**
|
||||
* 地图倾角
|
||||
*/
|
||||
@@ -1301,6 +1314,10 @@ declare interface ChartIndicatorNameStyle {
|
||||
* 指标/名称间距
|
||||
*/
|
||||
nameValueSpacing: number
|
||||
/**
|
||||
* 指标名称位置
|
||||
*/
|
||||
namePosition?: 'top' | 'bottom'
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@ declare interface Chart {
|
||||
tableRow: []
|
||||
}
|
||||
customCalc: any
|
||||
customSumResult?: Record<string, any>
|
||||
}
|
||||
xAxis?: Axis[]
|
||||
xAxisExt?: Axis[]
|
||||
|
||||
@@ -9,7 +9,6 @@ import YAxisSelector from '@/views/chart/components/editor/editor-style/componen
|
||||
import DualYAxisSelector from '@/views/chart/components/editor/editor-style/components/DualYAxisSelector.vue'
|
||||
import TitleSelector from '@/views/chart/components/editor/editor-style/components/TitleSelector.vue'
|
||||
import LegendSelector from '@/views/chart/components/editor/editor-style/components/LegendSelector.vue'
|
||||
import SummarySelector from '@/views/chart/components/editor/editor-style/components/SummarySelector.vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import CollapseSwitchItem from '@/components/collapse-switch-item/src/CollapseSwitchItem.vue'
|
||||
@@ -22,6 +21,7 @@ import BackgroundOverallCommon from '@/components/visualization/component-backgr
|
||||
import TableHeaderSelector from '@/views/chart/components/editor/editor-style/components/table/TableHeaderSelector.vue'
|
||||
import TableCellSelector from '@/views/chart/components/editor/editor-style/components/table/TableCellSelector.vue'
|
||||
import TableTotalSelector from '@/views/chart/components/editor/editor-style/components/table/TableTotalSelector.vue'
|
||||
import SummarySelector from '@/views/chart/components/editor/editor-style/components/table/SummarySelector.vue'
|
||||
import MiscStyleSelector from '@/views/chart/components/editor/editor-style/components/MiscStyleSelector.vue'
|
||||
import IndicatorValueSelector from '@/views/chart/components/editor/editor-style/components/IndicatorValueSelector.vue'
|
||||
import IndicatorNameSelector from '@/views/chart/components/editor/editor-style/components/IndicatorNameSelector.vue'
|
||||
|
||||
@@ -45,6 +45,11 @@ const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat(
|
||||
)
|
||||
const fontLetterSpace = CHART_FONT_LETTER_SPACE
|
||||
|
||||
const namePositionList = [
|
||||
{ name: t('chart.name_position_top'), value: 'top' },
|
||||
{ name: t('chart.name_position_bottom'), value: 'bottom' }
|
||||
]
|
||||
|
||||
const state = reactive({
|
||||
indicatorNameForm: JSON.parse(JSON.stringify(DEFAULT_INDICATOR_NAME_STYLE)),
|
||||
basicStyleForm: {} as ChartBasicStyle
|
||||
@@ -275,6 +280,27 @@ defineExpose({ getFormData })
|
||||
@change="changeTitleStyle('nameValueSpacing')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="form-item name-value-spacing-input"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.name_position')"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.indicatorNameForm.namePosition"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
@change="changeTitleStyle('namePosition')"
|
||||
>
|
||||
<el-option
|
||||
class="custom-style-option"
|
||||
v-for="option in namePositionList"
|
||||
:key="option.value"
|
||||
:label="option.name"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -553,6 +553,59 @@ onMounted(() => {
|
||||
<!--gauge-end-->
|
||||
|
||||
<!--liquid-begin-->
|
||||
<el-form-item
|
||||
v-show="showProperty('liquidShowBorder')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-checkbox
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.liquidShowBorder"
|
||||
@change="changeMisc('liquidShowBorder')"
|
||||
>
|
||||
{{ t('chart.liquid_show_border') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-row :guter="8">
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
v-show="showProperty('liquidBorderWidth')"
|
||||
class="form-item"
|
||||
:label="t('chart.liquid_border_width')"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="state.miscForm.liquidBorderWidth"
|
||||
:disabled="!state.miscForm.liquidShowBorder"
|
||||
:effect="themes"
|
||||
:min="1"
|
||||
:max="100"
|
||||
size="small"
|
||||
controls-position="right"
|
||||
@change="changeMisc('liquidBorderWidth')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
v-show="showProperty('liquidBorderDistance')"
|
||||
class="form-item"
|
||||
:label="t('chart.liquid_border_distance')"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="state.miscForm.liquidBorderDistance"
|
||||
:disabled="!state.miscForm.liquidShowBorder"
|
||||
:effect="themes"
|
||||
:min="1"
|
||||
:max="100"
|
||||
size="small"
|
||||
controls-position="right"
|
||||
@change="changeMisc('liquidBorderDistance')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="8">
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
||||
import { computed, onMounted, PropType, reactive, watch, ref, nextTick, inject } from 'vue'
|
||||
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||
import { cloneDeep, defaultsDeep, filter, find } from 'lodash-es'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import CustomAggrEdit from './CustomAggrEdit.vue'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { batchOptStatus } = storeToRefs(dvMainStore)
|
||||
const { t } = useI18n()
|
||||
@@ -30,6 +32,7 @@ const state = reactive({
|
||||
show: boolean
|
||||
field: string
|
||||
summary: string
|
||||
originName?: string
|
||||
}
|
||||
})
|
||||
|
||||
@@ -37,7 +40,12 @@ const emit = defineEmits(['onBasicStyleChange'])
|
||||
const changeBasicStyle = (prop?: string, requestData = false) => {
|
||||
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
|
||||
}
|
||||
|
||||
const changeSummaryType = () => {
|
||||
if (state.currentAxisSummary.summary === 'custom' && !state.currentAxisSummary.originName) {
|
||||
return
|
||||
}
|
||||
changeBasicStyle('seriesSummary')
|
||||
}
|
||||
watch(
|
||||
[
|
||||
() => props.chart.customAttr.basicStyle.showSummary,
|
||||
@@ -65,15 +73,38 @@ const summaryTypes = [
|
||||
{ key: 'sum', name: t('chart.sum') },
|
||||
{ key: 'avg', name: t('chart.avg') },
|
||||
{ key: 'max', name: t('chart.max') },
|
||||
{ key: 'min', name: t('chart.min') }
|
||||
// { key: 'stddev_pop', name: t('chart.stddev_pop') },
|
||||
// { key: 'var_pop', name: t('chart.var_pop') }
|
||||
{ key: 'min', name: t('chart.min') },
|
||||
{ key: 'custom', name: t('commons.custom') }
|
||||
]
|
||||
|
||||
function onSelectAxis(value) {
|
||||
state.currentAxisSummary = find(state.basicStyleForm.seriesSummary, s => s.field === value)
|
||||
}
|
||||
|
||||
const calcEdit = ref()
|
||||
const editCalcField = ref(false)
|
||||
const dimension = inject('dimension', () => [])
|
||||
const quota = inject('quota', () => [])
|
||||
const editField = () => {
|
||||
editCalcField.value = true
|
||||
nextTick(() => {
|
||||
calcEdit.value.initEdit(
|
||||
state.currentAxisSummary,
|
||||
quota().filter(ele => ele.id !== '-1')
|
||||
)
|
||||
})
|
||||
}
|
||||
const closeEditCalc = () => {
|
||||
editCalcField.value = false
|
||||
}
|
||||
const confirmEditCalc = () => {
|
||||
calcEdit.value.setFieldForm()
|
||||
const obj = cloneDeep(calcEdit.value.fieldForm)
|
||||
state.currentAxisSummary.originName = obj.originName
|
||||
setFieldDefaultValue(state.currentAxisSummary)
|
||||
closeEditCalc()
|
||||
changeSummaryType()
|
||||
}
|
||||
const init = () => {
|
||||
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
|
||||
|
||||
@@ -112,7 +143,14 @@ const init = () => {
|
||||
state.currentAxisSummary = undefined
|
||||
}
|
||||
}
|
||||
|
||||
const setFieldDefaultValue = field => {
|
||||
field.extField = 2
|
||||
field.chartId = props.chart.id
|
||||
field.datasetGroupId = props.chart.tableId
|
||||
field.lastSyncTime = null
|
||||
field.columnIndex = dimension().length + quota().length
|
||||
field.deExtractType = field.deType
|
||||
}
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
@@ -173,21 +211,41 @@ onMounted(() => {
|
||||
|
||||
<div class="indented-container">
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-select
|
||||
v-model="state.currentAxisSummary.summary"
|
||||
:class="'form-item-' + themes"
|
||||
class="form-item"
|
||||
:effect="themes"
|
||||
:disabled="!state.currentAxisSummary.show"
|
||||
@change="changeBasicStyle('seriesSummary')"
|
||||
>
|
||||
<el-option v-for="c in summaryTypes" :key="c.key" :value="c.key" :label="c.name" />
|
||||
</el-select>
|
||||
<el-col :span="state.currentAxisSummary.summary === 'custom' ? 19 : 22" :offset="2">
|
||||
<el-select
|
||||
v-model="state.currentAxisSummary.summary"
|
||||
:class="'form-item-' + themes"
|
||||
class="form-item"
|
||||
:effect="themes"
|
||||
:disabled="!state.currentAxisSummary.show"
|
||||
@change="changeSummaryType"
|
||||
>
|
||||
<el-option v-for="c in summaryTypes" :key="c.key" :value="c.key" :label="c.name" />
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col v-if="state.currentAxisSummary.summary === 'custom'" :span="2" :offset="1">
|
||||
<el-icon style="cursor: pointer">
|
||||
<Setting @click="editField()" />
|
||||
</el-icon>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</el-form>
|
||||
</div>
|
||||
<!--图表计算字段-->
|
||||
<el-dialog
|
||||
v-model="editCalcField"
|
||||
width="1000px"
|
||||
title="自定义总计"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<custom-aggr-edit ref="calcEdit" />
|
||||
<template #footer>
|
||||
<el-button secondary @click="closeEditCalc()">{{ t('dataset.cancel') }} </el-button>
|
||||
<el-button type="primary" @click="confirmEditCalc()">{{ t('dataset.confirm') }} </el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
@@ -344,7 +344,10 @@ export const DEFAULT_MISC: ChartMiscAttr = {
|
||||
symbolSize: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
liquidShowBorder: false,
|
||||
liquidBorderWidth: 4,
|
||||
liquidBorderDistance: 8
|
||||
}
|
||||
|
||||
export const DEFAULT_MARK = {
|
||||
@@ -548,7 +551,8 @@ export const DEFAULT_INDICATOR_NAME_STYLE: ChartIndicatorNameStyle = {
|
||||
fontFamily: 'Microsoft YaHei',
|
||||
letterSpace: 0,
|
||||
fontShadow: false,
|
||||
nameValueSpacing: 0
|
||||
nameValueSpacing: 0,
|
||||
namePosition: 'bottom'
|
||||
}
|
||||
|
||||
export const DEFAULT_TITLE_STYLE_BASE: ChartTextStyle = {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/uti
|
||||
import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { defaultsDeep } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
const DEFAULT_LIQUID_DATA = []
|
||||
@@ -28,7 +29,15 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
||||
'border-style': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha'],
|
||||
'label-selector': ['fontSize', 'color', 'labelFormatter'],
|
||||
'misc-selector': ['liquidShape', 'liquidSize', 'liquidMaxType', 'liquidMaxField'],
|
||||
'misc-selector': [
|
||||
'liquidShape',
|
||||
'liquidSize',
|
||||
'liquidMaxType',
|
||||
'liquidMaxField',
|
||||
'liquidShowBorder',
|
||||
'liquidBorderWidth',
|
||||
'liquidBorderDistance'
|
||||
],
|
||||
'title-selector': [
|
||||
'title',
|
||||
'fontSize',
|
||||
@@ -131,6 +140,15 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
||||
radius: radius,
|
||||
shape: shape
|
||||
}
|
||||
const { misc } = customAttr
|
||||
if (misc?.liquidShowBorder) {
|
||||
defaultsDeep(size, {
|
||||
outline: {
|
||||
border: misc.liquidBorderWidth ?? DEFAULT_MISC.liquidBorderWidth,
|
||||
distance: misc.liquidBorderDistance ?? DEFAULT_MISC.liquidBorderDistance
|
||||
}
|
||||
})
|
||||
}
|
||||
return { ...options, ...size }
|
||||
}
|
||||
|
||||
|
||||
@@ -354,7 +354,12 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
s2Options.style.rowCfg = { heightByField }
|
||||
// 计算汇总加入到数据里,冻结最后一行
|
||||
s2Options.frozenTrailingRowCount = 1
|
||||
const summaryObj = getSummaryRow(data, yAxis, basicStyle.seriesSummary) as any
|
||||
const summaryObj = getSummaryRow(
|
||||
data,
|
||||
yAxis,
|
||||
basicStyle.seriesSummary,
|
||||
chart.data.customSumResult
|
||||
) as any
|
||||
data.push(summaryObj)
|
||||
}
|
||||
s2Options.dataCell = viewMeta => {
|
||||
|
||||
@@ -2389,7 +2389,7 @@ const getWrapTextHeight = (wrapText, textStyle, spreadsheet, maxLines) => {
|
||||
}
|
||||
|
||||
// 导出获取汇总行的函数
|
||||
export function getSummaryRow(data, axis, sumCon = []) {
|
||||
export function getSummaryRow(data, axis, sumCon = [], customSumResult = {}) {
|
||||
const summaryObj = { SUMMARY: true }
|
||||
for (let i = 0; i < axis.length; i++) {
|
||||
const a = axis[i].dataeaseName
|
||||
@@ -2473,6 +2473,9 @@ export function getSummaryRow(data, axis, sumCon = []) {
|
||||
.toNumber() // 计算总体标准差
|
||||
}
|
||||
break
|
||||
case 'custom':
|
||||
summaryObj[a] = customSumResult[a]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: 'preview'
|
||||
},
|
||||
// 显示悬浮按钮
|
||||
showPopBar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
downloadStatus: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
@@ -133,6 +138,7 @@ defineExpose({
|
||||
:show-position="showPosition"
|
||||
:download-status="downloadStatus"
|
||||
:outer-screen-adaptor="screenAdaptor"
|
||||
:show-pop-bar="showPopBar"
|
||||
:show-linkage-button="showLinkageButton"
|
||||
></de-preview>
|
||||
</div>
|
||||
|
||||
@@ -215,6 +215,7 @@ defineExpose({
|
||||
:canvas-view-info="state.canvasViewInfoPreview"
|
||||
:dv-info="state.dvInfo"
|
||||
:cur-gap="state.curPreviewGap"
|
||||
:show-pop-bar="true"
|
||||
:show-linkage-button="false"
|
||||
:is-selector="props.isSelector"
|
||||
></de-preview>
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
exportLogPDF,
|
||||
exportLogTemplate
|
||||
} from '@/api/visualization/dataVisualization'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
const userStore = useUserStoreWithOut()
|
||||
|
||||
const userName = computed(() => userStore.getName)
|
||||
@@ -100,6 +101,12 @@ const loadCanvasData = (dvId, weight?, ext?) => {
|
||||
state.dvInfo = dvInfo
|
||||
state.curPreviewGap = curPreviewGap
|
||||
dataInitState.value = true
|
||||
// 修复铺满全屏模版导出错位问题
|
||||
if (props.showPosition !== 'multiplexing') {
|
||||
dvMainStore.setCanvasStyle(deepCopy(canvasStyleResult))
|
||||
dvMainStore.setComponentData(deepCopy(canvasDataResult))
|
||||
}
|
||||
|
||||
if (props.showPosition === 'preview') {
|
||||
dvMainStore.updateCurDvInfo(dvInfo)
|
||||
nextTick(() => {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script lang="ts" setup>
|
||||
import dvFolder from '@/assets/svg/dv-folder.svg'
|
||||
import icon_dashboard from '@/assets/svg/icon_dashboard.svg'
|
||||
|
||||
import { getDefaultSettings } from '@/api/common'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import icon_right_outlined from '@/assets/svg/icon_right_outlined.svg'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import dvSortAsc from '@/assets/svg/dv-sort-asc.svg'
|
||||
import dvSortDesc from '@/assets/svg/dv-sort-desc.svg'
|
||||
import { ref, computed, onMounted, watch, onUnmounted } from 'vue'
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import treeSort from '@/utils/treeSortUtils'
|
||||
import { BusiTreeRequest } from '@/models/tree/TreeNode'
|
||||
import { interactiveStoreWithOut } from '@/store/modules/interactive'
|
||||
@@ -31,6 +31,7 @@ const interactiveStore = interactiveStoreWithOut()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { dvInfo } = storeToRefs(dvMainStore)
|
||||
const { wsCache } = useCache('sessionStorage')
|
||||
const { wsCache: wsCacheLocal } = useCache()
|
||||
const { t } = useI18n()
|
||||
|
||||
const dfsTree = (ids, arr) => {
|
||||
@@ -176,15 +177,19 @@ const getTree = async () => {
|
||||
}
|
||||
|
||||
const setSortType = () => {
|
||||
const type = wsCache.get('mobile-sort-type')
|
||||
let sortType = sortList[Number(wsCacheLocal.get('TreeSort-backend')) ?? 1].value
|
||||
const type = wsCacheLocal.get('mobile-sort-type') ?? sortType
|
||||
sortTypeChange(type || curSortType.value)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
wsCache.set('mobile-sort-type', curSortType.value)
|
||||
})
|
||||
const sortTypeChangeMobile = type => {
|
||||
wsCacheLocal.set('mobile-sort-type', type)
|
||||
sortTypeChange(type)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
const defaultSort = await getDefaultSettings()
|
||||
wsCacheLocal.set('TreeSort-backend', defaultSort['basic.defaultSort'] ?? '1')
|
||||
getTree()
|
||||
activeDirectName.value = wsCache.get('activeDirectName')
|
||||
if (wsCache.get('activeTabbar') !== 'direct' || !activeDirectName.value) return
|
||||
@@ -239,7 +244,7 @@ onMounted(() => {
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-dropdown @command="sortTypeChange" trigger="click">
|
||||
<el-dropdown @command="sortTypeChangeMobile" trigger="click">
|
||||
<el-icon class="filter-icon-span">
|
||||
<Icon v-if="curSortType.includes('asc')" name="dv-sort-asc" class="opt-icon"
|
||||
><dvSortAsc class="svg-icon opt-icon"
|
||||
|
||||
@@ -301,8 +301,7 @@ onMounted(() => {
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ticket {
|
||||
height: auto;
|
||||
max-height: 560px;
|
||||
height: 100%;
|
||||
.ticket-model {
|
||||
display: flex;
|
||||
height: 22px;
|
||||
@@ -378,12 +377,7 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
.ticket-table {
|
||||
min-height: 156px;
|
||||
padding: 0 0;
|
||||
height: 50px;
|
||||
overflow-y: overlay;
|
||||
position: relative;
|
||||
height: calc(100% - 124px);
|
||||
height: 400px;
|
||||
|
||||
:deep(.ticket-exp-head) {
|
||||
display: flex;
|
||||
|
||||
@@ -295,7 +295,7 @@ const continueCreating = () => {
|
||||
init(null, pid.value)
|
||||
}
|
||||
|
||||
const handleShowFinishPage = ({ id, name, pid }) => {
|
||||
const handleShowFinishPage = ({ id, name, pid: pidVal }) => {
|
||||
isShowFinishPage()
|
||||
.then(res => {
|
||||
if (editDs.value || !res.data) {
|
||||
@@ -308,7 +308,7 @@ const handleShowFinishPage = ({ id, name, pid }) => {
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
pid.value = pid
|
||||
pid.value = pidVal
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -19,7 +19,7 @@
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<dataease.version>2.10.15</dataease.version>
|
||||
<dataease.version>2.10.16</dataease.version>
|
||||
<java.version>21</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
|
||||
|
||||
@@ -19,4 +19,6 @@ public class UserItem implements Serializable {
|
||||
private Long id;
|
||||
@Schema(description = "用户名称")
|
||||
private String name;
|
||||
@Schema(description = "账号")
|
||||
private String account;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.Data;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -68,7 +69,7 @@ public class Configuration {
|
||||
protected static final Pattern HOST_PORT_PATTERN = Pattern.compile("//([^:/]+)(?::(\\d+))?");
|
||||
protected static final Pattern PARAMETERS_PATTERN = Pattern.compile("([^&=]+)=([^&]*)");
|
||||
private static final Pattern DB_NAME_PATTERN = Pattern.compile("//[^/]+/([^?]+)");
|
||||
private Map<String, String> parameters;
|
||||
private Map<String, String> parameters = new HashMap<>();
|
||||
protected void parseHostAndPort(String jdbcUrl) {
|
||||
Matcher matcher = HOST_PORT_PATTERN.matcher(jdbcUrl);
|
||||
if (matcher.find()) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.dataease.extensions.view.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -34,4 +36,11 @@ public class ChartViewFieldDTO extends ChartViewFieldBaseDTO implements Serializ
|
||||
*/
|
||||
@JsonIgnore
|
||||
private FieldSource source;
|
||||
|
||||
/**
|
||||
* 显隐
|
||||
*/
|
||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
private Boolean show;
|
||||
private String field;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user