Skip to content

Commit

Permalink
Pick combo 修改相关 (#9878)
Browse files Browse the repository at this point in the history
* fix: 修复 table2 树形数据展示对应错误问题

* fix: 修复 combo 同步父级数据可能存在展示值和实际值不一致的问题 Close: #8773 (#8831)

* fix: 修复 combo 中有 pipeIn & pipeOut 场景时报错 Close: #8970

* fix: 修复 combo tabs 模式新成员中有必填字段未填写也能通过校验的问题

* fix: 修复 combo 可能无限触发 onChange 的问题

* fix: 修复 combo 同步父级数据可能存在展示值和实际值不一致的问题 Close: #8773

* fix: 修复 combo 中有 pipeIn & pipeOut 场景时报错 Close: #8970 (#8980)

* fix: 修复页面设计器重复执行onChange的问题

* fix: 修复数据下发同步问题 (#9625)

* fix: 修复 crud 重置失效的问题 Close: #9686 (#9693)

* fix: crud2条件查询表单重置失效 (#9706)

* chore: combo 中减少表单项重绘

* fix typecheck error

---------

Co-authored-by: wutong25 <wutong25@baidu.com>
Co-authored-by: walkin <wyc19966@hotmail.com>
  • Loading branch information
3 people committed Mar 26, 2024
1 parent b365862 commit 6d3cac5
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 91 deletions.
3 changes: 2 additions & 1 deletion packages/amis-core/src/SchemaRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ export const RENDERER_TRANSMISSION_OMIT_PROPS = [
'label',
'renderLabel',
'trackExpression',
'editorSetting'
'editorSetting',
'updatePristineAfterStoreDataReInit'
];

const componentCache: SimpleMap = new SimpleMap();
Expand Down
24 changes: 16 additions & 8 deletions packages/amis-core/src/WithStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ export function HocStoreFactory(renderer: {
...(store.hasRemoteData ? store.data : null), // todo 只保留 remote 数据
...this.formatData(props.defaultData),
...this.formatData(props.data)
})
}),
props.updatePristineAfterStoreDataReInit === false
);
}
} else if (
Expand All @@ -234,7 +235,8 @@ export function HocStoreFactory(renderer: {
store,
props.syncSuperStore === true
)
)
),
props.updatePristineAfterStoreDataReInit === false
);
} else if (props.data && (props.data as any).__super) {
store.initData(
Expand All @@ -250,16 +252,20 @@ export function HocStoreFactory(renderer: {
props.store?.storeType === 'ComboStore'
? undefined
: syncDataFromSuper(
props.data,
{...store.data, ...props.data},
(props.data as any).__super,
(prevProps.data as any).__super,
store,
false
)
)
),
props.updatePristineAfterStoreDataReInit === false
);
} else {
store.initData(createObject(props.scope, props.data));
store.initData(
createObject(props.scope, props.data),
props.updatePristineAfterStoreDataReInit === false
);
}
} else if (
!props.trackExpression &&
Expand All @@ -282,8 +288,9 @@ export function HocStoreFactory(renderer: {
...store.data
}),

store.storeType === 'FormStore' &&
prevProps.store?.storeType === 'CRUDStore'
props.updatePristineAfterStoreDataReInit === false ||
(store.storeType === 'FormStore' &&
prevProps.store?.storeType === 'CRUDStore')
);
}
// nextProps.data.__super !== props.data.__super) &&
Expand All @@ -299,7 +306,8 @@ export function HocStoreFactory(renderer: {
createObject(props.scope, {
// ...nextProps.data,
...store.data
})
}),
props.updatePristineAfterStoreDataReInit === false
);
}
}
Expand Down
128 changes: 79 additions & 49 deletions packages/amis-core/src/renderers/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {isAlive} from 'mobx-state-tree';

import type {LabelAlign} from './Item';
import {injectObjectChain} from '../utils';
import {reaction} from 'mobx';

export interface FormHorizontal {
left?: number;
Expand Down Expand Up @@ -371,6 +372,7 @@ export interface FormProps
onFailed?: (reason: string, errors: any) => any;
onFinished: (values: object, action: any) => any;
onValidate: (values: object, form: any) => any;
onValidChange?: (valid: boolean, props: any) => void; // 表单数据合法性变更
messages: {
fetchSuccess?: string;
fetchFailed?: string;
Expand Down Expand Up @@ -443,6 +445,8 @@ export default class Form extends React.Component<FormProps, object> {
'onChange',
'onFailed',
'onFinished',
'onValidate',
'onValidChange',
'onSaved',
'canAccessSuperData',
'lazyChange',
Expand All @@ -460,8 +464,7 @@ export default class Form extends React.Component<FormProps, object> {
[propName: string]: Array<() => Promise<any>>;
} = {};
asyncCancel: () => void;
disposeOnValidate: () => void;
disposeRulesValidate: () => void;
toDispose: Array<() => void> = [];
shouldLoadInitApi: boolean = false;
timer: ReturnType<typeof setTimeout>;
mounted: boolean;
Expand Down Expand Up @@ -518,6 +521,18 @@ export default class Form extends React.Component<FormProps, object> {
)
);
}

// withStore 里面与上层数据会做同步
// 这个时候变更的数据没有同步 onChange 出去,出现数据不一致的问题。
// https://github.com/baidu/amis/issues/8773
this.toDispose.push(
reaction(
() => store.initedAt,
() => {
store.inited && this.emitChange(!!this.props.submitOnChange, true);
}
)
);
}

componentDidMount() {
Expand All @@ -531,6 +546,7 @@ export default class Form extends React.Component<FormProps, object> {
store,
messages: {fetchSuccess, fetchFailed},
onValidate,
onValidChange,
promptPageLeave,
env,
rules
Expand All @@ -540,49 +556,63 @@ export default class Form extends React.Component<FormProps, object> {

if (onValidate) {
const finalValidate = promisify(onValidate);
this.disposeOnValidate = this.addHook(async () => {
const result = await finalValidate(store.data, store);

if (result && isObject(result)) {
Object.keys(result).forEach(key => {
let msg = result[key];
const items = store.getItemsByPath(key);

// 没有找到
if (!Array.isArray(items) || !items.length) {
return;
}

// 在setError之前,提前把残留的error信息清除掉,否则每次onValidate后都会一直把报错 append 上去
items.forEach(item => item.clearError());

if (msg) {
msg = Array.isArray(msg) ? msg : [msg];
items.forEach(item => item.addError(msg));
}

delete result[key];
});
this.toDispose.push(
this.addHook(async () => {
const result = await finalValidate(store.data, store);

if (result && isObject(result)) {
Object.keys(result).forEach(key => {
let msg = result[key];
const items = store.getItemsByPath(key);

// 没有找到
if (!Array.isArray(items) || !items.length) {
return;
}

// 在setError之前,提前把残留的error信息清除掉,否则每次onValidate后都会一直把报错 append 上去
items.forEach(item => item.clearError());

if (msg) {
msg = Array.isArray(msg) ? msg : [msg];
items.forEach(item => item.addError(msg));
}

delete result[key];
});

isEmpty(result)
? store.clearRestError()
: store.setRestError(Object.keys(result).map(key => result[key]));
}
})
);
}

isEmpty(result)
? store.clearRestError()
: store.setRestError(Object.keys(result).map(key => result[key]));
}
});
// 表单校验结果发生变化时,触发 onValidChange
if (onValidChange) {
this.toDispose.push(
reaction(
() => store.valid,
valid => onValidChange(valid, this.props)
)
);
}

if (Array.isArray(rules) && rules.length) {
this.disposeRulesValidate = this.addHook(() => {
if (!store.valid) {
return;
}
this.toDispose.push(
this.addHook(() => {
if (!store.valid) {
return;
}

rules.forEach(
item =>
!evalExpression(item.rule, store.data) &&
store.addRestError(item.message, item.name)
);
});
rules.forEach(
item =>
!evalExpression(item.rule, store.data) &&
store.addRestError(item.message, item.name)
);
})
);
}

if (isEffectiveApi(initApi, store.data, initFetch, initFetchOn)) {
Expand Down Expand Up @@ -654,8 +684,8 @@ export default class Form extends React.Component<FormProps, object> {
// this.lazyHandleChange.flush();
this.lazyEmitChange.cancel();
this.asyncCancel && this.asyncCancel();
this.disposeOnValidate && this.disposeOnValidate();
this.disposeRulesValidate && this.disposeRulesValidate();
this.toDispose.forEach(fn => fn());
this.toDispose = [];
window.removeEventListener('beforeunload', this.beforePageUnload);
this.unBlockRouting?.();
}
Expand Down Expand Up @@ -984,21 +1014,21 @@ export default class Form extends React.Component<FormProps, object> {
};
}

async emitChange(submit: boolean) {
async emitChange(submit: boolean, skipIfNothingChanges: boolean = false) {
const {onChange, store, submitOnChange, dispatchEvent, data} = this.props;

if (!isAlive(store)) {
return;
}

const diff = difference(store.data, store.pristine);
if (skipIfNothingChanges && !Object.keys(diff).length) {
return;
}

// 提前准备好 onChange 的参数。
// 因为 store.data 会在 await 期间被 WithStore.componentDidUpdate 中的 store.initData 改变。导致数据丢失
const changeProps = [
store.data,
difference(store.data, store.pristine),
this.props
];

const changeProps = [store.data, diff, this.props];
const dispatcher = await dispatchEvent(
'change',
createObject(data, store.data)
Expand Down
13 changes: 11 additions & 2 deletions packages/amis-core/src/store/combo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export const ComboStore = iRendererStore
minLength: 0,
maxLength: 0,
length: 0,
activeKey: 0
activeKey: 0,
memberValidMap: types.optional(types.frozen(), {})
})
.views(self => {
function getForms() {
Expand Down Expand Up @@ -166,13 +167,21 @@ export const ComboStore = iRendererStore
self.activeKey = key;
}

function setMemberValid(valid: boolean, index: number) {
self.memberValidMap = {
...self.memberValidMap,
[index]: valid
};
}

return {
config,
setActiveKey,
bindUniuqueItem,
unBindUniuqueItem,
addForm,
onChildStoreDispose
onChildStoreDispose,
setMemberValid
};
});

Expand Down
2 changes: 2 additions & 0 deletions packages/amis-ui/scss/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,7 @@
--Tabs-onActive-bg: var(--background);
--Tabs-onActive-borderColor: var(--borderColor);
--Tabs-onActive-color: var(--colors-neutral-text-2);
--Tabs-onError-color: var(--colors-error-5);
--Tabs-onDisabled-color: var(--colors-neutral-text-7);
--Tabs-onHover-borderColor: var(--colors-neutral-line-8);
--Tabs-add-icon-size: #{px2rem(15px)};
Expand Down Expand Up @@ -4120,6 +4121,7 @@
var(--combo-vertical-right-border-color)
var(--combo-vertical-bottom-border-color)
var(--combo-vertical-left-border-color);
--Combo--vertical-item--onError-borderColor: var(--colors-error-5);
--Combo--vertical-item-borderRadius: var(
--combo-vertical-top-left-border-radius
)
Expand Down
4 changes: 4 additions & 0 deletions packages/amis-ui/scss/components/_tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@
border-color: var(--Tabs-onActive-borderColor);
border-bottom-color: transparent;
}

&.has-error > a:first-child {
color: var(--Tabs-onError-color) !important;
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions packages/amis-ui/scss/components/form/_combo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@
var(--combo-vertical-paddingRight) var(--combo-vertical-paddingBottom)
var(--combo-vertical-paddingLeft);
position: relative;

&.has-error {
border-color: var(
--Combo--vertical-item--onError-borderColor
) !important; // 因为下面的规则权重更高 &:not(.is-disabled) > .#{$ns}Combo-items > .#{$ns}Combo-item:hover
}
}

> .#{$ns}Combo-items > .#{$ns}Combo-item {
Expand Down
1 change: 1 addition & 0 deletions packages/amis-ui/src/components/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export interface TabProps extends ThemeProps {
tip?: string;
tab?: Schema;
className?: string;
tabClassName?: string;
activeKey?: string | number;
reload?: boolean;
mountOnEnter?: boolean;
Expand Down

0 comments on commit 6d3cac5

Please sign in to comment.