被雨水过滤的空气-Rairn 53d0c2dd23
feat: support file collection (#1636)
* feat: support to add File collection

* feat: support to upload files

* refactor: rename 'ReadPretty.Attachment' to 'ReadPretty.File'

* feat: support to associate the File collection

* refactor: add Preview and replace Upload.Selector

* fix(Preview): fix some problems in ReadPretty mode

* feat: use 'preview' as a default title field

* feat: support only local storage now

* fix: should not show 'Add new' button

* chore: add default value for file storage

* fix: fix preview field of file collection cannot be displayed normally

* fix: only Table and Details can display File collection

* chore: translate

* refactor: migration to plugin from core

* refactor: change 'preview' to 'url'

* fix: only 'belongsTo' and 'belongsToMany' can linked file collection

* fix: fix storage and add a field called storage in file collection

* feat: add 'deletable' to configure the visibility of the delete button

* fix: fix can't upload attachment problem

* fix: remove more option

* fix: can't use preview to filter

* fix: remove Import action option

* refactor: remove useless code

* chore: optimize condition

* chore: remove comment

* test: windows compatible

* refactor: optimize upload

* fix: upload action

* fix: createAction

* fix: uploads

* fix: file collection cannot be inherited by other collections

* fix: url should be editable

* fix: url is filterable

* fix: use input interface for url field

* fix: fix error

* fix: remove subform

* Revert "chore: translate"

This reverts commit 53cd346dab8cbee0c52a9da3cf83a99dff2def34.

* refactor: move translation to plugin

* fix: title is editable

* fix: collection?.template === 'file'

* fix: fix order of URL

* fix(collection-manager): allow collectionCategories:list

* chore: add translation

* fix(upload): should enable to use drawer

* refactor: move code to plugin

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
2023-04-06 12:43:40 +08:00

120 lines
3.8 KiB
TypeScript

import { Field } from '@formily/core';
import { connect, useField, useFieldSchema } from '@formily/react';
import { merge } from '@formily/shared';
import { concat } from 'lodash';
import React, { useEffect } from 'react';
import { useActionContext, useCompile, useComponent, useFormBlockContext, useRecord } from '..';
import { CollectionFieldProvider } from './CollectionFieldProvider';
import { useCollectionField } from './hooks';
// TODO: 初步适配
const InternalField: React.FC = (props) => {
const field = useField<Field>();
const fieldSchema = useFieldSchema();
const { uiSchema, defaultValue } = useCollectionField();
const component = useComponent(uiSchema?.['x-component'] || 'Input');
const compile = useCompile();
const setFieldProps = (key, value) => {
field[key] = typeof field[key] === 'undefined' ? value : field[key];
};
const setRequired = () => {
if (typeof fieldSchema['required'] === 'undefined') {
field.required = !!uiSchema['required'];
}
};
const ctx = useFormBlockContext();
useEffect(() => {
if (ctx?.field) {
ctx.field.added = ctx.field.added || new Set();
ctx.field.added.add(fieldSchema.name);
}
});
// TODO: 初步适配
useEffect(() => {
if (!uiSchema) {
return;
}
setFieldProps('content', uiSchema['x-content']);
setFieldProps('title', uiSchema.title);
setFieldProps('description', uiSchema.description);
if (ctx?.form) {
setFieldProps('initialValue', fieldSchema.default || defaultValue);
}
if (!field.validator && (uiSchema['x-validator'] || fieldSchema['x-validator'])) {
const concatSchema = concat([], uiSchema['x-validator'] || [], fieldSchema['x-validator'] || []);
field.validator = concatSchema;
}
if (fieldSchema['x-disabled'] === true) {
field.disabled = true;
}
if (fieldSchema['x-read-pretty'] === true) {
field.readPretty = true;
}
setRequired();
// @ts-ignore
field.dataSource = uiSchema.enum;
const originalProps = compile(uiSchema['x-component-props']) || {};
const componentProps = merge(originalProps, field.componentProps || {});
field.component = [component, componentProps];
// if (interfaceType === 'input') {
// field.componentProps.ellipsis = true;
// } else if (interfaceType === 'textarea') {
// field.componentProps.ellipsis = true;
// } else if (interfaceType === 'markdown') {
// field.componentProps.ellipsis = true;
// } else if (interfaceType === 'attachment') {
// field.componentProps.size = 'small';
// }
}, [JSON.stringify(uiSchema)]);
if (!uiSchema) {
return null;
}
return React.createElement(component, props, props.children);
};
export const InternalFallbackField = () => {
const { uiSchema } = useCollectionField();
const field = useField<Field>();
const fieldSchema = useFieldSchema();
const record = useRecord();
const displayKey = fieldSchema['x-component-props']?.fieldNames?.label ?? 'id';
const value = record[fieldSchema.name];
useEffect(() => {
field.title = fieldSchema.title ?? fieldSchema.name;
}, [uiSchema?.title]);
let displayText = value;
if (Array.isArray(value) || typeof value === 'object') {
displayText = []
.concat(value)
.map((i) => i[displayKey])
.join(', ');
}
return <div>{displayText}</div>;
};
export const CollectionField = connect((props) => {
const fieldSchema = useFieldSchema();
const field = fieldSchema?.['x-component-props']?.['field'];
const { snapshot } = useActionContext();
return (
<CollectionFieldProvider
name={fieldSchema.name}
field={field}
fallback={snapshot ? <InternalFallbackField /> : null}
>
<InternalField {...props} />
</CollectionFieldProvider>
);
});
export default CollectionField;