Merge branch 'dev-v2' into pr@dev-v2@feat_report_pdf

This commit is contained in:
fit2cloud-chenyw 2024-05-16 20:26:05 +08:00
commit fec12e16cd
12 changed files with 399 additions and 162 deletions

View File

@ -220,13 +220,15 @@ public class PermissionManage {
private String handleSysVariable(UserFormVO userEntity, String sysVariable) {
String value = null;
System.out.println(sysVariable);
System.out.println(JsonUtil.toJSONString(userEntity));
if (StringUtils.isNotBlank(sysVariable) && sysVariable.startsWith("${") && sysVariable.endsWith("}")) {
String variableId = sysVariable.substring(2, sysVariable.length() - 1);
for (SysVariableValueItem variable : userEntity.getVariables()) {
if (variableId.equalsIgnoreCase(variable.getVariableId())) {
if (variableId.equalsIgnoreCase(variable.getVariableId().toString())) {
if (variable.getSysVariableDto().getType().equalsIgnoreCase("text")) {
for (SysVariableValueDto sysVariableValueDto : variable.getValueList()) {
if (sysVariableValueDto.getId().toString().equals(variable.getVariableValueId())) {
if (sysVariableValueDto.getId().equals(variable.getVariableValueId())) {
value = sysVariableValueDto.getValue();
}
}

View File

@ -18,6 +18,7 @@
"@antv/l7plot": "^0.5.5",
"@antv/s2": "^1.49.0",
"@codemirror/lang-sql": "^6.4.0",
"@npkg/tinymce-plugins": "^0.0.7",
"@tinymce/tinymce-vue": "^5.1.0",
"@vueuse/core": "^9.13.0",
"ace-builds": "^1.15.3",

View File

@ -16,6 +16,7 @@ export interface EnumValue {
displayId?: string
sortId?: string
sort?: string
searchText: string
}
interface Fields {

View File

@ -47,6 +47,7 @@ import 'tinymce/plugins/contextmenu' // contextmenu
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/nonbreaking'
import 'tinymce/plugins/pagebreak'
import '@npkg/tinymce-plugins/letterspacing'
import './plugins' //
import { computed, nextTick, reactive, ref, toRefs, watch, onMounted, PropType } from 'vue'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
@ -121,10 +122,10 @@ const init = ref({
skin_url: formatDataEaseBi('./tinymce-dataease-private/skins/ui/oxide'), //
content_css: formatDataEaseBi('./tinymce-dataease-private/skins/content/default/content.css'),
plugins:
'vertical-content advlist autolink link image lists charmap media wordcount table contextmenu directionality pagebreak', //
'vertical-content advlist autolink link image lists charmap media wordcount table contextmenu directionality pagebreak letterspacing', //
//
toolbar:
'undo redo |fontselect fontsizeselect |forecolor backcolor bold italic |underline strikethrough link| formatselect |' +
'undo redo | fontselect fontsizeselect |forecolor backcolor bold italic letterspacing |underline strikethrough link| formatselect |' +
'top-align center-align bottom-align | alignleft aligncenter alignright | bullist numlist |' +
' blockquote subscript superscript removeformat | table image | fullscreen ' +
'| bdmap indent2em lineheight formatpainter axupimgs',

View File

@ -9,6 +9,7 @@ import {
nextTick,
computed,
inject,
onUnmounted,
Ref
} from 'vue'
import { enumValueObj, type EnumValue, getEnumValue } from '@/api/dataset'
@ -84,11 +85,15 @@ const setDefaultMapValue = arr => {
}
})
Object.values(defaultMapValue).forEach(ele => {
defaultValue = [...defaultValue, ...(ele as unknown as string[])]
defaultValue = [...new Set([...defaultValue, ...(ele as unknown as string[])])]
})
return defaultValue
}
onUnmounted(() => {
enumValueArr = []
})
const handleValueChange = () => {
const value = Array.isArray(selectValue.value) ? [...selectValue.value] : selectValue.value
if (!props.isConfig) {
@ -144,27 +149,57 @@ const handleFieldIdDefaultChange = (val: string[]) => {
})
}
const setOldMapValue = arr => {
const { displayId } = config.value
if (!displayId) {
return []
}
let defaultMapValue = {}
let defaultValue = []
arr.forEach(ele => {
defaultMapValue[ele] = []
})
enumValueArr.forEach(ele => {
if (defaultMapValue[ele[displayId]]) {
defaultMapValue[ele[displayId]].push(ele)
}
})
Object.values(defaultMapValue).forEach(ele => {
defaultValue = [...defaultValue, ...(ele as unknown as string[])]
})
return defaultValue
}
const handleFieldIdChange = (val: EnumValue) => {
enumValueArr = []
loading.value = true
enumValueObj(val)
.then(res => {
enumValueArr = res || []
let oldArr = []
let oldEnumValueArr = []
if (selectValue.value?.length && config.value.multiple) {
oldArr = [...selectValue.value]
oldEnumValueArr = setOldMapValue(oldArr)
}
enumValueArr = [...res, ...oldEnumValueArr] || []
options.value = [
...new Set(
(res || []).map(ele => {
return ele[val.displayId || val.queryId]
})
(res || [])
.map(ele => {
return ele[val.displayId || val.queryId]
})
.concat(oldArr)
)
].map(ele => {
return {
label: ele,
value: ele
value: ele,
checked: oldArr.includes(ele)
}
})
})
.finally(() => {
loading.value = false
if (isFromRemote.value) return
if (config.value.defaultValueCheck) {
selectValue.value = Array.isArray(config.value.defaultValue)
? [...config.value.defaultValue]
@ -199,6 +234,11 @@ const visible = ref(false)
const visibleChange = (val: boolean) => {
setTimeout(() => {
visible.value = !val
if (!val) {
isFromRemote.value = false
searchText.value = ''
remoteMethod('')
}
}, 50)
}
@ -310,6 +350,19 @@ watch(
}
)
const searchText = ref('')
const isFromRemote = ref(false)
const clear = () => {
remoteMethod('')
}
const remoteMethod = (query: string) => {
if (config.value.optionValueSource !== 1) return
isFromRemote.value = true
searchText.value = query
debounceOptions(1)
}
watch(
() => config.value.valueSource,
() => {
@ -342,7 +395,13 @@ const setOptions = (num: number) => {
break
case 1:
if (field.id) {
handleFieldIdChange({ queryId: field.id, displayId: displayId || field.id, sort, sortId })
handleFieldIdChange({
queryId: field.id,
displayId: displayId || field.id,
sort,
sortId,
searchText: searchText.value
})
} else {
options.value = []
}
@ -414,9 +473,10 @@ defineExpose({
multiple
show-checked
clearable
radio
:style="selectStyle"
collapse-tags
:remote="config.optionValueSource === 1"
:remote-method="remoteMethod"
:options="options"
collapse-tags-tooltip
></el-select-v2>
@ -430,6 +490,9 @@ defineExpose({
ref="single"
:style="selectStyle"
filterable
@clear="clear"
:remote="config.optionValueSource === 1"
:remote-method="remoteMethod"
radio
@visible-change="visibleChange"
:popper-class="

View File

@ -3,13 +3,16 @@ import { computed, inject, onMounted, PropType, reactive, ref, watch } from 'vue
import { useI18n } from '@/hooks/web/useI18n'
import { COLOR_PANEL, DEFAULT_QUADRANT_STYLE } from '@/views/chart/components/editor/util/chart'
import { useEmitt } from '@/hooks/web/useEmitt'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { deepCopy } from '@/utils/utils'
useEmitt({
name: 'quadrant-default-baseline',
callback: args => quadrantDefaultBaseline(args)
})
const quotaData = ref<Axis[]>(inject('quotaData'))
const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut()
const props = defineProps({
chart: {
type: Object,
@ -25,9 +28,29 @@ const props = defineProps({
})
const predefineColors = COLOR_PANEL
const regionStyle = []
const labels = []
const isDashboard = dvMainStore.dvInfo.type === 'dashboard'
for (let i = 0; i < 4; i++) {
regionStyle.push({
fill: isDashboard ? '#fdfcfc' : 'rgb(2,4,8,1)',
fillOpacity: 1
})
labels.push({
content: '',
style: {
fill: isDashboard ? 'rgb(2,4,8,1)' : '#fdfcfc',
fillOpacity: 0.5,
fontSize: 14
}
})
}
const state = reactive({
quadrantForm: JSON.parse(JSON.stringify(DEFAULT_QUADRANT_STYLE))
quadrantForm: {
...JSON.parse(JSON.stringify(DEFAULT_QUADRANT_STYLE)),
regionStyle,
labels
}
})
const toolTip = computed(() => {
return props.themes === 'dark' ? 'ndark' : 'dark'
@ -84,19 +107,27 @@ const init = () => {
}
if (customAttr.quadrant) {
state.quadrantForm = customAttr.quadrant
} else {
changeStyle()
}
}
}
const showProperty = prop => props.propertyInner?.includes(prop)
const tabActive = ref(1)
onMounted(() => {
init()
})
</script>
<template>
<el-form ref="quadrantForm" :model="state.quadrantForm" size="small" label-position="top">
<el-form
ref="quadrantForm"
class="quadrant"
:model="state.quadrantForm"
size="small"
label-position="top"
>
<template v-if="showProperty('lineStyle')">
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
>{{ t('chart.quadrant') }}{{ t('chart.split_line') }}</label
@ -113,12 +144,12 @@ onMounted(() => {
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<el-tooltip :content="t('chart.alpha')" :effect="toolTip" placement="top">
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
:effect="props.themes"
v-model="state.quadrantForm.lineStyle.opacity"
:placeholder="t('chart.alpha')"
:placeholder="t('chart.not_alpha')"
@change="changeStyle()"
>
<el-option
@ -182,147 +213,226 @@ onMounted(() => {
</el-form-item>
</div>
</template>
<div
v-for="(l, index) in state.quadrantForm.labels"
:key="index"
style="flex-direction: row; justify-content: space-between"
>
<el-divider
class="m-divider"
v-if="index < state.quadrantForm.labels.length"
:class="'m-divider--' + themes"
/>
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
>{{ t('chart.quadrant') }}{{ index + 1 }}</label
<el-tabs v-model="tabActive" class="quadrant-tab-header" :class="{ dark: themes === 'dark' }">
<el-tab-pane
:name="index + 1"
v-for="(l, index) in state.quadrantForm.labels"
:key="index"
:label="t('chart.quadrant') + (index + 1)"
class="padding-tab"
>
<template v-if="showProperty('regionStyle')">
<div style="display: flex">
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">{{
t('chart.backgroundColor')
}}</label>
</div>
<div style="display: flex">
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px">
<el-color-picker
v-model="state.quadrantForm.regionStyle[index].fill"
class="color-picker-style"
:predefine="predefineColors"
@change="changeStyle()"
:effect="themes"
is-custom
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<el-tooltip :content="t('chart.alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
:effect="props.themes"
v-model="state.quadrantForm.regionStyle[index].fillOpacity"
:placeholder="t('chart.alpha')"
@change="changeStyle()"
<div style="flex-direction: row; justify-content: space-between">
<template v-if="showProperty('regionStyle')">
<div style="display: flex">
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">{{
t('chart.backgroundColor')
}}</label>
</div>
<div style="display: flex">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-right: 4px"
>
<el-option
v-for="option in fillOpacityList"
:key="option.value"
:label="option.name"
:value="option.value"
<el-color-picker
v-model="state.quadrantForm.regionStyle[index].fill"
class="color-picker-style"
:predefine="predefineColors"
@change="changeStyle()"
:effect="themes"
is-custom
/>
</el-select>
</el-tooltip>
</el-form-item>
</div>
</template>
<template v-if="showProperty('label')">
<el-form-item class="form-item" :class="'form-item-' + themes" :label="t('chart.text')">
<el-input
:effect="props.themes"
v-model="l.content"
size="small"
maxlength="50"
@blur="changeStyle()"
/>
</el-form-item>
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">
{{ t('chart.text') }}{{ t('chart.chart_style') }}</label
>
<div style="display: flex">
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px">
<el-color-picker
v-model="l.style.fill"
class="color-picker-style"
:predefine="predefineColors"
@change="changeStyle()"
:effect="themes"
is-custom
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<el-tooltip :content="t('chart.alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
:effect="props.themes"
v-model="l.style.fillOpacity"
:placeholder="t('chart.alpha')"
@change="changeStyle()"
</el-form-item>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-left: 4px"
>
<el-option
v-for="option in fillOpacityList"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-tooltip>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<el-tooltip :content="t('chart.font_size')" :effect="toolTip" placement="top">
<el-select
style="width: 108px"
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
:effect="props.themes"
v-model="state.quadrantForm.regionStyle[index].fillOpacity"
:placeholder="t('chart.not_alpha')"
@change="changeStyle()"
>
<el-option
v-for="option in fillOpacityList"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-tooltip>
</el-form-item>
</div>
</template>
<template v-if="showProperty('label')">
<el-form-item class="form-item" :class="'form-item-' + themes" :label="t('chart.text')">
<el-input
:effect="props.themes"
v-model="l.style.fontSize"
:placeholder="t('chart.axis_name_fontsize')"
@change="changeStyle()"
v-model="l.content"
size="small"
maxlength="50"
@blur="changeStyle()"
/>
</el-form-item>
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">
{{ t('chart.text') }}{{ t('chart.chart_style') }}</label
>
<div style="display: flex">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-right: 4px"
>
<el-option
v-for="option in fontSizeList"
:key="option.value"
:label="option.name"
:value="option.value"
<el-color-picker
v-model="l.style.fill"
class="color-picker-style"
:predefine="predefineColors"
@change="changeStyle()"
:effect="themes"
is-custom
/>
</el-select>
</el-tooltip>
</el-form-item>
</el-form-item>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-left: 4px"
>
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
:effect="props.themes"
v-model="l.style.fillOpacity"
:placeholder="t('chart.not_alpha')"
@change="changeStyle()"
>
<el-option
v-for="option in fillOpacityList"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-tooltip>
</el-form-item>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-left: 4px"
>
<el-tooltip :content="t('chart.font_size')" :effect="toolTip" placement="top">
<el-select
style="width: 108px"
:effect="props.themes"
v-model="l.style.fontSize"
:placeholder="t('chart.axis_name_fontsize')"
@change="changeStyle()"
>
<el-option
v-for="option in fontSizeList"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-tooltip>
</el-form-item>
</div>
</template>
</div>
</template>
</div>
</el-tab-pane>
</el-tabs>
</el-form>
</template>
<style lang="less" scoped>
.custom-form-item-label {
margin-bottom: 4px;
line-height: 20px;
color: #646a73;
font-size: 12px;
font-style: normal;
font-weight: 400;
padding: 2px 12px 0 0;
.quadrant {
.custom-form-item-label {
margin-bottom: 4px;
line-height: 20px;
color: #646a73;
font-size: 12px;
font-style: normal;
font-weight: 400;
padding: 2px 12px 0 0;
&.custom-form-item-label--dark {
color: #a6a6a6;
&.custom-form-item-label--dark {
color: #a6a6a6;
}
}
}
.form-item-checkbox {
margin-bottom: 10px !important;
}
.form-item-checkbox {
margin-bottom: 10px !important;
}
.m-divider {
border-color: rgba(31, 35, 41, 0.15);
margin: 0 0 16px;
.m-divider {
border-color: rgba(31, 35, 41, 0.15);
margin: 0 0 16px;
&.m-divider--dark {
border-color: rgba(235, 235, 235, 0.15);
&.m-divider--dark {
border-color: rgba(235, 235, 235, 0.15);
}
}
.quadrant-tab-header {
--ed-tabs-header-height: 34px;
--custom-tab-color: #646a73;
:deep(.ed-tabs__nav-wrap::after) {
background-color: unset;
}
&.dark {
--custom-tab-color: #a6a6a6;
}
height: 100%;
:deep(.ed-tabs__header) {
border-top: solid 1px @side-outline-border-color;
}
:deep(.ed-tabs__item) {
font-weight: 400;
font-size: 12px;
padding: 0 12px !important;
margin-right: 0 !important;
color: var(--custom-tab-color);
}
:deep(.is-active) {
font-weight: 500;
color: var(--ed-color-primary, #3370ff);
}
:deep(.ed-tabs__nav-scroll) {
padding-left: 0 !important;
}
:deep(.ed-tabs__header) {
margin: 0 !important;
}
:deep(.ed-tabs__content) {
height: calc(100% - 33px);
overflow-y: auto;
overflow-x: hidden;
}
}
.padding-tab {
padding: 0;
height: 100%;
width: 100%;
display: flex;
:deep(.ed-scrollbar) {
&.has-footer {
height: calc(100% - 81px);
}
}
:deep(.ed-footer) {
padding: 0;
height: 114px;
}
}
}
</style>

View File

@ -59,6 +59,9 @@ const snapshotStore = snapshotStoreWithOut()
const dvMainStore = dvMainStoreWithOut()
const { canvasCollapse, curComponent, componentData, editMode } = storeToRefs(dvMainStore)
const router = useRouter()
let componentNameEdit = ref(false)
let inputComponentName = ref('')
let componentNameInput = ref(null)
const { t } = useI18n()
const loading = ref(false)
@ -92,6 +95,35 @@ const editCalcField = ref(false)
const isCalcFieldAdd = ref(true)
const calcEdit = ref()
const route = useRoute()
const onComponentNameChange = () => {
snapshotStore.recordSnapshotCache()
}
const closeEditComponentName = () => {
componentNameEdit.value = false
if (!inputComponentName.value || !inputComponentName.value.trim()) {
return
}
if (inputComponentName.value.trim() === view.value.title) {
return
}
if (inputComponentName.value.trim().length > 64 || inputComponentName.value.trim().length < 2) {
ElMessage.warning('名称字段长度2-64个字符')
editComponentName()
return
}
view.value.title = inputComponentName.value
inputComponentName.value = ''
}
const editComponentName = () => {
componentNameEdit.value = true
inputComponentName.value = view.value.title
nextTick(() => {
componentNameInput.value.focus()
})
}
const toolTip = computed(() => {
return props.themes === 'dark' ? 'ndark' : 'dark'
})
@ -1480,7 +1512,9 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
</div>
<div v-if="!canvasCollapse.chartAreaCollapse" style="width: 240px" class="view-panel-row">
<el-row class="editor-title">
<span style="font-size: 14px">{{ view.title }}</span>
<span class="name-area" @dblclick="editComponentName" id="component-name">{{
view.title
}}</span>
</el-row>
<el-row style="height: calc(100vh - 110px); overflow-y: auto">
@ -2853,6 +2887,15 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
<FilterTree ref="filterTree" @filter-data="changeFilterData" />
</div>
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
<Teleport v-if="componentNameEdit" :to="'#component-name'">
<input
width="100%"
@change="onComponentNameChange"
ref="componentNameInput"
v-model="inputComponentName"
@blur="closeEditComponentName"
/>
</Teleport>
</template>
<style lang="less" scoped>
@ -3956,4 +3999,24 @@ span {
margin-bottom: 8px;
}
}
.name-area {
position: relative;
line-height: 24px;
height: 24px;
font-size: 14px !important;
width: 300px;
overflow: hidden;
cursor: pointer;
input {
position: absolute;
left: 0;
width: 100%;
outline: none;
border: 1px solid #295acc;
border-radius: 4px;
padding: 0 4px;
height: 100%;
}
}
</style>

View File

@ -7,10 +7,8 @@ import { flow, parseJson } from '../../../util'
import { valueFormatter } from '../../../formatter'
import { useI18n } from '@/hooks/web/useI18n'
import { isEmpty } from 'lodash-es'
import { DEFAULT_QUADRANT_STYLE } from '@/views/chart/components/editor/util/chart'
const { t } = useI18n()
/**
* 象限图
*/
@ -396,9 +394,6 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
...chart.customStyle.yAxisExt.axisLine,
show: true
}
chart.customAttr.quadrant = {
...DEFAULT_QUADRANT_STYLE
}
return chart
}

View File

@ -44,9 +44,6 @@ public class UserFormVO implements Serializable {
@Schema(description = "模式")
private String model;
@Schema(description = "系统变量")
private String sysVariable;
@Schema(description = "系统变量")
private List<SysVariableValueItem> variables;
}

View File

@ -2,7 +2,6 @@ package io.dataease.api.permissions.user.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.api.permissions.variable.dto.SysVariableValueItem;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -28,5 +27,5 @@ public class UserGridVO {
@Schema(description = "创建时间")
private Long createTime;
@Schema(description = "系统变量")
private List<SysVariableValueItem> variables;
private String sysVariable;
}

View File

@ -36,7 +36,7 @@ public interface SysVariablesApi {
@Operation(summary = "详细信息")
@GetMapping("/detail/{id}")
SysVariableDto detail(@PathVariable String id);
SysVariableDto detail(@PathVariable Long id);
@Operation(summary = "查询")
@PostMapping("/query")
@ -55,7 +55,7 @@ public interface SysVariablesApi {
void deleteValue(@PathVariable String id);
@GetMapping("/value/selected/{id}")
List<SysVariableValueDto> selectVariableValue(@PathVariable("id") String id);
List<SysVariableValueDto> selectVariableValue(@PathVariable("id") Long id);
@PostMapping("/value/selected/{goPage}/{pageSize}")
IPage<SysVariableValueDto> selectPage(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody SysVariableValueDto sysVariableValueDto);

View File

@ -8,12 +8,17 @@ import java.util.List;
@Data
public class SysVariableValueItem {
private SysVariableDto sysVariableDto;
@JsonSerialize(using = ToStringSerializer.class)
private String variableId;
@JsonSerialize(using = ToStringSerializer.class)
private String variableValueId;
@JsonSerialize(using = ToStringSerializer.class)
private String variableValue;
@JsonSerialize(using = ToStringSerializer.class)
private String variableValue2;
private String variableType;
@JsonSerialize(using = ToStringSerializer.class)
private Long variableId;
@JsonSerialize(using = ToStringSerializer.class)
private Long variableValueId;
private String variableName;
private List<SysVariableValueDto> valueList;
private SysVariableDto sysVariableDto;
}