mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-01 18:52:20 +08:00
refactor: define and compute rules for field interface, field type, and data type
This commit is contained in:
parent
ed57a43ec9
commit
f6982f5dfe
@ -27,7 +27,7 @@ import * as components from './components';
|
||||
import { useFieldInterfaceOptions } from './interfaces';
|
||||
import { ItemType, MenuItemType } from 'antd/es/menu/interface';
|
||||
|
||||
const getSchema = (schema: CollectionFieldInterface, record: any, compile, fieldTypeOptions) => {
|
||||
const getSchema = (schema: CollectionFieldInterface, record: any, compile) => {
|
||||
if (!schema) {
|
||||
return;
|
||||
}
|
||||
@ -43,6 +43,22 @@ const getSchema = (schema: CollectionFieldInterface, record: any, compile, field
|
||||
initialValue.reverseField.name = `f_${uid()}`;
|
||||
}
|
||||
|
||||
// 基于当前选中的 fieldInterface 构建 fieldType 选项
|
||||
const fieldTypeOptions = [];
|
||||
const fieldType = schema.default?.type;
|
||||
const availableFieldTypes = schema.availableOptions?.all[schema.name][fieldType] || [];
|
||||
|
||||
if (fieldType && availableFieldTypes.length > 0) {
|
||||
fieldTypeOptions.push({
|
||||
label: fieldType,
|
||||
value: fieldType,
|
||||
children: availableFieldTypes.map((availableType) => ({
|
||||
label: availableType,
|
||||
value: availableType,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
// 设置 fieldType 默认值为第一组的最深层级路径
|
||||
if (fieldTypeOptions && fieldTypeOptions.length > 0) {
|
||||
const getFirstLeafPath = (options) => {
|
||||
@ -69,60 +85,62 @@ const getSchema = (schema: CollectionFieldInterface, record: any, compile, field
|
||||
|
||||
// initialValue.uiSchema.title = schema.title;
|
||||
return {
|
||||
type: 'object',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-component-props': {
|
||||
getContainer: '{{ getContainer }}',
|
||||
},
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
return useRequest(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
data: initialValue,
|
||||
}),
|
||||
options,
|
||||
);
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-component-props': {
|
||||
getContainer: '{{ getContainer }}',
|
||||
},
|
||||
},
|
||||
title: `${compile(record.title)} - ${compile('{{ t("Add field") }}')}`,
|
||||
properties: {
|
||||
summary: {
|
||||
type: 'void',
|
||||
'x-component': 'FieldSummary',
|
||||
'x-component-props': {
|
||||
schemaKey: schema.name,
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
return useRequest(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
data: initialValue,
|
||||
}),
|
||||
options,
|
||||
);
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
...properties,
|
||||
description: {
|
||||
type: 'string',
|
||||
title: '{{t("Description")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
},
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
action1: {
|
||||
title: '{{ t("Cancel") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useCancelAction }}',
|
||||
},
|
||||
title: `${compile(record.title)} - ${compile('{{ t("Add field") }}')}`,
|
||||
properties: {
|
||||
summary: {
|
||||
type: 'void',
|
||||
'x-component': 'FieldSummary',
|
||||
'x-component-props': {
|
||||
schemaKey: schema.name,
|
||||
},
|
||||
action2: {
|
||||
title: '{{ t("Submit") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction: '{{ useCreateCollectionField }}',
|
||||
},
|
||||
// @ts-ignore
|
||||
...properties,
|
||||
description: {
|
||||
type: 'string',
|
||||
title: '{{t("Description")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
},
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
action1: {
|
||||
title: '{{ t("Cancel") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useCancelAction }}',
|
||||
},
|
||||
},
|
||||
action2: {
|
||||
title: '{{ t("Submit") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction: '{{ useCreateCollectionField }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -130,6 +148,7 @@ const getSchema = (schema: CollectionFieldInterface, record: any, compile, field
|
||||
},
|
||||
},
|
||||
},
|
||||
fieldTypeOptions,
|
||||
};
|
||||
};
|
||||
|
||||
@ -193,6 +212,7 @@ export const AddFieldAction = (props) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [targetScope, setTargetScope] = useState();
|
||||
const [schema, setSchema] = useState({});
|
||||
const [fieldTypeOptions, setFieldTypeOptions] = useState([]);
|
||||
const compile = useCompile();
|
||||
const { t } = useTranslation();
|
||||
const { isDialect } = useDialect();
|
||||
@ -210,50 +230,6 @@ export const AddFieldAction = (props) => {
|
||||
const dm = useDataSourceManager();
|
||||
const interfaces = dm.collectionFieldInterfaceManager.getFieldInterfaces();
|
||||
|
||||
const fieldTypeOptions = useMemo(() => {
|
||||
const { availableFieldInterfaces } = getTemplate(record.template) || {};
|
||||
const { exclude, include } = (availableFieldInterfaces || {}) as any;
|
||||
|
||||
// 根据 fieldType 分组 interfaces
|
||||
const fieldTypeGroups = {};
|
||||
|
||||
interfaces.forEach((fieldInterface) => {
|
||||
// 检查是否符合模板限制
|
||||
if (include?.length && !include.includes(fieldInterface.name)) {
|
||||
return;
|
||||
}
|
||||
if (exclude?.length && exclude.includes(fieldInterface.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldType = fieldInterface.default?.type;
|
||||
const availableFieldTypes = fieldInterface.availableFieldTypes || [];
|
||||
|
||||
if (fieldType && availableFieldTypes.length > 0) {
|
||||
if (!fieldTypeGroups[fieldType]) {
|
||||
fieldTypeGroups[fieldType] = [];
|
||||
}
|
||||
|
||||
// 为每个 availableFieldType 创建选项
|
||||
availableFieldTypes.forEach((availableType) => {
|
||||
if (!fieldTypeGroups[fieldType].find((item) => item.value === availableType)) {
|
||||
fieldTypeGroups[fieldType].push({
|
||||
label: availableType,
|
||||
value: availableType,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 转换为 antd 级联组件需要的数据结构
|
||||
return Object.keys(fieldTypeGroups).map((fieldType) => ({
|
||||
label: fieldType,
|
||||
value: fieldType,
|
||||
children: fieldTypeGroups[fieldType],
|
||||
}));
|
||||
}, [interfaces, getTemplate, record, compile]);
|
||||
|
||||
const getFieldOptions = useCallback(() => {
|
||||
const { availableFieldInterfaces } = getTemplate(record.template) || {};
|
||||
const { exclude, include } = (availableFieldInterfaces || {}) as any;
|
||||
@ -355,9 +331,10 @@ export const AddFieldAction = (props) => {
|
||||
//@ts-ignore
|
||||
const targetScope = e.item.props['data-targetScope'];
|
||||
targetScope && setTargetScope(targetScope);
|
||||
const schema = getSchema(getInterface(e.key), record, compile, fieldTypeOptions);
|
||||
if (schema) {
|
||||
setSchema(schema);
|
||||
const result = getSchema(getInterface(e.key), record, compile);
|
||||
if (result) {
|
||||
setSchema(result.schema);
|
||||
setFieldTypeOptions(result.fieldTypeOptions);
|
||||
setVisible(true);
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,10 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { isArr, isEmpty, isValid } from '@formily/shared';
|
||||
import { registerValidateRules } from '@formily/validator';
|
||||
import { CollectionFieldInterface } from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
import {
|
||||
AvailableFieldOptions,
|
||||
CollectionFieldInterface,
|
||||
} from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
import { i18n } from '../../i18n';
|
||||
import { defaultProps, operators, primaryKey, unique } from './properties';
|
||||
|
||||
@ -59,7 +62,29 @@ export class InputFieldInterface extends CollectionFieldInterface {
|
||||
},
|
||||
};
|
||||
fieldType = 'string';
|
||||
availableFieldTypes = ['varchar', 'char'];
|
||||
availableOptions: AvailableFieldOptions = {
|
||||
all: {
|
||||
input: {
|
||||
string: ['varchar', 'char'],
|
||||
},
|
||||
textarea: {
|
||||
text: ['text'],
|
||||
},
|
||||
},
|
||||
available: {
|
||||
input: {
|
||||
string: {
|
||||
varchar: ['varchar'],
|
||||
char: ['varchar', 'char'],
|
||||
},
|
||||
},
|
||||
textarea: {
|
||||
text: {
|
||||
text: ['text'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
availableTypes = ['varchar', 'char'];
|
||||
hasDefaultValue = true;
|
||||
properties = {
|
||||
|
@ -10,7 +10,10 @@
|
||||
import { registerValidateFormats } from '@formily/core';
|
||||
import { i18n } from '../../i18n';
|
||||
import { defaultProps, operators, unique, autoIncrement, primaryKey } from './properties';
|
||||
import { CollectionFieldInterface } from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
import {
|
||||
AvailableFieldOptions,
|
||||
CollectionFieldInterface,
|
||||
} from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
|
||||
registerValidateFormats({
|
||||
odd: /^-?\d*[13579]$/,
|
||||
@ -37,6 +40,35 @@ export class IntegerFieldInterface extends CollectionFieldInterface {
|
||||
},
|
||||
};
|
||||
availableTypes = ['bigInt', 'integer', 'sort'];
|
||||
availableOptions: AvailableFieldOptions = {
|
||||
all: {
|
||||
integer: {
|
||||
bigInt: ['bigInt', 'tinyint', 'integer'],
|
||||
},
|
||||
number: {
|
||||
double: ['double', 'float', 'decimal'],
|
||||
},
|
||||
input: {
|
||||
string: ['varchar', 'char'],
|
||||
},
|
||||
textarea: {
|
||||
text: ['text'],
|
||||
},
|
||||
},
|
||||
available: {
|
||||
input: {
|
||||
string: {
|
||||
varchar: ['varchar'],
|
||||
char: ['varchar', 'char'],
|
||||
},
|
||||
},
|
||||
textarea: {
|
||||
text: {
|
||||
text: ['text'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
hasDefaultValue = true;
|
||||
properties = {
|
||||
...defaultProps,
|
||||
|
@ -10,7 +10,10 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { i18n } from '../../i18n';
|
||||
import { defaultProps, operators } from './properties';
|
||||
import { CollectionFieldInterface } from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
import {
|
||||
AvailableFieldOptions,
|
||||
CollectionFieldInterface,
|
||||
} from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
|
||||
export class TextareaFieldInterface extends CollectionFieldInterface {
|
||||
name = 'textarea';
|
||||
@ -27,6 +30,20 @@ export class TextareaFieldInterface extends CollectionFieldInterface {
|
||||
},
|
||||
};
|
||||
availableTypes = ['text', 'json', 'string'];
|
||||
availableOptions: AvailableFieldOptions = {
|
||||
all: {
|
||||
textarea: {
|
||||
text: ['text'],
|
||||
},
|
||||
},
|
||||
available: {
|
||||
textarea: {
|
||||
text: {
|
||||
text: ['text'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
hasDefaultValue = true;
|
||||
titleUsable = true;
|
||||
properties = {
|
||||
|
@ -13,6 +13,8 @@ import type { CollectionFieldOptions } from '../collection';
|
||||
import { CollectionFieldInterfaceManager } from './CollectionFieldInterfaceManager';
|
||||
import { defaultProps } from '../../collection-manager/interfaces/properties';
|
||||
import { tval } from '@nocobase/utils/client';
|
||||
import type { DefaultOptionType as CascaderOptionType } from 'antd/lib/cascader';
|
||||
import _ from 'lodash';
|
||||
export type CollectionFieldInterfaceFactory = new (
|
||||
collectionFieldInterfaceManager: CollectionFieldInterfaceManager,
|
||||
) => CollectionFieldInterface;
|
||||
@ -24,7 +26,23 @@ export interface CollectionFieldInterfaceComponentOption {
|
||||
useProps?: () => any;
|
||||
}
|
||||
|
||||
export type AvailableFieldTypes = string[];
|
||||
type FieldInterfaceName = string;
|
||||
type FieldTypeName = string;
|
||||
type FieldDataType = string;
|
||||
export interface AvailableFieldOptions {
|
||||
all: {
|
||||
[key: FieldInterfaceName]: {
|
||||
[key: FieldTypeName]: FieldDataType[];
|
||||
};
|
||||
};
|
||||
available: {
|
||||
[key: FieldInterfaceName]: {
|
||||
[key: FieldTypeName]: {
|
||||
[key: FieldDataType]: FieldDataType[];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export abstract class CollectionFieldInterface {
|
||||
constructor(public collectionFieldInterfaceManager: CollectionFieldInterfaceManager) {}
|
||||
@ -33,7 +51,7 @@ export abstract class CollectionFieldInterface {
|
||||
title?: string;
|
||||
description?: string;
|
||||
order?: number;
|
||||
availableFieldTypes?: AvailableFieldTypes;
|
||||
availableOptions?: AvailableFieldOptions;
|
||||
default?: {
|
||||
type: string;
|
||||
uiSchema?: ISchema;
|
||||
@ -174,4 +192,99 @@ export abstract class CollectionFieldInterface {
|
||||
|
||||
this.filterable.operators.push(operatorOption);
|
||||
}
|
||||
|
||||
getAllAvailableTypes(): string[] {
|
||||
if (!this.availableOptions?.all || !this.name) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const interfaceOptions = this.availableOptions.all[this.name];
|
||||
if (!interfaceOptions) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const allTypes: string[] = [];
|
||||
Object.values(interfaceOptions).forEach((typeArray) => {
|
||||
if (Array.isArray(typeArray)) {
|
||||
allTypes.push(...typeArray);
|
||||
}
|
||||
});
|
||||
|
||||
return [...new Set(allTypes)];
|
||||
}
|
||||
|
||||
getAvailableOptions(options: {
|
||||
currentValue: [FieldInterfaceName, ...FieldTypeName[], FieldDataType];
|
||||
interfaces: Record<string, CollectionFieldInterface>;
|
||||
compile: (v: string) => string;
|
||||
}): CascaderOptionType[] {
|
||||
const { currentValue, interfaces, compile } = options;
|
||||
const dataType = currentValue[currentValue.length - 1];
|
||||
const allAvailableOptions = this.availableOptions?.all || {};
|
||||
const availableOptions = this.availableOptions?.available || {};
|
||||
|
||||
const result = this.buildTree({
|
||||
all: allAvailableOptions,
|
||||
available: availableOptions,
|
||||
dataType,
|
||||
interfaceMap: interfaces,
|
||||
compile,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private buildTree(options: {
|
||||
all;
|
||||
available;
|
||||
dataType;
|
||||
compile: (v: string) => string;
|
||||
interfaceMap?: Record<string, CollectionFieldInterface>;
|
||||
}) {
|
||||
const { all, available, dataType, compile, interfaceMap } = options;
|
||||
if (Array.isArray(all)) {
|
||||
const allowed = Array.isArray(available?.[dataType]) ? available[dataType] : [];
|
||||
return all.map((item) => ({
|
||||
label: item,
|
||||
value: item,
|
||||
disabled: !allowed.includes(item),
|
||||
}));
|
||||
}
|
||||
|
||||
return Object.entries(all).map(([key, value]) => {
|
||||
const next = available?.[key];
|
||||
const children = this.buildTree({ all: value, available: next, dataType, compile });
|
||||
const disabled = Array.isArray(value) ? children.every((child) => child.disabled) : !next;
|
||||
const label = interfaceMap ? compile(interfaceMap[key]?.title) : key;
|
||||
return {
|
||||
label,
|
||||
value: key,
|
||||
disabled,
|
||||
children,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// validateFieldType<T extends AvailableFieldOptions>(value: string): keyof T {
|
||||
// const fieldTypes = this.availableOptions[this.name];
|
||||
// if (!(value in Object.keys(fieldTypes))) {
|
||||
// throw new Error(`Field type "${value}" is not supported by interface "${this.name}".`);
|
||||
// }
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
validateFieldDataType(fieldType: string, value: string) {
|
||||
const fieldTypes = this.availableOptions[this.name];
|
||||
if (!fieldTypes || !Array.isArray(fieldTypes)) {
|
||||
throw new Error(`Field type "${value}" is not supported by interface "${this.name}".`);
|
||||
}
|
||||
const dataTypes = Object.keys(fieldTypes).find((x) => x === fieldType);
|
||||
if (!dataTypes || !Array.isArray(dataTypes)) {
|
||||
throw new Error(`Field type "${dataTypes}" is not supported by interface "${this.name}".`);
|
||||
}
|
||||
const newValue = dataTypes.find((x) => x === value);
|
||||
newValue;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import { FieldContext, FormContext, useField } from '@formily/react';
|
||||
import {
|
||||
Action,
|
||||
AddCollectionField,
|
||||
CollectionFieldInterface,
|
||||
EditCollectionField,
|
||||
Input,
|
||||
isDeleteButtonDisabled,
|
||||
@ -79,15 +80,12 @@ const tableContainer = css`
|
||||
flex: 1.5;
|
||||
width: 0;
|
||||
&:nth-child(4) {
|
||||
flex: 1.8; /* Field interface column */
|
||||
flex: 2.5; /* Combined Field interface + type column */
|
||||
}
|
||||
&:nth-child(5) {
|
||||
flex: 1.8; /* Field type column */
|
||||
}
|
||||
&:nth-child(6) {
|
||||
flex: 1.2; /* Title field column */
|
||||
}
|
||||
&:nth-child(7) {
|
||||
&:nth-child(6) {
|
||||
flex: 2; /* Description column */
|
||||
}
|
||||
&:last-child {
|
||||
@ -108,48 +106,17 @@ const tableContainer = css`
|
||||
|
||||
const titlePrompt = 'Default title for each record';
|
||||
|
||||
const convertFieldTypeToOptions = (fieldType: string[]) => {
|
||||
if (!fieldType || !Array.isArray(fieldType) || fieldType.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const fieldTypeHierarchy = {
|
||||
string: [
|
||||
{ label: 'varchar', value: 'varchar' },
|
||||
{ label: 'char', value: 'char' },
|
||||
{ label: 'text', value: 'text' },
|
||||
],
|
||||
integer: [
|
||||
{ label: 'int', value: 'int' },
|
||||
{ label: 'bigint', value: 'bigint' },
|
||||
{ label: 'smallint', value: 'smallint' },
|
||||
],
|
||||
float: [
|
||||
{ label: 'decimal', value: 'decimal' },
|
||||
{ label: 'double', value: 'double' },
|
||||
],
|
||||
boolean: [{ label: 'boolean', value: 'boolean' }],
|
||||
date: [
|
||||
{ label: 'date', value: 'date' },
|
||||
{ label: 'datetime', value: 'datetime' },
|
||||
{ label: 'timestamp', value: 'timestamp' },
|
||||
],
|
||||
};
|
||||
|
||||
if (fieldType.length >= 1) {
|
||||
const firstLevel = fieldType[0];
|
||||
const children = fieldTypeHierarchy[firstLevel] || [];
|
||||
|
||||
return [
|
||||
{
|
||||
label: firstLevel,
|
||||
value: firstLevel,
|
||||
children: children.length > 0 ? children : undefined,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
// Field Interface -> Field Type -> Data Type
|
||||
const createFieldTypeOptions = (
|
||||
currentValue: [string, ...string[], string],
|
||||
getInterface: (name: string) => CollectionFieldInterface,
|
||||
interfaces: Record<string, CollectionFieldInterface>,
|
||||
compile,
|
||||
) => {
|
||||
const [interfaceName] = currentValue;
|
||||
const currentInterface = getInterface(interfaceName);
|
||||
const options = currentInterface.getAvailableOptions({ currentValue, interfaces, compile });
|
||||
return options;
|
||||
};
|
||||
|
||||
const CurrentFields = (props) => {
|
||||
@ -178,60 +145,23 @@ const CurrentFields = (props) => {
|
||||
{
|
||||
dataIndex: 'interface',
|
||||
title: t('Field interface'),
|
||||
render: (value, record) => {
|
||||
const handleChange = async (selectedInterface) => {
|
||||
try {
|
||||
await api.request({
|
||||
url: `collections.fields:update?filterByTk=${record.name}&associatedIndex=${filterByTk}`,
|
||||
method: 'post',
|
||||
data: { interface: selectedInterface },
|
||||
});
|
||||
ctx?.refresh?.();
|
||||
await props.refreshAsync();
|
||||
refreshCM();
|
||||
message.success(t('Saved successfully'));
|
||||
} catch (error) {
|
||||
console.error('Failed to update field interface:', error);
|
||||
message.error(t('Save failed'));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
placeholder={t('Select field interface')}
|
||||
size="small"
|
||||
style={{ width: '100%', minWidth: 120 }}
|
||||
disabled={targetTemplate?.forbidDeletion}
|
||||
showSearch
|
||||
filterOption={(input, option) => {
|
||||
const label = option?.children || '';
|
||||
return String(label).toLowerCase().includes(input.toLowerCase());
|
||||
}}
|
||||
>
|
||||
{Object.keys(interfaces).map((interfaceKey) => {
|
||||
const interfaceItem = interfaces[interfaceKey];
|
||||
return (
|
||||
<Select.Option key={interfaceKey} value={interfaceKey}>
|
||||
{compile(interfaceItem.title)}
|
||||
</Select.Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'fieldType',
|
||||
title: t('Field type'),
|
||||
render: (value, record) => {
|
||||
const handleChange = async (selectedValues) => {
|
||||
try {
|
||||
const [interfaceValue, fieldTypeValue, dataTypeValue] = selectedValues || [];
|
||||
|
||||
const updateData: any = {};
|
||||
if (interfaceValue) {
|
||||
updateData.interface = interfaceValue;
|
||||
}
|
||||
if (fieldTypeValue || dataTypeValue) {
|
||||
updateData.fieldType = selectedValues;
|
||||
}
|
||||
|
||||
// await api.request({
|
||||
// url: `collections.fields:update?filterByTk=${record.name}&associatedIndex=${filterByTk}`,
|
||||
// method: 'post',
|
||||
// data: { fieldType: selectedValues },
|
||||
// data: updateData,
|
||||
// });
|
||||
ctx?.refresh?.();
|
||||
await props.refreshAsync();
|
||||
@ -243,20 +173,26 @@ const CurrentFields = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
return value && Array.isArray(value) && value.length > 0 ? (
|
||||
const currentValue: any = []; // [interface, fieldType, dataType]
|
||||
if (value) {
|
||||
currentValue.push(value);
|
||||
if (record.fieldType && Array.isArray(record.fieldType) && record.fieldType.length > 0) {
|
||||
currentValue.push(...record.fieldType);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Cascader
|
||||
value={value}
|
||||
options={convertFieldTypeToOptions(value)}
|
||||
value={currentValue.length > 0 ? currentValue : undefined}
|
||||
options={createFieldTypeOptions(currentValue, getInterface, interfaces, compile)}
|
||||
onChange={handleChange}
|
||||
placeholder={t('Select field type')}
|
||||
expandTrigger="hover"
|
||||
changeOnSelect={true}
|
||||
size="small"
|
||||
style={{ width: '100%', minWidth: 120 }}
|
||||
changeOnSelect={false}
|
||||
style={{ width: '100%', minWidth: 100 }}
|
||||
disabled={targetTemplate?.forbidDeletion}
|
||||
showSearch
|
||||
/>
|
||||
) : (
|
||||
<span style={{ color: '#ccc' }}>-</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
@ -351,7 +287,7 @@ const CurrentFields = (props) => {
|
||||
|
||||
const InheritFields = (props) => {
|
||||
const compile = useCompile();
|
||||
const { getInterface } = useCollectionManager_deprecated();
|
||||
const { getInterface, interfaces } = useCollectionManager_deprecated();
|
||||
const { targetKey } = props.collectionResource || {};
|
||||
const parentRecord = useRecord();
|
||||
const [loadingRecord, setLoadingRecord] = React.useState(null);
|
||||
@ -371,29 +307,29 @@ const InheritFields = (props) => {
|
||||
dataIndex: 'name',
|
||||
title: t('Field name'),
|
||||
},
|
||||
{
|
||||
dataIndex: 'interface',
|
||||
title: t('Field interface'),
|
||||
render: (value) => <Tag>{compile(getInterface(value)?.title)}</Tag>,
|
||||
},
|
||||
{
|
||||
dataIndex: 'fieldType',
|
||||
title: t('Field type'),
|
||||
render: (value) => {
|
||||
return value && Array.isArray(value) && value.length > 0 ? (
|
||||
render: (value, record) => {
|
||||
const currentValue: any = []; // [interface, fieldType, dataType]
|
||||
if (record.interface) {
|
||||
currentValue.push(record.interface);
|
||||
if (value && Array.isArray(value) && value.length > 0) {
|
||||
currentValue.push(...value);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Cascader
|
||||
value={value}
|
||||
options={convertFieldTypeToOptions(value)}
|
||||
value={currentValue.length > 0 ? currentValue : undefined}
|
||||
options={createFieldTypeOptions(currentValue, getInterface, interfaces, compile)}
|
||||
placeholder={t('Select field type')}
|
||||
expandTrigger="hover"
|
||||
changeOnSelect={true}
|
||||
changeOnSelect={false}
|
||||
size="small"
|
||||
style={{ width: '100%', minWidth: 120 }}
|
||||
style={{ width: '100%', minWidth: 150 }}
|
||||
disabled={true}
|
||||
open={false}
|
||||
/>
|
||||
) : (
|
||||
<span style={{ color: '#ccc' }}>-</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
@ -498,10 +434,6 @@ const CollectionFieldsInternal = () => {
|
||||
dataIndex: 'name',
|
||||
title: t('Field name'),
|
||||
},
|
||||
{
|
||||
dataIndex: 'interface',
|
||||
title: t('Field interface'),
|
||||
},
|
||||
{
|
||||
dataIndex: 'fieldType',
|
||||
title: t('Field type'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user