mirror of
https://github.com/dataease/dataease.git
synced 2025-02-25 03:52:59 +08:00
fix(查询组件): 支持组件级联
This commit is contained in:
parent
6208e27eb1
commit
6cabbd5b6c
@ -17,6 +17,7 @@ export interface EnumValue {
|
||||
sortId?: string
|
||||
sort?: string
|
||||
searchText: string
|
||||
filter?: Array<{}>
|
||||
}
|
||||
|
||||
interface Fields {
|
||||
|
@ -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}`)
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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({
|
||||
|
Loading…
Reference in New Issue
Block a user