update: 场景联动ParamsDropdown 添加插槽

This commit is contained in:
xieyonghong 2023-03-10 10:03:01 +08:00
parent 7f3978fe17
commit b583fa77a9
11 changed files with 173 additions and 77 deletions

View File

@ -1,8 +1,17 @@
<template> <template>
<j-dropdown class='scene-select' trigger='click'> <j-dropdown
<div :class='dropdownButtonClass'> class='scene-select'
<AIcon v-if='!!icon' :type='icon' /> trigger='click'
{{ label }} v-model:visible='visible'
@visibleChange='visibleChange'
>
<div @click.prevent='visible = true'>
<slot :label='label'>
<div :class='dropdownButtonClass' >
<AIcon v-if='!!icon' :type='icon' />
{{ label }}
</div>
</slot>
</div> </div>
<template #overlay> <template #overlay>
<div class='scene-select-content'> <div class='scene-select-content'>
@ -18,7 +27,7 @@
:type='component' :type='component'
@change='timeSelect' @change='timeSelect'
/> />
<div v-else> <div style='min-width: 400px' v-else>
<j-tree <j-tree
:selectedKeys='selectValue ? [selectValue] : []' :selectedKeys='selectValue ? [selectValue] : []'
:treeData='options' :treeData='options'
@ -89,20 +98,18 @@ const props = defineProps({
component: { component: {
type: String, type: String,
default: 'select' // 'select' | 'treeSelect' default: 'select' // 'select' | 'treeSelect'
} },
}) })
const emit = defineEmits<Emit>() const emit = defineEmits<Emit>()
const label = ref<LabelType>(props.placeholder) const label = ref<LabelType>(props.placeholder)
const selectValue = ref(props.value) const selectValue = ref(props.value)
const flatMapTree = new Map() const visible = ref(false)
const LabelStyle = computed(() => { const visibleChange = (v: boolean) => {
return { visible.value = v
color: selectValue.value ? '#' : '#' }
}
})
const dropdownButtonClass = computed(() => ({ const dropdownButtonClass = computed(() => ({
'dropdown-button': true, 'dropdown-button': true,
@ -112,24 +119,34 @@ const dropdownButtonClass = computed(() => ({
'type': props.type === 'type', 'type': props.type === 'type',
})) }))
const treeSelect = (v: any) => { const treeSelect = (v: any, option: any) => {
const node = option.node
visible.value = false
label.value = node.fullname || node.name
selectValue.value = v[0]
emit('update:value', node[props.valueName])
emit('select', node)
} }
const timeSelect = (v: string) => { const timeSelect = (v: string) => {
selectValue.value = v
visible.value = false
emit('update:value', v) emit('update:value', v)
emit('select', v) emit('select', v)
} }
const menuSelect = (v: any) => { const menuSelect = (v: any) => {
const option = getOption(props.options, props.value, props.valueName) const option = getOption(props.options, props.value, props.valueName)
selectValue.value = v.key
visible.value = false
emit('update:value', v.key) emit('update:value', v.key)
emit('select', option) emit('select', option)
} }
watchEffect(() => { watchEffect(() => {
const option = getOption(props.options, props.value, props.valueName) const option = getOption(props.options, props.value, props.valueName)
if (option && Object.keys(option).length) { selectValue.value = props.value
if (option) {
label.value = option[props.labelName] || option.name label.value = option[props.labelName] || option.name
} else { } else {
label.value = props.value || props.placeholder label.value = props.value || props.placeholder

View File

@ -55,6 +55,9 @@ const click = (e: any) => {
}) })
} }
watch(() => props.value, () => {
myValue.value = props.value
}, { immediate: true})
</script> </script>
<style scoped lang='less'> <style scoped lang='less'>

View File

@ -62,7 +62,7 @@ const change = (e: string) => {
} }
</script> </script>
<style lang='less'> <style lang='less' scoped>
.dropdown-time-picker { .dropdown-time-picker {
>div{ >div{
position: relative !important; position: relative !important;
@ -86,4 +86,8 @@ const change = (e: string) => {
box-shadow: unset; box-shadow: unset;
} }
} }
.wrapper{
display: none;
}
</style> </style>

View File

@ -26,7 +26,7 @@ export const getComponent = (type: string): string => {
} }
export const getOption = (data: any[], value?: string | number | boolean, key: string = 'name'): DropdownButtonOptions | any => { export const getOption = (data: any[], value?: string | number | boolean, key: string = 'name'): DropdownButtonOptions | any => {
let option = {} let option
if (!value) return option if (!value) return option
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const item = data[i] const item = data[i]
@ -35,7 +35,9 @@ export const getOption = (data: any[], value?: string | number | boolean, key: s
break break
} else if (item.children && item.children.length){ } else if (item.children && item.children.length){
option = getOption(item.children, value, key) option = getOption(item.children, value, key)
if (option) break if (option) {
break
}
} }
} }
return option return option

View File

@ -5,9 +5,13 @@
v-model:visible='visible' v-model:visible='visible'
@visibleChange='visibleChange' @visibleChange='visibleChange'
> >
<div class='dropdown-button value' @click.prevent='visible = true'> <div>
<AIcon v-if='!!icon' :type='icon' /> <slot :label='label'>
{{ label }} <div class='dropdown-button value' @click.prevent='visible = true'>
<AIcon v-if='!!icon' :type='icon' />
{{ label }}
</div>
</slot>
</div> </div>
<template #overlay> <template #overlay>
<div class='scene-select-content'> <div class='scene-select-content'>
@ -24,32 +28,36 @@
@change='timeChange' @change='timeChange'
/> />
<DropdownMenus <DropdownMenus
v-if='["metric","enum", "boolean"].includes(item.component)' v-if='["select","enum", "boolean"].includes(item.component)'
:options='options' :options='["metric", "upper"].includes(item.key) ? metricOption : options'
@change='onSelect' @change='onSelect'
/> />
<div
v-else-if='item.component === "tree"'
style='min-width: 400px'
>
<j-tree
:selectedKeys='myValue ? [myValue] : []'
:treeData='item.key === "upper" ? metricOption : options'
@select='treeSelect'
:height='450'
:virtual='true'
>
<template #title="{ name, description }">
<j-space>
{{ name }}
<span v-if='description' class='tree-title-description'>{{ description }}</span>
</j-space>
</template>
</j-tree>
</div>
<ValueItem <ValueItem
v-else-if='valueItemKey.includes(item.component)' v-else
v-model:modelValue='myValue' v-model:modelValue='myValue'
:itemType='getComponent(item.component)' :itemType='getComponent(item.component)'
:options='options' :options='item.key === "upper" ? metricOption : options'
@change='valueItemChange' @change='valueItemChange'
/> />
<j-tree
v-else
:selectedKeys='myValue ? [myValue] : []'
:treeData='options'
@select='treeSelect'
:height='450'
:virtual='true'
>
<template #title="{ name, description }">
<j-space>
{{ name }}
<span v-if='description' class='tree-title-description'>{{ description }}</span>
</j-space>
</template>
</j-tree>
</div> </div>
</j-tab-pane> </j-tab-pane>
</j-tabs> </j-tabs>
@ -101,10 +109,9 @@ const updateValue = () => {
} }
const treeSelect = (e: any) => { const treeSelect = (e: any) => {
console.log('treeSelect', e)
visible.value = false visible.value = false
label.value = e.fullname || e.name label.value = e.fullname || e.name
emit('update:value', e.id) emit('update:value', e[props.valueName])
emit('select', e) emit('select', e)
} }
@ -133,14 +140,16 @@ const visibleChange = (v: boolean) => {
visible.value = v visible.value = v
} }
watch([props.options, props.value], () => { watchEffect(() => {
const option = getOption(props.options, props.value as string, props.valueName) // label const option = getOption(props.options, props.value as string, props.valueName) // label
if (option && Object.keys(option).length) { myValue.value = props.value
mySource.value = props.source
if (option) {
label.value = option[props.labelName] || option.name label.value = option[props.labelName] || option.name
} else { } else {
label.value = props.value || props.placeholder label.value = props.value || props.placeholder
} }
}, { immediate: true }) })
</script> </script>

View File

@ -12,8 +12,7 @@ export type DropdownButtonOptions = {
export type TabsOption = { export type TabsOption = {
label: string; label: string;
key: string; key: string;
component: string, component: string
options: DropdownButtonOptions[]
} }
type ValueArrayType = [string, number] type ValueArrayType = [string, number]
export type ValueType = string | number | undefined | ValueArrayType export type ValueType = string | number | undefined | ValueArrayType
@ -47,6 +46,10 @@ export const defaultSetting = {
type: Array as PropType<Array<DropdownButtonOptions>>, type: Array as PropType<Array<DropdownButtonOptions>>,
default: () => [] default: () => []
}, },
metricOption: {
type: Array as PropType<Array<DropdownButtonOptions>>,
default: () => []
},
metricOptions: { // 指标值 metricOptions: { // 指标值
type: Array as PropType<Array<DropdownButtonOptions>>, type: Array as PropType<Array<DropdownButtonOptions>>,
default: () => [] default: () => []

View File

@ -40,10 +40,8 @@
icon='icon-canshu' icon='icon-canshu'
placeholder='参数值' placeholder='参数值'
:options='valueOptions' :options='valueOptions'
:tabsOptions='[ :metricOption='metricOption'
{ label: "手动输入", component: "input", key: "fixed" }, :tabsOptions='tabsOptions'
{ label: "指标值", component: "time", key: "manual" }
]'
v-model:value='paramsValue.value.value' v-model:value='paramsValue.value.value'
v-model:source='paramsValue.value.source' v-model:source='paramsValue.value.source'
/> />
@ -52,10 +50,8 @@
icon='icon-canshu' icon='icon-canshu'
placeholder='参数值' placeholder='参数值'
:options='valueOptions' :options='valueOptions'
:tabsOptions='[ :metricOption='metricOption'
{ label: "手动输入", component: "time", key: "fixed" }, :tabsOptions='tabsOptions'
{ label: "指标值", component: "input", key: "manual" },
]'
v-model:value='paramsValue.value.value' v-model:value='paramsValue.value.value'
v-model:source='paramsValue.value.source' v-model:source='paramsValue.value.source'
/> />
@ -80,6 +76,16 @@ import ParamsDropdown, { DoubleParamsDropdown } from '../ParamsDropdown'
import { inject } from 'vue' import { inject } from 'vue'
import { ContextKey } from './util' import { ContextKey } from './util'
type Emit = {
(e: 'update:value', data: TermsType): void
}
type TabsOption = {
label: string;
key: string;
component: string
}
const props = defineProps({ const props = defineProps({
isFirst: { isFirst: {
type: Boolean, type: Boolean,
@ -98,7 +104,7 @@ const props = defineProps({
default: () => ({ default: () => ({
column: '', column: '',
type: '', type: '',
termType: undefined, termType: 'eq',
value: { value: {
source: 'fixed', source: 'fixed',
value: undefined value: undefined
@ -107,6 +113,8 @@ const props = defineProps({
} }
}) })
const emit = defineEmits<Emit>()
const paramsValue = reactive<TermsType>({ const paramsValue = reactive<TermsType>({
column: props.value.column, column: props.value.column,
type: props.value.type, type: props.value.type,
@ -115,21 +123,56 @@ const paramsValue = reactive<TermsType>({
}) })
const showDelete = ref(false) const showDelete = ref(false)
const columnOptions: any = inject(ContextKey) const columnOptions: any = inject(ContextKey) //
const options = ref<any>([]) const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) //
const valueOptions = ref<any[]>([]) //
const metricOption = ref<any[]>([]) // termType
const tabsOptions = ref<Array<TabsOption>>([{ label: '手动输入', key: 'manual', component: 'string' }])
let metricsCacheOption: any[] = [] //
const termTypeOptions = computed(() => { const handOptionByColumn = (option: any) => {
if (option) {
termTypeOptions.value = option.termTypes || []
metricsCacheOption = option.metrics || []
tabsOptions.value.length = 1
tabsOptions.value[0].component = option.dataType
if (option.metrics && option.metrics.length) {
tabsOptions.value.push(
{ label: '指标值', key: 'metric', component: 'select' }
)
}
if (option.dataType === 'boolean') {
valueOptions.value = [
{ label: '是', value: true },
{ label: '否', value: false },
]
} else if(option.dataType === 'enum') {
valueOptions.value = option.options?.map((item: any) => ({ ...item, label: item.name, value: item.id})) || []
} else{
valueOptions.value = option.options || []
}
} else {
termTypeOptions.value = []
metricsCacheOption = []
valueOptions.value = []
}
}
watchEffect(() => {
const option = getOption(columnOptions.value, paramsValue.column, 'column') const option = getOption(columnOptions.value, paramsValue.column, 'column')
return option && Object.keys(option).length ? option.termTypes : [] handOptionByColumn(option)
})
const tabsOptions = computed(() => {
// valueoption
return []
}) })
const showDouble = computed(() => { const showDouble = computed(() => {
return paramsValue.termType ? ['nbtw', 'btw', 'in', 'nin'].includes(paramsValue.termType) : false const isRange = paramsValue.termType ? ['nbtw', 'btw', 'in', 'nin'].includes(paramsValue.termType) : false
if (metricsCacheOption.length) {
metricOption.value = metricsCacheOption.filter(item => isRange ? item.range : !item.range)
} else {
metricOption.value = []
}
return isRange
}) })
const mouseover = () => { const mouseover = () => {
@ -145,11 +188,20 @@ const mouseout = () => {
} }
const columnSelect = () => { const columnSelect = () => {
paramsValue.termType = 'eq'
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
}
emit('update:value', { ...paramsValue })
} }
const termsTypeSelect = () => { const termsTypeSelect = () => {
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
}
emit('update:value', { ...paramsValue })
} }
const termAdd = () => { const termAdd = () => {
@ -160,10 +212,6 @@ const onDelete = () => {
} }
const valueOptions = computed(() => {
return []
})
nextTick(() => { nextTick(() => {
Object.assign(paramsValue, props.value) Object.assign(paramsValue, props.value)
}) })

View File

@ -77,11 +77,21 @@ const rules = [{
} }
}] }]
const handleParamsData = (data: any[]): any[] => {
return data?.map(item => {
return {
...item,
key: item.column,
children: handleParamsData(item.children)
}
}) || []
}
const queryColumn = (dataModel: FormModelType) => { const queryColumn = (dataModel: FormModelType) => {
const cloneDevice = cloneDeep(dataModel) const cloneDevice = cloneDeep(dataModel)
cloneDevice.branches = cloneDevice.branches?.filter(item => !!item) cloneDevice.branches = cloneDevice.branches?.filter(item => !!item)
getParseTerm(cloneDevice).then(res => { getParseTerm(cloneDevice).then(res => {
columnOptions.value = res.result columnOptions.value = handleParamsData(res.result as any[])
}) })
} }

View File

@ -121,7 +121,7 @@
</page-container> </page-container>
</template> </template>
<script setup lang='ts'> <script setup lang='ts' name='Scene'>
import SaveModal from './Save/save.vue'; import SaveModal from './Save/save.vue';
import type { SceneItem } from './typings'; import type { SceneItem } from './typings';
import { useMenuStore } from 'store/menu'; import { useMenuStore } from 'store/menu';

View File

@ -187,7 +187,7 @@ export type TriggerType = {
}; };
export interface TermsVale { export interface TermsVale {
source: keyof typeof Source; source: string;
/** 手动输入值,source为 manual 时不能为空 */ /** 手动输入值,source为 manual 时不能为空 */
value?: Record<string, any> | any[]; value?: Record<string, any> | any[];
/** 指标值,source为 metric 时不能为空 */ /** 指标值,source为 metric 时不能为空 */

View File

@ -3695,8 +3695,8 @@ jetlinks-store@^0.0.3:
jetlinks-ui-components@^1.0.4: jetlinks-ui-components@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.4.tgz#34b70f75dcc4ea679f0da6674a3f372dfc4acab4" resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.4.tgz#41d52892f0f4d38adc6df02a87290a3042eb5645"
integrity sha512-ffDi9NyD51hPzu6iRBhibxlI36In5igUciMugm+Lui2LxnYdGbXGvB0i4y6xKaGg4jRDJ/lDX+b6AvuIrlb1lg== integrity sha512-aX+XiGigzxZnrG52xqipxd+WuFwBeZ6+dvLkcvOfLLBqSu8sgfvr/8NJ5hFgv5Eo2QFnUJq3Qf4HXLw9Ogv/yw==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15" ant-design-vue "^3.2.15"