feat(仪表板、数据大屏): 仪表板大屏支持通用设置添加对数值格式的统一处理 (#17575)

This commit is contained in:
王嘉豪
2025-12-11 17:02:08 +08:00
committed by GitHub
parent ee2591a51f
commit 5b982628a3
10 changed files with 350 additions and 8 deletions

View File

@@ -17,6 +17,8 @@ import { useEmitt } from '@/hooks/web/useEmitt'
import { merge } from 'lodash-es'
import CanvasBackground from '@/components/visualization/component-background/CanvasBackground.vue'
import SeniorStyleSetting from '@/components/dashboard/subject-setting/dashboard-style/SeniorStyleSetting.vue'
import ValueFormatterSetting from '@/components/dashboard/subject-setting/dashboard-style/ValueFormatterSetting.vue'
import { formatterViewInfo } from '@/views/chart/components/js/formatter'
const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const { canvasStyleData, componentData, canvasViewInfo } = storeToRefs(dvMainStore)
@@ -51,12 +53,18 @@ const onColorChange = val => {
const onTextChange = val => {
themeAttrChange('customStyle', 'text', val)
}
const onFormatterItemChange = val => {
themeAttrChange('formatterCfg', 'formatterCfg', val)
}
const themeAttrChange = (custom, property, value) => {
if (canvasAttrInit) {
Object.keys(canvasViewInfo.value).forEach(function (viewId) {
const viewInfo = canvasViewInfo.value[viewId]
try {
if (custom === 'customAttr') {
if (custom === 'formatterCfg') {
formatterViewInfo(viewInfo, value)
} else if (custom === 'customAttr') {
merge(viewInfo['customAttr'], value)
} else {
Object.keys(value).forEach(function (key) {
@@ -154,6 +162,12 @@ const saveSelfSubject = () => {
>
<filter-style-simple-selector />
</el-collapse-item>
<el-collapse-item :title="t('visualization.number_formatter')" name="formatterItem">
<ValueFormatterSetting
:formatter-cfg="canvasStyleData.component.formatterItem"
@onFormatterItemChange="onFormatterItemChange"
></ValueFormatterSetting>
</el-collapse-item>
<el-collapse-item
:title="t('components.advanced_style_settings')"
name="seniorStyleSetting"

View File

@@ -210,9 +210,7 @@
class="radio-span"
@change="themeChange"
>
<el-radio label="all" :effect="themes">
{{ t('visualization.view') }}
</el-radio>
<el-radio label="all" :effect="themes"> {{ t('visualization.view') }} 22 </el-radio>
<el-radio label="custom" :effect="themes">
{{ resourceType }}
</el-radio>

View File

@@ -0,0 +1,238 @@
<script lang="tsx" setup>
import { useI18n } from '@/hooks/web/useI18n'
import { reactive, toRefs } from 'vue'
import {
isEnLocal,
formatterType,
getUnitTypeList,
onChangeFormatCfgUnitLanguage,
valueFormatter,
initFormatCfgUnit
} from '@/views/chart/components/js/formatter'
import { ElFormItem } from 'element-plus-secondary'
const { t } = useI18n()
const emit = defineEmits(['onFormatterItemChange'])
const props = defineProps({
formatterCfg: {
type: Object,
required: true
},
themes: {
type: String,
default: 'light'
}
})
const { formatterCfg } = toRefs(props)
const state = reactive({
typeList: formatterType,
exampleResult: '20000000'
})
function changeUnitLanguage(cfg: BaseFormatter, lang) {
onChangeFormatCfgUnitLanguage(cfg, lang)
getExampleValue()
}
const init = () => {
if (!formatterCfg.value) {
formatterCfg.value = formatterCfg
initFormatCfgUnit(formatterCfg.value)
}
}
const onFormatChange = () => {
getExampleValue()
emit('onFormatterItemChange', formatterCfg.value)
}
const getExampleValue = () => {
state.exampleResult = valueFormatter(20000000, formatterCfg.value)
}
init()
getExampleValue()
</script>
<template>
<div>
<el-form
ref="form"
:effect="themes"
:model="formatterCfg"
class="formatter-form"
label-position="top"
>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.value_formatter_type')"
>
<el-radio-group
class="radio-span"
:effect="themes"
v-model="formatterCfg.type"
@change="onFormatChange"
>
<el-radio
:effect="themes"
v-for="radio in state.typeList"
:key="radio.value"
:label="radio.value"
>{{ t('chart.' + radio.name) }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="formatterCfg.type !== 'auto'"
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.value_formatter_decimal_count')"
>
<el-input-number
controls-position="right"
v-model="formatterCfg.decimalCount"
:effect="themes"
size="small"
:min="0"
:max="10"
@change="onFormatChange"
/>
</el-form-item>
<template v-if="formatterCfg.type !== 'percent'">
<el-row :gutter="8">
<el-col :span="12" v-if="!isEnLocal">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.value_formatter_unit_language')"
>
<el-select
v-model="formatterCfg.unitLanguage"
size="small"
:placeholder="t('chart.pls_select_field')"
:effect="themes"
@change="v => changeUnitLanguage(formatterCfg, v)"
>
<el-option
:effect="themes"
size="small"
:label="t('chart.value_formatter_unit_language_ch')"
value="ch"
/>
<el-option
size="small"
:effect="themes"
:label="t('chart.value_formatter_unit_language_en')"
value="en"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="isEnLocal ? 24 : 12">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.value_formatter_unit')"
>
<el-select
:effect="themes"
size="small"
v-model="formatterCfg.unit"
:placeholder="t('chart.pls_select_field')"
@change="onFormatChange"
style="width: 100%"
>
<el-option
:effect="themes"
size="small"
v-for="item in getUnitTypeList(formatterCfg.unitLanguage)"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</template>
<el-form-item
:effect="themes"
class="form-item"
:class="'form-item-' + themes"
:label="t('chart.value_formatter_suffix')"
>
<el-input
v-model="formatterCfg.suffix"
:effect="themes"
size="small"
clearable
:placeholder="t('commons.input_content')"
@change="onFormatChange"
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" :effect="themes">
<el-checkbox
:effect="themes"
size="small"
v-model="formatterCfg.thousandSeparator"
@change="onFormatChange"
:label="t('chart.value_formatter_thousand_separator')"
/>
</el-form-item>
<div style="line-height: 22px">
<span style="color: #646a73">{{ t('chart.value_formatter_example') }}</span>
<span style="margin-left: 12px">{{ state.exampleResult }}</span>
</div>
</el-form>
</div>
</template>
<style lang="less" scoped>
.el-form-item {
margin-bottom: 10px !important;
}
.formatter-form {
margin-bottom: 16px;
:deep(.ed-form-item) {
margin-bottom: 16px;
}
:deep(.ed-form-item__label) {
color: #1f2329;
margin-bottom: 8px !important;
font-size: 14px !important;
font-weight: 400 !important;
}
:deep(.ed-checkbox) {
color: #1f2329;
}
}
.el-select-dropdown__item :deep(span) {
font-size: 14px !important;
}
.exp-style {
color: #c0c4cc;
font-size: 12px;
}
.form-item-dark {
:deep(.ed-form-item__label) {
color: #6a6a6a;
font-size: 12px !important;
font-weight: 400;
line-height: 20px;
}
}
</style>

View File

@@ -15,6 +15,8 @@ import SeniorStyleSetting from '@/components/dashboard/subject-setting/dashboard
import Icon from '../icon-custom/src/Icon.vue'
import CanvasBaseSetting from '@/components/visualization/CanvasBaseSetting.vue'
import { useI18n } from '@/hooks/web/useI18n'
import ValueFormatterSetting from '@/components/dashboard/subject-setting/dashboard-style/ValueFormatterSetting.vue'
import { formatterViewInfo } from '@/views/chart/components/js/formatter'
const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const { canvasStyleData, canvasViewInfo } = storeToRefs(dvMainStore)
@@ -35,6 +37,10 @@ const init = () => {
})
}
const onFormatterItemChange = val => {
themeAttrChange('formatterCfg', 'formatterCfg', val)
}
const onColorChange = val => {
themeAttrChange('customAttr', 'color', val)
}
@@ -53,7 +59,9 @@ const themeAttrChange = (custom, property, value) => {
Object.keys(canvasViewInfo.value).forEach(function (viewId) {
try {
const viewInfo = canvasViewInfo.value[viewId]
if (custom === 'customAttr') {
if (custom === 'formatterCfg') {
formatterViewInfo(viewInfo, value)
} else if (custom === 'customAttr') {
if (viewInfo.type === 'flow-map') {
const { customAttr } = viewInfo
const tmpValue = cloneDeep(value)
@@ -172,6 +180,17 @@ onMounted(() => {
>
<overall-setting style="padding-bottom: 8px" themes="dark" />
</el-collapse-item>
<el-collapse-item
effect="dark"
:title="t('visualization.number_formatter')"
name="formatterItem"
>
<ValueFormatterSetting
:formatter-cfg="canvasStyleData.component.formatterItem"
themes="dark"
@onFormatterItemChange="onFormatterItemChange"
></ValueFormatterSetting>
</el-collapse-item>
<el-collapse-item
effect="dark"
:title="t('visualization.advanced_style_settings')"

View File

@@ -2945,6 +2945,7 @@ export default {
column_name: 'Field name'
},
visualization: {
number_formatter: 'Number Content Format',
jump_dialog_background: 'Jump pop-up background color',
jump_dialog_button: 'Jump pop-up button color',
sqlbot_query_tips: 'Smart Data Query',

View File

@@ -2864,6 +2864,7 @@ export default {
column_name: '欄位名稱'
},
visualization: {
number_formatter: '數字內容格式',
jump_dialog_background: '跳轉彈框背景色',
jump_dialog_button: '跳轉彈框按鈕色',
sqlbot_query_tips: '智能問數',

View File

@@ -2870,6 +2870,7 @@ export default {
column_name: '字段名称'
},
visualization: {
number_formatter: '数字内容格式',
jump_dialog_background: '跳转弹框背景色',
jump_dialog_button: '跳转弹框按钮色',
sqlbot_query_tips: '智能问数',

View File

@@ -46,6 +46,7 @@ import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { useCache } from '@/hooks/web/useCache'
import { isDesktop } from '@/utils/ModelUtil'
import { ShorthandMode } from '@/Types'
import { formatterItem } from '@/views/chart/components/js/formatter'
const { t } = useI18n()
const appearanceStore = useAppearanceStoreWithOut()
const { wsCache } = useCache()
@@ -340,6 +341,9 @@ export function historyAdaptor(
canvasStyleResult['dialogBackgroundColor'] = canvasStyleResult['dialogBackgroundColor'] || '#fff'
canvasStyleResult['dialogButton'] = canvasStyleResult['dialogButton'] || '#020408'
canvasStyleResult['component']['formatterItem'] =
canvasStyleResult['component']['formatterItem'] || deepCopy(formatterItem)
canvasDataResult.forEach(componentItem => {
historyItemAdaptor(componentItem, reportFilterInfo, attachInfo, canvasVersion, canvasInfo)
})

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import { find } from 'lodash-es'
import { find, merge } from 'lodash-es'
import { useI18n } from '@/hooks/web/useI18n'
import { getLocale } from '@/utils/utils'
import { parseJson } from '@/views/chart/components/js/util'
@@ -255,3 +255,65 @@ export const calcNiceMinValue = (chart, options, tmpOptions) => {
}
return { ...tmpOptions, ...axis }
}
/**
* 适配图表数字格式化属性
* @param viewInfo
* @param value
*/
export const formatterViewInfo = (viewInfo, value) => {
viewInfo.xAxis.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
viewInfo.xAxisExt.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
viewInfo.yAxis.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
viewInfo.extStack.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
viewInfo.extBubble.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
viewInfo.extLabel.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
viewInfo.extTooltip.forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
//customAttr
viewInfo['customAttr']['label']['labelFormatter'] = merge(
viewInfo['customAttr']['label']['labelFormatter'],
value
)
viewInfo['customAttr']['label']['quotaLabelFormatter'] = merge(
viewInfo['customAttr']['label']['quotaLabelFormatter'],
value
)
viewInfo['customAttr']['label']['totalFormatter'] = merge(
viewInfo['customAttr']['label']['totalFormatter'],
value
)
viewInfo['customAttr']['tooltip']['tooltipFormatter'] = merge(
viewInfo['customAttr']['tooltip']['tooltipFormatter'],
value
)
viewInfo['customAttr']['tooltip']['seriesTooltipFormatter'].forEach(function (item) {
item['formatterCfg'] = merge(item['formatterCfg'], value)
})
//customStyle
viewInfo['customStyle']['xAxis']['axisLabelFormatter'] = merge(
viewInfo['customStyle']['xAxis']['axisLabelFormatter'],
value
)
viewInfo['customStyle']['yAxis']['axisLabelFormatter'] = merge(
viewInfo['customStyle']['yAxis']['axisLabelFormatter'],
value
)
viewInfo['customStyle']['yAxisExt']['axisLabelFormatter'] = merge(
viewInfo['customStyle']['yAxisExt']['axisLabelFormatter'],
value
)
}