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