feat(查询组件): 支持组件级联
This commit is contained in:
parent
bfb8032398
commit
31758cf333
283
core/core-frontend/src/custom-component/v-query/QueryCascade.vue
Normal file
283
core/core-frontend/src/custom-component/v-query/QueryCascade.vue
Normal 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>
|
||||||
@ -1,6 +1,15 @@
|
|||||||
getLastStart
|
getLastStart
|
||||||
<script lang="ts" setup>
|
<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 { storeToRefs } from 'pinia'
|
||||||
import { addQueryCriteriaConfig } from './options'
|
import { addQueryCriteriaConfig } from './options'
|
||||||
import { getCustomTime } from './time-format'
|
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 = ({
|
const validateConditionType = ({
|
||||||
defaultConditionValueF,
|
defaultConditionValueF,
|
||||||
defaultConditionValueS,
|
defaultConditionValueS,
|
||||||
@ -1989,11 +2004,13 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-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="cancelClick">{{ t('chart.cancel') }} </el-button>
|
||||||
<el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button>
|
<el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<CascadeDialog ref="cascadeDialog"></CascadeDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@ -2040,6 +2057,12 @@ defineExpose({
|
|||||||
.query-condition-configuration {
|
.query-condition-configuration {
|
||||||
--ed-font-weight-primary: 400;
|
--ed-font-weight-primary: 400;
|
||||||
|
|
||||||
|
.query-cascade {
|
||||||
|
position: absolute;
|
||||||
|
left: 24px;
|
||||||
|
bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.ed-dialog__headerbtn {
|
.ed-dialog__headerbtn {
|
||||||
top: 21px;
|
top: 21px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user