feat: 添加汇总的提供请求链接地址
This commit is contained in:
		
							parent
							
								
									f98a4305f3
								
							
						
					
					
						commit
						07068febbd
					
				@ -1,16 +1,30 @@
 | 
			
		||||
import { useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { useDesignable, useFieldNames } from '@nocobase/client';
 | 
			
		||||
import { App, Button, Flex, Modal, Select } from 'antd';
 | 
			
		||||
import { useDesignable, useFieldNames, useFilterBlock } from '@nocobase/client';
 | 
			
		||||
import { App, Button, Flex, Input, Modal, Select } from 'antd';
 | 
			
		||||
import React, { useContext, useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from '../../locale';
 | 
			
		||||
import { GroupBlockContext } from '../../schema-initializer/GroupBlockInitializer';
 | 
			
		||||
import { transformers } from './transformers';
 | 
			
		||||
import { DeleteOutlined } from '@ant-design/icons';
 | 
			
		||||
import { DeleteOutlined, PullRequestOutlined } from '@ant-design/icons';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
 | 
			
		||||
export type SelectedField = {
 | 
			
		||||
  field: string | string[];
 | 
			
		||||
  alias?: string;
 | 
			
		||||
};
 | 
			
		||||
export type fieldOptionType = {
 | 
			
		||||
  label: string;
 | 
			
		||||
  fieldFormat: {
 | 
			
		||||
    fieldValue: string;
 | 
			
		||||
    option: string;
 | 
			
		||||
    type: string;
 | 
			
		||||
    decimal?: string;
 | 
			
		||||
    requestUrl?: string;
 | 
			
		||||
  };
 | 
			
		||||
  aggregation?: string;
 | 
			
		||||
  field?: [string];
 | 
			
		||||
  display?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const GroupConfigure = (props) => {
 | 
			
		||||
  const { visible, setVisible } = useContext(GroupBlockContext);
 | 
			
		||||
@ -18,16 +32,36 @@ export const GroupConfigure = (props) => {
 | 
			
		||||
  const { dn } = useDesignable();
 | 
			
		||||
  const { modal } = App.useApp();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const measure = fieldSchema['x-decorator-props']?.params?.measures;
 | 
			
		||||
  const [fieldOption, setFieldOption] = useState(
 | 
			
		||||
    JSON.parse(JSON.stringify(measure.filter((item) => item.fieldFormat))),
 | 
			
		||||
  );
 | 
			
		||||
  const valueOption = measure.map((item) => {
 | 
			
		||||
  const measures = fieldSchema['x-decorator-props']?.params?.measures;
 | 
			
		||||
  const option: fieldOptionType[] = [];
 | 
			
		||||
  const params = fieldSchema['x-decorator-props']?.params;
 | 
			
		||||
  if (params['config']) {
 | 
			
		||||
    if (params['config']['measures']) {
 | 
			
		||||
      option.push(...params['config']['measures']);
 | 
			
		||||
    }
 | 
			
		||||
    if (params['config']['request']) {
 | 
			
		||||
      option.push(...params['config']['request']);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const [fieldOption, setFieldOption] = useState(JSON.parse(JSON.stringify(option)));
 | 
			
		||||
  const fieldType = [
 | 
			
		||||
    {
 | 
			
		||||
      label: '字段配置',
 | 
			
		||||
      value: 'field',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      label: '请求配置',
 | 
			
		||||
      value: 'custom',
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
  const valueOption = measures.map((item) => {
 | 
			
		||||
    return {
 | 
			
		||||
      label: item.label,
 | 
			
		||||
      value: item.field[0],
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const decimal = transformers.option.filter((item) => item.value === 'decimal')[0].childrens;
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (!visible) {
 | 
			
		||||
@ -39,16 +73,31 @@ export const GroupConfigure = (props) => {
 | 
			
		||||
      title={t('Configure Group')}
 | 
			
		||||
      open={visible}
 | 
			
		||||
      onOk={() => {
 | 
			
		||||
        measure.forEach((measureItem) => {
 | 
			
		||||
          delete measureItem['fieldFormat'];
 | 
			
		||||
          fieldOption.forEach((fieldOptionItem) => {
 | 
			
		||||
            if (measureItem.field[0] === fieldOptionItem?.fieldFormat?.fieldValue) {
 | 
			
		||||
        const request = [];
 | 
			
		||||
        const configMeasures = [];
 | 
			
		||||
        fieldOption.forEach((fieldOptionItem) => {
 | 
			
		||||
          if (fieldOptionItem.fieldFormat.type === 'field') {
 | 
			
		||||
            const { measureItem, index } = measures
 | 
			
		||||
              .map((measureItem, index) => {
 | 
			
		||||
                if (measureItem.field[0] === fieldOptionItem?.fieldFormat?.fieldValue) {
 | 
			
		||||
                  return { measureItem, index };
 | 
			
		||||
                } else {
 | 
			
		||||
                  return {};
 | 
			
		||||
                }
 | 
			
		||||
              })
 | 
			
		||||
              .filter((value) => value.measureItem)[0];
 | 
			
		||||
            if (measureItem) {
 | 
			
		||||
              measureItem['fieldFormat'] = { ...fieldOptionItem.fieldFormat };
 | 
			
		||||
              configMeasures.push(measureItem);
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
          } else if (fieldOptionItem.fieldFormat.type === 'custom') {
 | 
			
		||||
            request.push({ ...fieldOptionItem, label: '自定义请求', field: [uid()] });
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        fieldSchema['x-decorator-props']['params'].measures = measure;
 | 
			
		||||
        fieldSchema['x-decorator-props']['params']['config'] = {
 | 
			
		||||
          measures: configMeasures,
 | 
			
		||||
          request,
 | 
			
		||||
        };
 | 
			
		||||
        dn.emit('patch', {
 | 
			
		||||
          schema: fieldSchema,
 | 
			
		||||
        });
 | 
			
		||||
@ -74,14 +123,37 @@ export const GroupConfigure = (props) => {
 | 
			
		||||
          return (
 | 
			
		||||
            <div style={{ marginBottom: '7px' }} key={index}>
 | 
			
		||||
              <Select
 | 
			
		||||
                options={valueOption}
 | 
			
		||||
                placeholder="Field"
 | 
			
		||||
                options={fieldType}
 | 
			
		||||
                placeholder="Type"
 | 
			
		||||
                style={{ marginRight: '5px' }}
 | 
			
		||||
                value={item?.fieldFormat?.fieldValue ? item?.fieldFormat?.fieldValue : undefined}
 | 
			
		||||
                value={item?.fieldFormat?.type ? item?.fieldFormat?.type : undefined}
 | 
			
		||||
                onChange={(v) => {
 | 
			
		||||
                  fieldConfig('field', fieldOption, setFieldOption, index, v);
 | 
			
		||||
                  fieldConfig('type', fieldOption, setFieldOption, index, v);
 | 
			
		||||
                }}
 | 
			
		||||
              />
 | 
			
		||||
              {item?.fieldFormat?.type === 'field' ? (
 | 
			
		||||
                <Select
 | 
			
		||||
                  options={valueOption}
 | 
			
		||||
                  placeholder="Field"
 | 
			
		||||
                  style={{ marginRight: '5px' }}
 | 
			
		||||
                  value={item?.fieldFormat?.fieldValue ? item?.fieldFormat?.fieldValue : undefined}
 | 
			
		||||
                  onChange={(v) => {
 | 
			
		||||
                    fieldConfig('field', fieldOption, setFieldOption, index, v);
 | 
			
		||||
                  }}
 | 
			
		||||
                />
 | 
			
		||||
              ) : null}
 | 
			
		||||
              {item?.fieldFormat?.type === 'custom' ? (
 | 
			
		||||
                <Input
 | 
			
		||||
                  addonBefore={<PullRequestOutlined />}
 | 
			
		||||
                  placeholder="RequestUrl"
 | 
			
		||||
                  allowClear
 | 
			
		||||
                  style={{ marginRight: '5px', marginTop: '5px', marginBottom: '5px' }}
 | 
			
		||||
                  defaultValue={item?.fieldFormat?.requestUrl ? item?.fieldFormat?.requestUrl : undefined}
 | 
			
		||||
                  onChange={(v) => {
 | 
			
		||||
                    fieldConfig('url', fieldOption, setFieldOption, index, v.currentTarget.value);
 | 
			
		||||
                  }}
 | 
			
		||||
                />
 | 
			
		||||
              ) : null}
 | 
			
		||||
              <Select
 | 
			
		||||
                options={transformers.option}
 | 
			
		||||
                placeholder="Format"
 | 
			
		||||
@ -129,6 +201,16 @@ const fieldConfig = (type, fieldOption, setFieldOption, index?, record?) => {
 | 
			
		||||
    option.push({});
 | 
			
		||||
  } else if (type === 'del') {
 | 
			
		||||
    option.splice(index, 1);
 | 
			
		||||
  } else if (type === 'type') {
 | 
			
		||||
    option[index]['fieldFormat'] = {
 | 
			
		||||
      ...option[index]['fieldFormat'],
 | 
			
		||||
      type: record,
 | 
			
		||||
    };
 | 
			
		||||
  } else if (type === 'url') {
 | 
			
		||||
    option[index]['fieldFormat'] = {
 | 
			
		||||
      ...option[index]['fieldFormat'],
 | 
			
		||||
      requestUrl: record,
 | 
			
		||||
    };
 | 
			
		||||
  } else if (type === 'field') {
 | 
			
		||||
    option[index]['fieldFormat'] = {
 | 
			
		||||
      ...option[index]['fieldFormat'],
 | 
			
		||||
 | 
			
		||||
@ -1,40 +1,73 @@
 | 
			
		||||
import { useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { useBlockRequestContext } from '@nocobase/client';
 | 
			
		||||
import { findFilterTargets, useAPIClient, useBlockRequestContext, useFilterBlock } from '@nocobase/client';
 | 
			
		||||
import { Descriptions, DescriptionsProps, Spin } from 'antd';
 | 
			
		||||
import { transformers } from '../components/GroupBlockConfigure/transformers';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import { useAsyncEffect } from 'ahooks';
 | 
			
		||||
 | 
			
		||||
type DataItem = {
 | 
			
		||||
  labels: string[];
 | 
			
		||||
  values: number[];
 | 
			
		||||
};
 | 
			
		||||
type requestData = {
 | 
			
		||||
  label: string;
 | 
			
		||||
  value: number | DataItem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const GroupBlock = (props) => {
 | 
			
		||||
  const field = useField<any>();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const measures = fieldSchema.parent['x-decorator-props'].params?.measures;
 | 
			
		||||
  const params = fieldSchema.parent['x-decorator-props'].params;
 | 
			
		||||
  const { resource, service } = useBlockRequestContext();
 | 
			
		||||
  const { getDataBlocks } = useFilterBlock();
 | 
			
		||||
  const { targets = [], uid } = findFilterTargets(fieldSchema);
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const [result, setResult] = useState([]);
 | 
			
		||||
  const items: DescriptionsProps['items'] = [];
 | 
			
		||||
  const Blocks = getDataBlocks();
 | 
			
		||||
  if (!service.params.length) {
 | 
			
		||||
    getDataBlocks().map((block) => {
 | 
			
		||||
      if (Object.keys(block.defaultFilter).length) {
 | 
			
		||||
        getDataBlocks().forEach((getblock) => {
 | 
			
		||||
          if (getblock.uid !== block.uid && getblock.collection.name === block.collection.name) {
 | 
			
		||||
            service.params = block.defaultFilter;
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useAsyncEffect(async () => {
 | 
			
		||||
    const filter = service?.params[0] ? service.params[0].filter : service?.params;
 | 
			
		||||
    setResult(
 | 
			
		||||
      await Promise.all(
 | 
			
		||||
        params?.config?.request?.map(async (requeatItem) => {
 | 
			
		||||
          return [
 | 
			
		||||
            await api.request({
 | 
			
		||||
              url: requeatItem.fieldFormat.requestUrl,
 | 
			
		||||
              params: {
 | 
			
		||||
                filter: { ...filter },
 | 
			
		||||
              },
 | 
			
		||||
            }),
 | 
			
		||||
            requeatItem,
 | 
			
		||||
          ];
 | 
			
		||||
        }),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }, [Blocks, service.params, service.params[0]]);
 | 
			
		||||
 | 
			
		||||
  if (service.loading && !field.loaded) {
 | 
			
		||||
    return <Spin />;
 | 
			
		||||
  }
 | 
			
		||||
  const data = service.data?.data[0] ?? {};
 | 
			
		||||
  const { option: tOption } = transformers;
 | 
			
		||||
  measures.forEach((measuresItem) => {
 | 
			
		||||
    if (measuresItem.fieldFormat) {
 | 
			
		||||
      const value = measuresItem.fieldFormat.fieldValue;
 | 
			
		||||
      const option = measuresItem.fieldFormat.option;
 | 
			
		||||
      const decimal = measuresItem.fieldFormat.decimal;
 | 
			
		||||
      if (option && option !== 'decimal') {
 | 
			
		||||
        const component = tOption.filter((tValue) => tValue.value === option)[0].component;
 | 
			
		||||
        data[value] = String(data[value]).includes(',') ? String(data[value]).replace(/,/g, '') : data[value];
 | 
			
		||||
        data[value] = component(data[value]);
 | 
			
		||||
      } else if (option && option === 'decimal') {
 | 
			
		||||
        const component = tOption
 | 
			
		||||
          .filter((tValue) => tValue.value === 'decimal')[0]
 | 
			
		||||
          .childrens.filter((decimalOption) => decimalOption.value === decimal)[0].component;
 | 
			
		||||
        data[value] = String(data[value]).includes(',') ? String(data[value]).replace(/,/g, '') : data[value];
 | 
			
		||||
        data[value] = component(data[value]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  params?.config?.measures?.forEach((measuresItem) => {
 | 
			
		||||
    const value = measuresItem.fieldFormat.fieldValue;
 | 
			
		||||
    data[value] = fieldTransformers(measuresItem, data[value]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const items: DescriptionsProps['items'] = [];
 | 
			
		||||
  for (const key in data) {
 | 
			
		||||
    measures?.forEach((value) => {
 | 
			
		||||
    params?.config?.measures?.forEach((value) => {
 | 
			
		||||
      if (value.field[0] === key) {
 | 
			
		||||
        if (value.display) {
 | 
			
		||||
          items.push({
 | 
			
		||||
@ -47,5 +80,38 @@ export const GroupBlock = (props) => {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  result.forEach(([data, requeatItem]) => {
 | 
			
		||||
    data?.data?.data?.forEach((requestData: requestData) => {
 | 
			
		||||
      const dataItem = { key: requestData.label, label: requestData.label, children: '' };
 | 
			
		||||
      if (typeof requestData.value === 'object') {
 | 
			
		||||
        requestData.value.labels.forEach((labelItem, index) => {
 | 
			
		||||
          dataItem.children =
 | 
			
		||||
            dataItem.children + `  ${labelItem} ${fieldTransformers(requeatItem, requestData.value['values'][index])}`;
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        dataItem.children = fieldTransformers(requeatItem, requestData.value.toString());
 | 
			
		||||
      }
 | 
			
		||||
      items.push(dataItem);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  return <Descriptions title="汇总:" items={items} />;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const fieldTransformers = (item, data) => {
 | 
			
		||||
  const { option: tOption } = transformers;
 | 
			
		||||
  if (item.fieldFormat) {
 | 
			
		||||
    const option = item.fieldFormat.option;
 | 
			
		||||
    const decimal = item.fieldFormat.decimal;
 | 
			
		||||
    if (option && option !== 'decimal') {
 | 
			
		||||
      const component = tOption.filter((tValue) => tValue.value === option)[0].component;
 | 
			
		||||
      data = String(data).includes(',') ? String(data).replace(/,/g, '') : data;
 | 
			
		||||
      return component(data);
 | 
			
		||||
    } else if (option && option === 'decimal') {
 | 
			
		||||
      const component = tOption
 | 
			
		||||
        .filter((tValue) => tValue.value === 'decimal')[0]
 | 
			
		||||
        .childrens.filter((decimalOption) => decimalOption.value === decimal)[0].component;
 | 
			
		||||
      data = String(data).includes(',') ? String(data).replace(/,/g, '') : data;
 | 
			
		||||
      return component(data);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -121,38 +121,6 @@ export const GroupBlockInitializer = () => {
 | 
			
		||||
export const groupBlockSettings = new SchemaSettings({
 | 
			
		||||
  name: 'groupBlockSettings',
 | 
			
		||||
  items: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
      name: 'displayFields',
 | 
			
		||||
      componentProps: { title: 'display Fields' },
 | 
			
		||||
      useChildren() {
 | 
			
		||||
        const item = [];
 | 
			
		||||
        const { dn } = useDesignable();
 | 
			
		||||
        const fieldSchema = useFieldSchema();
 | 
			
		||||
        const measures = fieldSchema['x-decorator-props'].params?.measures;
 | 
			
		||||
        if (measures && measures.length) {
 | 
			
		||||
          measures.forEach((value) => {
 | 
			
		||||
            item.push({
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              Component: () => (
 | 
			
		||||
                <SchemaSettingsSwitchItem
 | 
			
		||||
                  title={value.label}
 | 
			
		||||
                  checked={value.display}
 | 
			
		||||
                  onChange={(chang) => {
 | 
			
		||||
                    value.display = chang;
 | 
			
		||||
                    dn.emit('patch', {
 | 
			
		||||
                      schema: fieldSchema,
 | 
			
		||||
                    });
 | 
			
		||||
                    dn.refresh();
 | 
			
		||||
                  }}
 | 
			
		||||
                />
 | 
			
		||||
              ),
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        return item;
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'Configure',
 | 
			
		||||
      Component: GroupBlockConfigure,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user