fix: improve the display of the title field (#1741)
* fix: fix the displaying problem of Select * fix: fix error * fix: filter out fields * feat: format date * feat: optimize * fix: fix error * feat: use the default title field * fix: fix bug
This commit is contained in:
parent
7b892cec50
commit
71af0f16a9
@ -42,6 +42,12 @@ const titlePrompt = 'Default title for each record';
|
|||||||
const expectTypes = ['string', 'integer', 'bigInt', 'float', 'double', 'decimal', 'date', 'dateonly', 'time'];
|
const expectTypes = ['string', 'integer', 'bigInt', 'float', 'double', 'decimal', 'date', 'dateonly', 'time'];
|
||||||
const excludeInterfaces = ['icon'];
|
const excludeInterfaces = ['icon'];
|
||||||
|
|
||||||
|
// 是否可以作为标题字段
|
||||||
|
export const isTitleField = (field) => {
|
||||||
|
if (!field) return false;
|
||||||
|
return !field.isForeignKey && expectTypes.includes(field.type) && !excludeInterfaces.includes(field.interface);
|
||||||
|
};
|
||||||
|
|
||||||
const CurrentFields = (props) => {
|
const CurrentFields = (props) => {
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { getInterface } = useCollectionManager();
|
const { getInterface } = useCollectionManager();
|
||||||
@ -91,7 +97,7 @@ const CurrentFields = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return expectTypes.includes(record.type) && !excludeInterfaces.includes(record.interface) ? (
|
return isTitleField(record) ? (
|
||||||
<Tooltip title={t(titlePrompt)} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
|
<Tooltip title={t(titlePrompt)} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
|
||||||
<Switch
|
<Switch
|
||||||
size="small"
|
size="small"
|
||||||
@ -201,7 +207,7 @@ const InheritFields = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return expectTypes.includes(record.type) && !excludeInterfaces.includes(record.interface) ? (
|
return isTitleField(record) ? (
|
||||||
<Tooltip title={t(titlePrompt)} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
|
<Tooltip title={t(titlePrompt)} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
|
||||||
<Switch
|
<Switch
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -47,6 +47,11 @@ export const linkTo: IField = {
|
|||||||
},
|
},
|
||||||
availableTypes: ['belongsToMany'],
|
availableTypes: ['belongsToMany'],
|
||||||
schemaInitialize(schema: ISchema, { readPretty, block, targetCollection }) {
|
schemaInitialize(schema: ISchema, { readPretty, block, targetCollection }) {
|
||||||
|
if (targetCollection?.titleField && schema['x-component-props']) {
|
||||||
|
schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
|
||||||
|
schema['x-component-props'].fieldNames.label = targetCollection.titleField;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetCollection?.template === 'file') {
|
if (targetCollection?.template === 'file') {
|
||||||
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
||||||
fieldNames.label = 'preview';
|
fieldNames.label = 'preview';
|
||||||
|
@ -51,8 +51,13 @@ export const m2m: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
availableTypes:['belongsToMany'],
|
availableTypes: ['belongsToMany'],
|
||||||
schemaInitialize(schema: ISchema, { readPretty, block, targetCollection }) {
|
schemaInitialize(schema: ISchema, { readPretty, block, targetCollection }) {
|
||||||
|
if (targetCollection?.titleField && schema['x-component-props']) {
|
||||||
|
schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
|
||||||
|
schema['x-component-props'].fieldNames.label = targetCollection.titleField;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetCollection?.template === 'file') {
|
if (targetCollection?.template === 'file') {
|
||||||
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
||||||
fieldNames.label = 'preview';
|
fieldNames.label = 'preview';
|
||||||
|
@ -52,6 +52,11 @@ export const m2o: IField = {
|
|||||||
},
|
},
|
||||||
availableTypes:['belongsTo'],
|
availableTypes:['belongsTo'],
|
||||||
schemaInitialize(schema: ISchema, { block, readPretty, targetCollection }) {
|
schemaInitialize(schema: ISchema, { block, readPretty, targetCollection }) {
|
||||||
|
if (targetCollection?.titleField && schema['x-component-props']) {
|
||||||
|
schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
|
||||||
|
schema['x-component-props'].fieldNames.label = targetCollection.titleField;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetCollection?.template === 'file') {
|
if (targetCollection?.template === 'file') {
|
||||||
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
||||||
fieldNames.label = 'preview';
|
fieldNames.label = 'preview';
|
||||||
|
@ -51,7 +51,12 @@ export const o2m: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
availableTypes: ['hasMany'],
|
availableTypes: ['hasMany'],
|
||||||
schemaInitialize(schema: ISchema, { field, block, readPretty }) {
|
schemaInitialize(schema: ISchema, { field, block, readPretty, targetCollection }) {
|
||||||
|
if (targetCollection?.titleField && schema['x-component-props']) {
|
||||||
|
schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
|
||||||
|
schema['x-component-props'].fieldNames.label = targetCollection.titleField;
|
||||||
|
}
|
||||||
|
|
||||||
if (block === 'Form') {
|
if (block === 'Form') {
|
||||||
if (schema['x-component'] === 'TableField') {
|
if (schema['x-component'] === 'TableField') {
|
||||||
const association = `${field.collectionName}.${field.name}`;
|
const association = `${field.collectionName}.${field.name}`;
|
||||||
|
@ -475,6 +475,11 @@ export const obo: IField = {
|
|||||||
schema['x-component-props']['size'] = 'small';
|
schema['x-component-props']['size'] = 'small';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetCollection?.titleField && schema['x-component-props']) {
|
||||||
|
schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
|
||||||
|
schema['x-component-props'].fieldNames.label = targetCollection.titleField;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetCollection?.template === 'file') {
|
if (targetCollection?.template === 'file') {
|
||||||
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
const fieldNames = schema['x-component-props']['fieldNames'] || { label: 'preview', value: 'id' };
|
||||||
fieldNames.label = 'preview';
|
fieldNames.label = 'preview';
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
useCollectionManager,
|
useCollectionManager,
|
||||||
useSortFields,
|
useSortFields,
|
||||||
} from '../../../collection-manager';
|
} from '../../../collection-manager';
|
||||||
|
import { isTitleField } from '../../../collection-manager/Configuration/CollectionFields';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
import { useCompile, useDesignable, useFieldComponentOptions, useFieldTitle } from '../../hooks';
|
import { useCompile, useDesignable, useFieldComponentOptions, useFieldTitle } from '../../hooks';
|
||||||
import { removeNullCondition } from '../filter';
|
import { removeNullCondition } from '../filter';
|
||||||
@ -91,7 +92,7 @@ interface AssociationSelectInterface {
|
|||||||
|
|
||||||
export const AssociationSelect = InternalAssociationSelect as unknown as AssociationSelectInterface;
|
export const AssociationSelect = InternalAssociationSelect as unknown as AssociationSelectInterface;
|
||||||
|
|
||||||
AssociationSelect.Designer = () => {
|
AssociationSelect.Designer = function Designer() {
|
||||||
const { getCollectionFields, getInterface, getCollectionJoinField, getCollection } = useCollectionManager();
|
const { getCollectionFields, getInterface, getCollectionJoinField, getCollection } = useCollectionManager();
|
||||||
const { getField, template } = useCollection();
|
const { getField, template } = useCollection();
|
||||||
const { form } = useFormBlockContext();
|
const { form } = useFormBlockContext();
|
||||||
@ -99,7 +100,6 @@ AssociationSelect.Designer = () => {
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const tk = useFilterByTk();
|
const tk = useFilterByTk();
|
||||||
const {} = useCollection();
|
|
||||||
const { dn, refresh, insertAdjacent } = useDesignable();
|
const { dn, refresh, insertAdjacent } = useDesignable();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
@ -134,7 +134,7 @@ AssociationSelect.Designer = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const options = targetFields
|
const options = targetFields
|
||||||
.filter((field) => !field?.target && field.type !== 'boolean')
|
.filter((field) => isTitleField(field))
|
||||||
.map((field) => ({
|
.map((field) => ({
|
||||||
value: field?.name,
|
value: field?.name,
|
||||||
label: compile(field?.uiSchema?.title) || field?.name,
|
label: compile(field?.uiSchema?.title) || field?.name,
|
||||||
@ -691,7 +691,7 @@ AssociationSelect.Designer = () => {
|
|||||||
* 用于筛选表单区块
|
* 用于筛选表单区块
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
AssociationSelect.FilterDesigner = () => {
|
AssociationSelect.FilterDesigner = function FilterDesigner() {
|
||||||
const { getCollectionFields, getInterface, getCollectionJoinField } = useCollectionManager();
|
const { getCollectionFields, getInterface, getCollectionJoinField } = useCollectionManager();
|
||||||
const { getField } = useCollection();
|
const { getField } = useCollection();
|
||||||
const { form } = useFormBlockContext();
|
const { form } = useFormBlockContext();
|
||||||
|
@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { ACLCollectionFieldProvider } from '../../../acl/ACLProvider';
|
import { ACLCollectionFieldProvider } from '../../../acl/ACLProvider';
|
||||||
import { BlockRequestContext, useFilterByTk, useFormBlockContext } from '../../../block-provider';
|
import { BlockRequestContext, useFilterByTk, useFormBlockContext } from '../../../block-provider';
|
||||||
import { Collection, useCollection, useCollectionManager } from '../../../collection-manager';
|
import { Collection, useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
|
import { isTitleField } from '../../../collection-manager/Configuration/CollectionFields';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
import { useCompile, useDesignable, useFieldComponentOptions } from '../../hooks';
|
import { useCompile, useDesignable, useFieldComponentOptions } from '../../hooks';
|
||||||
import { BlockItem } from '../block-item';
|
import { BlockItem } from '../block-item';
|
||||||
@ -70,7 +71,7 @@ export const FormItem: any = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
FormItem.Designer = () => {
|
FormItem.Designer = function Designer() {
|
||||||
const { getCollectionFields, getInterface, getCollectionJoinField, getCollection } = useCollectionManager();
|
const { getCollectionFields, getInterface, getCollectionJoinField, getCollection } = useCollectionManager();
|
||||||
const { getField } = useCollection();
|
const { getField } = useCollection();
|
||||||
const tk = useFilterByTk();
|
const tk = useFilterByTk();
|
||||||
@ -97,11 +98,14 @@ FormItem.Designer = () => {
|
|||||||
initialValue['required'] = field.required;
|
initialValue['required'] = field.required;
|
||||||
}
|
}
|
||||||
const options = targetFields
|
const options = targetFields
|
||||||
.filter((field) => !field?.target && field.type !== 'boolean')
|
.filter((field) => {
|
||||||
|
return isTitleField(field);
|
||||||
|
})
|
||||||
.map((field) => ({
|
.map((field) => ({
|
||||||
value: field?.name,
|
value: field?.name,
|
||||||
label: compile(field?.uiSchema?.title) || field?.name,
|
label: compile(field?.uiSchema?.title) || field?.name,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let readOnlyMode = 'editable';
|
let readOnlyMode = 'editable';
|
||||||
if (fieldSchema['x-disabled'] === true) {
|
if (fieldSchema['x-disabled'] === true) {
|
||||||
readOnlyMode = 'readonly';
|
readOnlyMode = 'readonly';
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { LoadingOutlined } from '@ant-design/icons';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
import { connect, mapProps, mapReadPretty, useFieldSchema } from '@formily/react';
|
||||||
import { SelectProps } from 'antd';
|
import { SelectProps, Tag } from 'antd';
|
||||||
|
import moment from 'moment';
|
||||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
import { ResourceActionOptions, useRequest } from '../../../api-client';
|
import { ResourceActionOptions, useRequest } from '../../../api-client';
|
||||||
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
||||||
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
import { useCompile } from '../../hooks';
|
import { useCompile } from '../../hooks';
|
||||||
import { Select, defaultFieldNames } from '../select';
|
import { Select, defaultFieldNames } from '../select';
|
||||||
import { ReadPretty } from './ReadPretty';
|
import { ReadPretty } from './ReadPretty';
|
||||||
@ -15,6 +17,7 @@ export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
|
|||||||
wait?: number;
|
wait?: number;
|
||||||
manual?: boolean;
|
manual?: boolean;
|
||||||
mapOptions?: (data: any) => RemoteSelectProps['fieldNames'];
|
mapOptions?: (data: any) => RemoteSelectProps['fieldNames'];
|
||||||
|
targetField?: any;
|
||||||
service: ResourceActionOptions<P>;
|
service: ResourceActionOptions<P>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,10 +31,73 @@ const InternalRemoteSelect = connect(
|
|||||||
objectValue,
|
objectValue,
|
||||||
manual = true,
|
manual = true,
|
||||||
mapOptions,
|
mapOptions,
|
||||||
|
targetField: _targetField,
|
||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const firstRun = useRef(false);
|
const firstRun = useRef(false);
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { getField } = useCollection();
|
||||||
|
const { getCollectionJoinField } = useCollectionManager();
|
||||||
|
const collectionField = getField(fieldSchema.name);
|
||||||
|
const targetField =
|
||||||
|
_targetField ||
|
||||||
|
(collectionField?.target &&
|
||||||
|
fieldNames?.label &&
|
||||||
|
getCollectionJoinField(`${collectionField.target}.${fieldNames.label}`));
|
||||||
|
|
||||||
|
const mapOptionsToTags = useCallback(
|
||||||
|
(options) => {
|
||||||
|
try {
|
||||||
|
return options.map((option) => {
|
||||||
|
let label = option[fieldNames.label];
|
||||||
|
|
||||||
|
if (targetField?.uiSchema?.enum) {
|
||||||
|
if (Array.isArray(label)) {
|
||||||
|
label = label
|
||||||
|
.map((item, index) => {
|
||||||
|
const option = targetField.uiSchema.enum.find((i) => i.value === item);
|
||||||
|
if (option) {
|
||||||
|
return (
|
||||||
|
<Tag key={index} color={option.color} style={{ marginRight: 3 }}>
|
||||||
|
{option?.label || item}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <Tag>{item}</Tag>;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.reverse();
|
||||||
|
} else {
|
||||||
|
const item = targetField.uiSchema.enum.find((i) => i.value === label);
|
||||||
|
if (item) {
|
||||||
|
label = <Tag color={item.color}>{item.label}</Tag>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetField?.type === 'date') {
|
||||||
|
label = moment(label).format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapOptions) {
|
||||||
|
return mapOptions({
|
||||||
|
[fieldNames.label]: label,
|
||||||
|
[fieldNames.value]: option[fieldNames.value],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
[fieldNames.label]: label || option[fieldNames.value],
|
||||||
|
[fieldNames.value]: option[fieldNames.value],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[targetField?.uiSchema, fieldNames],
|
||||||
|
);
|
||||||
|
|
||||||
const { data, run, loading } = useRequest(
|
const { data, run, loading } = useRequest(
|
||||||
{
|
{
|
||||||
@ -82,11 +148,8 @@ const InternalRemoteSelect = connect(
|
|||||||
|
|
||||||
const getOptionsByFieldNames = useCallback(
|
const getOptionsByFieldNames = useCallback(
|
||||||
(item) => {
|
(item) => {
|
||||||
if (mapOptions) {
|
|
||||||
return mapOptions(item);
|
|
||||||
}
|
|
||||||
return Object.keys(fieldNames).reduce((obj, key) => {
|
return Object.keys(fieldNames).reduce((obj, key) => {
|
||||||
const value = item[fieldNames[key]];
|
let value = item[fieldNames[key]];
|
||||||
if (value) {
|
if (value) {
|
||||||
// support hidden, disabled, etc.
|
// support hidden, disabled, etc.
|
||||||
obj[['label', 'value', 'options'].includes(key) ? fieldNames[key] : key] =
|
obj[['label', 'value', 'options'].includes(key) ? fieldNames[key] : key] =
|
||||||
@ -138,7 +201,7 @@ const InternalRemoteSelect = connect(
|
|||||||
value={value}
|
value={value}
|
||||||
{...others}
|
{...others}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
options={options}
|
options={mapOptionsToTags(options)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -21,9 +21,10 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
const { useProps } = props;
|
const { useProps } = props;
|
||||||
const { defaultValues, collectionName } = useProps();
|
const { defaultValues, collectionName } = useProps();
|
||||||
const { collectionList, getEnableFieldTree } = useCollectionState(collectionName);
|
const { collectionList, getEnableFieldTree } = useCollectionState(collectionName);
|
||||||
const { getCollection } = useCollectionManager();
|
const { getCollection, getCollectionField } = useCollectionManager();
|
||||||
const collection = getCollection(collectionName);
|
const collection = getCollection(collectionName);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const field = getCollectionField(`${collectionName}.${collection?.titleField || 'id'}`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
@ -83,16 +84,24 @@ export const FormDataTemplates = observer((props: any) => {
|
|||||||
multiple: false,
|
multiple: false,
|
||||||
objectValue: false,
|
objectValue: false,
|
||||||
manual: false,
|
manual: false,
|
||||||
mapOptions: (item) => {
|
targetField: field,
|
||||||
return {
|
mapOptions(option) {
|
||||||
...item,
|
try {
|
||||||
[collection.titleField || 'label']: `#${item.id} ${item[collection.titleField] || ''}`,
|
const label = collection?.titleField || 'id';
|
||||||
value: item.id,
|
option[label] = (
|
||||||
};
|
<>
|
||||||
|
#{option.id} {option[label]}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
return option;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return option;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fieldNames: {
|
fieldNames: {
|
||||||
label: collection.titleField || 'label',
|
label: collection?.titleField || 'id',
|
||||||
value: 'value',
|
value: 'id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'x-reactions': [
|
'x-reactions': [
|
||||||
|
Loading…
Reference in New Issue
Block a user