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?: {
 | 
			
		||||
    /** field uid */
 | 
			
		||||
    uid: string;
 | 
			
		||||
    /** associated fields */
 | 
			
		||||
    /** associated field */
 | 
			
		||||
    field?: string;
 | 
			
		||||
  }[];
 | 
			
		||||
  uid?: string;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
import { useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import React, { createContext, useEffect, useRef } from 'react';
 | 
			
		||||
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 { removeNullCondition } from '../schema-component';
 | 
			
		||||
import { useAssociatedFields } from './utils';
 | 
			
		||||
 | 
			
		||||
type Collection = ReturnType<typeof useCollection>;
 | 
			
		||||
@ -16,6 +17,8 @@ export interface DataBlock {
 | 
			
		||||
  collection: Collection;
 | 
			
		||||
  /** 根据提供的参数执行该方法即可刷新数据区块的数据 */
 | 
			
		||||
  doFilter: (params: any, params2?: any) => Promise<void>;
 | 
			
		||||
  /** 清除筛选区块设置的筛选参数 */
 | 
			
		||||
  clearFilter: (uid: string) => void;
 | 
			
		||||
  /** 数据区块表中所有的关系字段 */
 | 
			
		||||
  associatedFields?: CollectionFieldOptions[];
 | 
			
		||||
  /** 通过右上角菜单设置的过滤条件 */
 | 
			
		||||
@ -72,6 +75,24 @@ export const FilterBlockRecord = ({
 | 
			
		||||
      defaultFilter: params?.filter || {},
 | 
			
		||||
      service,
 | 
			
		||||
      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 { 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 { removeNullCondition } from '../schema-component';
 | 
			
		||||
import { findFilterOperators } from '../schema-component/antd/form-item/SchemaSettingOptions';
 | 
			
		||||
import { useFilterBlock } from './FilterProvider';
 | 
			
		||||
 | 
			
		||||
@ -87,3 +92,78 @@ export const isAssocField = (field?: FieldOptions) => {
 | 
			
		||||
export const isSameCollection = (c1: Collection, c2: Collection) => {
 | 
			
		||||
  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 './collection-manager';
 | 
			
		||||
export * from './document-title';
 | 
			
		||||
export * from './filter-provider';
 | 
			
		||||
export * from './formula';
 | 
			
		||||
export * from './i18n';
 | 
			
		||||
export * from './icon';
 | 
			
		||||
 | 
			
		||||
@ -496,6 +496,7 @@ SchemaSettings.ConnectDataBlocks = (props: { type: FilterBlockType; emptyDescrip
 | 
			
		||||
              targets.push({ uid: block.uid });
 | 
			
		||||
            } else {
 | 
			
		||||
              targets = targets.filter((target) => target.uid !== block.uid);
 | 
			
		||||
              block.clearFilter(uid);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            updateFilterTargets(fieldSchema, targets);
 | 
			
		||||
@ -537,6 +538,7 @@ SchemaSettings.ConnectDataBlocks = (props: { type: FilterBlockType; emptyDescrip
 | 
			
		||||
        onChange={(value) => {
 | 
			
		||||
          if (value === '') {
 | 
			
		||||
            targets = targets.filter((target) => target.uid !== block.uid);
 | 
			
		||||
            block.clearFilter(uid);
 | 
			
		||||
          } else {
 | 
			
		||||
            targets = targets.filter((target) => target.uid !== block.uid);
 | 
			
		||||
            targets.push({ uid: block.uid, field: value });
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,17 @@
 | 
			
		||||
import { useCollection, useProps, ActionContext, RecordProvider, useRecord, useCompile } from '@nocobase/client';
 | 
			
		||||
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 { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
 | 
			
		||||
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 { 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';
 | 
			
		||||
 | 
			
		||||
const selectedImage = '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=='
 | 
			
		||||
const selectedImage =
 | 
			
		||||
  '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) => {
 | 
			
		||||
  const { fieldNames, dataSource = [], fixedBlock, zoom, selectedRecordKeys, setSelectedRecordKeys } = useProps(props);
 | 
			
		||||
@ -22,7 +24,9 @@ export const MapBlock = (props) => {
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const [selectingMode, setSelecting] = useState('');
 | 
			
		||||
  const { t } = useMapTranslation();
 | 
			
		||||
  const compile = useCompile()
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const { isConnected, doFilter } = useFilterAPI();
 | 
			
		||||
  const [, setPrevSelected] = useState(null);
 | 
			
		||||
  const selectingModeRef = useRef(selectingMode);
 | 
			
		||||
  selectingModeRef.current = selectingMode;
 | 
			
		||||
 | 
			
		||||
@ -31,10 +35,12 @@ export const MapBlock = (props) => {
 | 
			
		||||
    const selected = typeof state === 'undefined' ? extData.selected : !state;
 | 
			
		||||
    extData.selected = !selected;
 | 
			
		||||
    if ('setIcon' in overlay) {
 | 
			
		||||
      overlay.setIcon(new mapRef.current.aMap.Icon({
 | 
			
		||||
        imageSize: [19, 32],
 | 
			
		||||
        image: selected ? defaultImage : selectedImage
 | 
			
		||||
      } as AMap.IconOpts));
 | 
			
		||||
      overlay.setIcon(
 | 
			
		||||
        new mapRef.current.aMap.Icon({
 | 
			
		||||
          imageSize: [19, 32],
 | 
			
		||||
          image: selected ? defaultImage : selectedImage,
 | 
			
		||||
        } as AMap.IconOpts),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    (overlay as AMap.Polygon).setOptions({
 | 
			
		||||
      extData,
 | 
			
		||||
@ -106,6 +112,7 @@ export const MapBlock = (props) => {
 | 
			
		||||
        const overlay = mapRef.current.setOverlay(field.type, data, {
 | 
			
		||||
          strokeColor: '#4e9bff',
 | 
			
		||||
          fillColor: '#4e9bff',
 | 
			
		||||
          cursor: 'pointer',
 | 
			
		||||
          label: {
 | 
			
		||||
            direction: 'bottom',
 | 
			
		||||
            offset: [0, 5],
 | 
			
		||||
@ -137,6 +144,27 @@ export const MapBlock = (props) => {
 | 
			
		||||
        const data = dataSource?.find((item) => {
 | 
			
		||||
          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) {
 | 
			
		||||
          setVisible(true);
 | 
			
		||||
          setRecord(data);
 | 
			
		||||
@ -152,7 +180,7 @@ export const MapBlock = (props) => {
 | 
			
		||||
      });
 | 
			
		||||
      events.forEach((e) => e());
 | 
			
		||||
    };
 | 
			
		||||
  }, [dataSource, isMapInitialization, fieldNames, field.type]);
 | 
			
		||||
  }, [dataSource, isMapInitialization, fieldNames, field.type, isConnected]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    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 {
 | 
			
		||||
  useCollection,
 | 
			
		||||
  useCollectionFilterOptions,
 | 
			
		||||
  useDesignable,
 | 
			
		||||
  useSchemaTemplate,
 | 
			
		||||
  FilterBlockType,
 | 
			
		||||
  FixedBlockDesignerItem,
 | 
			
		||||
  GeneralSchemaDesigner,
 | 
			
		||||
  SchemaSettings,
 | 
			
		||||
  mergeFilter,
 | 
			
		||||
  useCollection,
 | 
			
		||||
  useCollectionFilterOptions,
 | 
			
		||||
  useCollectionManager,
 | 
			
		||||
  useDesignable,
 | 
			
		||||
  useSchemaTemplate,
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import set from 'lodash/set';
 | 
			
		||||
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.Template componentName={'Map'} collectionName={name} resourceName={defaultResource} />
 | 
			
		||||
      <SchemaSettings.Divider />
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
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>({});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,8 @@ export const createMapBlockSchema = (options) => {
 | 
			
		||||
    },
 | 
			
		||||
    'x-designer': 'MapBlockDesigner',
 | 
			
		||||
    'x-component': 'CardItem',
 | 
			
		||||
    // 保存当前筛选区块所能过滤的数据区块
 | 
			
		||||
    'x-filter-targets': [],
 | 
			
		||||
    properties: {
 | 
			
		||||
      actions: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
@ -75,6 +77,5 @@ export const createMapBlockSchema = (options) => {
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  console.log(JSON.stringify(schema, null, 2));
 | 
			
		||||
  return schema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user