Commit e6353bc8599d3372d2e5df0dd998ff9fc906fa37
1 parent
a27a5e41
perf: visual board implement map component data source bind
Showing
2 changed files
with
47 additions
and
42 deletions
1 | +<script lang="ts"> | ||
2 | + export type OptionsItem = { label: string; value: string; disabled?: boolean }; | ||
3 | + export interface OnChangeHookParams { | ||
4 | + options: Ref<OptionsItem[]>; | ||
5 | + } | ||
6 | +</script> | ||
7 | + | ||
1 | <script lang="ts" setup> | 8 | <script lang="ts" setup> |
2 | - import { ref, watchEffect, computed, unref, watch } from 'vue'; | 9 | + import { ref, watchEffect, computed, unref, watch, Ref } from 'vue'; |
3 | import { Select } from 'ant-design-vue'; | 10 | import { Select } from 'ant-design-vue'; |
4 | import { isFunction } from '/@/utils/is'; | 11 | import { isFunction } from '/@/utils/is'; |
5 | import { useRuleFormItem } from '/@/hooks/component/useFormItem'; | 12 | import { useRuleFormItem } from '/@/hooks/component/useFormItem'; |
@@ -8,8 +15,6 @@ | @@ -8,8 +15,6 @@ | ||
8 | import { LoadingOutlined } from '@ant-design/icons-vue'; | 15 | import { LoadingOutlined } from '@ant-design/icons-vue'; |
9 | import { useI18n } from '/@/hooks/web/useI18n'; | 16 | import { useI18n } from '/@/hooks/web/useI18n'; |
10 | 17 | ||
11 | - type OptionsItem = { label: string; value: string; disabled?: boolean }; | ||
12 | - | ||
13 | const emit = defineEmits(['options-change', 'change']); | 18 | const emit = defineEmits(['options-change', 'change']); |
14 | const props = withDefaults( | 19 | const props = withDefaults( |
15 | defineProps<{ | 20 | defineProps<{ |
@@ -22,12 +27,16 @@ | @@ -22,12 +27,16 @@ | ||
22 | labelField?: string; | 27 | labelField?: string; |
23 | valueField?: string; | 28 | valueField?: string; |
24 | immediate?: boolean; | 29 | immediate?: boolean; |
30 | + queryEmptyDataAgin?: boolean; | ||
31 | + onChangeHook?: ({ options }: OnChangeHookParams) => void; | ||
32 | + dropdownVisibleChangeHook?: ({ options }: OnChangeHookParams) => void; | ||
25 | }>(), | 33 | }>(), |
26 | { | 34 | { |
27 | resultField: '', | 35 | resultField: '', |
28 | labelField: 'label', | 36 | labelField: 'label', |
29 | valueField: 'value', | 37 | valueField: 'value', |
30 | immediate: true, | 38 | immediate: true, |
39 | + queryEmptyDataAgin: true, | ||
31 | } | 40 | } |
32 | ); | 41 | ); |
33 | const options = ref<OptionsItem[]>([]); | 42 | const options = ref<OptionsItem[]>([]); |
@@ -42,7 +51,6 @@ | @@ -42,7 +51,6 @@ | ||
42 | 51 | ||
43 | const getOptions = computed(() => { | 52 | const getOptions = computed(() => { |
44 | const { labelField, valueField = 'value', numberToString } = props; | 53 | const { labelField, valueField = 'value', numberToString } = props; |
45 | - | ||
46 | return unref(options).reduce((prev, next: Recordable) => { | 54 | return unref(options).reduce((prev, next: Recordable) => { |
47 | if (next) { | 55 | if (next) { |
48 | const value = next[valueField]; | 56 | const value = next[valueField]; |
@@ -92,24 +100,34 @@ | @@ -92,24 +100,34 @@ | ||
92 | } | 100 | } |
93 | 101 | ||
94 | async function handleFetch() { | 102 | async function handleFetch() { |
95 | - if (!props.immediate && unref(isFirstLoad)) { | 103 | + const { immediate, dropdownVisibleChangeHook } = props; |
104 | + if (!immediate && unref(isFirstLoad)) { | ||
96 | await fetch(); | 105 | await fetch(); |
97 | isFirstLoad.value = false; | 106 | isFirstLoad.value = false; |
98 | } | 107 | } |
108 | + if (dropdownVisibleChangeHook && isFunction(dropdownVisibleChangeHook)) { | ||
109 | + dropdownVisibleChangeHook({ options }); | ||
110 | + } | ||
99 | } | 111 | } |
100 | 112 | ||
101 | function emitChange() { | 113 | function emitChange() { |
102 | emit('options-change', unref(getOptions)); | 114 | emit('options-change', unref(getOptions)); |
103 | } | 115 | } |
104 | 116 | ||
105 | - function handleChange(_, ...args) { | 117 | + function handleChange(value: string, ...args) { |
106 | emitData.value = args; | 118 | emitData.value = args; |
107 | - if (!_) handleSearch(); | 119 | + if (!value && props.queryEmptyDataAgin) handleSearch(); |
120 | + const { onChangeHook } = props; | ||
121 | + if (!onChangeHook && !isFunction(onChangeHook)) return; | ||
122 | + onChangeHook({ options }); | ||
108 | } | 123 | } |
109 | 124 | ||
110 | async function handleSearch(params?: string) { | 125 | async function handleSearch(params?: string) { |
111 | - const searchApi = props.searchApi; | ||
112 | - if (!searchApi || !isFunction(searchApi)) return; | 126 | + let { searchApi, api } = props; |
127 | + if (!searchApi || !isFunction(searchApi)) { | ||
128 | + if (!api || !isFunction(api)) return; | ||
129 | + searchApi = api; | ||
130 | + } | ||
113 | options.value = []; | 131 | options.value = []; |
114 | try { | 132 | try { |
115 | loading.value = true; | 133 | loading.value = true; |
@@ -135,6 +153,7 @@ | @@ -135,6 +153,7 @@ | ||
135 | <Select | 153 | <Select |
136 | @dropdownVisibleChange="handleFetch" | 154 | @dropdownVisibleChange="handleFetch" |
137 | v-bind="attrs" | 155 | v-bind="attrs" |
156 | + show-search | ||
138 | @change="handleChange" | 157 | @change="handleChange" |
139 | :options="getOptions" | 158 | :options="getOptions" |
140 | @search="handleSearch" | 159 | @search="handleSearch" |
@@ -2,6 +2,8 @@ import { getAllDeviceByOrg, getDeviceAttributes, getGatewaySlaveDevice } from '/ | @@ -2,6 +2,8 @@ import { getAllDeviceByOrg, getDeviceAttributes, getGatewaySlaveDevice } from '/ | ||
2 | import { getOrganizationList } from '/@/api/system/system'; | 2 | import { getOrganizationList } from '/@/api/system/system'; |
3 | import { FormSchema } from '/@/components/Form'; | 3 | import { FormSchema } from '/@/components/Form'; |
4 | import { copyTransFun } from '/@/utils/fnUtils'; | 4 | import { copyTransFun } from '/@/utils/fnUtils'; |
5 | +import { OnChangeHookParams } from '/@/components/Form/src/components/ApiSearchSelect.vue'; | ||
6 | +import { unref } from 'vue'; | ||
5 | 7 | ||
6 | export enum BasicConfigField { | 8 | export enum BasicConfigField { |
7 | NAME = 'name', | 9 | NAME = 'name', |
@@ -366,84 +368,68 @@ export const mapFormSchema: FormSchema[] = [ | @@ -366,84 +368,68 @@ export const mapFormSchema: FormSchema[] = [ | ||
366 | }, | 368 | }, |
367 | { | 369 | { |
368 | field: DataSourceField.LONGITUDE_ATTRIBUTE, | 370 | field: DataSourceField.LONGITUDE_ATTRIBUTE, |
369 | - component: 'ApiSelect', | 371 | + component: 'ApiSearchSelect', |
370 | label: '经度属性', | 372 | label: '经度属性', |
371 | colProps: { span: 8 }, | 373 | colProps: { span: 8 }, |
372 | rules: [{ required: true, message: '属性为必填项' }], | 374 | rules: [{ required: true, message: '属性为必填项' }], |
373 | - componentProps({ formModel, formActionType }) { | ||
374 | - const { updateSchema, setFieldsValue } = formActionType; | 375 | + componentProps({ formModel }) { |
375 | const organizationId = formModel[DataSourceField.ORIGINATION_ID]; | 376 | const organizationId = formModel[DataSourceField.ORIGINATION_ID]; |
376 | const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE]; | 377 | const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE]; |
377 | const deviceId = formModel[DataSourceField.DEVICE_ID]; | 378 | const deviceId = formModel[DataSourceField.DEVICE_ID]; |
378 | const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID]; | 379 | const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID]; |
379 | - | ||
380 | - let attrs: Record<'label' | 'value', string>[] = []; | ||
381 | return { | 380 | return { |
382 | api: async () => { | 381 | api: async () => { |
383 | if (organizationId && deviceId) { | 382 | if (organizationId && deviceId) { |
384 | try { | 383 | try { |
385 | if (isGatewayDevice && slaveDeviceId) { | 384 | if (isGatewayDevice && slaveDeviceId) { |
386 | - return (attrs = await getDeviceAttribute(slaveDeviceId)); | 385 | + return await getDeviceAttribute(slaveDeviceId); |
387 | } | 386 | } |
388 | if (!isGatewayDevice) { | 387 | if (!isGatewayDevice) { |
389 | - return (attrs = await getDeviceAttribute(deviceId)); | 388 | + return await getDeviceAttribute(deviceId); |
390 | } | 389 | } |
391 | } catch (error) {} | 390 | } catch (error) {} |
392 | } | 391 | } |
393 | return []; | 392 | return []; |
394 | }, | 393 | }, |
395 | placeholder: '请选择经度属性', | 394 | placeholder: '请选择经度属性', |
396 | - getPopupContainer: () => document.body, | ||
397 | - onChange: (value: string) => { | ||
398 | - if (!value) return; | ||
399 | - setFieldsValue({ [DataSourceField.LATITUDE_ATTRIBUTE]: null }); | ||
400 | - updateSchema({ | ||
401 | - field: DataSourceField.LATITUDE_ATTRIBUTE, | ||
402 | - componentProps: { | ||
403 | - options: attrs.filter((item) => item.value !== value), | ||
404 | - }, | ||
405 | - }); | 395 | + dropdownVisibleChangeHook: ({ options }: OnChangeHookParams) => { |
396 | + options.value = unref(options).filter( | ||
397 | + (item) => item.value !== formModel[DataSourceField.LATITUDE_ATTRIBUTE] | ||
398 | + ); | ||
406 | }, | 399 | }, |
400 | + getPopupContainer: () => document.body, | ||
407 | }; | 401 | }; |
408 | }, | 402 | }, |
409 | }, | 403 | }, |
410 | { | 404 | { |
411 | field: DataSourceField.LATITUDE_ATTRIBUTE, | 405 | field: DataSourceField.LATITUDE_ATTRIBUTE, |
412 | - component: 'ApiSelect', | 406 | + component: 'ApiSearchSelect', |
413 | label: '纬度属性', | 407 | label: '纬度属性', |
414 | colProps: { span: 8 }, | 408 | colProps: { span: 8 }, |
415 | rules: [{ required: true, message: '属性为必填项' }], | 409 | rules: [{ required: true, message: '属性为必填项' }], |
416 | - componentProps({ formModel, formActionType }) { | ||
417 | - const { updateSchema, setFieldsValue } = formActionType; | 410 | + componentProps({ formModel }) { |
418 | const organizationId = formModel[DataSourceField.ORIGINATION_ID]; | 411 | const organizationId = formModel[DataSourceField.ORIGINATION_ID]; |
419 | const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE]; | 412 | const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE]; |
420 | const deviceId = formModel[DataSourceField.DEVICE_ID]; | 413 | const deviceId = formModel[DataSourceField.DEVICE_ID]; |
421 | const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID]; | 414 | const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID]; |
422 | - let attrs: Record<'label' | 'value', string>[] = []; | ||
423 | - | ||
424 | return { | 415 | return { |
425 | api: async () => { | 416 | api: async () => { |
426 | if (organizationId && deviceId) { | 417 | if (organizationId && deviceId) { |
427 | try { | 418 | try { |
428 | if (isGatewayDevice && slaveDeviceId) { | 419 | if (isGatewayDevice && slaveDeviceId) { |
429 | - return (attrs = await getDeviceAttribute(slaveDeviceId)); | 420 | + return getDeviceAttribute(slaveDeviceId); |
430 | } | 421 | } |
431 | if (!isGatewayDevice) { | 422 | if (!isGatewayDevice) { |
432 | - return (attrs = await getDeviceAttribute(deviceId)); | 423 | + return await getDeviceAttribute(deviceId); |
433 | } | 424 | } |
434 | } catch (error) {} | 425 | } catch (error) {} |
435 | } | 426 | } |
436 | return []; | 427 | return []; |
437 | }, | 428 | }, |
438 | - onChange: (value: string) => { | ||
439 | - if (!value) return; | ||
440 | - setFieldsValue({ [DataSourceField.LONGITUDE_ATTRIBUTE]: null }); | ||
441 | - updateSchema({ | ||
442 | - field: DataSourceField.LATITUDE_ATTRIBUTE, | ||
443 | - componentProps: { | ||
444 | - options: attrs.filter((item) => item.value !== value), | ||
445 | - }, | ||
446 | - }); | 429 | + dropdownVisibleChangeHook: ({ options }: OnChangeHookParams) => { |
430 | + options.value = unref(options).filter( | ||
431 | + (item) => item.value !== formModel[DataSourceField.LONGITUDE_ATTRIBUTE] | ||
432 | + ); | ||
447 | }, | 433 | }, |
448 | placeholder: '请选择纬度属性', | 434 | placeholder: '请选择纬度属性', |
449 | getPopupContainer: () => document.body, | 435 | getPopupContainer: () => document.body, |