form 改造

This commit is contained in:
liaoxuezhi 2021-05-30 00:24:23 +08:00
parent a3dbf4703a
commit cee031d534
7 changed files with 220 additions and 43 deletions

View File

@ -334,7 +334,6 @@ const maybeFormItem = [
'hbox',
'panel',
'service',
'tabs',
'anchor-nav'
];
@ -385,23 +384,77 @@ function wrapControl(item: any) {
};
}
function controlToNormalRenderer(item: any) {
return item && controlMapping[item.type]
? {
...item,
type: controlMapping[item.type]
}
: ~maybeFormItem.indexOf(item?.type)
? wrapControl(item)
: item;
}
addSchemaFilter(function (schema: Schema) {
// controls 转成 body
if (schema?.type === 'combo' && Array.isArray(schema.conditions)) {
schema = {
...schema,
conditions: schema.conditions.map(condition => {
if (Array.isArray(condition.controls)) {
condition = {
...condition,
body: condition.controls.map(controlToNormalRenderer)
};
delete condition.controls;
}
return condition;
})
};
}
if (Array.isArray(schema?.controls)) {
schema = {
...schema,
body: schema?.controls.map(item =>
item && controlMapping[item.type]
? {
...item,
type: controlMapping[item.type]
}
: ~maybeFormItem.indexOf(item?.type)
? wrapControl(item)
: item
[schema.type === 'combo' ? `items` : 'body']: schema?.controls.map(
controlToNormalRenderer
)
};
delete schema.controls;
} else if (schema?.type === 'tabs' && Array.isArray(schema.tabs)) {
schema = {
...schema,
tabs: schema.tabs.map(tab => {
if (Array.isArray(tab.controls)) {
tab = {
...tab,
body: tab?.controls.map(controlToNormalRenderer)
};
}
return tab;
})
};
} else if (schema?.type === 'anchor-nav' && Array.isArray(schema.links)) {
schema = {
...schema,
links: schema.links.map(link => {
if (Array.isArray(link.controls)) {
link = {
...link,
body: link?.controls.map(controlToNormalRenderer)
};
}
return link;
})
};
} else if (schema?.type === 'input-array' && Array.isArray(schema.items)) {
schema = {
...schema,
items: schema.items.map(controlToNormalRenderer)
};
}
return schema;

View File

@ -34,7 +34,7 @@ import {SchemaApi, SchemaClassName, SchemaIcon, SchemaTpl} from '../../Schema';
export type ComboCondition = {
test: string;
controls: Array<FormControlSchema>;
body: Array<FormControlSchema>;
label: string;
scaffold?: any;
mode?: string;
@ -118,7 +118,7 @@ export interface ComboControlSchema extends FormBaseControl {
/**
*
*/
controls?: Array<ComboSubControl>;
items?: Array<ComboSubControl>;
/**
*
@ -319,7 +319,7 @@ export default class ComboControl extends React.Component<ComboProps> {
'lazyLoad',
'changeImmediately',
'strictMode',
'controls',
'items',
'conditions',
'messages'
];
@ -931,7 +931,7 @@ export default class ComboControl extends React.Component<ComboProps> {
translate: __
} = this.props;
let controls = this.props.controls;
let items = this.props.items;
let value = this.props.value;
if (flat && typeof value === 'string') {
@ -1029,18 +1029,18 @@ export default class ComboControl extends React.Component<ComboProps> {
if (Array.isArray(conditions) && conditions.length) {
condition = this.pickCondition(data);
controls = condition ? condition.controls : undefined;
items = condition ? condition.body : undefined;
}
let finnalControls =
flat && controls
flat && items
? [
{
...(controls && controls[0]),
...(items && items[0]),
name: 'flat'
}
]
: controls;
: items;
const hasUnique =
Array.isArray(finnalControls) &&
@ -1082,7 +1082,7 @@ export default class ComboControl extends React.Component<ComboProps> {
`multiple/${index}`,
{
type: 'form',
controls: finnalControls,
body: finnalControls,
wrapperComponent: 'div',
wrapWithPanel: false,
mode: subFormMode,
@ -1152,7 +1152,7 @@ export default class ComboControl extends React.Component<ComboProps> {
translate: __
} = this.props;
let controls = this.props.controls;
let items = this.props.items;
let value = this.props.value;
if (flat && typeof value === 'string') {
@ -1210,18 +1210,18 @@ export default class ComboControl extends React.Component<ComboProps> {
if (Array.isArray(conditions) && conditions.length) {
condition = this.pickCondition(data);
controls = condition ? condition.controls : undefined;
items = condition ? condition.body : undefined;
}
let finnalControls =
flat && controls
flat && items
? [
{
...(controls && controls[0]),
...(items && items[0]),
name: 'flat'
}
]
: controls;
: items;
return (
<div
@ -1265,7 +1265,7 @@ export default class ComboControl extends React.Component<ComboProps> {
`multiple/${index}`,
{
type: 'form',
controls: finnalControls,
body: finnalControls,
wrapperComponent: 'div',
wrapWithPanel: false,
mode: multiLine ? subFormMode : 'row',
@ -1365,13 +1365,13 @@ export default class ComboControl extends React.Component<ComboProps> {
translate: __
} = this.props;
let controls = this.props.controls;
let items = this.props.items;
const data = isObject(value) ? this.formatValue(value) : this.defaultValue;
let condition: ComboCondition | null = null;
if (Array.isArray(conditions) && conditions.length) {
condition = this.pickCondition(data);
controls = condition ? condition.controls : undefined;
items = condition ? condition.body : undefined;
}
return (
@ -1400,12 +1400,12 @@ export default class ComboControl extends React.Component<ComboProps> {
) : null}
<div className={cx(`Combo-itemInner`)}>
{controls ? (
{items ? (
render(
'single',
{
type: 'form',
controls,
body: items,
wrapperComponent: 'div',
wrapWithPanel: false,
mode: multiLine ? 'normal' : 'row',

View File

@ -10,7 +10,8 @@ import {
isObject,
guid,
isEmpty,
autobind
autobind,
getVariable
} from '../../utils/helper';
import {IIRendererStore, IRendererStore} from '../../store';
import {ScopedContext, IScopedContext} from '../../Scoped';
@ -177,7 +178,7 @@ export function warpControl<
}
// 同步 value
model.changeTmpValue(propValue);
model.changeTmpValue(propValue ?? value);
}
componentDidMount() {
@ -266,19 +267,43 @@ export function warpControl<
);
}
let modified = false;
if (model && props.value !== prevProps.value) {
if (props.value !== model.tmpValue) {
model.changeTmpValue(props.value);
modified = true;
}
} else if (
model &&
props.data !== prevProps.data &&
(!model.emitedValue || model.emitedValue === model.tmpValue)
) {
model.changeEmitedValue(undefined);
const value = getVariable(
props.data,
model.name,
props.canAccessSuperData !== false
);
const prevValue = getVariable(
prevProps.data,
model.name,
props.canAccessSuperData !== false
);
if (value !== prevValue && value !== model.tmpValue) {
model.changeTmpValue(value);
modified = true;
}
}
if (modified) {
if (
props.validateOnChange === true ||
(props.validateOnChange !== false &&
(form?.submited || (isAlive(model) && model.validated)))
(props.formSubmited || (isAlive(model!) && model!.validated)))
) {
this.validate();
} else if (props.validateOnChange === false) {
model.reset();
model!.reset();
}
}
}
@ -440,19 +465,26 @@ export function warpControl<
const {
formStore: form,
onChange,
$schema: {name, onChange: onFormItemChange}
$schema: {name, onChange: onFormItemChange},
data,
canAccessSuperData
} = this.props;
if (!this.model) {
return;
}
const value = this.model.tmpValue;
const oldValue = this.model.value;
const oldValue = getVariable(
data,
this.model.name,
canAccessSuperData !== false
);
if (oldValue === value) {
return;
}
this.model.changeEmitedValue(value);
onFormItemChange?.(value, oldValue, this.model, form);
onChange?.(value, name!, submitOnChange === true);
}

View File

@ -143,7 +143,7 @@ export default class FieldSetControl extends React.Component<
}
@Renderer({
test: /(^|\/)form(?:.+)?\/control\/fieldSet$/i,
test: /(^|\/)fieldSet$/i,
weight: -100,
name: 'fieldset'
})

View File

@ -1331,7 +1331,8 @@ export default class Form extends React.Component<FormProps, object> {
controlWidth,
resolveDefinitions,
lazyChange,
formLazyChange
formLazyChange,
canAccessSuperData
} = props;
const subProps = {
@ -1341,6 +1342,7 @@ export default class Form extends React.Component<FormProps, object> {
(control as Schema).type
}-${key}`,
formInited: form.inited,
formSubmited: form.submited,
formMode: mode,
formHorizontal: horizontal,
controlWidth,
@ -1355,10 +1357,11 @@ export default class Form extends React.Component<FormProps, object> {
removeHook: this.removeHook,
renderFormItems: this.renderFormItems,
formPristine: form.pristine,
value: (control as any)?.name
? getVariable(form.data, (control as any)?.name)
: (control as any)?.value,
defaultValue: (control as any)?.value
canAccessSuperData
// value: (control as any)?.name
// ? getVariable(form.data, (control as any)?.name, canAccessSuperData)
// : (control as any)?.value,
// defaultValue: (control as any)?.value
};
let subSchema: any = {

View File

@ -7,7 +7,9 @@ import {
autobind,
isDisabled,
isObject,
createObject
createObject,
getVariable,
getVariable
} from '../utils/helper';
import findIndex from 'lodash/findIndex';
import {Tabs as CTabs, Tab} from '../components/Tabs';
@ -170,6 +172,31 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
componentDidMount() {
this.autoJumpToNeighbour(this.activeKey);
let {name, value, onChange, source, tabs, data} = this.props;
// 如果没有配置 name ,说明不需要同步表单值
if (
!name ||
typeof onChange !== 'function' ||
// 如果关联某个变量数据,则不启用
source
) {
return;
}
value = value ?? getVariable(data, name);
// 如果有值,切到对应的 tab
if (value && Array.isArray(tabs)) {
const key = this.resolveKeyByValue(value);
key !== undefined && this.handleSelect(key);
} else {
const tab = this.resolveTabByKey(this.activeKey);
if (tab && value !== ((tab as any).value ?? tab.title)) {
onChange((tab as any).value ?? tab.title, name);
}
}
}
componentDidUpdate(preProps: TabsProps, prevState: any) {
@ -219,6 +246,62 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
}
this.autoJumpToNeighbour(this.activeKey);
let {name, value, onChange, source, data} = this.props;
// 如果没有配置 name ,说明不需要同步表单值
if (
!name ||
typeof onChange !== 'function' ||
// 如果关联某个变量数据,则不启用
source
) {
return;
}
let key: any;
value = value ?? getVariable(data, name);
const prevValue =
preProps.value ?? getVariable(preProps.data, preProps.name);
if (
value !== prevValue &&
(key = this.resolveKeyByValue(value)) !== undefined &&
key !== this.activeKey
) {
this.handleSelect(key);
} else if (this.activeKey !== prevState.activeKey) {
const tab = this.resolveTabByKey(this.activeKey);
if (tab && value !== ((tab as any).value ?? tab.title)) {
onChange((tab as any).value ?? tab.title, name);
}
}
}
resolveTabByKey(key: any) {
const tabs = this.props.tabs;
if (!Array.isArray(tabs)) {
return;
}
return find(tabs, (tab: TabSchema, index) =>
tab.hash ? tab.hash === key : index === key
);
}
resolveKeyByValue(value: any) {
const tabs = this.props.tabs;
if (!Array.isArray(tabs)) {
return;
}
const tab: TabSchema = find(
tabs,
tab => ((tab as any).value ?? tab.title) === value
) as TabSchema;
return tab && tab.hash ? tab.hash : tabs.indexOf(tab);
}
@autobind
@ -417,7 +500,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
}
@Renderer({
test: /(^|\/)tabs$/,
type: 'tabs',
name: 'tabs'
})
export class TabsRenderer extends Tabs {}

View File

@ -60,6 +60,7 @@ export const FormItemStore = StoreNode.named('FormItemStore')
loading: false,
required: false,
tmpValue: types.frozen(),
emitedValue: types.frozen(),
rules: types.optional(types.frozen(), {}),
messages: types.optional(types.frozen(), {}),
errorData: types.optional(types.array(ErrorDetail), []),
@ -789,6 +790,10 @@ export const FormItemStore = StoreNode.named('FormItemStore')
self.tmpValue = value;
}
function changeEmitedValue(value: any) {
self.emitedValue = value;
}
function addSubFormItem(item: IFormItemStore) {
self.itemsRef.push(item.id);
}
@ -819,6 +824,7 @@ export const FormItemStore = StoreNode.named('FormItemStore')
openDialog,
closeDialog,
changeTmpValue,
changeEmitedValue,
addSubFormItem,
removeSubFormItem
};