feat(查询组件): 支持组件级联

This commit is contained in:
dataeaseShu 2024-06-17 18:29:24 +08:00
parent bfb8032398
commit 31758cf333
2 changed files with 307 additions and 1 deletions

View File

@ -0,0 +1,283 @@
<script lang="ts" setup>
import { ref, shallowRef } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { guid } from '@/views/visualized/data/dataset/form/util.js'
const { t } = useI18n()
const dialogVisible = ref(false)
const handleBeforeClose = () => {
dialogVisible.value = false
}
const cascadeList = ref([])
const optionsMap = shallowRef({})
const datasetMap = shallowRef([])
const cancelClick = () => {
handleBeforeClose()
}
const confirmClick = () => {
handleBeforeClose()
}
const init = () => {
dialogVisible.value = true
}
const disabledDatasetId = shallowRef([])
const visibleChange = (val, index, idx) => {
let topId = ''
let topIdArr = []
let bottomId = ''
let bottomIdArr = []
for (let i in cascadeList.value[index]) {
if (i > idx) {
if (cascadeList.value[index][i].datasetId && !bottomId) {
bottomId = cascadeList.value[index][i].datasetId
}
continue
}
if (cascadeList.value[index][i].datasetId) {
topId = cascadeList.value[index][i].datasetId
}
if (i === idx) {
topId = (cascadeList.value[index][idx - 1] || {}).datasetId
}
}
cascadeList.value.forEach(ele => {
let tentativeTopArr = []
let tentativeBottomArr = []
for (let i in ele) {
if (topIdArr[topIdArr.length - 1] === tentativeTopArr || bottomId === ele[i].datasetId) {
if (bottomId === ele[i].datasetId) {
bottomIdArr.push(tentativeBottomArr)
}
if (bottomIdArr[bottomIdArr.length - 1] === tentativeBottomArr) {
tentativeBottomArr.push(ele[i].datasetId)
}
continue
}
if (ele[i].datasetId) {
tentativeTopArr.push(ele[i].datasetId)
}
if (topId === ele[i].datasetId) {
topIdArr.push(tentativeTopArr)
}
}
})
if (val) {
disabledDatasetId.value = [...new Set([...topIdArr.flat(), ...bottomIdArr.flat()])]
}
}
const addCascadeItem = item => {
item.push({
datasetId: '',
topLevelIsSameDataset: false,
fieldId: '',
placeholder: item.length ? '' : '第一级无需配置被级联字段',
id: guid()
})
setPlaceholder(item.length - 1, item)
}
const setPlaceholder = (idx, item) => {
if (
item[idx] &&
item[idx - 1] &&
item[idx].datasetId &&
item[idx].datasetId === item[idx - 1].datasetId
) {
item[idx].placeholder = '与上一级使用同一个数据集,无需配置被级联字段'
item[idx].fieldId = ''
}
}
const deleteCascade = (idx, item) => {
item.splice(idx, 1)
item[0].fieldId = ''
item[0].placeholder = '第一级无需配置被级联字段'
setPlaceholder(idx, item)
}
const addCascadeBlock = () => {
const arr = []
addCascadeItem(arr)
cascadeList.value.push(arr)
}
const indexCascade = ' 一二三四五'
defineExpose({
init
})
</script>
<template>
<el-dialog
class="query-condition-cascade"
v-model="dialogVisible"
width="900px"
@click.stop
:before-close="handleBeforeClose"
@mousedown.stop
@mousedup.stop
>
<template #title>
<div class="title">
查询条件级联配置<span class="tip">(仅上级能级联下级,不可反向级联)</span>
</div>
</template>
<div class="content">
<el-icon style="font-size: 16px">
<Icon name="icon_info_colorful"></Icon>
</el-icon>
基于当前查询组件的查询条件,如果需要进行及联配置,需要满足以下条件:<br />
1展示类型为:文本下拉组件和数字下拉组件;2选项值来源为:选择数据集<br />
</div>
<el-button text @click="addCascadeBlock">
<template #icon>
<Icon name="icon_add_outlined"></Icon>
</template>
添加级联配置
</el-button>
<div class="cascade-content" v-for="(item, index) in cascadeList" :key="index">
<el-button text @click="addCascadeItem(item)">
<template #icon>
<Icon name="icon_add_outlined"></Icon>
</template>
添加级联条件
</el-button>
<div class="cascade-item">
<div class="label">查询条件层级</div>
<div class="item-name">请选择查询条件</div>
<div class="cascade-icon"></div>
<div class="item-field">请选择被级联字段</div>
</div>
<div class="cascade-item" v-for="(ele, idx) in item" :key="ele.id">
<div class="label">{{ indexCascade[idx + 1] }}</div>
<div class="item-name">
<el-select v-model="ele.datasetId" style="width: 300px">
<el-option
v-for="item in datasetMap"
:key="item.value"
@visible-change="val => visibleChange(val, index, idx)"
:label="item.label"
:value="item.value"
:disabled="disabledDatasetId.includes(item.value)"
/>
</el-select>
</div>
<div class="cascade-icon">
<el-icon>
<Icon name="join-join"></Icon>
</el-icon>
</div>
<div class="item-field">
<el-select
:placeholder="ele.placeholder"
:disabled="!!ele.placeholder"
v-model="ele.fieldId"
style="width: 300px"
>
<el-option
v-for="item in optionsMap[ele.datasetId]"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<el-button @click="deleteCascade(idx, item)" class="cascade-delete" text>
<template #icon>
<Icon name="icon_delete-trash_outlined"></Icon>
</template>
</el-button>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancelClick">{{ t('chart.cancel') }} </el-button>
<el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button>
</div>
</template>
</el-dialog>
</template>
<style lang="less" scoped>
.query-condition-cascade {
.title {
.tip {
font-size: 12px;
color: #646a73;
}
}
.content {
height: 62px;
width: 852px;
border-radius: 4px;
background: #e1eaff;
position: relative;
padding: 9px 0 9px 40px;
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
font-size: 14px;
font-weight: 400;
.ed-icon {
position: absolute;
top: 10.6px;
left: 16px;
font-size: 14px;
color: var(--ed-color-primary, #3370ff);
}
margin-bottom: 16px;
}
.cascade-content {
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
border: 1px solid #e4e7ed;
padding: 24px;
padding-top: 8px;
margin-top: 8px;
.cascade-item {
display: flex;
align-items: center;
width: 100%;
height: 40px;
.label {
width: 100px;
}
.item-name {
width: 300px;
}
.cascade-icon {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
font-size: 20px;
}
.item-field {
width: 300px;
}
.cascade-delete {
width: 40px;
font-size: 20px;
color: #646a73;
margin-left: 20px;
}
}
}
}
</style>

View File

@ -1,6 +1,15 @@
getLastStart
<script lang="ts" setup>
import { ref, reactive, nextTick, computed, shallowRef, toRefs, watch } from 'vue'
import {
ref,
reactive,
nextTick,
computed,
shallowRef,
toRefs,
watch,
defineAsyncComponent
} from 'vue'
import { storeToRefs } from 'pinia'
import { addQueryCriteriaConfig } from './options'
import { getCustomTime } from './time-format'
@ -436,6 +445,12 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
}
}
const CascadeDialog = defineAsyncComponent(() => import('./QueryCascade.vue'))
const cascadeDialog = ref()
const openCascadeDialog = () => {
cascadeDialog.value.init()
}
const validateConditionType = ({
defaultConditionValueF,
defaultConditionValueS,
@ -1989,11 +2004,13 @@ defineExpose({
</div>
<template #footer>
<div class="dialog-footer">
<el-button class="query-cascade" @click="openCascadeDialog">查询组件级联配置</el-button>
<el-button @click="cancelClick">{{ t('chart.cancel') }} </el-button>
<el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button>
</div>
</template>
</el-dialog>
<CascadeDialog ref="cascadeDialog"></CascadeDialog>
</template>
<style lang="less">
@ -2040,6 +2057,12 @@ defineExpose({
.query-condition-configuration {
--ed-font-weight-primary: 400;
.query-cascade {
position: absolute;
left: 24px;
bottom: 24px;
}
.ed-dialog__headerbtn {
top: 21px;
display: flex;