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

This commit is contained in:
dataeaseShu 2024-06-19 15:00:34 +08:00
parent 6208e27eb1
commit 6cabbd5b6c
5 changed files with 175 additions and 10 deletions

View File

@ -17,6 +17,7 @@ export interface EnumValue {
sortId?: string
sort?: string
searchText: string
filter?: Array<{}>
}
interface Fields {

View File

@ -253,10 +253,15 @@ const queryDataForId = id => {
const getQueryConditionWidth = () => {
return customStyle.queryConditionWidth
}
const getCascadeList = () => {
return props.element.cascade
}
provide('unmount-select', unMountSelect)
provide('release-unmount-select', releaseSelect)
provide('query-data-for-id', queryDataForId)
provide('com-width', getQueryConditionWidth)
provide('cascade-list', getCascadeList)
onBeforeUnmount(() => {
emitter.off(`addQueryCriteria${element.value.id}`)

View File

@ -1,17 +1,22 @@
<script lang="ts" setup>
import { ref, shallowRef } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { ElMessage } from 'element-plus-secondary'
import { guid } from '@/views/visualized/data/dataset/form/util.js'
import { listByDsIds } from '@/api/dataset'
import { cloneDeep } from 'lodash-es'
interface Cascade {
datasetId: string
name: string
queryId: string
deType: string
fieldId: string
}
type cascadeMap = Record<string, Cascade>
const { t } = useI18n()
let deTypeMap = shallowRef({})
const emits = defineEmits(['saveCascade'])
const dialogVisible = ref(false)
const handleBeforeClose = () => {
@ -25,14 +30,47 @@ const cancelClick = () => {
}
const confirmClick = () => {
const { isError, arr } = setCascadeArrBack()
if (isError) {
ElMessage.error('查询条件或字段不能为空!')
return
}
emits('saveCascade', arr)
handleBeforeClose()
}
const setCascadeArrBack = () => {
let isError = false
const arr = cloneDeep(cascadeList.value)
arr.forEach(ele => {
ele.forEach(item => {
if (!item.placeholder && !item.fieldId) {
isError = true
}
if (!item.datasetId) {
isError = true
}
item.selectValue = []
})
})
return {
arr,
isError
}
}
const init = (cascadeMap: cascadeMap) => {
datasetMap.value = Object.values(cascadeMap).map(ele => ({
label: ele.name,
value: `${ele.datasetId}--${ele.queryId}`
deType: ele.deType,
value: `${ele.datasetId}--${ele.queryId}--${ele.fieldId}`
}))
let obj = {}
Object.values(cascadeMap).forEach(ele => {
obj[`${ele.datasetId}--${ele.queryId}--${ele.fieldId}`] = ele.deType
})
deTypeMap.value = obj
listByDsIds(datasetMap.value.map(ele => ele.value.split('--')[0]))
.then(res => {
for (let i in res || {}) {
@ -93,14 +131,15 @@ const visibleChange = (val, index, idx) => {
})
if (val) {
disabledDatasetId.value = [...new Set([...topIdArr.flat(), ...bottomIdArr.flat()])]
disabledDatasetId.value = [...new Set([...topIdArr.flat(), ...bottomIdArr.flat()])].filter(
ele => !!ele
)
}
}
const addCascadeItem = item => {
item.push({
datasetId: '',
topLevelIsSameDataset: false,
fieldId: '',
placeholder: item.length ? '' : '第一级无需配置被级联字段',
id: guid()
@ -175,7 +214,7 @@ defineExpose({
添加级联配置
</el-button>
<div class="cascade-content" v-for="(item, index) in cascadeList" :key="index">
<el-button text @click="addCascadeItem(item)">
<el-button :disabled="item.length === 5" text @click="addCascadeItem(item)">
<template #icon>
<Icon name="icon_add_outlined"></Icon>
</template>
@ -201,7 +240,10 @@ defineExpose({
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="disabledDatasetId.includes(item.value)"
:disabled="
disabledDatasetId.includes(item.value) ||
(!!ele.datasetId && deTypeMap[ele.datasetId] !== item.deType)
"
/>
</el-select>
</div>

View File

@ -8,7 +8,8 @@ import {
shallowRef,
toRefs,
watch,
defineAsyncComponent
defineAsyncComponent,
provide
} from 'vue'
import { storeToRefs } from 'pinia'
import { addQueryCriteriaConfig } from './options'
@ -109,6 +110,29 @@ const datasetFieldList = computed(() => {
})
.filter(ele => !!ele)
})
const setCascadeDefault = val => {
conditions.value.forEach(ele => {
if (
ele.optionValueSource === 1 &&
[0, 2, 5].includes(+ele.displayType) &&
val.includes(ele.id)
) {
ele.selectValue = Array.isArray(ele.selectValue) ? [] : undefined
ele.defaultValue = Array.isArray(ele.defaultValue) ? [] : undefined
ele.mapValue = Array.isArray(ele.mapValue) ? [] : undefined
ele.defaultMapValue = Array.isArray(ele.defaultMapValue) ? [] : undefined
}
})
}
let cascadeArr = []
const saveCascade = arr => {
cascadeArr = arr
}
const getCascadeList = () => {
return cascadeArr
}
provide('set-cascade-default', setCascadeDefault)
provide('cascade-list', getCascadeList)
const curComponent = ref()
const manual = ref()
@ -449,12 +473,13 @@ const CascadeDialog = defineAsyncComponent(() => import('./QueryCascade.vue'))
const cascadeDialog = ref()
const openCascadeDialog = () => {
const cascadeMap = conditions.value
.filter(ele => [0, 2, 5].includes(+ele.displayType))
.filter(ele => [0, 2, 5].includes(+ele.displayType) && ele.optionValueSource === 1)
.reduce((pre, next) => {
pre[next.id] = {
datasetId: next.dataset.id,
name: next.name,
queryId: next.id,
fieldId: next.field.id,
deType: next.field.deType
}
return pre
@ -669,6 +694,8 @@ const confirmClick = () => {
)
})
queryElement.value.propValue = cloneDeep(conditions.value)
queryElement.value.cascade = cloneDeep(cascadeArr)
cascadeArr = []
snapshotStore.recordSnapshotCache()
}
@ -747,7 +774,7 @@ const init = (queryId: string) => {
}
renameInput.value = []
handleCondition({ id: queryId })
cascadeArr = cloneDeep(queryElement.value.cascade || [])
dialogVisible.value = true
const datasetFieldIdList = datasetFieldList.value.map(ele => ele.tableId)
for (const i in datasetMap) {
@ -2020,7 +2047,7 @@ defineExpose({
</div>
</template>
</el-dialog>
<CascadeDialog ref="cascadeDialog"></CascadeDialog>
<CascadeDialog @saveCascade="saveCascade" ref="cascadeDialog"></CascadeDialog>
</template>
<style lang="less">

View File

@ -14,6 +14,7 @@ import {
} from 'vue'
import { enumValueObj, type EnumValue, getEnumValue } from '@/api/dataset'
import { cloneDeep, debounce } from 'lodash-es'
import { useEmitt } from '@/hooks/web/useEmitt'
interface SelectConfig {
selectValue: any
@ -28,6 +29,9 @@ interface SelectConfig {
sort: string
sortId: string
checkedFields: string[]
dataset: {
id: string
}
field: {
id: string
}
@ -70,6 +74,12 @@ const unMountSelect: Ref = inject('unmount-select')
const releaseSelect = inject('release-unmount-select', Function, true)
const queryDataForId = inject('query-data-for-id', Function, true)
const queryConditionWidth = inject('com-width', Function, true)
const cascadeList = inject('cascade-list', Function, true)
const setCascadeDefault = inject('set-cascade-default', Function, true)
const cascade = computed(() => {
return cascadeList() || []
})
const setDefaultMapValue = arr => {
const { displayId, field } = config.value
@ -96,6 +106,71 @@ onUnmounted(() => {
enumValueArr = []
})
const setCascadeValueBack = val => {
cascade.value.forEach(ele => {
ele.forEach(item => {
if (item.datasetId.split('--')[1] === config.value.id) {
item.selectValue = Array.isArray(val) ? [...val] : val
}
})
})
}
const emitCascade = () => {
cascade.value.forEach(ele => {
let trigger = false
ele.forEach(item => {
if (item.datasetId.split('--')[1] === config.value.id) {
trigger = true
} else if (trigger) {
useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`)
trigger = false
}
})
})
}
const emitCascadeConfig = () => {
const arr = []
cascade.value.forEach(ele => {
let trigger = false
ele.forEach(item => {
if (item.datasetId.split('--')[1] === config.value.id) {
trigger = true
} else if (trigger) {
arr.push(item.datasetId.split('--')[1])
trigger = false
}
})
})
return arr
}
const getCascadeFieldId = () => {
const filter = []
cascade.value.forEach(ele => {
let condition = null
ele.forEach(item => {
const [_, queryId, fieldId] = item.datasetId.split('--')
if (queryId === config.value.id && condition) {
if (item.fieldId) {
condition.fieldId = item.fieldId
}
filter.push(condition)
} else {
if (!!item.selectValue.length) {
condition = {
fieldId: fieldId,
operator: 'in',
value: [...item.selectValue]
}
}
}
})
})
return filter
}
const handleValueChange = () => {
const value = Array.isArray(selectValue.value) ? [...selectValue.value] : selectValue.value
if (!props.isConfig) {
@ -105,9 +180,13 @@ const handleValueChange = () => {
config.value.mapValue = setDefaultMapValue(
Array.isArray(selectValue.value) ? [...selectValue.value] : [selectValue.value]
)
setCascadeValueBack(config.value.mapValue)
emitCascade()
return
}
setCascadeDefault(emitCascadeConfig())
config.value.defaultValue = value
config.value.mapValue = setDefaultMapValue(
Array.isArray(selectValue.value) ? [...selectValue.value] : [selectValue.value]
@ -115,6 +194,7 @@ const handleValueChange = () => {
config.value.defaultMapValue = setDefaultMapValue(
Array.isArray(selectValue.value) ? [...selectValue.value] : [selectValue.value]
)
setCascadeValueBack(config.value.mapValue)
}
const displayTypeChange = () => {
@ -406,7 +486,8 @@ const setOptions = (num: number) => {
displayId: displayId || field.id,
sort,
sortId,
searchText: searchText.value
searchText: searchText.value,
filter: getCascadeFieldId()
})
} else {
options.value = []
@ -452,8 +533,17 @@ const selectStyle = computed(() => {
const mult = ref()
const single = ref()
const getOptionFromCascade = () => {
if (config.value.optionValueSource !== 1 || ![0, 2, 5].includes(+config.value.displayType)) return
debounceOptions(1)
}
onBeforeMount(() => {
init()
useEmitt({
name: `${config.value.id}-select`,
callback: getOptionFromCascade
})
})
defineExpose({