fix: 数据源构造器 & Form & CRUD2 & Service相关问题修复 (#8002)

This commit is contained in:
RUNZE LU 2023-09-04 15:56:02 +08:00 committed by GitHub
parent 60bacb2cc2
commit 03bf01fc30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 588 additions and 246 deletions

View File

@ -5,5 +5,5 @@
"packages/amis-ui",
"packages/amis"
],
"version": "3.4.0"
"version": "3.4.0-alpha.4"
}

View File

@ -1,6 +1,6 @@
{
"name": "amis-core",
"version": "3.4.0",
"version": "3.4.0-alpha.4",
"description": "amis-core",
"main": "lib/index.js",
"module": "esm/index.js",
@ -46,7 +46,7 @@
"esm"
],
"dependencies": {
"amis-formula": "^3.4.0",
"amis-formula": "^3.4.0-alpha.4",
"classnames": "2.3.2",
"file-saver": "^2.0.2",
"hoist-non-react-statics": "^3.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "amis-editor-core",
"version": "5.5.0",
"version": "5.5.1-alpha.8",
"description": "amis 可视化编辑器",
"main": "lib/index.js",
"module": "esm/index.js",

View File

@ -36,6 +36,7 @@
display: flex;
align-items: center;
justify-content: flex-start;
max-width: 140px;
& > span {
max-width: 100%;
@ -85,6 +86,7 @@
height: #{px2rem(20px)};
margin-right: #{px2rem(8px)};
scale: 0.9;
max-width: 80px;
&--cascading {
color: #531dab;

View File

@ -8,5 +8,6 @@
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: baseline;
}
}

View File

@ -41,6 +41,7 @@
@import './control/_status';
@import './control/_icon-button-group-control';
@import './control/_flex-setting-control';
@import './control/table-column-width-control.scss';
@import './control/crud2-control';
/* 样式控件 */

View File

@ -230,6 +230,37 @@ export class EditorManager {
// 自动加载预先注册的自定义组件
autoPreRegisterEditorCustomPlugins();
/** 在顶层对外部注册的Plugin和builtInPlugins合并去重 */
const externalPlugins = (config?.plugins || []).forEach(external => {
if (
Array.isArray(external) ||
!external.priority ||
!Number.isInteger(external.priority)
) {
return;
}
const idx = builtInPlugins.findIndex(
builtIn =>
!Array.isArray(builtIn) &&
!Array.isArray(external) &&
builtIn.id === external.id &&
builtIn?.prototype instanceof BasePlugin
);
if (~idx) {
const current = builtInPlugins[idx] as PluginClass;
const currentPriority =
current.priority && Number.isInteger(current.priority)
? current.priority
: 0;
/** 同ID Plugin根据优先级决定是否替换掉Builtin中的Plugin */
if (external.priority > currentPriority) {
builtInPlugins.splice(idx, 1);
}
}
});
this.plugins = (config.disableBultinPlugin ? [] : builtInPlugins) // 页面设计器注册的插件列表
.concat(this.normalizeScene(config?.plugins))
.filter(p => {

View File

@ -1,6 +1,6 @@
{
"name": "amis-editor",
"version": "5.5.0",
"version": "5.5.1-alpha.8",
"description": "amis 可视化编辑器",
"main": "lib/index.js",
"module": "esm/index.js",

View File

@ -277,7 +277,22 @@ export class ApiDSBuilder extends DSBuilder<
)}</pre>`
)
})
: null
: null,
/** CRUD的快速编辑接口 */
...(feat === 'List' && renderer === 'crud' && !inScaffold
? [
getSchemaTpl('apiControl', {
...baseApiSchemaConfig,
name: 'quickSaveApi',
label: tipedLabel('快速保存', '快速编辑后用来批量保存的 API')
}),
getSchemaTpl('apiControl', {
...baseApiSchemaConfig,
name: 'quickSaveItemApi',
label: tipedLabel('快速保存单条', '即时保存时使用的 API')
})
]
: [])
].filter(Boolean);
}
@ -300,7 +315,7 @@ export class ApiDSBuilder extends DSBuilder<
label: renderLabel === false ? false : '字段',
renderer,
feat,
options: {
config: {
showInputType:
renderer === 'form' ||
(renderer === 'crud' &&
@ -374,7 +389,7 @@ export class ApiDSBuilder extends DSBuilder<
label: key,
name: key,
displayType: 'tpl',
inputType: inputType,
inputType,
checked: true
});
});
@ -455,6 +470,7 @@ export class ApiDSBuilder extends DSBuilder<
actions: [
{
actionType: 'search',
groupType: 'component',
componentId: componentId
}
]
@ -529,20 +545,21 @@ export class ApiDSBuilder extends DSBuilder<
buildBaseFormSchema(
options: ApiDSBuilderOptions<DSRendererType>,
schemaPatch?: GenericSchema
schemaPatch?: GenericSchema,
componentId?: string
) {
schemaPatch = schemaPatch || {};
const {feat, renderer, scaffoldConfig} = options || {};
if (!feat) {
return {...schemaPatch};
return {...schemaPatch, ...(componentId ? {id: componentId} : {})};
}
const fieldsKey = this.getFieldsKey(options);
const apiKey = this.getApiKey(options);
const fields: ScaffoldField[] = (scaffoldConfig as any)?.[fieldsKey] ?? [];
const apiSchema = (scaffoldConfig as any)?.[apiKey];
const id = generateNodeId();
const id = componentId ?? generateNodeId();
let schema: GenericSchema = {
id,
type: 'form',
@ -580,7 +597,7 @@ export class ApiDSBuilder extends DSBuilder<
schema.static = true;
}
return {...schema, ...schemaPatch};
return {...schema, ...schemaPatch, id};
}
async buildInsertSchema<T extends DSRendererType>(
@ -591,10 +608,10 @@ export class ApiDSBuilder extends DSBuilder<
const {insertApi} = scaffoldConfig || {};
if (renderer === 'form') {
return this.buildBaseFormSchema({...options});
return this.buildBaseFormSchema({...options}, undefined, componentId);
}
const formId = generateNodeId();
const formId = componentId ?? generateNodeId();
const formActions = [
{
type: 'button',
@ -693,7 +710,7 @@ export class ApiDSBuilder extends DSBuilder<
const isForm = renderer === 'form';
if (isForm) {
return this.buildBaseFormSchema(options);
return this.buildBaseFormSchema(options, undefined, componentId);
}
const {editApi, initApi} = scaffoldConfig || {};
@ -750,7 +767,7 @@ export class ApiDSBuilder extends DSBuilder<
const isForm = renderer === 'form';
if (isForm) {
return this.buildBaseFormSchema(options);
return this.buildBaseFormSchema(options, undefined, componentId);
}
const formId = generateNodeId();
@ -816,15 +833,14 @@ export class ApiDSBuilder extends DSBuilder<
actions: [
{
actionType: 'ajax',
args: {
api: deleteApi,
data: {
'&': '$$'
}
api: deleteApi,
data: {
'&': '$$'
}
},
{
actionType: 'search',
groupType: 'component',
componentId: componentId
}
]
@ -855,12 +871,11 @@ export class ApiDSBuilder extends DSBuilder<
actions: [
{
actionType: 'ajax',
args: {
api: bulkDeleteApi
}
api: bulkDeleteApi
},
{
actionType: 'search',
groupType: 'component',
componentId: componentId
}
]
@ -1265,18 +1280,22 @@ export class ApiDSBuilder extends DSBuilder<
const actions = get(host, 'onEvent.click.actions', []);
const actionSchema = actions.find(
(action: any) =>
action?.actionType === 'ajax' && action?.args?.api != null
action?.actionType === 'ajax' &&
(action?.api != null || action?.args?.api != null)
);
bulkDeleteApi = get(actionSchema, 'args.api', '');
bulkDeleteApi =
get(actionSchema, 'api', '') || get(actionSchema, 'args.api', '');
} else if (value === 'Delete') {
feats.push('Delete');
const actions = get(host, 'onEvent.click.actions', []);
const actionSchema = actions.find(
(action: any) =>
action?.actionType === 'ajax' && action?.args?.api != null
action?.actionType === 'ajax' &&
(action?.api != null || action?.args?.api != null)
);
deleteApi = get(actionSchema, 'args.api', '');
deleteApi =
get(actionSchema, 'api', '') || get(actionSchema, 'args.api', '');
} else if (Array.isArray(value) && value.includes('SimpleQuery')) {
feats.push('SimpleQuery');
@ -1384,13 +1403,14 @@ export class ApiDSBuilder extends DSBuilder<
const {feat, scaffoldConfig} = options;
const {initApi, __pristineSchema} = scaffoldConfig || {};
let formSchema: GenericSchema;
const id = __pristineSchema?.id ?? generateNodeId();
if (feat === 'Insert') {
formSchema = await this.buildInsertSchema<'form'>(options);
formSchema = await this.buildInsertSchema<'form'>(options, id);
} else if (feat === 'Edit') {
formSchema = await this.buildEditSchema(options);
formSchema = await this.buildEditSchema(options, id);
} else {
formSchema = await this.buildBulkEditSchema(options);
formSchema = await this.buildBulkEditSchema(options, id);
}
const baseSchema = {
@ -1400,8 +1420,6 @@ export class ApiDSBuilder extends DSBuilder<
};
if (__pristineSchema && isObject(__pristineSchema)) {
const id = __pristineSchema.id ?? generateNodeId();
return {
...__pristineSchema,
...baseSchema,

View File

@ -51,12 +51,12 @@ export interface DSBuilderInterface<
/** 是否为默认 */
isDefault?: boolean;
/** 是否默认隐藏 */
defaultHidden?: boolean;
/** 实例获取数据源的key */
key: string;
/** 是否禁用 */
disabledOn?: () => boolean;
/** 获取功能场景的value */
getFeatValueByKey(feat: DSFeatureType): string;
@ -185,7 +185,7 @@ export abstract class DSBuilder<T extends DSBuilderBaseOptions>
readonly order: number;
/** 是否为默认 */
readonly isDefault?: boolean;
defaultHidden?: boolean;
features: DSFeatureType[];
constructor(readonly manager: EditorManager) {}

View File

@ -43,7 +43,9 @@ export class DSBuilderManager {
}
getDefaultBuilderKey() {
const collections = Array.from(this.builders.entries());
const collections = Array.from(this.builders.entries()).filter(
([_, builder]) => builder?.disabledOn?.() !== true
);
const [defaultKey, _] =
collections.find(([_, builder]) => builder.isDefault === true) ??
collections.sort((lhs, rhs) => {
@ -55,17 +57,22 @@ export class DSBuilderManager {
}
getDefaultBuilder() {
const collections = Array.from(this.builders.entries()).filter(
([_, builder]) => builder?.disabledOn?.() !== true
);
const [_, defaultBuilder] =
Array.from(this.builders.entries()).find(
([_, builder]) => builder.isDefault === true
) ?? [];
collections.find(([_, builder]) => builder.isDefault === true) ??
collections.sort((lhs, rhs) => {
return (lhs[1].order ?? 0) - (rhs[1].order ?? 0);
})?.[0] ??
[];
return defaultBuilder!;
return defaultBuilder;
}
getAvailableBuilders() {
return Array.from(this.builders.entries())
.filter(item => item[1]?.defaultHidden !== true)
.filter(([_, builder]) => builder?.disabledOn?.() !== true)
.sort((lhs, rhs) => {
return (lhs[1].order ?? 0) - (rhs[1].order ?? 0);
});

View File

@ -4,6 +4,7 @@
*/
import React from 'react';
import cx from 'classnames';
import isFunction from 'lodash/isFunction';
import flattenDeep from 'lodash/flattenDeep';
import cloneDeep from 'lodash/cloneDeep';
@ -12,7 +13,7 @@ import uniqBy from 'lodash/uniqBy';
import get from 'lodash/get';
import uniq from 'lodash/uniq';
import sortBy from 'lodash/sortBy';
import {toast, autobind, isObject} from 'amis';
import {toast, autobind, isObject, Icon} from 'amis';
import {
BasePlugin,
ScaffoldForm,
@ -46,9 +47,8 @@ import type {CRUDScaffoldConfig} from '../../builder/type';
/** 需要动态控制的属性 */
export type CRUD2DynamicControls = Partial<
Record<
'columns' | 'toolbar' | 'filters',
| Record<string, any>
| ((context: BuildPanelEventContext) => Record<string, any>)
'columns' | 'toolbar' | 'filters' | 'primaryField',
(context: BuildPanelEventContext) => any
>
>;
export class BaseCRUDPlugin extends BasePlugin {
@ -214,7 +214,9 @@ export class BaseCRUDPlugin extends BasePlugin {
};
}
),
getSchemaTpl('primaryField')
getSchemaTpl('primaryField', {
visibleOn: `!data.dsType || data.dsType !== '${ModelDSBuilderKey}'`
})
]
},
{
@ -332,7 +334,8 @@ export class BaseCRUDPlugin extends BasePlugin {
return errors;
}
const fieldErrors = FieldSetting.validator(form.data[fieldsKey]);
const fieldErrors = false;
// FieldSetting.validator(form.data[fieldsKey]);
if (fieldErrors) {
errors[fieldsKey] = fieldErrors;
@ -441,7 +444,9 @@ export class BaseCRUDPlugin extends BasePlugin {
/** 工具栏配置 */
toolbar: context => this.renderToolbarCollapse(context),
/** 搜索栏 */
filters: context => this.renderFiltersCollapse(context)
filters: context => this.renderFiltersCollapse(context),
/** 主键 */
primaryField: context => getSchemaTpl('primaryField')
};
/** 需要动态控制的控件 */
@ -494,7 +499,10 @@ export class BaseCRUDPlugin extends BasePlugin {
/** 其他类别 */
this.renderOthersCollapse(context),
/** 状态类别 */
getSchemaTpl('status', {readonly: false})
{
title: '状态',
body: [getSchemaTpl('hidden'), getSchemaTpl('visible')]
}
].filter(Boolean)
)
]
@ -503,6 +511,9 @@ export class BaseCRUDPlugin extends BasePlugin {
/** 基础配置 */
renderBasicPropsCollapse(context: BuildPanelEventContext) {
/** 动态加载的配置集合 */
const dc = this.dynamicControls;
return {
title: '基本',
order: 1,
@ -552,7 +563,7 @@ export class BaseCRUDPlugin extends BasePlugin {
};
}),
/** 主键配置TODO支持联合主键 */
getSchemaTpl('primaryField'),
dc?.primaryField?.(context),
{
name: 'placeholder',
pipeIn: defaultValue('暂无数据'),
@ -653,12 +664,15 @@ export class BaseCRUDPlugin extends BasePlugin {
/** 分页类别 */
renderPaginationCollapse(context: BuildPanelEventContext) {
const isPagination = 'data.loadType === "pagination"';
const isInfinity = 'data.loadType === "more"';
return {
order: 30,
title: '分页设置',
body: [
{
label: '更多模式',
label: '分页模式',
type: 'select',
name: 'loadType',
options: [
@ -725,20 +739,55 @@ export class BaseCRUDPlugin extends BasePlugin {
getSchemaTpl('switch', {
name: 'loadDataOnce',
label: '前端分页',
visibleOn: 'data.loadType === "pagination"'
visibleOn: isPagination
}),
getSchemaTpl('switch', {
name: 'loadDataOnceFetchOnFilter',
label: tipedLabel(
'过滤时刷新',
'在开启前端分页时,表头过滤后是否重新请求初始化 API'
),
visibleOn: isPagination + ' && data.loadDataOnce'
}),
getSchemaTpl('switch', {
name: 'keepItemSelectionOnPageChange',
label: tipedLabel(
'保留选择项',
'默认切换页面、搜索后,用户选择项会被清空,开启此功能后会保留用户选择,可以实现跨页面批量操作。'
),
pipeIn: defaultValue(false),
visibleOn: isPagination
}),
getSchemaTpl('switch', {
name: 'autoJumpToTopOnPagerChange',
label: tipedLabel('翻页后回到顶部', '当切分页的时候,是否自动跳顶部'),
pipeIn: defaultValue(true),
visibleOn: isPagination
}),
{
name: 'perPage',
type: 'input-number',
label: tipedLabel(
'每页数量',
'无限加载时,根据此项设置其每页加载数量,留空即不限制'
),
clearValueOnEmpty: true,
clearable: true,
pipeIn: defaultValue(10),
visibleOn: isInfinity
},
{
type: 'button',
label: '点击编辑分页组件',
block: true,
className: 'm-b',
className: 'mb-1',
level: 'enhance',
// icon: 'fa fa-plus',
visibleOn: 'data.loadType === "pagination"',
onClick: () => {
const findPage: any = findSchema(
context?.schema ?? context?.node?.schema ?? {},
item => item.type === 'pagination',
context?.node?.schema ?? {},
item =>
item.type === 'pagination' || item.behavior === 'Pagination',
'headerToolbar',
'footerToolbar'
);
@ -749,26 +798,7 @@ export class BaseCRUDPlugin extends BasePlugin {
}
this.manager.setActiveId(findPage.$$id);
}
},
{
name: 'perPage',
type: 'input-number',
label: '每页数量',
visibleOn: 'data.loadType === "more"'
},
getSchemaTpl('switch', {
name: 'keepItemSelectionOnPageChange',
label: tipedLabel(
'保留选择项',
'默认切换页面、搜索后,用户选择项会被清空,开启此功能后会保留用户选择,可以实现跨页面批量操作。'
),
visibleOn: 'data.loadType === "pagination"'
}),
getSchemaTpl('switch', {
name: 'autoJumpToTopOnPagerChange',
label: tipedLabel('翻页后回到顶部', '当切分页的时候,是否自动跳顶部'),
visibleOn: 'data.loadType === "pagination"'
})
}
]
};
}
@ -779,27 +809,47 @@ export class BaseCRUDPlugin extends BasePlugin {
order: 25,
title: '其他',
body: [
getSchemaTpl('interval', {
formItems: [
getSchemaTpl('switch', {
name: 'silentPolling',
label: '静默拉取',
pipeIn: defaultValue(false)
})
],
intervalConfig: {
control: {
type: 'input-number',
name: 'interval'
}
},
switchMoreConfig: {
isChecked: (e: any) => {
return !!get(e.data, 'interval');
},
autoFocus: false,
trueValue: 10000
{
type: 'ae-switch-more',
mode: 'normal',
formType: 'extend',
visibleOn: 'data.api',
label: tipedLabel(
'接口轮询',
'开启初始化接口轮询,开启后会按照设定的时间间隔轮询调用接口'
),
autoFocus: false,
form: {
body: [
{
type: 'input-number',
name: 'interval',
label: tipedLabel('轮询间隔', '定时刷新间隔,单位 ms'),
step: 10,
min: 1000
},
getSchemaTpl('tplFormulaControl', {
name: 'stopAutoRefreshWhen',
label: tipedLabel(
'停止条件',
'定时刷新停止表达式,条件满足后则停止定时刷新,否则会持续轮询调用初始化接口。'
),
visibleOn: '!!data.interval'
}),
getSchemaTpl('switch', {
name: 'stopAutoRefreshWhenModalIsOpen',
label: tipedLabel(
'模态窗口期间停止',
'当页面中存在弹窗时停止接口轮询,避免中断操作'
)
})
]
}
},
getSchemaTpl('switch', {
name: 'silentPolling',
label: tipedLabel('静默拉取', '刷新时是否隐藏加载动画'),
pipeIn: defaultValue(false)
})
]
};
@ -821,12 +871,12 @@ export class BaseCRUDPlugin extends BasePlugin {
getSchemaTpl('className', {
name: 'headerToolbarClassName',
label: '顶部外层'
label: '顶部工具栏'
}),
getSchemaTpl('className', {
name: 'footerToolbarClassName',
label: '底部外层'
label: '底部工具栏'
})
]
})
@ -848,6 +898,30 @@ export class BaseCRUDPlugin extends BasePlugin {
};
}
/** 重新构建 API */
panelFormPipeOut = async (schema: any) => {
const entity = schema?.api?.entity;
if (!entity || schema?.dsType !== ModelDSBuilderKey) {
return schema;
}
const builder = this.dsManager.getBuilderBySchema(schema);
try {
const updatedSchema = await builder.buildApiSchema({
schema,
renderer: 'crud',
sourceKey: 'api'
});
return updatedSchema;
} catch (e) {
console.error(e);
}
return schema;
};
emptyContainer = (align?: 'left' | 'right', body: any[] = []) => ({
type: 'container',
body,

View File

@ -1,4 +1,4 @@
import {setVariable} from 'amis-core';
import {setVariable, someTree} from 'amis-core';
import {
BaseEventContext,
BasePlugin,

View File

@ -1,7 +1,7 @@
import cx from 'classnames';
import flatten from 'lodash/flatten';
import cloneDeep from 'lodash/cloneDeep';
import {isObject, someTree} from 'amis-core';
import {isObject} from 'amis-core';
import {
BasePlugin,
tipedLabel,
@ -13,8 +13,6 @@ import {
defaultValue,
getSchemaTpl,
jsonToJsonSchema,
BuildPanelEventContext,
BasicPanelItem,
RendererPluginAction,
RendererPluginEvent,
EditorNodeType,
@ -34,12 +32,17 @@ import {getEventControlConfig} from '../../renderer/event-control/helper';
import {FieldSetting} from '../../renderer/FieldSetting';
import type {FormSchema} from 'amis/lib/Schema';
import type {IFormStore, IFormItemStore, RendererConfig, Schema} from 'amis-core';
import type {
IFormStore,
IFormItemStore,
Schema,
RendererConfig
} from 'amis-core';
import type {FormScaffoldConfig} from '../../builder';
export type FormPluginFeat = Extract<
DSFeatureType,
'Insert' | 'Edit' | 'BulkEdit'
'Insert' | 'Edit' | 'BulkEdit' | 'View'
>;
export interface ExtendFormSchema extends FormSchema {
@ -70,7 +73,7 @@ export class FormPlugin extends BasePlugin {
$schema = '/schemas/FormSchema.json';
tags = ['功能', '数据容器'];
tags = ['数据容器'];
order = -900;
@ -365,7 +368,7 @@ export class FormPlugin extends BasePlugin {
}> = [
{label: '新增', value: DSFeatureEnum.Insert},
{label: '编辑', value: DSFeatureEnum.Edit},
{label: '批量编辑', value: DSFeatureEnum.BulkEdit},
{label: '批量编辑', value: DSFeatureEnum.BulkEdit, disabled: true},
{label: '查看', value: DSFeatureEnum.View, disabled: true}
];
@ -380,6 +383,8 @@ export class FormPlugin extends BasePlugin {
/** 表单脚手架 */
get scaffoldForm(): ScaffoldForm {
const features = this.Features.filter(f => !f.disabled);
return {
title: '表单创建向导',
mode: {
@ -396,7 +401,7 @@ export class FormPlugin extends BasePlugin {
name: 'feat',
label: '使用场景',
value: DSFeatureEnum.Insert,
options: this.Features,
options: features,
onChange: (
value: FormPluginFeat,
oldValue: FormPluginFeat,
@ -462,7 +467,7 @@ export class FormPlugin extends BasePlugin {
}),
/** 数据源相关配置 */
...flatten(
this.Features.map(feat =>
features.map(feat =>
this.dsManager.buildCollectionFromBuilders(
(builder, builderKey) => {
return {
@ -944,6 +949,24 @@ export class FormPlugin extends BasePlugin {
defaultValue: 'normal'
}),
getSchemaTpl('horizontal'),
{
name: 'labelAlign',
label: '标签对齐方式',
type: 'button-group-select',
size: 'sm',
visibleOn: "${mode === 'horizontal'}",
pipeIn: defaultValue('right', false),
options: [
{
label: '左对齐',
value: 'left'
},
{
label: '右对齐',
value: 'right'
}
]
},
{
label: '列数',
name: 'columnCount',
@ -1033,6 +1056,31 @@ export class FormPlugin extends BasePlugin {
];
};
/** 重新构建 API */
panelFormPipeOut = async (schema: any) => {
const entity = schema?.api?.entity;
if (!entity || schema?.dsType !== ModelDSBuilderKey) {
return schema;
}
const builder = this.dsManager.getBuilderBySchema(schema);
try {
const updatedSchema = await builder.buildApiSchema({
schema,
renderer: 'form',
sourceKey: 'api',
feat: schema.feat ?? 'Insert'
});
return updatedSchema;
} catch (e) {
console.error(e);
}
return schema;
};
afterUpdate(event: PluginEvent<ChangeEventContext>) {
const context = event.context;

View File

@ -1064,12 +1064,14 @@ export class TableControlPlugin extends BasePlugin {
filterProps(props: any) {
const arr = resolveArrayDatasource(props);
/** 可 */
if (!Array.isArray(arr) || !arr.length) {
const mockedData: any = {};
if (Array.isArray(props.columns)) {
props.columns.forEach((column: any) => {
if (column.name) {
/** 可编辑状态下不写入 Mock 数据,避免误导用户 */
if (column.name && !props.editable) {
setVariable(mockedData, column.name, mockValue(column));
}
});

View File

@ -7,6 +7,7 @@ import {
getSchemaTpl,
registerEditorPlugin
} from 'amis-editor-core';
import sortBy from 'lodash/sortBy';
import {getEventControlConfig} from '../renderer/event-control/helper';
export class PaginationPlugin extends BasePlugin {
@ -131,15 +132,29 @@ export class PaginationPlugin extends BasePlugin {
}
],
pipeIn: (value: any) => {
if (!value) {
value = this.lastLayoutSetting;
} else if (typeof value === 'string') {
if (typeof value === 'string') {
value = (value as string).split(',');
} else if (!value || !Array.isArray(value)) {
value = this.lastLayoutSetting;
}
return this.layoutOptions.map(v => ({
...v,
checked: value.includes(v.value)
}));
return sortBy(
this.layoutOptions.map(op => ({
...op,
checked: value.includes(op.value)
})),
[
item => {
const idx = value.findIndex(v => v === item.value);
return ~idx ? idx : Infinity;
}
]
);
// return this.layoutOptions.map(v => ({
// ...v,
// checked: value.includes(v.value)
// }));
},
pipeOut: (value: any[]) => {
this.lastLayoutSetting = value
@ -191,7 +206,7 @@ export class PaginationPlugin extends BasePlugin {
}),
{
name: 'perPage',
type: 'input-text',
type: 'input-number',
label: '默认每页条数',
visibleOn:
'(!data.mode || data.mode === "normal") && data.layout?.includes("perPage")'
@ -212,7 +227,11 @@ export class PaginationPlugin extends BasePlugin {
},
{
title: '状态',
body: [getSchemaTpl('disabled')]
body: [
getSchemaTpl('disabled'),
getSchemaTpl('hidden'),
getSchemaTpl('visible')
]
}
])
},

View File

@ -328,6 +328,29 @@ export class ServicePlugin extends BasePlugin {
]);
};
panelFormPipeOut = async (schema: any) => {
const entity = schema?.api?.entity;
if (!entity || schema?.dsType !== ModelDSBuilderKey) {
return schema;
}
const builder = this.dsManager.getBuilderBySchema(schema);
try {
const updatedSchema = await builder.buildApiSchema({
schema,
renderer: 'service',
sourceKey: 'api'
});
return updatedSchema;
} catch (e) {
console.error(e);
}
return schema;
};
async buildDataSchemas(
node: EditorNodeType,
region?: EditorNodeType,
@ -358,29 +381,6 @@ export class ServicePlugin extends BasePlugin {
return jsonschema;
}
panelFormPipeOut = async (schema: any) => {
const entity = schema?.api?.entity;
if (!entity || schema?.dsType !== ModelDSBuilderKey) {
return schema;
}
const builder = this.dsManager.getBuilderBySchema(schema);
try {
const updatedSchema = await builder.buildApiSchema({
schema,
renderer: 'service',
sourceKey: 'api'
});
return updatedSchema;
} catch (e) {
console.error(e);
}
return schema;
};
rendererBeforeDispatchEvent(node: EditorNodeType, e: any, data: any) {
if (e === 'fetchInited') {
const scope = this.manager.dataSchema.getScope(`${node.id}-${node.type}`);

View File

@ -297,6 +297,7 @@ export type Table2DynamicControls = Partial<
| 'quickSaveItemApi'
| 'draggable'
| 'itemDraggableOn'
| 'saveOrderApi'
| 'columnTogglable',
(context: BaseEventContext) => any
>
@ -654,48 +655,70 @@ export class Table2Plugin extends BasePlugin {
}
protected _dynamicControls: Table2DynamicControls = {
primaryField: () => {
return getSchemaTpl('primaryField');
primaryField: context => {
return getSchemaTpl('primaryField', {
/** CRUD下该项配置提升到CRUD中 */
hiddenOn: `data.type && (data.type === "crud" || data.type === "crud2")`
});
},
quickSaveApi: () => {
quickSaveApi: context => {
return getSchemaTpl('apiControl', {
label: '快速保存',
name: 'quickSaveApi',
renderLabel: true
renderLabel: false,
label: {
type: 'tpl',
tpl: '快速保存',
className: 'flex items-end'
}
});
},
quickSaveItemApi: () => {
quickSaveItemApi: context => {
return getSchemaTpl('apiControl', {
label: '快速保存单条',
name: 'quickSaveItemApi',
renderLabel: true
renderLabel: false,
label: {
type: 'tpl',
tpl: '快速保存单条',
className: 'flex items-end'
}
});
},
rowSelectionKeyField: () => {
rowSelectionKeyField: context => {
return {
type: 'input-text',
name: 'rowSelection.keyField',
label: '数据源key'
};
},
expandableKeyField: () => {
expandableKeyField: context => {
return {
type: 'input-text',
name: 'rowSelection.keyField',
label: '数据源key'
};
},
draggable: () =>
draggable: context =>
getSchemaTpl('switch', {
name: 'draggable',
label: '可拖拽'
}),
itemDraggableOn: () =>
itemDraggableOn: context =>
getSchemaTpl('formulaControl', {
label: '可拖拽条件',
name: 'itemDraggableOn'
}),
columnTogglable: () => false
saveOrderApi: context => {
return getSchemaTpl('apiControl', {
name: 'saveOrderApi',
renderLabel: false,
label: {
type: 'tpl',
tpl: '保存排序',
className: 'flex items-end'
}
});
},
columnTogglable: context => false
};
/** 需要动态控制的控件 */
@ -713,9 +736,12 @@ export class Table2Plugin extends BasePlugin {
this._dynamicControls = {...this._dynamicControls, ...controls};
}
isCRUDContext(context: BaseEventContext) {
return context.schema.type === 'crud2' || context.schema.type === 'crud';
}
panelBodyCreator = (context: BaseEventContext) => {
const isCRUDBody =
context.schema.type === 'crud2' || context.schema.type === 'crud';
const isCRUDBody = this.isCRUDContext(context);
const dc = this.dynamicControls;
return getSchemaTpl('tabs', [
@ -734,8 +760,8 @@ export class Table2Plugin extends BasePlugin {
pipeIn: defaultValue('${items}')
}),
dc?.primaryField?.(context),
dc?.quickSaveApi?.(context),
dc?.quickSaveItemApi?.(context),
isCRUDBody ? null : dc?.quickSaveApi?.(context),
isCRUDBody ? null : dc?.quickSaveItemApi?.(context),
getSchemaTpl('switch', {
name: 'title',
label: '显示标题',
@ -799,13 +825,14 @@ export class Table2Plugin extends BasePlugin {
}),
getSchemaTpl('tablePlaceholder', {
hidden: isCRUDBody
}),
{
type: 'input-number',
name: 'combineNum',
label: '合并单元格'
}
]
})
// TODD: 组件功能没有支持,暂时隐藏
// {
// type: 'input-number',
// name: 'combineNum',
// label: '合并单元格'
// }
].filter(Boolean)
},
{
title: '列设置',
@ -1070,6 +1097,7 @@ export class Table2Plugin extends BasePlugin {
},
dc?.draggable?.(context),
dc?.itemDraggableOn?.(context),
dc?.saveOrderApi?.(context),
{
name: 'showBadge',
label: '行角标',

View File

@ -32,7 +32,7 @@ interface FieldSettingProps extends FormControlProps {
/** 脚手架渲染类型 */
renderer?: string;
feat: DSFeatureType;
options: {
config: {
showInputType?: boolean;
showDisplayType?: boolean;
};
@ -50,7 +50,7 @@ export class FieldSetting extends React.Component<
{loading: boolean}
> {
static defaultProps = {
options: {
config: {
showInputType: true,
showDisplayType: true
}
@ -308,11 +308,11 @@ export class FieldSetting extends React.Component<
defaultValue: formDefaultValue,
env,
renderer,
options,
config,
data: ctx,
feat
} = this.props;
const {showDisplayType, showInputType} = options || {};
const {showDisplayType, showInputType} = config || {};
const isForm = renderer === 'form';
const defaultValue = Array.isArray(formDefaultValue)
? {items: formDefaultValue}

View File

@ -168,11 +168,15 @@ export default class TableColumnWidthControl extends React.Component<
control: {
type: 'input-number',
min: 0,
value,
onChange: (val: number) => this.handleChange('fixed', val)
value
// onChange: (val: number) => this.handleChange('fixed', val)
},
unit: 'px'
})
unit: 'px',
className: 'mt-3'
}),
{
onChange: (val: number) => this.handleChange('fixed', val)
}
);
}

View File

@ -6,8 +6,8 @@
import React from 'react';
import {findDOMNode} from 'react-dom';
import Sortable from 'sortablejs';
import get from 'lodash/get';
import {FormItem, Button, Icon, toast, Tag, Spinner, autobind} from 'amis';
import {TooltipWrapper} from 'amis-ui';
import {JSONPipeIn} from 'amis-editor-core';
import AddColumnModal from './AddColumnModal';
@ -208,14 +208,17 @@ export class CRUDColumnControl extends React.Component<
@autobind
handleEdit(item: Option) {
const {manager} = this.props;
const {manager, node} = this.props;
const columns = node?.schema?.columns ?? [];
const idx = columns.findIndex(c => c.id === item.pristine.id);
if (!item.nodeId) {
if (!~idx) {
toast.warning(`未找到对应列「${item.label}`);
return;
}
manager.setActiveId(item.nodeId);
// FIXME: 理论上用item.nodeId就可以不知道为何会重新构建一次导致store中node.id更新
manager.setActiveId(columns[idx]?.$$id);
}
/** 添加列 */
@ -322,16 +325,33 @@ export class CRUDColumnControl extends React.Component<
@autobind
renderOption(item: Option, index: number) {
const {classnames: cx, data: ctx, render} = this.props;
const {
classnames: cx,
data: ctx,
render,
popOverContainer,
env
} = this.props;
return (
<li
key={index}
className={cx('ae-CRUDConfigControl-list-item', 'is-draggable')}
>
<div className={cx('ae-CRUDConfigControl-list-item-info')}>
<span>{item.label}</span>
</div>
<TooltipWrapper
tooltip={{
content: item.label,
tooltipTheme: 'dark',
style: {fontSize: '12px'}
}}
container={popOverContainer || env?.getModalContainer?.()}
trigger={['hover']}
delay={150}
>
<div className={cx('ae-CRUDConfigControl-list-item-info')}>
<span>{item.label}</span>
</div>
</TooltipWrapper>
<div className={cx('ae-CRUDConfigControl-list-item-actions')}>
{item.hidden || !item?.context?.isCascadingField ? null : (

View File

@ -17,6 +17,7 @@ import {
Tag,
autobind
} from 'amis';
import {TooltipWrapper} from 'amis-ui';
import {DSFeatureEnum} from '../../builder/constants';
import {traverseSchemaDeep} from '../../builder/utils';
import {deepRemove} from '../../plugin/CRUD2/utils';
@ -103,7 +104,7 @@ export class CRUDFiltersControl extends React.Component<
? (option.label as any).tpl /** 处理 SchemaObject 的场景 */
: option.name,
value: option.name ?? (option as any).key,
/** 使用$$id用于定位 */
/** 使用id用于定位 */
nodeId: option.$$id,
pristine: option
};
@ -455,7 +456,7 @@ export class CRUDFiltersControl extends React.Component<
value.filter(
(item: any) =>
item?.behavior !== DSFeatureEnum.AdvancedQuery &&
item.type === 'condition-builder'
item.type !== 'condition-builder'
)
];
}
@ -674,13 +675,24 @@ export class CRUDFiltersControl extends React.Component<
@autobind
renderOption(item: Option, index: number) {
const {classnames: cx, feat} = this.props;
const {classnames: cx, feat, popOverContainer, env} = this.props;
return (
<li key={index} className={cx('ae-CRUDConfigControl-list-item')}>
<div className={cx('ae-CRUDConfigControl-list-item-info')}>
<span>{item.label}</span>
</div>
<TooltipWrapper
tooltip={{
content: item.label,
tooltipTheme: 'dark',
style: {fontSize: '12px'}
}}
container={popOverContainer || env?.getModalContainer?.()}
trigger={['hover']}
delay={150}
>
<div className={cx('ae-CRUDConfigControl-list-item-info')}>
<span>{item.label}</span>
</div>
</TooltipWrapper>
<div className={cx('ae-CRUDConfigControl-list-item-actions')}>
{item?.context?.isCascadingField ? (
@ -688,8 +700,8 @@ export class CRUDFiltersControl extends React.Component<
label={item?.context?.modelLabel}
displayMode="normal"
className={cx(
'CRUDConfigControl-list-item-tag',
'CRUDConfigControl-list-item-tag--cascading'
'ae-CRUDConfigControl-list-item-tag',
'ae-CRUDConfigControl-list-item-tag--cascading'
)}
/>
) : null}

View File

@ -7,6 +7,7 @@ import React from 'react';
import {findDOMNode} from 'react-dom';
import cloneDeep from 'lodash/cloneDeep';
import {FormItem, Button, Icon, toast, Spinner, autobind} from 'amis';
import {TooltipWrapper} from 'amis-ui';
import {findTreeAll} from 'amis-core';
import {JSONPipeIn} from 'amis-editor-core';
import {DSFeature, DSFeatureType, DSFeatureEnum} from '../../builder';
@ -17,7 +18,9 @@ import type {EditorNodeType} from 'amis-editor-core';
import type {ColumnSchema} from 'amis/lib/renderers/Table2';
import type {DSBuilderInterface} from '../../builder';
type ActionValue = Extract<DSFeatureType, 'Insert' | 'BulkEdit' | 'BulkDelete'>;
type ActionValue =
| Extract<DSFeatureType, 'Insert' | 'BulkEdit' | 'BulkDelete'>
| 'custom';
interface Option {
label: string;
@ -81,7 +84,12 @@ export class CRUDToolbarControl extends React.Component<
const store = manager.store;
const node: EditorNodeType = store.getNodeById(nodeId);
const actions = findTreeAll(node.children, item =>
['Insert', 'BulkEdit', 'BulkDelete'].includes(item.schema.behavior)
[
DSFeatureEnum.Insert,
DSFeatureEnum.BulkEdit,
DSFeatureEnum.BulkDelete,
'custom'
].includes(item.schema.behavior)
) as unknown as EditorNodeType[];
return actions;
@ -98,7 +106,7 @@ export class CRUDToolbarControl extends React.Component<
const behavior = schema.behavior as ActionValue;
return {
label: DSFeature[behavior].label,
label: this.getOptionLabel(schema, behavior),
value: behavior,
nodeId: schema.$$id,
node: node,
@ -109,6 +117,10 @@ export class CRUDToolbarControl extends React.Component<
this.setState({options});
}
getOptionLabel(schema: any, behavior: ActionValue) {
return behavior === 'custom' ? schema.label : DSFeature[behavior].label;
}
@autobind
handleEdit(item: Option) {
const {manager} = this.props;
@ -188,6 +200,18 @@ export class CRUDToolbarControl extends React.Component<
CRUDSchemaID
);
break;
default:
scaffold = {
type: 'button',
label: '按钮',
behavior: 'custom',
className: 'm-r-xs',
onEvent: {
click: {
actions: []
}
}
};
}
if (!scaffold) {
@ -199,7 +223,7 @@ export class CRUDToolbarControl extends React.Component<
const actionSchema = JSONPipeIn({...scaffold});
options.push({
label: DSFeature[type].label,
label: this.getOptionLabel(actionSchema, type),
value: type,
nodeId: actionSchema.$$id,
pristine: actionSchema
@ -245,13 +269,24 @@ export class CRUDToolbarControl extends React.Component<
@autobind
renderOption(item: Option, index: number) {
const {classnames: cx} = this.props;
const {classnames: cx, popOverContainer, env} = this.props;
return (
<li key={index} className={cx('ae-CRUDConfigControl-list-item')}>
<div className={cx('ae-CRUDConfigControl-list-item-info')}>
<span>{item.label}</span>
</div>
<TooltipWrapper
tooltip={{
content: item.label,
tooltipTheme: 'dark',
style: {fontSize: '12px'}
}}
container={popOverContainer || env?.getModalContainer?.()}
trigger={['hover']}
delay={150}
>
<div className={cx('ae-CRUDConfigControl-list-item-info')}>
<span>{item.label}</span>
</div>
</TooltipWrapper>
<div className={cx('ae-CRUDConfigControl-list-item-actions')}>
<Button
@ -283,44 +318,49 @@ export class CRUDToolbarControl extends React.Component<
const options = this.state.options;
const actions = this.collection.concat();
options.forEach(item => {
if (actions.includes(item.value)) {
const idx = actions.indexOf(item.value);
if (~idx) {
actions.splice(idx, 1);
}
}
});
// options.forEach(item => {
// if (actions.includes(item.value)) {
// const idx = actions.indexOf(item.value);
// if (~idx) {
// actions.splice(idx, 1);
// }
// }
// });
const optionValues = options.map(item => item.value);
return (
<header className={cx('ae-CRUDConfigControl-header')}>
<span className={cx('Form-label')}></span>
{render(
'crud-toolbar-control-dropdown',
{
type: 'dropdown-button',
closeOnClick: true,
hideCaret: true,
level: 'link',
align: 'right',
trigger: ['click'],
popOverContainer:
env.getModalContainer ?? this.dom ?? document.body,
icon: 'column-add',
label: '添加操作',
className: cx('ae-CRUDConfigControl-dropdown'),
disabledTip: {
content: '暂无可添加操作',
tooltipTheme: 'dark'
},
buttons: actions.map(item => ({
{render('crud-toolbar-control-dropdown', {
type: 'dropdown-button',
closeOnClick: true,
hideCaret: true,
level: 'link',
align: 'right',
trigger: ['click'],
popOverContainer: env.getModalContainer ?? this.dom ?? document.body,
icon: 'column-add',
label: '添加操作',
className: cx('ae-CRUDConfigControl-dropdown'),
disabledTip: {
content: '暂无可添加操作',
tooltipTheme: 'dark'
},
buttons: actions
.map((item: Exclude<ActionValue, 'custom'>) => ({
type: 'button',
label: DSFeature[item].label,
disabled: !!~optionValues.findIndex(op => op === item),
onClick: () => this.handleAddAction(item)
}))
},
{disabled: actions.length === 0}
)}
.concat({
type: 'button',
label: '自定义按钮',
disabled: false,
onClick: () => this.handleAddAction('custom')
})
})}
</header>
);
}

View File

@ -2702,7 +2702,7 @@ export const getEventControlConfig = (
: ACTION_TYPE_TREE(manager);
const allComponents = manager?.store?.getComponentTreeSource();
const checkComponent = (node: any, action: RendererPluginAction) => {
const actionType = action.actionType!;
const actionType = action?.actionType;
const actions = manager?.pluginActions[node.type];
const haveChild = !!node.children?.length;
let isSupport = false;
@ -2756,6 +2756,10 @@ export const getEventControlConfig = (
return manager.dataSchema;
},
getComponents: (action: RendererPluginAction) => {
if (!action) {
return [];
}
let components = manager?.store?.getComponentTreeSource();
let finalCmpts: any[] = [];
if (isSubEditor) {

View File

@ -748,7 +748,7 @@ export class EventControl extends React.Component<
getContextSchemas,
...actionConfig,
groupType: actionConfig?.__actionType || action.actionType,
__actionDesc: actionNode!.description!, // 树节点描述
__actionDesc: actionNode?.description ?? '', // 树节点描述
__actionSchema: actionNode!.schema, // 树节点schema
__subActions: hasSubActionNode?.actions, // 树节点子动作
__cmptTreeSource: supportComponents ?? [],

View File

@ -1702,6 +1702,5 @@ setSchemaTpl('primaryField', {
'主键',
'每行记录的唯一标识符,通常用于行选择、批量操作等场景。'
),
pipeIn: defaultValue('id'),
required: true
pipeIn: defaultValue('id')
});

View File

@ -1,6 +1,6 @@
{
"name": "amis-formula",
"version": "3.4.0",
"version": "3.4.0-alpha.4",
"description": "负责 amis 里面的表达式实现,内置公式,编辑器等",
"main": "lib/index.js",
"module": "esm/index.js",

View File

@ -3,7 +3,7 @@
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"version": "3.4.0",
"version": "3.4.0-alpha.4",
"description": "",
"scripts": {
"build": "npm run clean-dist && NODE_ENV=production rollup -c ",
@ -36,8 +36,8 @@
},
"dependencies": {
"@rc-component/mini-decimal": "^1.0.1",
"amis-core": "^3.4.0",
"amis-formula": "^3.4.0",
"amis-core": "^3.4.0-alpha.4",
"amis-formula": "^3.4.0-alpha.4",
"classnames": "2.3.2",
"codemirror": "^5.63.0",
"downshift": "6.1.12",

View File

@ -149,7 +149,10 @@ export class Tag extends React.Component<TagProps> {
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
<span className={cx('Tag-text')}>
<span
className={cx('Tag-text')}
title={typeof label === 'string' ? label : undefined}
>
{prevIcon}
{label || children}
</span>
@ -187,6 +190,7 @@ class CheckableTagComp extends React.Component<CheckableTagProps> {
})}
onClick={disabled ? noop : this.handleClick}
style={style}
title={typeof label === 'string' ? label : undefined}
>
{label || children}
</span>

View File

@ -132,7 +132,16 @@ const FormulaInput: React.FC<FormulaInputProps> = props => {
);
};
const cmptValue = pipInValue(value ?? inputSettings.defaultValue);
let cmptValue = pipInValue(value ?? inputSettings.defaultValue);
/** 数据来源可能是从 query中下发的CRUD查询表头导致数字或者布尔值被转为 string 格式,这里预处理一下 */
if (schemaType === 'number') {
cmptValue = isNaN(+cmptValue) ? cmptValue : +cmptValue;
} else if (schemaType === 'boolean') {
cmptValue =
cmptValue === 'true' ? true : cmptValue === 'false' ? false : cmptValue;
}
const targetVariable =
variables && cmptValue != null && typeof cmptValue === 'string'
? findTree(variables, item => {

View File

@ -468,7 +468,7 @@ export class Table extends React.PureComponent<TableProps, TableState> {
}
current && this.updateTableDom(current);
if (this.props.draggable) {
if (this.props.draggable && this.tbodyDom?.current) {
this.initDragging();
}

View File

@ -1,6 +1,6 @@
{
"name": "amis",
"version": "3.4.0",
"version": "3.4.0-alpha.4",
"description": "一种MIS页面生成工具",
"main": "lib/index.js",
"module": "esm/index.js",
@ -37,8 +37,8 @@
}
],
"dependencies": {
"amis-core": "^3.4.0",
"amis-ui": "^3.4.0",
"amis-core": "^3.4.0-alpha.4",
"amis-ui": "^3.4.0-alpha.4",
"attr-accept": "2.2.2",
"blueimp-canvastoblob": "2.1.0",
"classnames": "2.3.2",

View File

@ -598,7 +598,8 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
)
)) &&
// 弹窗期间不进行刷新
(!stopAutoRefreshWhenModalIsOpen || !store.dialogOpen) &&
(!stopAutoRefreshWhenModalIsOpen ||
(!store.dialogOpen && !store?.parentStore?.dialogOpen)) &&
(this.timer = setTimeout(
this.getData.bind(this, silentPolling, undefined, true),
Math.max(interval, 1000)
@ -1084,6 +1085,9 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
// onAction: onAction
};
if (schema.type === 'pagination') {
}
return render(region, schema, {
data,
...props,

View File

@ -212,6 +212,11 @@ export interface TableControlSchema
*
*/
footerAddBtn?: SchemaCollection;
/**
*
*/
autoFocus?: boolean;
}
export interface TableProps
@ -603,7 +608,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
}
async addItem(index: number, isDispatch: boolean = true) {
const {needConfirm, scaffold, columns, data} = this.props;
const {needConfirm, scaffold, columns, data, autoFocus} = this.props;
const items = this.state.items.concat();
let value: any = {
__isPlaceholder: true
@ -667,6 +672,14 @@ export default class FormTable extends React.Component<TableProps, TableState> {
} else {
this.startEdit(index, true);
}
requestAnimationFrame(() => {
this.tableRef?.current?.scrollIntoView?.({
behavior: 'smooth',
block: 'end',
inline: 'nearest'
});
});
}
);

View File

@ -1632,7 +1632,9 @@ export default class Table extends React.Component<TableProps, object> {
label: false,
className: cx('Table-searchableForm-checkbox'),
inputClassName: cx('Table-searchableForm-checkbox-inner'),
name: `__search_${column.searchable?.name ?? column.name}`,
name: `${
column.searchable.strategy === 'jsonql' ? '' : '__search_'
}${column.searchable?.name ?? column.name}`,
option: column.searchable?.label ?? column.label,
value: column.enableSearch,
badge: {