Merge pull request #11684 from dataease/pr@dev-v2@refactor_outer-params-dataset

refactor(仪表板、数据大屏): 外部参数配置样式逻辑调整
This commit is contained in:
王嘉豪 2024-08-22 13:04:35 +08:00 committed by GitHub
commit c7a2bb2230
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 302 additions and 79 deletions

View File

@ -1,12 +1,18 @@
package io.dataease.visualization.server;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ibm.icu.impl.coll.CollationLoader;
import io.dataease.api.dataset.vo.CoreDatasetGroupVO;
import io.dataease.api.dataset.vo.CoreDatasetTableFieldVO;
import io.dataease.api.visualization.VisualizationOuterParamsApi;
import io.dataease.api.visualization.dto.VisualizationOuterParamsDTO;
import io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO;
import io.dataease.api.visualization.response.VisualizationOuterParamsBaseResponse;
import io.dataease.api.visualization.vo.DataVisualizationVO;
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
import io.dataease.engine.constant.DeTypeConstants;
import io.dataease.extensions.view.dto.SqlVariableDetails;
import io.dataease.utils.BeanUtils;
import io.dataease.utils.JsonUtil;
import io.dataease.visualization.dao.auto.entity.VisualizationOuterParams;
@ -15,11 +21,11 @@ import io.dataease.visualization.dao.auto.entity.VisualizationOuterParamsTargetV
import io.dataease.visualization.dao.auto.mapper.VisualizationOuterParamsInfoMapper;
import io.dataease.visualization.dao.auto.mapper.VisualizationOuterParamsMapper;
import io.dataease.visualization.dao.auto.mapper.VisualizationOuterParamsTargetViewInfoMapper;
import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper;
import io.dataease.visualization.dao.ext.mapper.ExtVisualizationOuterParamsMapper;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -44,6 +50,9 @@ public class VisualizationOuterParamsService implements VisualizationOuterParams
@Resource
private VisualizationOuterParamsTargetViewInfoMapper outerParamsTargetViewInfoMapper;
@Resource
private CoreDatasetTableMapper coreDatasetTableMapper;
@Override
public VisualizationOuterParamsDTO queryWithVisualizationId(String visualizationId) {
@ -97,6 +106,29 @@ public class VisualizationOuterParamsService implements VisualizationOuterParams
@Override
public List<CoreDatasetGroupVO> queryDsWithVisualizationId(String visualizationId) {
return extOuterParamsMapper.queryDsWithVisualizationId(visualizationId);
List<CoreDatasetGroupVO> result = extOuterParamsMapper.queryDsWithVisualizationId(visualizationId);
if(!CollectionUtils.isEmpty(result)){
result.forEach(coreDatasetGroupVO -> {
List<CoreDatasetTableFieldVO> fields = coreDatasetGroupVO.getDatasetFields();
QueryWrapper<CoreDatasetTable> wrapper = new QueryWrapper<>();
wrapper.eq("dataset_group_id", coreDatasetGroupVO.getId());
List<CoreDatasetTable> tableResult = coreDatasetTableMapper.selectList(wrapper);
if(!CollectionUtils.isEmpty(tableResult)){
tableResult.forEach(coreDatasetTable -> {
String sqlVarDetail = coreDatasetTable.getSqlVariableDetails();
if(StringUtils.isNotEmpty(sqlVarDetail)){
TypeReference<List<SqlVariableDetails>> listTypeReference = new TypeReference<List<SqlVariableDetails>>() {
};
List<SqlVariableDetails> defaultsSqlVariableDetails = JsonUtil.parseList(sqlVarDetail, listTypeReference);
defaultsSqlVariableDetails.forEach(sqlVariableDetails -> {
String varFieldId = coreDatasetTable.getId()+"|DE|"+sqlVariableDetails.getVariableName();
fields.add(new CoreDatasetTableFieldVO(varFieldId,sqlVariableDetails.getVariableName(), DeTypeConstants.DE_STRING));
});
}
});
}
});
}
return result;
}
}

View File

@ -33,11 +33,16 @@
column="{dataset_group_id=id}"
select="getDsFieldInfo">
</collection>
<collection property="datasetViews" ofType="io.dataease.api.chart.vo.ChartBaseVO"
column="{dataset_group_id=id,visualizationId = visualizationId}"
select="getViewInfo">
</collection>
</resultMap>
<resultMap id="OuterParamsInfoMap" type="io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO" extends="BaseResultMapParamsInfo">
<collection property="targetViewInfoList" ofType="io.dataease.visualization.dao.auto.entity.VisualizationOuterParamsTargetViewInfo">
<result column="target_view_id" jdbcType="VARCHAR" property="targetViewId"/>
<result column="target_ds_id" jdbcType="VARCHAR" property="targetDsId"/>
<result column="target_field_id" jdbcType="VARCHAR" property="targetFieldId"/>
</collection>
</resultMap>
@ -124,21 +129,32 @@
<select id="queryDsWithVisualizationId" resultMap="BaseDsResultMapDTO">
SELECT DISTINCT
cdg.*
cdg.*,#{visualizationId} as visualizationId
FROM
core_dataset_group cdg
INNER JOIN core_chart_view ccv ON cdg.id = ccv.table_id
INNER JOIN core_chart_view ccv ON cdg.id = ccv.table_id and ccv.type != 'VQuery'
INNER JOIN data_visualization_info dvi ON ccv.scene_id = dvi.id
WHERE
ccv.scene_id = #{visualizationId}
AND dvi.id = #{visualizationId}
AND FIND_IN_SET(
ccv.id,
dvi.component_data)
AND LOCATE(ccv.id, dvi.component_data)
</select>
<select id="getDsFieldInfo" resultType="io.dataease.api.dataset.vo.CoreDatasetTableFieldVO">
select cdtf.*,cdtf.id as attachId from core_dataset_table_field cdtf where cdtf.dataset_group_id = #{dataset_group_id}
</select>
<select id="getViewInfo" resultType="io.dataease.api.chart.vo.ChartBaseVO">
SELECT DISTINCT
ccv.id as chartId,ccv.title as chartName,ccv.type as chartType
FROM
core_chart_view ccv
INNER JOIN data_visualization_info dvi ON ccv.scene_id = dvi.id
WHERE
ccv.table_id = #{dataset_group_id}
AND ccv.type != 'VQuery'
AND dvi.id = #{visualizationId}
AND LOCATE(ccv.id, dvi.component_data)
</select>
</mapper>

View File

@ -110,7 +110,7 @@ export const export2AppCheck = params => {
export const queryOuterParamsDsInfo = async dvId => {
return request.get({
url: '/dataVisualization/queryDsWithVisualizationId/' + dvId,
url: '/outerParams/queryDsWithVisualizationId/' + dvId,
method: 'get',
loading: false
})

View File

@ -70,91 +70,140 @@
</el-col>
<el-col :span="16" class="preview-show">
<el-row v-if="state.curNodeId">
<el-row style="margin-top: 5px">
<el-row class="new-params-title"> 选择参数关联组件 </el-row>
<el-row class="new-params-filter" v-if="state.outerParamsInfo?.filterInfo.length">
<div style="display: flex" class="inner-content">
<div style="flex: 1">联动组件</div>
<div style="width: 36px"></div>
<div style="flex: 1">联动组件字段</div>
<div style="width: 32px"></div>
<div style="width: 16px">
<div class="expand-custom">
<el-icon @click="() => (state.filterExpand = !state.filterExpand)"
><CaretBottom v-show="state.filterExpand" />
<CaretRight v-show="!state.filterExpand" />
</el-icon>
</div>
</div>
<div style="flex: 1">查询组件</div>
<div style="flex: 1">关联条件</div>
</div>
<div style="width: 100%; max-height: 350px; overflow-y: auto">
<div class="outer-filter-content">
<div
style="display: flex; padding: 0 16px 8px"
v-for="(targetViewInfo, index) in state.outerParamsInfo.targetViewInfoList"
v-show="state.filterExpand"
style="display: flex"
class="inner-filter-content"
v-for="(baseFilter, index) in state.outerParamsInfo?.filterInfo"
:key="index"
>
<div style="width: 16px"></div>
<div style="flex: 1; line-height: 32px">
<Icon style="margin-top: 4px" class-name="view-type-icon" name="filter" />
<span>{{ baseFilter.label }}</span>
</div>
<div style="flex: 1">
<div class="select-filed">
<el-select
v-model="baseFilter.filterSelected"
filterable
style="width: 100%"
placeholder="请选择查询条件"
@change="viewInfoOnChange(targetViewInfo)"
>
<el-option
v-for="item in baseFilter.propValue"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span style="font-size: 12px"> {{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
</div>
</el-row>
<el-row class="new-params-ds" v-if="state.outerParamsInfo?.datasetInfo.length">
<div style="display: flex" class="inner-content">
<div style="width: 16px">
<div class="expand-custom">
<el-icon @click="() => (state.datasetExpand = !state.datasetExpand)"
><CaretBottom v-show="state.datasetExpand" />
<CaretRight v-show="!state.datasetExpand" />
</el-icon>
</div>
</div>
<div style="flex: 1">图表</div>
<div style="flex: 1">关联字段或参数</div>
</div>
<div class="outer-filter-content">
<div
v-show="state.datasetExpand"
class="inner-dataset-content"
v-for="(baseDatasetInfo, index) in state.outerParamsInfo?.datasetInfo"
:key="index"
>
<div style="display: flex; width: 100%">
<div style="width: 16px">
<el-icon
@click="() => (baseDatasetInfo.viewExpand = !baseDatasetInfo.viewExpand)"
><CaretBottom v-show="baseDatasetInfo.viewExpand" />
<CaretRight v-show="!baseDatasetInfo.viewExpand" />
</el-icon>
</div>
<div style="flex: 1; line-height: 32px">
<el-icon>
<Icon name="icon_dataset" />
</el-icon>
<span>{{ baseDatasetInfo.name }}</span>
</div>
<div style="flex: 1">
<el-select
v-model="targetViewInfo.targetViewId"
v-model="baseDatasetInfo.fieldIdSelected"
filterable
style="width: 100%"
size="small"
:placeholder="t('visualization.please_select')"
@change="viewInfoOnChange(targetViewInfo)"
placeholder="请选择"
>
<el-option
v-for="item in state.currentLinkPanelViewArray.filter(
curItem =>
!viewSelectedField.includes(curItem.id) ||
curItem.id === targetViewInfo.targetViewId
)"
v-for="item in baseDatasetInfo.datasetFields"
:key="item.id"
:label="item.title"
:label="item.name"
:value="item.id"
>
<Icon
class-name="view-type-icon"
style="margin-right: 4px"
:name="item.type"
/>
<span style="font-size: 12px"> {{ item.title }}</span>
</el-option>
</el-select>
</div>
</div>
<el-icon class="link-icon-join">
<Icon style="width: 20px; height: 20px" name="dv-link-target" />
</el-icon>
<div style="flex: 1">
<div class="select-filed">
<el-select
v-model="targetViewInfo.targetFieldId"
filterable
:disabled="fieldIdDisabledCheck(targetViewInfo)"
style="width: 100%"
size="small"
:placeholder="t('visualization.please_select')"
>
<el-option
v-for="viewField in getFieldArray(targetViewInfo.targetViewId)"
:key="viewField.id"
:label="viewField.name"
:value="viewField.id"
>
<Icon
style="width: 14px; height: 14px"
:name="`field_${fieldType[viewField.deType]}`"
:className="`field-icon-${fieldType[viewField.deType]}`"
:name="`field_${fieldType[item.deType]}`"
:className="`field-icon-${fieldType[item.deType]}`"
/>
<span style="font-size: 12px">{{ viewField.name }}</span>
<span style="font-size: 12px">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<el-button class="m-del-icon-btn" text @click="deleteOuterParamsField(index)">
<el-icon size="20px">
<Icon name="icon_delete-trash_outlined" />
</el-icon>
</el-button>
<div class="ds-view-content" v-show="baseDatasetInfo.viewExpand">
<div style="width: 100%">
<span>选择关联的图表</span>
<el-checkbox
v-model="baseDatasetInfo.checkAll"
:indeterminate="baseDatasetInfo.checkAllIsIndeterminate"
@change="batchSelectChange($event, baseDatasetInfo)"
>全选</el-checkbox
>
</div>
<div style="display: flex; width: 100%">
<div
style="width: 50%"
v-for="viewInfo in baseDatasetInfo.datasetViews"
:key="viewInfo"
>
<el-checkbox v-model="viewInfo.checked" />
<Icon
class-name="view-type-icon"
style="margin: 0 4px"
:name="viewInfo.chartType"
/>
<span style="font-size: 12px"> {{ viewInfo.chartName }}</span>
</div>
</div>
</div>
</div>
</div>
<el-row style="width: 100%; padding-left: 16px">
<el-button type="primary" icon="Plus" text @click="addOuterParamsField">
{{ t('visualization.add_param_link_field') }}
</el-button>
</el-row>
</el-row>
</el-row>
<div v-else class="empty">
@ -177,7 +226,7 @@
import { ref, reactive, computed, nextTick } from 'vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { ElMessage } from 'element-plus-secondary'
import { ElCol, ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import { deepCopy } from '@/utils/utils'
import generateID from '@/utils/generateID'
@ -196,6 +245,8 @@ const curEditDataId = ref(null)
const snapshotStore = snapshotStoreWithOut()
const state = reactive({
filterExpand: true,
datasetExpand: true,
loading: false,
outerParamsSetVisible: false,
optMenu: [
@ -220,6 +271,7 @@ const state = reactive({
outerParamsInfoArray: []
},
baseDatasetInfo: [],
baseFilterInfo: [],
outerParamsInfoArray: [],
mapOuterParamsInfoArray: {},
panelList: [],
@ -286,12 +338,27 @@ const getFieldArray = id => {
}
const initParams = async () => {
state.baseFilterInfo = []
state.baseDatasetInfo = []
//
componentData.value.forEach(componentItem => {
if (componentItem.component === 'VQuery') {
state.baseFilterInfo.push(componentItem)
}
})
//
await queryOuterParamsDsInfo(dvInfo.value.id).then(rsp => {
state.baseDatasetInfo = rsp.data
})
//
queryWithVisualizationId(dvInfo.value.id).then(rsp => {
state.outerParams = rsp.data
state.outerParamsInfoArray = state.outerParams?.outerParamsInfoArray
if (state.outerParamsInfoArray.length >= 1) {
state.outerParamsInfoArray.forEach(outerParamsInfo => {
const newBaseFilterInfo = deepCopy(state.baseFilterInfo)
const newBaseDatasetInfo = deepCopy(state.baseDatasetInfo)
paramsCheckedAdaptor(outerParamsInfo, newBaseFilterInfo, newBaseDatasetInfo)
state.mapOuterParamsInfoArray[outerParamsInfo.paramsInfoId] = outerParamsInfo
})
state.curNodeId = null
@ -301,12 +368,52 @@ const initParams = async () => {
})
}
})
await queryOuterParamsDsInfo(dvInfo.value.id).then(rsp => {
state.baseDatasetInfo = rsp.data
})
getPanelViewList(dvInfo.value.id)
}
const paramsCheckedAdaptor = (outerParamsInfo, newBaseFilterInfo, newBaseDatasetInfo) => {
const dsFieldIdSelected = {}
const viewMatchIds = []
outerParamsInfo.targetViewInfoList.forEach(targetViewInfo => {
viewMatchIds.push(targetViewInfo.targetViewId)
dsFieldIdSelected[targetViewInfo.targetDsId] =
targetViewInfo.targetFieldId === 'empty'
? targetViewInfo.targetViewId
: targetViewInfo.targetFieldId
})
if (newBaseDatasetInfo) {
newBaseDatasetInfo.forEach(datasetInfo => {
datasetInfo['fieldIdSelected'] = dsFieldIdSelected[datasetInfo.id]
datasetInfo['viewExpand'] = true
let viewCheckCount = 0
datasetInfo.datasetViews.forEach(dsView => {
if (viewMatchIds.includes(dsView.chartId)) {
dsView['checked'] = true
viewCheckCount++
} else {
dsView['checked'] = false
}
})
datasetInfo['checkAll'] = viewCheckCount === datasetInfo.datasetViews.length
datasetInfo['checkAllIsIndeterminate'] =
viewCheckCount > 0 && viewCheckCount < datasetInfo.datasetViews.length
})
}
if (newBaseFilterInfo) {
newBaseFilterInfo.forEach(filterInfo => {
filterInfo['filterSelected'] = dsFieldIdSelected[filterInfo.id]
})
}
outerParamsInfo['filterInfo'] = newBaseFilterInfo
outerParamsInfo['datasetInfo'] = newBaseDatasetInfo
console.log('outerParamsInfo=' + JSON.stringify(outerParamsInfo))
console.log('newBaseFilterInfo=' + JSON.stringify(newBaseFilterInfo))
console.log('newBaseDatasetInfo=' + JSON.stringify(newBaseDatasetInfo))
console.log('dsFieldIdSelected=' + JSON.stringify(dsFieldIdSelected))
console.log('viewMatchIds=' + JSON.stringify(viewMatchIds))
}
const cancel = () => {
state.outerParamsSetVisible = false
}
@ -414,6 +521,14 @@ const removeOuterParamsInfo = (node, data) => {
state.curNodeId = null
}
}
const batchSelectChange = (value, baseDatasetInfo) => {
// do change
baseDatasetInfo.datasetViews.forEach(viewInfo => {
viewInfo.checked = value
})
baseDatasetInfo.checkAll = value
baseDatasetInfo.checkAllIsIndeterminate = false
}
const optInit = () => {
state.outerParamsSetVisible = true
@ -497,7 +612,7 @@ defineExpose({
.view-type-icon {
color: var(--ed-color-primary);
width: 22px;
height: 16px;
height: 14px;
}
.custom-tree {
@ -533,8 +648,21 @@ defineExpose({
.inner-content {
width: 100%;
padding: 16px 16px 8px 16px;
font-size: 14px !important;
font-size: 14px;
}
.outer-filter-content {
width: 100%;
}
.inner-filter-content {
width: 100%;
margin-top: 12px;
}
.inner-dataset-content {
width: 100%;
margin-top: 12px;
}
.slot-class {
@ -648,4 +776,40 @@ defineExpose({
.params-class ::deep(.ed-dialog__body) {
padding: 10px 20px 20px;
}
.new-params-title {
height: 56px;
font-size: 14px;
font-weight: 500;
padding: 16px;
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
}
.new-params-filter {
padding: 16px;
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
}
.new-params-ds {
padding: 16px;
}
.expand-custom {
width: 16px;
height: 16px;
border-radius: 4px;
padding: 0px 1px;
&:hover {
background: rgba(31, 35, 41, 0.1);
cursor: pointer;
}
}
.ds-view-content {
width: 100%;
border-radius: 4px;
margin-top: 8px;
padding: 12px;
background: rgba(245, 246, 247, 1);
}
</style>

View File

@ -2,6 +2,7 @@ package io.dataease.api.dataset.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.api.chart.vo.ChartBaseVO;
import lombok.Data;
import java.io.Serializable;
@ -88,4 +89,6 @@ public class CoreDatasetGroupVO implements Serializable {
private String unionSql;
private List<CoreDatasetTableFieldVO> datasetFields = new ArrayList<>();
private List<ChartBaseVO> datasetViews = new ArrayList<>();
}

View File

@ -3,10 +3,12 @@ package io.dataease.api.dataset.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class CoreDatasetTableFieldVO implements Serializable {
private static final long serialVersionUID = 1L;
@ -121,4 +123,10 @@ public class CoreDatasetTableFieldVO implements Serializable {
// 附加ID 兼容自定义参数ID
private String attachId;
public CoreDatasetTableFieldVO(String attachId, String name, Integer deType) {
this.attachId = attachId;
this.name = name;
this.deType = deType;
}
}