mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
fix: 修复弹窗中的弹窗编辑器中出现重复的问题 (#10073)
This commit is contained in:
parent
8563dd04ea
commit
c9073e9716
@ -40,6 +40,7 @@ export interface EditorProps extends PluginEventListener {
|
|||||||
superEditorData?: any;
|
superEditorData?: any;
|
||||||
withSuperDataSchema?: boolean;
|
withSuperDataSchema?: boolean;
|
||||||
/** 当前 Editor 为 SubEditor 时触发的宿主节点 */
|
/** 当前 Editor 为 SubEditor 时触发的宿主节点 */
|
||||||
|
hostManager?: EditorManager;
|
||||||
hostNode?: EditorNodeType;
|
hostNode?: EditorNodeType;
|
||||||
dataBindingChange?: (
|
dataBindingChange?: (
|
||||||
value: string,
|
value: string,
|
||||||
@ -154,6 +155,7 @@ export default class Editor extends Component<EditorProps> {
|
|||||||
onChange,
|
onChange,
|
||||||
showCustomRenderersPanel,
|
showCustomRenderersPanel,
|
||||||
superEditorData,
|
superEditorData,
|
||||||
|
hostManager,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@ -179,7 +181,7 @@ export default class Editor extends Component<EditorProps> {
|
|||||||
this.store.setShowCustomRenderersPanel(showCustomRenderersPanel);
|
this.store.setShowCustomRenderersPanel(showCustomRenderersPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.manager = new EditorManager(config, this.store);
|
this.manager = new EditorManager(config, this.store, hostManager);
|
||||||
|
|
||||||
// 子编辑器不再重新设置 editorStore
|
// 子编辑器不再重新设置 editorStore
|
||||||
if (!(props.isSubEditor && (window as any).editorStore)) {
|
if (!(props.isSubEditor && (window as any).editorStore)) {
|
||||||
|
@ -4,17 +4,20 @@ import React from 'react';
|
|||||||
import {EditorStoreType} from '../../store/editor';
|
import {EditorStoreType} from '../../store/editor';
|
||||||
import {JSONGetById, modalsToDefinitions, translateSchema} from '../../util';
|
import {JSONGetById, modalsToDefinitions, translateSchema} from '../../util';
|
||||||
import {Button, Icon, ListMenu, PopOverContainer, confirm} from 'amis';
|
import {Button, Icon, ListMenu, PopOverContainer, confirm} from 'amis';
|
||||||
|
import {EditorManager} from '../../manager';
|
||||||
|
|
||||||
export interface DialogListProps {
|
export interface DialogListProps {
|
||||||
classnames: ClassNamesFn;
|
classnames: ClassNamesFn;
|
||||||
store: EditorStoreType;
|
store: EditorStoreType;
|
||||||
|
manager: EditorManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default observer(function DialogList({
|
export default observer(function DialogList({
|
||||||
classnames: cx,
|
classnames: cx,
|
||||||
store
|
store,
|
||||||
|
manager
|
||||||
}: DialogListProps) {
|
}: DialogListProps) {
|
||||||
const modals = store.modals;
|
const modals = store.modals.filter(item => !item.disabled);
|
||||||
|
|
||||||
const handleAddDialog = React.useCallback(() => {
|
const handleAddDialog = React.useCallback(() => {
|
||||||
const modal = {
|
const modal = {
|
||||||
@ -29,7 +32,7 @@ export default observer(function DialogList({
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
store.openSubEditor({
|
manager.openSubEditor({
|
||||||
title: '编辑弹窗',
|
title: '编辑弹窗',
|
||||||
value: modal,
|
value: modal,
|
||||||
onChange: ({definitions, ...modal}: any, diff: any) => {
|
onChange: ({definitions, ...modal}: any, diff: any) => {
|
||||||
@ -42,19 +45,12 @@ export default observer(function DialogList({
|
|||||||
const index = parseInt(event.currentTarget.getAttribute('data-index')!, 10);
|
const index = parseInt(event.currentTarget.getAttribute('data-index')!, 10);
|
||||||
const modal = store.modals[index];
|
const modal = store.modals[index];
|
||||||
const modalId = modal.$$id!;
|
const modalId = modal.$$id!;
|
||||||
store.openSubEditor({
|
manager.openSubEditor({
|
||||||
title: '编辑弹窗',
|
title: '编辑弹窗',
|
||||||
value: {
|
value: {
|
||||||
type: 'dialog',
|
type: 'dialog',
|
||||||
...(modal as any),
|
...(modal as any),
|
||||||
definitions: modalsToDefinitions(
|
definitions: modalsToDefinitions(store.modals, {}, modal)
|
||||||
store.modals.filter(
|
|
||||||
(m: any) =>
|
|
||||||
// 不要把自己下发,不允许弹窗自己再弹出自己
|
|
||||||
// 不要下发自己内容里面内嵌的弹窗,否则会导致子弹窗里面的弹窗列表重复
|
|
||||||
m.$$id !== modalId && !JSONGetById(modal, m.$$id)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
onChange: ({definitions, ...modal}: any, diff: any) => {
|
onChange: ({definitions, ...modal}: any, diff: any) => {
|
||||||
store.updateModal(modalId, modal, definitions);
|
store.updateModal(modalId, modal, definitions);
|
||||||
|
@ -273,7 +273,7 @@ export class OutlinePanel extends React.Component<PanelProps> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {curSearchElemKey} = this.state;
|
const {curSearchElemKey} = this.state;
|
||||||
const {store} = this.props;
|
const {store, manager} = this.props;
|
||||||
const outlineTabsKey = store.outlineTabsKey || 'component-outline';
|
const outlineTabsKey = store.outlineTabsKey || 'component-outline';
|
||||||
const options = store.outline;
|
const options = store.outline;
|
||||||
|
|
||||||
@ -341,7 +341,7 @@ export class OutlinePanel extends React.Component<PanelProps> {
|
|||||||
eventKey={'dialog-outline'}
|
eventKey={'dialog-outline'}
|
||||||
title={'弹窗列表'}
|
title={'弹窗列表'}
|
||||||
>
|
>
|
||||||
<DialogList store={store} classnames={cx} />
|
<DialogList manager={manager} store={store} classnames={cx} />
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -146,6 +146,7 @@ export class SubEditor extends React.Component<SubEditorProps> {
|
|||||||
ref={store.subEditorRef}
|
ref={store.subEditorRef}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
data={store.subEditorContext?.data}
|
data={store.subEditorContext?.data}
|
||||||
|
hostManager={manager}
|
||||||
hostNode={store.subEditorContext?.hostNode}
|
hostNode={store.subEditorContext?.hostNode}
|
||||||
superEditorData={superEditorData}
|
superEditorData={superEditorData}
|
||||||
schemaFilter={manager.config.schemaFilter}
|
schemaFilter={manager.config.schemaFilter}
|
||||||
|
@ -215,7 +215,8 @@ export class EditorManager {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly config: EditorManagerConfig,
|
readonly config: EditorManagerConfig,
|
||||||
readonly store: EditorStoreType
|
readonly store: EditorStoreType,
|
||||||
|
readonly parent?: EditorManager
|
||||||
) {
|
) {
|
||||||
// 传给 amis 渲染器的默认 env
|
// 传给 amis 渲染器的默认 env
|
||||||
this.env = {
|
this.env = {
|
||||||
@ -1358,6 +1359,20 @@ export class EditorManager {
|
|||||||
* @param config
|
* @param config
|
||||||
*/
|
*/
|
||||||
openSubEditor(config: SubEditorContext) {
|
openSubEditor(config: SubEditorContext) {
|
||||||
|
if (
|
||||||
|
['dialog', 'drawer', 'confirmDialog'].includes(config.value.type) &&
|
||||||
|
this.parent
|
||||||
|
) {
|
||||||
|
let parent: EditorManager | undefined = this.parent;
|
||||||
|
while (parent) {
|
||||||
|
if (parent.store.schema.$$id === config.value.$$id) {
|
||||||
|
toast.warning('所选弹窗已经被打开,不能多次打开');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.store.openSubEditor(config);
|
this.store.openSubEditor(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2212,6 +2227,7 @@ export class EditorManager {
|
|||||||
this.trigger('dispose', {
|
this.trigger('dispose', {
|
||||||
data: this
|
data: this
|
||||||
});
|
});
|
||||||
|
delete (this as any).parent;
|
||||||
this.toDispose.forEach(fn => fn());
|
this.toDispose.forEach(fn => fn());
|
||||||
this.toDispose = [];
|
this.toDispose = [];
|
||||||
this.plugins.forEach(p => p.dispose?.());
|
this.plugins.forEach(p => p.dispose?.());
|
||||||
|
@ -133,6 +133,10 @@ export type EditorModalBody = (DialogSchema | DrawerSchema) & {
|
|||||||
// 如果是公共弹窗,在 definitions 中的 key
|
// 如果是公共弹窗,在 definitions 中的 key
|
||||||
$$ref?: string;
|
$$ref?: string;
|
||||||
|
|
||||||
|
// 内嵌弹窗会转成公共弹窗下发给子弹窗,否则子弹窗里面无法选择
|
||||||
|
// 这类会在 definition 里面标记原始位置
|
||||||
|
$$originId?: string;
|
||||||
|
|
||||||
// 弹出方式
|
// 弹出方式
|
||||||
actionType?: string;
|
actionType?: string;
|
||||||
};
|
};
|
||||||
@ -548,10 +552,14 @@ export const MainStore = types
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isSubEditor = self.isSubEditor;
|
||||||
|
|
||||||
return JSONPipeOut(
|
return JSONPipeOut(
|
||||||
JSONGetById(self.schema, self.activeId),
|
JSONGetById(self.schema, self.activeId),
|
||||||
getEnv(self).isHiddenProps ||
|
getEnv(self).isHiddenProps ||
|
||||||
((key, props) =>
|
((key, props) =>
|
||||||
|
// 如果是子弹窗,不显示 definitions,要是通过代码模式改了,就麻烦了
|
||||||
|
(isSubEditor && key === 'definitions') ||
|
||||||
(key.substring(0, 2) === '$$' &&
|
(key.substring(0, 2) === '$$' &&
|
||||||
key !== '$$comments' &&
|
key !== '$$comments' &&
|
||||||
key !== '$$commonSchema') ||
|
key !== '$$commonSchema') ||
|
||||||
@ -1015,15 +1023,7 @@ export const MainStore = types
|
|||||||
get modals(): Array<EditorModalBody> {
|
get modals(): Array<EditorModalBody> {
|
||||||
const schema = self.schema;
|
const schema = self.schema;
|
||||||
const modals: Array<DialogSchema | DrawerSchema> = [];
|
const modals: Array<DialogSchema | DrawerSchema> = [];
|
||||||
Object.keys(schema.definitions || {}).forEach(key => {
|
|
||||||
const definition = schema.definitions[key];
|
|
||||||
if (['dialog', 'drawer'].includes(definition.type)) {
|
|
||||||
modals.push({
|
|
||||||
...definition,
|
|
||||||
$$ref: key
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
JSONTraverse(schema, (value: any, key: string, host: any) => {
|
JSONTraverse(schema, (value: any, key: string, host: any) => {
|
||||||
if (
|
if (
|
||||||
key === 'actionType' &&
|
key === 'actionType' &&
|
||||||
@ -1031,12 +1031,7 @@ export const MainStore = types
|
|||||||
) {
|
) {
|
||||||
const key = value === 'drawer' ? 'drawer' : 'dialog';
|
const key = value === 'drawer' ? 'drawer' : 'dialog';
|
||||||
const body = host[key] || host['args'];
|
const body = host[key] || host['args'];
|
||||||
if (
|
if (body && !body.$ref) {
|
||||||
body &&
|
|
||||||
!body.$ref &&
|
|
||||||
body.$$id &&
|
|
||||||
!modals.find(m => (m as any).$$originId === body.$$id)
|
|
||||||
) {
|
|
||||||
modals.push({
|
modals.push({
|
||||||
...body,
|
...body,
|
||||||
actionType: value
|
actionType: value
|
||||||
@ -1045,6 +1040,37 @@ export const MainStore = types
|
|||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 公共组件排在前面
|
||||||
|
Object.keys(schema.definitions || {})
|
||||||
|
.reverse()
|
||||||
|
.forEach(key => {
|
||||||
|
const definition = schema.definitions[key];
|
||||||
|
if (['dialog', 'drawer'].includes(definition.type)) {
|
||||||
|
// 不要把已经内嵌弹窗中的弹窗再放到外面
|
||||||
|
if (
|
||||||
|
definition.$$originId &&
|
||||||
|
modals.find(item => item.$$id === definition.$$originId)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modals.unshift({
|
||||||
|
...definition,
|
||||||
|
$$ref: key
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 子弹窗时,自己就是个弹窗
|
||||||
|
if (['dialog', 'drawer', 'confirmDialog'].includes(schema.type)) {
|
||||||
|
modals.unshift({
|
||||||
|
...schema,
|
||||||
|
// 如果还包含这个,子弹窗里面收集弹窗的时候会出现多份内嵌弹窗
|
||||||
|
definitions: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return modals;
|
return modals;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1397,7 +1397,12 @@ export const scrollToActive = debounce((selector: string) => {
|
|||||||
}
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
export function addModal(schema: any, modal: any, definitions?: any) {
|
export function addModal(
|
||||||
|
schema: any,
|
||||||
|
modal: any,
|
||||||
|
definitions?: any,
|
||||||
|
isKeyValid?: (key: string) => boolean
|
||||||
|
) {
|
||||||
schema = {...schema, definitions: {...schema.definitions}};
|
schema = {...schema, definitions: {...schema.definitions}};
|
||||||
|
|
||||||
// 如果有传入definitions,则合并到schema中
|
// 如果有传入definitions,则合并到schema中
|
||||||
@ -1407,7 +1412,10 @@ export function addModal(schema: any, modal: any, definitions?: any) {
|
|||||||
|
|
||||||
let idx = 1;
|
let idx = 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!schema.definitions[`modal-ref-${idx}`]) {
|
if (
|
||||||
|
!schema.definitions[`modal-ref-${idx}`] &&
|
||||||
|
(!isKeyValid || isKeyValid(`modal-ref-${idx}`))
|
||||||
|
) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
idx++;
|
idx++;
|
||||||
@ -1435,16 +1443,42 @@ export function addModal(schema: any, modal: any, definitions?: any) {
|
|||||||
*/
|
*/
|
||||||
export function modalsToDefinitions(
|
export function modalsToDefinitions(
|
||||||
modals: Array<EditorModalBody>,
|
modals: Array<EditorModalBody>,
|
||||||
definitions: any = {}
|
definitions: any = {},
|
||||||
|
edtingModal?: EditorModalBody
|
||||||
) {
|
) {
|
||||||
let schema = {
|
let schema = {
|
||||||
definitions
|
definitions
|
||||||
};
|
};
|
||||||
|
|
||||||
modals.forEach((modal, idx) => {
|
modals.forEach((modal, idx) => {
|
||||||
|
if (
|
||||||
|
edtingModal &&
|
||||||
|
(edtingModal.$$ref
|
||||||
|
? edtingModal.$$ref === modal.$$ref
|
||||||
|
: edtingModal.$$id === modal.$$id)
|
||||||
|
) {
|
||||||
|
// 自己不需要转成 definitions
|
||||||
|
return;
|
||||||
|
} else if (
|
||||||
|
!modal.$$ref &&
|
||||||
|
modal.$$id &&
|
||||||
|
(JSONGetById(schema.definitions, modal.$$id) ||
|
||||||
|
(edtingModal && JSONGetById(edtingModal, modal.$$id)))
|
||||||
|
) {
|
||||||
|
// 内嵌弹窗,已经包含在 definitions 里面了
|
||||||
|
// 不需要转成 definitions
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (modal.$$ref) {
|
if (modal.$$ref) {
|
||||||
schema.definitions[modal.$$ref] = JSONPipeIn(modal);
|
schema.definitions[modal.$$ref] = JSONPipeIn(modal);
|
||||||
} else {
|
} else {
|
||||||
[schema] = addModal(schema, {...modal, $$originId: modal.$$id});
|
[schema] = addModal(
|
||||||
|
schema,
|
||||||
|
{...modal, $$originId: modal.$$id},
|
||||||
|
undefined,
|
||||||
|
key => !modals.find(m => m.$$ref && m.$$ref === key)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return schema.definitions;
|
return schema.definitions;
|
||||||
|
@ -79,7 +79,7 @@ function DialogActionPanel({
|
|||||||
subscribeSchemaSubmit((schema: any, nodeSchema: any, id: string) => {
|
subscribeSchemaSubmit((schema: any, nodeSchema: any, id: string) => {
|
||||||
const rawActions = JSONGetById(schema, id)?.onEvent[eventKey]?.actions;
|
const rawActions = JSONGetById(schema, id)?.onEvent[eventKey]?.actions;
|
||||||
if (!rawActions || !Array.isArray(rawActions)) {
|
if (!rawActions || !Array.isArray(rawActions)) {
|
||||||
throw new Error('动作配置错误');
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionSchema =
|
const actionSchema =
|
||||||
@ -88,8 +88,9 @@ function DialogActionPanel({
|
|||||||
? rawActions.length - 1
|
? rawActions.length - 1
|
||||||
: actionIndex
|
: actionIndex
|
||||||
];
|
];
|
||||||
const modals: Array<LocalModal> = actionSchema.__actionModals;
|
const modals: Array<LocalModal> = actionSchema?.__actionModals;
|
||||||
if (!Array.isArray(modals)) {
|
if (!Array.isArray(modals)) {
|
||||||
|
// 不是编辑确定触发的,直接返回
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +289,7 @@ function DialogActionPanel({
|
|||||||
actionSchema.actionType === 'drawer' ? 'drawer' : 'dialog'
|
actionSchema.actionType === 'drawer' ? 'drawer' : 'dialog'
|
||||||
] || actionSchema.args;
|
] || actionSchema.args;
|
||||||
|
|
||||||
|
const schema = store.schema;
|
||||||
const modals: Array<LocalModal> = store.modals.map(modal => {
|
const modals: Array<LocalModal> = store.modals.map(modal => {
|
||||||
const isCurrentActionModal = modal.$$id === dialogBody?.$$id;
|
const isCurrentActionModal = modal.$$id === dialogBody?.$$id;
|
||||||
|
|
||||||
@ -310,7 +312,11 @@ function DialogActionPanel({
|
|||||||
value: modal.$$id,
|
value: modal.$$id,
|
||||||
modal: modal,
|
modal: modal,
|
||||||
isCurrentActionModal,
|
isCurrentActionModal,
|
||||||
data: modal.data
|
data: modal.data,
|
||||||
|
// 当前编辑的弹窗不让再里面再次弹出
|
||||||
|
disabled: modal.$$ref
|
||||||
|
? modal.$$ref === schema.$$ref
|
||||||
|
: modal.$$id === schema.$$id
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -458,7 +464,7 @@ function DialogActionPanel({
|
|||||||
skipForm?: boolean,
|
skipForm?: boolean,
|
||||||
closePopOver?: () => void
|
closePopOver?: () => void
|
||||||
) => {
|
) => {
|
||||||
store.openSubEditor({
|
manager.openSubEditor({
|
||||||
title: '新建弹窗',
|
title: '新建弹窗',
|
||||||
value: {
|
value: {
|
||||||
type: 'dialog',
|
type: 'dialog',
|
||||||
@ -513,7 +519,7 @@ function DialogActionPanel({
|
|||||||
if (!currentModal) {
|
if (!currentModal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.openSubEditor({
|
manager.openSubEditor({
|
||||||
title: '编辑弹窗',
|
title: '编辑弹窗',
|
||||||
value: {
|
value: {
|
||||||
type: 'dialog',
|
type: 'dialog',
|
||||||
@ -526,7 +532,9 @@ function DialogActionPanel({
|
|||||||
],
|
],
|
||||||
...(currentModal.modal as any),
|
...(currentModal.modal as any),
|
||||||
definitions: modalsToDefinitions(
|
definitions: modalsToDefinitions(
|
||||||
modals.filter(item => !item.isActive).map(item => item.modal)
|
modals.map(item => item.modal),
|
||||||
|
{},
|
||||||
|
currentModal.modal
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onChange: ({definitions, ...modal}: any, diff: any) => {
|
onChange: ({definitions, ...modal}: any, diff: any) => {
|
||||||
|
@ -321,19 +321,12 @@ export const ACTION_TYPE_TREE = (manager: any): RendererPluginAction[] => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
const modalId = modal.$$id;
|
const modalId = modal.$$id;
|
||||||
store.openSubEditor({
|
manager.openSubEditor({
|
||||||
title: '编辑弹窗',
|
title: '编辑弹窗',
|
||||||
value: {
|
value: {
|
||||||
type: 'dialog',
|
type: 'dialog',
|
||||||
...modal,
|
...modal,
|
||||||
definitions: modalsToDefinitions(
|
definitions: modalsToDefinitions(store.modals, {}, modal)
|
||||||
store.modals.filter(
|
|
||||||
(m: any) =>
|
|
||||||
// 不要把自己下发,不允许弹窗自己再弹出自己
|
|
||||||
// 不要下发自己内容里面内嵌的弹窗,否则会导致子弹窗里面的弹窗列表重复
|
|
||||||
m.$$id !== modalId && !JSONGetById(modal, m.$$id)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
onChange: ({definitions, ...modal}: any, diff: any) => {
|
onChange: ({definitions, ...modal}: any, diff: any) => {
|
||||||
store.updateModal(modalId, modal, definitions);
|
store.updateModal(modalId, modal, definitions);
|
||||||
|
Loading…
Reference in New Issue
Block a user