feat(map): support to filter other blocks (#1691)
* feat(Map): support to filter other blocks * feat: highlight marker when selected * feat: clear filter params when cancel connect * feat: support line and polygon
This commit is contained in:
		
							parent
							
								
									e8bb962389
								
							
						
					
					
						commit
						06d67a93ab
					
				| @ -203,11 +203,11 @@ export const useCreateActionProps = () => { | |||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| interface FilterTarget { | export interface FilterTarget { | ||||||
|   targets?: { |   targets?: { | ||||||
|     /** field uid */ |     /** field uid */ | ||||||
|     uid: string; |     uid: string; | ||||||
|     /** associated fields */ |     /** associated field */ | ||||||
|     field?: string; |     field?: string; | ||||||
|   }[]; |   }[]; | ||||||
|   uid?: string; |   uid?: string; | ||||||
|  | |||||||
| @ -1,8 +1,9 @@ | |||||||
| import { useField, useFieldSchema } from '@formily/react'; | import { useField, useFieldSchema } from '@formily/react'; | ||||||
| import React, { createContext, useEffect, useRef } from 'react'; | import React, { createContext, useEffect, useRef } from 'react'; | ||||||
| import { useBlockRequestContext } from '../block-provider'; | import { useBlockRequestContext } from '../block-provider'; | ||||||
| import { SharedFilter } from '../block-provider/SharedFilterProvider'; | import { SharedFilter, mergeFilter } from '../block-provider/SharedFilterProvider'; | ||||||
| import { CollectionFieldOptions, useCollection } from '../collection-manager'; | import { CollectionFieldOptions, useCollection } from '../collection-manager'; | ||||||
|  | import { removeNullCondition } from '../schema-component'; | ||||||
| import { useAssociatedFields } from './utils'; | import { useAssociatedFields } from './utils'; | ||||||
| 
 | 
 | ||||||
| type Collection = ReturnType<typeof useCollection>; | type Collection = ReturnType<typeof useCollection>; | ||||||
| @ -16,6 +17,8 @@ export interface DataBlock { | |||||||
|   collection: Collection; |   collection: Collection; | ||||||
|   /** 根据提供的参数执行该方法即可刷新数据区块的数据 */ |   /** 根据提供的参数执行该方法即可刷新数据区块的数据 */ | ||||||
|   doFilter: (params: any, params2?: any) => Promise<void>; |   doFilter: (params: any, params2?: any) => Promise<void>; | ||||||
|  |   /** 清除筛选区块设置的筛选参数 */ | ||||||
|  |   clearFilter: (uid: string) => void; | ||||||
|   /** 数据区块表中所有的关系字段 */ |   /** 数据区块表中所有的关系字段 */ | ||||||
|   associatedFields?: CollectionFieldOptions[]; |   associatedFields?: CollectionFieldOptions[]; | ||||||
|   /** 通过右上角菜单设置的过滤条件 */ |   /** 通过右上角菜单设置的过滤条件 */ | ||||||
| @ -72,6 +75,24 @@ export const FilterBlockRecord = ({ | |||||||
|       defaultFilter: params?.filter || {}, |       defaultFilter: params?.filter || {}, | ||||||
|       service, |       service, | ||||||
|       dom: container.current, |       dom: container.current, | ||||||
|  |       clearFilter(uid: string) { | ||||||
|  |         const param = this.service.params?.[0] || {}; | ||||||
|  |         const storedFilter = this.service.params?.[1]?.filters || {}; | ||||||
|  |         delete storedFilter[uid]; | ||||||
|  |         const mergedFilter = mergeFilter([ | ||||||
|  |           ...Object.values(storedFilter).map((filter) => removeNullCondition(filter)), | ||||||
|  |           params?.filter || {}, | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         this.service.run( | ||||||
|  |           { | ||||||
|  |             ...param, | ||||||
|  |             page: 1, | ||||||
|  |             filter: mergedFilter, | ||||||
|  |           }, | ||||||
|  |           { filters: storedFilter }, | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|     }); |     }); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								packages/core/client/src/filter-provider/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/core/client/src/filter-provider/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | export * from './FilterProvider'; | ||||||
|  | export * from './utils'; | ||||||
|  | 
 | ||||||
| @ -1,6 +1,11 @@ | |||||||
| import { Schema, useFieldSchema } from '@formily/react'; | import { Schema, useFieldSchema } from '@formily/react'; | ||||||
| import { isPlainObject, isEmpty } from '@nocobase/utils/client'; | import { isEmpty, isPlainObject } from '@nocobase/utils/client'; | ||||||
|  | import _ from 'lodash'; | ||||||
|  | import { useCallback, useEffect, useState } from 'react'; | ||||||
|  | import { mergeFilter } from '../block-provider'; | ||||||
|  | import { FilterTarget, findFilterTargets } from '../block-provider/hooks'; | ||||||
| import { Collection, FieldOptions, useCollection } from '../collection-manager'; | import { Collection, FieldOptions, useCollection } from '../collection-manager'; | ||||||
|  | import { removeNullCondition } from '../schema-component'; | ||||||
| import { findFilterOperators } from '../schema-component/antd/form-item/SchemaSettingOptions'; | import { findFilterOperators } from '../schema-component/antd/form-item/SchemaSettingOptions'; | ||||||
| import { useFilterBlock } from './FilterProvider'; | import { useFilterBlock } from './FilterProvider'; | ||||||
| 
 | 
 | ||||||
| @ -87,3 +92,78 @@ export const isAssocField = (field?: FieldOptions) => { | |||||||
| export const isSameCollection = (c1: Collection, c2: Collection) => { | export const isSameCollection = (c1: Collection, c2: Collection) => { | ||||||
|   return c1.name === c2.name; |   return c1.name === c2.name; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export const useFilterAPI = () => { | ||||||
|  |   const fieldSchema = useFieldSchema(); | ||||||
|  |   const { getDataBlocks } = useFilterBlock(); | ||||||
|  |   const { targets, uid } = findFilterTargets(fieldSchema); | ||||||
|  |   const dataBlocks = getDataBlocks(); | ||||||
|  |   const [isConnected, setIsConnected] = useState(() => { | ||||||
|  |     return targets && targets.some((target) => dataBlocks.some((dataBlock) => dataBlock.uid === target.uid)); | ||||||
|  |   }); | ||||||
|  |   const targetsKeys = Object.keys(targets || {}); | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     setIsConnected(targets && targets.some((target) => dataBlocks.some((dataBlock) => dataBlock.uid === target.uid))); | ||||||
|  |   }, [targetsKeys.length, dataBlocks]); | ||||||
|  | 
 | ||||||
|  |   const doFilter = useCallback( | ||||||
|  |     ( | ||||||
|  |       value, | ||||||
|  |       field: string | ((target: FilterTarget['targets'][0]) => string) = 'id', | ||||||
|  |       operator: string | ((target: FilterTarget['targets'][0]) => string) = '$eq', | ||||||
|  |     ) => { | ||||||
|  |       dataBlocks.forEach((block) => { | ||||||
|  |         const target = targets.find((target) => target.uid === block.uid); | ||||||
|  |         if (!target) return; | ||||||
|  | 
 | ||||||
|  |         if (_.isFunction(field)) { | ||||||
|  |           field = field(target); | ||||||
|  |         } | ||||||
|  |         if (_.isFunction(operator)) { | ||||||
|  |           operator = operator(target); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const param = block.service.params?.[0] || {}; | ||||||
|  |         // 保留原有的 filter
 | ||||||
|  |         const storedFilter = block.service.params?.[1]?.filters || {}; | ||||||
|  | 
 | ||||||
|  |         if (value !== undefined) { | ||||||
|  |           storedFilter[uid] = { | ||||||
|  |             $and: [ | ||||||
|  |               { | ||||||
|  |                 [field]: { | ||||||
|  |                   [operator]: value, | ||||||
|  |                 }, | ||||||
|  |               }, | ||||||
|  |             ], | ||||||
|  |           }; | ||||||
|  |         } else { | ||||||
|  |           delete storedFilter[uid]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const mergedFilter = mergeFilter([ | ||||||
|  |           ...Object.values(storedFilter).map((filter) => removeNullCondition(filter)), | ||||||
|  |           block.defaultFilter, | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         block.doFilter( | ||||||
|  |           { | ||||||
|  |             ...param, | ||||||
|  |             page: 1, | ||||||
|  |             filter: mergedFilter, | ||||||
|  |           }, | ||||||
|  |           { filters: storedFilter }, | ||||||
|  |         ); | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     [dataBlocks], | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     /** 当前区块是否已连接其它区块 */ | ||||||
|  |     isConnected, | ||||||
|  |     /** 调用该方法进行过滤 */ | ||||||
|  |     doFilter, | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ export * from './board'; | |||||||
| export * from './china-region'; | export * from './china-region'; | ||||||
| export * from './collection-manager'; | export * from './collection-manager'; | ||||||
| export * from './document-title'; | export * from './document-title'; | ||||||
|  | export * from './filter-provider'; | ||||||
| export * from './formula'; | export * from './formula'; | ||||||
| export * from './i18n'; | export * from './i18n'; | ||||||
| export * from './icon'; | export * from './icon'; | ||||||
|  | |||||||
| @ -496,6 +496,7 @@ SchemaSettings.ConnectDataBlocks = (props: { type: FilterBlockType; emptyDescrip | |||||||
|               targets.push({ uid: block.uid }); |               targets.push({ uid: block.uid }); | ||||||
|             } else { |             } else { | ||||||
|               targets = targets.filter((target) => target.uid !== block.uid); |               targets = targets.filter((target) => target.uid !== block.uid); | ||||||
|  |               block.clearFilter(uid); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             updateFilterTargets(fieldSchema, targets); |             updateFilterTargets(fieldSchema, targets); | ||||||
| @ -537,6 +538,7 @@ SchemaSettings.ConnectDataBlocks = (props: { type: FilterBlockType; emptyDescrip | |||||||
|         onChange={(value) => { |         onChange={(value) => { | ||||||
|           if (value === '') { |           if (value === '') { | ||||||
|             targets = targets.filter((target) => target.uid !== block.uid); |             targets = targets.filter((target) => target.uid !== block.uid); | ||||||
|  |             block.clearFilter(uid); | ||||||
|           } else { |           } else { | ||||||
|             targets = targets.filter((target) => target.uid !== block.uid); |             targets = targets.filter((target) => target.uid !== block.uid); | ||||||
|             targets.push({ uid: block.uid, field: value }); |             targets.push({ uid: block.uid, field: value }); | ||||||
|  | |||||||
| @ -1,15 +1,17 @@ | |||||||
| import { useCollection, useProps, ActionContext, RecordProvider, useRecord, useCompile } from '@nocobase/client'; | import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons'; | ||||||
| import React, { useState, useRef, useEffect, useMemo } from 'react'; |  | ||||||
| import AMap, { AMapForwardedRefProps } from '../components/AMap'; |  | ||||||
| import { RecursionField, useFieldSchema, Schema } from '@formily/react'; |  | ||||||
| import { useMemoizedFn } from 'ahooks'; |  | ||||||
| import { css } from '@emotion/css'; | import { css } from '@emotion/css'; | ||||||
|  | import { RecursionField, Schema, useFieldSchema } from '@formily/react'; | ||||||
|  | import { ActionContext, RecordProvider, useCollection, useCompile, useFilterAPI, useProps } from '@nocobase/client'; | ||||||
|  | import { useMemoizedFn } from 'ahooks'; | ||||||
| import { Button, Space } from 'antd'; | import { Button, Space } from 'antd'; | ||||||
| import { ExpandOutlined, EnvironmentOutlined, CheckOutlined } from '@ant-design/icons'; | import React, { useEffect, useMemo, useRef, useState } from 'react'; | ||||||
|  | import AMap, { AMapForwardedRefProps } from '../components/AMap'; | ||||||
| import { useMapTranslation } from '../locale'; | import { useMapTranslation } from '../locale'; | ||||||
| 
 | 
 | ||||||
| const selectedImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA/CAMAAAC7OkrPAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAEJQTFRFAAAA8Yti8Yti8Itj8Iti74tj8Itj8YtiKwADKwADKhw5Kh07KwADKwADKwADKwAD4odn1YBlKwADKwADKwADKwAD/5y7LQAAABZ0Uk5TAP/8/f/B/PYOHjY3CCozLP3XCSkvMhA05K4AAAC4SURBVHic7dXLDoIwEIXhwSsoLSrw/q8qbSAiMy3/oivj2czmS5omnVORdapVJJFKBSEL2mrrUurbpdXa5dTH5dXi9tTsGNtX0TFG1OT+7PdY2YdEGd0FuFmUwXWm5UAZbCTKYA3SUrXZQTHLHbUy2OlsMO0ultLsajLlbEWZMEUZ+ig5E6YKM2GqMBOmGKubW1D3ps6g1nnvA5uGa5Os85E9nmF2ebYkzeKhc9wre4V+GMeh317hDfXgCWigIGJbAAAAAElFTkSuQmCC' | const selectedImage = | ||||||
| const defaultImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA/CAYAAACM5Lr9AAAFkklEQVR42s3VaWxUVRjG8ddiEKPRxAQTCVSWLnZaWmjpTgulpYUBExP9Agou4IKAogUKAgItlNJCgUIXINFPfsFoDCjibkQRI0QIICAQWUpZugKtpcv0+DxyYqaTe2/vTLf58Etu7znnPf+0k44opQw5i5qsjIFs2APHoBZatFq+02vZeq94yyKs0dOjsAzOTCtuVtNKWtX0UpeaXqHU07tgt4ZnvuMa93Avz/CsniE2WIQV3iEaCDnQ8F/MTgZ4h2d4ljNgmZ4pFszDpmIRIuFP57YWDMcFu7uHMziLMyEKxJBl2MbbM6DZub2NQ3sUZ3K2vkMMGIdNKbi1ADqcZe1q2i7VKzibd8BCEE8GUQ3PQ4ez3KWcGNCbeAfv0neKm85hWRvqo+Hu1LJ2HuwTvAt3tkAciKbDIDO/7iE4l7X9rpqCA30pa3uLwt3nYRAIuIfV5mcWN6msnapf8G405IGQMGry+prB0DiloqPfwng3G3SLDltXnTt5S6PK3NnRr9jAFhDJyLsZAJcz8SGcjOr+xAa0XGGTpOfeSMrYUKcyKlx+gS1oSkbY9VXpm2+rjHKXX2ALm2TS2qq96duaVHp5u19gC5skbc3V05N23FWT8NIfsIVNkra6siGttE2llbX7h9JWhaZ6mfj+lfaJZW3Kn6DJJRNWXWqbgN+Y39jRqtDUKKkrL15PxfdjammrfyhpVmiqlNQVfx9KwX/cFJT6A7awSVLeu1CeUlinxu9o8QsphbUKTWUyfvn5Wcm511QSXvoDtrBJkpedewzaE/E58wdsYZMopSQ55+z+pKK6fo9KKqpXaDkAIgxLWnomK3H1JZVQ0tyv2ICW6XAvLHHJ6QD4K6GgRsVjQ3/g3WzQLffCKGHJqfHgisOXaNy2f/oU7+TdukGIUW5xJ0vic6+oWGzsS7yTd4NoncPiF594GC7FFlSrcVub+gTv4p36btE6h1Fc9nFn7IpzKmZrY5/gXbwTxI0O8xD77rGPYtZeVtE42Jt4B+8C8WAcNu6dPwZDzVh8PYzdcqdXcDbvgMdBPDHEOG7R0Xkxqy6oKAzpDZzNO0AMmIfFvH1kABwZk1epIotv9yjOxOyj+g4xYB4W/dbvlAAdozGsJ3Gmni0mzMPGLvyN6IMo/NojNt/qEZyFmR+CWLAIW3CYaDDUR+D/TTgGdwdncJaeKRbMw8bM/9XdosjlZ5VjU0O3cAZngXTBPCzqzV/cPQAXHeuqVBgu8IVj/TXFGXqWdME8LHLez55mRSw9qUI31fuEZzFjNogNFmFvHPQUACfC8IUbUlTvlbDcSsWzeobYYB42+vWfjDwbnn3c6zCewdnnQGwyD4t47UcjAXA2JO+qCi6ss4V7eUafFZuswn4wM8ex+LgKwqV2cC/OzAXxgnlY+KvfmxkIVaPyr6tRhbWWuId79RnxgnmYY+53VlaHLj2lRm6stRSSc0ph7xoQL1mEzfnWyhPQNrKgGgE1hrjGPTAExEvmYWGvfNOVPUErz6vhiDDCNez5GMQHVmFfd2Vq6MLD6smCGkNc4x4QH5iHPfXyV125H64NX1eFkOpO+I5reo/4wDws9KUDdhSPxFdNIGLc8R3XQHxkFfalHYnB8w6qYRuqO+E7roH4yDws5MX9dtwHlYF5lQi6qYjPfKfXxEcWYbO/sKtsBP50QxFFI/D/De8qQLrBPCwYizY9M2r+of/D+Mx3ID6zDJv1uaVwGfAIBDqGJsbhZ9eQ/BuK+OwYlhzPNe7hXh9Yhe0zwqBB4IAYouCZn1wIXH5GEZ/d1sjBMzzrBfOwoBf2GWFYBMS4C03JWRA087OaoBmf3uCz5zrP8Kx9lmF7jXiE2RbBs95ghB0MIo8/pS0OeJAzvOBLmKY//BAGURBN+jmMa3qPkLdh/wKOL8SpLbnYFgAAAABJRU5ErkJggg==' |   'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA/CAMAAAC7OkrPAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAEJQTFRFAAAA8Yti8Yti8Itj8Iti74tj8Itj8YtiKwADKwADKhw5Kh07KwADKwADKwADKwAD4odn1YBlKwADKwADKwADKwAD/5y7LQAAABZ0Uk5TAP/8/f/B/PYOHjY3CCozLP3XCSkvMhA05K4AAAC4SURBVHic7dXLDoIwEIXhwSsoLSrw/q8qbSAiMy3/oivj2czmS5omnVORdapVJJFKBSEL2mrrUurbpdXa5dTH5dXi9tTsGNtX0TFG1OT+7PdY2YdEGd0FuFmUwXWm5UAZbCTKYA3SUrXZQTHLHbUy2OlsMO0ultLsajLlbEWZMEUZ+ig5E6YKM2GqMBOmGKubW1D3ps6g1nnvA5uGa5Os85E9nmF2ebYkzeKhc9wre4V+GMeh317hDfXgCWigIGJbAAAAAElFTkSuQmCC'; | ||||||
|  | const defaultImage = | ||||||
|  |   'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA/CAYAAACM5Lr9AAAFkklEQVR42s3VaWxUVRjG8ddiEKPRxAQTCVSWLnZaWmjpTgulpYUBExP9Agou4IKAogUKAgItlNJCgUIXINFPfsFoDCjibkQRI0QIICAQWUpZugKtpcv0+DxyYqaTe2/vTLf58Etu7znnPf+0k44opQw5i5qsjIFs2APHoBZatFq+02vZeq94yyKs0dOjsAzOTCtuVtNKWtX0UpeaXqHU07tgt4ZnvuMa93Avz/CsniE2WIQV3iEaCDnQ8F/MTgZ4h2d4ljNgmZ4pFszDpmIRIuFP57YWDMcFu7uHMziLMyEKxJBl2MbbM6DZub2NQ3sUZ3K2vkMMGIdNKbi1ADqcZe1q2i7VKzibd8BCEE8GUQ3PQ4ez3KWcGNCbeAfv0neKm85hWRvqo+Hu1LJ2HuwTvAt3tkAciKbDIDO/7iE4l7X9rpqCA30pa3uLwt3nYRAIuIfV5mcWN6msnapf8G405IGQMGry+prB0DiloqPfwng3G3SLDltXnTt5S6PK3NnRr9jAFhDJyLsZAJcz8SGcjOr+xAa0XGGTpOfeSMrYUKcyKlx+gS1oSkbY9VXpm2+rjHKXX2ALm2TS2qq96duaVHp5u19gC5skbc3V05N23FWT8NIfsIVNkra6siGttE2llbX7h9JWhaZ6mfj+lfaJZW3Kn6DJJRNWXWqbgN+Y39jRqtDUKKkrL15PxfdjammrfyhpVmiqlNQVfx9KwX/cFJT6A7awSVLeu1CeUlinxu9o8QsphbUKTWUyfvn5Wcm511QSXvoDtrBJkpedewzaE/E58wdsYZMopSQ55+z+pKK6fo9KKqpXaDkAIgxLWnomK3H1JZVQ0tyv2ICW6XAvLHHJ6QD4K6GgRsVjQ3/g3WzQLffCKGHJqfHgisOXaNy2f/oU7+TdukGIUW5xJ0vic6+oWGzsS7yTd4NoncPiF594GC7FFlSrcVub+gTv4p36btE6h1Fc9nFn7IpzKmZrY5/gXbwTxI0O8xD77rGPYtZeVtE42Jt4B+8C8WAcNu6dPwZDzVh8PYzdcqdXcDbvgMdBPDHEOG7R0Xkxqy6oKAzpDZzNO0AMmIfFvH1kABwZk1epIotv9yjOxOyj+g4xYB4W/dbvlAAdozGsJ3Gmni0mzMPGLvyN6IMo/NojNt/qEZyFmR+CWLAIW3CYaDDUR+D/TTgGdwdncJaeKRbMw8bM/9XdosjlZ5VjU0O3cAZngXTBPCzqzV/cPQAXHeuqVBgu8IVj/TXFGXqWdME8LHLez55mRSw9qUI31fuEZzFjNogNFmFvHPQUACfC8IUbUlTvlbDcSsWzeobYYB42+vWfjDwbnn3c6zCewdnnQGwyD4t47UcjAXA2JO+qCi6ss4V7eUafFZuswn4wM8ex+LgKwqV2cC/OzAXxgnlY+KvfmxkIVaPyr6tRhbWWuId79RnxgnmYY+53VlaHLj2lRm6stRSSc0ph7xoQL1mEzfnWyhPQNrKgGgE1hrjGPTAExEvmYWGvfNOVPUErz6vhiDDCNez5GMQHVmFfd2Vq6MLD6smCGkNc4x4QH5iHPfXyV125H64NX1eFkOpO+I5reo/4wDws9KUDdhSPxFdNIGLc8R3XQHxkFfalHYnB8w6qYRuqO+E7roH4yDws5MX9dtwHlYF5lQi6qYjPfKfXxEcWYbO/sKtsBP50QxFFI/D/De8qQLrBPCwYizY9M2r+of/D+Mx3ID6zDJv1uaVwGfAIBDqGJsbhZ9eQ/BuK+OwYlhzPNe7hXh9Yhe0zwqBB4IAYouCZn1wIXH5GEZ/d1sjBMzzrBfOwoBf2GWFYBMS4C03JWRA087OaoBmf3uCz5zrP8Kx9lmF7jXiE2RbBs95ghB0MIo8/pS0OeJAzvOBLmKY//BAGURBN+jmMa3qPkLdh/wKOL8SpLbnYFgAAAABJRU5ErkJggg=='; | ||||||
| 
 | 
 | ||||||
| export const MapBlock = (props) => { | export const MapBlock = (props) => { | ||||||
|   const { fieldNames, dataSource = [], fixedBlock, zoom, selectedRecordKeys, setSelectedRecordKeys } = useProps(props); |   const { fieldNames, dataSource = [], fixedBlock, zoom, selectedRecordKeys, setSelectedRecordKeys } = useProps(props); | ||||||
| @ -22,7 +24,9 @@ export const MapBlock = (props) => { | |||||||
|   const [visible, setVisible] = useState(false); |   const [visible, setVisible] = useState(false); | ||||||
|   const [selectingMode, setSelecting] = useState(''); |   const [selectingMode, setSelecting] = useState(''); | ||||||
|   const { t } = useMapTranslation(); |   const { t } = useMapTranslation(); | ||||||
|   const compile = useCompile() |   const compile = useCompile(); | ||||||
|  |   const { isConnected, doFilter } = useFilterAPI(); | ||||||
|  |   const [, setPrevSelected] = useState(null); | ||||||
|   const selectingModeRef = useRef(selectingMode); |   const selectingModeRef = useRef(selectingMode); | ||||||
|   selectingModeRef.current = selectingMode; |   selectingModeRef.current = selectingMode; | ||||||
| 
 | 
 | ||||||
| @ -31,10 +35,12 @@ export const MapBlock = (props) => { | |||||||
|     const selected = typeof state === 'undefined' ? extData.selected : !state; |     const selected = typeof state === 'undefined' ? extData.selected : !state; | ||||||
|     extData.selected = !selected; |     extData.selected = !selected; | ||||||
|     if ('setIcon' in overlay) { |     if ('setIcon' in overlay) { | ||||||
|       overlay.setIcon(new mapRef.current.aMap.Icon({ |       overlay.setIcon( | ||||||
|  |         new mapRef.current.aMap.Icon({ | ||||||
|           imageSize: [19, 32], |           imageSize: [19, 32], | ||||||
|         image: selected ? defaultImage : selectedImage |           image: selected ? defaultImage : selectedImage, | ||||||
|       } as AMap.IconOpts)); |         } as AMap.IconOpts), | ||||||
|  |       ); | ||||||
|     } |     } | ||||||
|     (overlay as AMap.Polygon).setOptions({ |     (overlay as AMap.Polygon).setOptions({ | ||||||
|       extData, |       extData, | ||||||
| @ -106,6 +112,7 @@ export const MapBlock = (props) => { | |||||||
|         const overlay = mapRef.current.setOverlay(field.type, data, { |         const overlay = mapRef.current.setOverlay(field.type, data, { | ||||||
|           strokeColor: '#4e9bff', |           strokeColor: '#4e9bff', | ||||||
|           fillColor: '#4e9bff', |           fillColor: '#4e9bff', | ||||||
|  |           cursor: 'pointer', | ||||||
|           label: { |           label: { | ||||||
|             direction: 'bottom', |             direction: 'bottom', | ||||||
|             offset: [0, 5], |             offset: [0, 5], | ||||||
| @ -137,6 +144,27 @@ export const MapBlock = (props) => { | |||||||
|         const data = dataSource?.find((item) => { |         const data = dataSource?.find((item) => { | ||||||
|           return extData.id === item[getPrimaryKey()]; |           return extData.id === item[getPrimaryKey()]; | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         // 筛选区块模式
 | ||||||
|  |         if (isConnected) { | ||||||
|  |           setPrevSelected((prev) => { | ||||||
|  |             prev && clearSelected(prev); | ||||||
|  |             if (prev === o) { | ||||||
|  |               clearSelected(o); | ||||||
|  | 
 | ||||||
|  |               // 删除过滤参数
 | ||||||
|  |               doFilter(null); | ||||||
|  |               return null; | ||||||
|  |             } else { | ||||||
|  |               selectMarker(o); | ||||||
|  |               doFilter(data[getPrimaryKey()], (target) => target.field || getPrimaryKey(), '$eq'); | ||||||
|  |             } | ||||||
|  |             return o; | ||||||
|  |           }); | ||||||
|  | 
 | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (data) { |         if (data) { | ||||||
|           setVisible(true); |           setVisible(true); | ||||||
|           setRecord(data); |           setRecord(data); | ||||||
| @ -152,7 +180,7 @@ export const MapBlock = (props) => { | |||||||
|       }); |       }); | ||||||
|       events.forEach((e) => e()); |       events.forEach((e) => e()); | ||||||
|     }; |     }; | ||||||
|   }, [dataSource, isMapInitialization, fieldNames, field.type]); |   }, [dataSource, isMapInitialization, fieldNames, field.type, isConnected]); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     setTimeout(() => { |     setTimeout(() => { | ||||||
| @ -254,3 +282,29 @@ const MapBlockDrawer = (props) => { | |||||||
|     ) |     ) | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | function clearSelected(marker: AMap.Marker | AMap.Polygon | AMap.Polyline | AMap.Circle) { | ||||||
|  |   if ((marker as AMap.Marker).dom) { | ||||||
|  |     (marker as AMap.Marker).dom.style.filter = 'none'; | ||||||
|  | 
 | ||||||
|  |     // AMap.Polygon | AMap.Polyline | AMap.Circle 都有 setOptions 方法
 | ||||||
|  |   } else if ((marker as AMap.Polygon).setOptions) { | ||||||
|  |     (marker as AMap.Polygon).setOptions({ | ||||||
|  |       strokeColor: '#4e9bff', | ||||||
|  |       fillColor: '#4e9bff', | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function selectMarker(marker: AMap.Marker | AMap.Polygon | AMap.Polyline | AMap.Circle) { | ||||||
|  |   if ((marker as AMap.Marker).dom) { | ||||||
|  |     (marker as AMap.Marker).dom.style.filter = 'brightness(1.2) contrast(1.2) hue-rotate(180deg)'; | ||||||
|  | 
 | ||||||
|  |     // AMap.Polygon | AMap.Polyline | AMap.Circle 都有 setOptions 方法
 | ||||||
|  |   } else if ((marker as AMap.Polygon).setOptions) { | ||||||
|  |     (marker as AMap.Polygon).setOptions({ | ||||||
|  |       strokeColor: '#F18b62', | ||||||
|  |       fillColor: '#F18b62', | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,14 +1,15 @@ | |||||||
| import { ISchema, useField, useFieldSchema } from '@formily/react'; | import { ISchema, useField, useFieldSchema } from '@formily/react'; | ||||||
| import { | import { | ||||||
|   useCollection, |   FilterBlockType, | ||||||
|   useCollectionFilterOptions, |  | ||||||
|   useDesignable, |  | ||||||
|   useSchemaTemplate, |  | ||||||
|   FixedBlockDesignerItem, |   FixedBlockDesignerItem, | ||||||
|   GeneralSchemaDesigner, |   GeneralSchemaDesigner, | ||||||
|   SchemaSettings, |   SchemaSettings, | ||||||
|   mergeFilter, |   mergeFilter, | ||||||
|  |   useCollection, | ||||||
|  |   useCollectionFilterOptions, | ||||||
|   useCollectionManager, |   useCollectionManager, | ||||||
|  |   useDesignable, | ||||||
|  |   useSchemaTemplate, | ||||||
| } from '@nocobase/client'; | } from '@nocobase/client'; | ||||||
| import set from 'lodash/set'; | import set from 'lodash/set'; | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
| @ -145,6 +146,7 @@ export const MapBlockDesigner = () => { | |||||||
|           }); |           }); | ||||||
|         }} |         }} | ||||||
|       /> |       /> | ||||||
|  |       <SchemaSettings.ConnectDataBlocks type={FilterBlockType.TABLE} emptyDescription={t('No blocks to connect')} /> | ||||||
|       <SchemaSettings.Divider /> |       <SchemaSettings.Divider /> | ||||||
|       <SchemaSettings.Template componentName={'Map'} collectionName={name} resourceName={defaultResource} /> |       <SchemaSettings.Template componentName={'Map'} collectionName={name} resourceName={defaultResource} /> | ||||||
|       <SchemaSettings.Divider /> |       <SchemaSettings.Divider /> | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import { useField, useFieldSchema } from '@formily/react'; | import { useField, useFieldSchema } from '@formily/react'; | ||||||
| import { BlockProvider, FixedBlockWrapper, SchemaComponentOptions, useBlockRequestContext } from '@nocobase/client'; | import { BlockProvider, FixedBlockWrapper, SchemaComponentOptions, useBlockRequestContext } from '@nocobase/client'; | ||||||
| import React, { createContext, useContext, useEffect, useState } from 'react'; | import React, { createContext, useContext, useState } from 'react'; | ||||||
| 
 | 
 | ||||||
| export const MapBlockContext = createContext<any>({}); | export const MapBlockContext = createContext<any>({}); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,6 +19,8 @@ export const createMapBlockSchema = (options) => { | |||||||
|     }, |     }, | ||||||
|     'x-designer': 'MapBlockDesigner', |     'x-designer': 'MapBlockDesigner', | ||||||
|     'x-component': 'CardItem', |     'x-component': 'CardItem', | ||||||
|  |     // 保存当前筛选区块所能过滤的数据区块
 | ||||||
|  |     'x-filter-targets': [], | ||||||
|     properties: { |     properties: { | ||||||
|       actions: { |       actions: { | ||||||
|         type: 'void', |         type: 'void', | ||||||
| @ -75,6 +77,5 @@ export const createMapBlockSchema = (options) => { | |||||||
|       }, |       }, | ||||||
|     }, |     }, | ||||||
|   }; |   }; | ||||||
|   console.log(JSON.stringify(schema, null, 2)); |  | ||||||
|   return schema; |   return schema; | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user