mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-05 07:27:09 +08:00
feat(editor): 优化依赖收集,数据源代码块分开收集
This commit is contained in:
parent
b215062177
commit
040b787e8f
@ -1,4 +1,4 @@
|
||||
import { computed, onBeforeUnmount, reactive, toRaw, watch } from 'vue';
|
||||
import { onBeforeUnmount, reactive, toRaw, watch } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import type TMagicCore from '@tmagic/core';
|
||||
@ -8,7 +8,7 @@ import type {
|
||||
EventOption,
|
||||
Id,
|
||||
MApp,
|
||||
MNode,
|
||||
MComponent,
|
||||
MPage,
|
||||
MPageFragment,
|
||||
} from '@tmagic/core';
|
||||
@ -22,7 +22,7 @@ import {
|
||||
Target,
|
||||
} from '@tmagic/core';
|
||||
import { ChangeRecord } from '@tmagic/form';
|
||||
import { getNodes, isPage, isValueIncludeDataSource, traverseNode } from '@tmagic/utils';
|
||||
import { getNodes, isPage, isValueIncludeDataSource } from '@tmagic/utils';
|
||||
|
||||
import PropsPanel from './layouts/PropsPanel.vue';
|
||||
import { isIncludeDataSource } from './utils/editor';
|
||||
@ -106,11 +106,12 @@ export const initServiceState = (
|
||||
const eventsList: Record<string, EventOption[]> = {};
|
||||
const methodsList: Record<string, EventOption[]> = {};
|
||||
|
||||
eventMethodList &&
|
||||
Object.keys(eventMethodList).forEach((type: string) => {
|
||||
if (eventMethodList) {
|
||||
for (const type of Object.keys(eventMethodList)) {
|
||||
eventsList[type] = eventMethodList[type].events;
|
||||
methodsList[type] = eventMethodList[type].methods;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
eventsService.setEvents(eventsList);
|
||||
eventsService.setMethods(methodsList);
|
||||
@ -123,10 +124,13 @@ export const initServiceState = (
|
||||
watch(
|
||||
() => props.datasourceConfigs,
|
||||
(configs) => {
|
||||
configs &&
|
||||
Object.entries(configs).forEach(([key, value]) => {
|
||||
dataSourceService.setFormConfig(key, value);
|
||||
});
|
||||
if (!configs) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(configs)) {
|
||||
dataSourceService.setFormConfig(key, value);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@ -136,10 +140,13 @@ export const initServiceState = (
|
||||
watch(
|
||||
() => props.datasourceValues,
|
||||
(values) => {
|
||||
values &&
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
dataSourceService.setFormValue(key, value);
|
||||
});
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
dataSourceService.setFormValue(key, value);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@ -152,18 +159,20 @@ export const initServiceState = (
|
||||
const eventsList: Record<string, EventOption[]> = {};
|
||||
const methodsList: Record<string, EventOption[]> = {};
|
||||
|
||||
eventMethodList &&
|
||||
Object.keys(eventMethodList).forEach((type: string) => {
|
||||
if (eventMethodList) {
|
||||
for (const type of Object.keys(eventMethodList)) {
|
||||
eventsList[type] = eventMethodList[type].events;
|
||||
methodsList[type] = eventMethodList[type].methods;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Object.entries(eventsList).forEach(([key, value]) => {
|
||||
for (const [key, value] of Object.entries(eventsList)) {
|
||||
dataSourceService.setFormEvent(key, value);
|
||||
});
|
||||
Object.entries(methodsList).forEach(([key, value]) => {
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(methodsList)) {
|
||||
dataSourceService.setFormMethod(key, value);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@ -203,6 +212,113 @@ export const initServiceEvents = (
|
||||
((event: 'update:modelValue', value: MApp | null) => void),
|
||||
{ editorService, codeBlockService, dataSourceService, depService }: Services,
|
||||
) => {
|
||||
const getTMagicApp = () => {
|
||||
const renderer = editorService.get('stage')?.renderer;
|
||||
if (!renderer) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (renderer.runtime) {
|
||||
return renderer.runtime.getApp?.();
|
||||
}
|
||||
|
||||
return new Promise<TMagicCore | undefined>((resolve) => {
|
||||
// 设置 10s 超时
|
||||
const timeout = globalThis.setTimeout(() => {
|
||||
resolve(undefined);
|
||||
}, 10000);
|
||||
|
||||
renderer.on('runtime-ready', () => {
|
||||
if (timeout) {
|
||||
globalThis.clearTimeout(timeout);
|
||||
}
|
||||
resolve(renderer.runtime?.getApp?.());
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const updateStageNodes = (nodes: MComponent[]) => {
|
||||
for (const node of nodes) {
|
||||
updateStageNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
const updateStageNode = (node: MComponent) => {
|
||||
const root = editorService.get('root');
|
||||
if (!root) return;
|
||||
|
||||
return editorService.get('stage')?.update({
|
||||
config: cloneDeep(node),
|
||||
parentId: editorService.getParentById(node.id)?.id,
|
||||
root: cloneDeep(root),
|
||||
});
|
||||
};
|
||||
|
||||
const updateDataSourceSchema = async () => {
|
||||
const root = editorService.get('root');
|
||||
const app = await getTMagicApp();
|
||||
|
||||
if (!app || !root) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (app.dsl) {
|
||||
app.dsl.dataSources = root.dataSources;
|
||||
}
|
||||
|
||||
if (root.dataSources) {
|
||||
app.dataSourceManager?.updateSchema(root.dataSources);
|
||||
}
|
||||
};
|
||||
|
||||
const dsDepCollectedHandler = async () => {
|
||||
const root = editorService.get('root');
|
||||
const app = await getTMagicApp();
|
||||
|
||||
if (root && app?.dsl) {
|
||||
app.dsl.dataSourceDeps = root.dataSourceDeps;
|
||||
}
|
||||
};
|
||||
|
||||
const collectIdle = (nodes: MComponent[], deep: boolean, type?: DepTargetType) =>
|
||||
Promise.all(
|
||||
nodes.map((node) => {
|
||||
let pageId: Id | undefined;
|
||||
|
||||
if (isPage(node)) {
|
||||
pageId = node.id;
|
||||
} else {
|
||||
const info = editorService.getNodeInfo(node.id);
|
||||
pageId = info.page?.id;
|
||||
}
|
||||
return depService.collectIdle([node], { pageId }, deep, type);
|
||||
}),
|
||||
);
|
||||
|
||||
watch(
|
||||
() => editorService.get('stage'),
|
||||
(stage) => {
|
||||
if (!stage) {
|
||||
return;
|
||||
}
|
||||
|
||||
stage.on('rerender', async () => {
|
||||
const node = editorService.get('node');
|
||||
|
||||
if (!node) return;
|
||||
|
||||
await collectIdle([node], true, DepTargetType.DATA_SOURCE);
|
||||
updateStageNode(node);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
const initDataSourceDepTarget = (ds: DataSourceSchema) => {
|
||||
depService.addTarget(createDataSourceTarget(ds, reactive({})));
|
||||
depService.addTarget(createDataSourceMethodTarget(ds, reactive({})));
|
||||
depService.addTarget(createDataSourceCondTarget(ds, reactive({})));
|
||||
};
|
||||
|
||||
const rootChangeHandler = async (value: MApp | null, preValue?: MApp | null) => {
|
||||
if (!value) return;
|
||||
|
||||
@ -214,17 +330,19 @@ export const initServiceEvents = (
|
||||
|
||||
depService.removeTargets(DepTargetType.CODE_BLOCK);
|
||||
|
||||
Object.entries(value.codeBlocks).forEach(([id, code]) => {
|
||||
for (const [id, code] of Object.entries(value.codeBlocks)) {
|
||||
depService.addTarget(createCodeBlockTarget(id, code));
|
||||
});
|
||||
}
|
||||
|
||||
dataSourceService.get('dataSources').forEach((ds) => {
|
||||
for (const ds of dataSourceService.get('dataSources')) {
|
||||
initDataSourceDepTarget(ds);
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(value.items)) {
|
||||
depService.clearIdleTasks();
|
||||
collectIdle(value.items, true);
|
||||
collectIdle(value.items, true).then(() => {
|
||||
updateStageNodes(value.items);
|
||||
});
|
||||
} else {
|
||||
depService.clear();
|
||||
delete value.dataSourceDeps;
|
||||
@ -252,61 +370,203 @@ export const initServiceEvents = (
|
||||
}
|
||||
};
|
||||
|
||||
const stage = computed(() => editorService.get('stage'));
|
||||
// 新增节点,收集依赖
|
||||
const nodeAddHandler = async (nodes: MComponent[]) => {
|
||||
await collectIdle(nodes, true);
|
||||
|
||||
watch(stage, (stage) => {
|
||||
if (!stage) {
|
||||
return;
|
||||
}
|
||||
|
||||
stage.on('rerender', () => {
|
||||
const node = editorService.get('node');
|
||||
|
||||
if (!node) return;
|
||||
|
||||
collectIdle([node], true);
|
||||
updateStage([node]);
|
||||
});
|
||||
});
|
||||
|
||||
const getApp = () => {
|
||||
const renderer = stage.value?.renderer;
|
||||
if (!renderer) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (renderer.runtime) {
|
||||
return renderer.runtime.getApp?.();
|
||||
}
|
||||
|
||||
return new Promise<TMagicCore | undefined>((resolve) => {
|
||||
const timeout = globalThis.setTimeout(() => {
|
||||
resolve(undefined);
|
||||
}, 10000);
|
||||
|
||||
renderer.on('runtime-ready', () => {
|
||||
if (timeout) {
|
||||
globalThis.clearTimeout(timeout);
|
||||
}
|
||||
resolve(renderer.runtime?.getApp?.());
|
||||
});
|
||||
});
|
||||
updateStageNodes(nodes);
|
||||
};
|
||||
|
||||
const updateDataSourceSchema = async () => {
|
||||
const root = editorService.get('root');
|
||||
const app = await getApp();
|
||||
// 节点更新,收集依赖
|
||||
// 仅当修改到数据源相关的才收集
|
||||
const nodeUpdateHandler = async (
|
||||
data: { newNode: MComponent; oldNode: MComponent; changeRecords?: ChangeRecord[] }[],
|
||||
) => {
|
||||
const needRecollectNodes: MComponent[] = [];
|
||||
const normalNodes: MComponent[] = [];
|
||||
for (const { newNode, oldNode, changeRecords } of data) {
|
||||
if (changeRecords?.length) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
forChangeRecords: for (const record of changeRecords) {
|
||||
if (!record.propPath) {
|
||||
needRecollectNodes.push(newNode);
|
||||
break forChangeRecords;
|
||||
}
|
||||
|
||||
if (root && app?.dsl) {
|
||||
app.dsl.dataSourceDeps = root.dataSourceDeps;
|
||||
app.dsl.dataSources = root.dataSources;
|
||||
// NODE_CONDS_KEY为显示条件key
|
||||
if (
|
||||
new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond`).test(record.propPath) ||
|
||||
new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond.(\\d)+.value`).test(record.propPath) ||
|
||||
record.propPath === NODE_CONDS_KEY ||
|
||||
isValueIncludeDataSource(record.value)
|
||||
) {
|
||||
needRecollectNodes.push(newNode);
|
||||
break forChangeRecords;
|
||||
}
|
||||
|
||||
// 修改的key在收集的依赖中,则需要触发重新收集
|
||||
for (const target of Object.values(depService.getTargets(DepTargetType.DATA_SOURCE))) {
|
||||
if (!target.deps[newNode.id]) {
|
||||
continue;
|
||||
}
|
||||
if (target.deps[newNode.id].keys.includes(record.propPath)) {
|
||||
needRecollectNodes.push(newNode);
|
||||
break forChangeRecords;
|
||||
}
|
||||
}
|
||||
|
||||
normalNodes.push(newNode);
|
||||
}
|
||||
} else if (isIncludeDataSource(newNode, oldNode)) {
|
||||
needRecollectNodes.push(newNode);
|
||||
} else {
|
||||
normalNodes.push(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (root?.dataSources) {
|
||||
if (needRecollectNodes.length) {
|
||||
// 有数据源依赖,需要等依赖重新收集完才更新stage
|
||||
await collectIdle(needRecollectNodes, true, DepTargetType.DATA_SOURCE);
|
||||
await collectIdle(needRecollectNodes, true, DepTargetType.DATA_SOURCE_COND);
|
||||
updateStageNodes(needRecollectNodes);
|
||||
} else {
|
||||
updateStageNodes(normalNodes);
|
||||
// 在上面判断是否需要收集数据源依赖中已经更新stage
|
||||
Promise.all([
|
||||
collectIdle(normalNodes, true, DepTargetType.CODE_BLOCK),
|
||||
collectIdle(normalNodes, true, DepTargetType.DATA_SOURCE_METHOD),
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
// 节点删除,清除对齐的依赖收集
|
||||
const nodeRemoveHandler = (nodes: MComponent[]) => {
|
||||
depService.clear(nodes);
|
||||
};
|
||||
|
||||
// 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
|
||||
const historyChangeHandler = async (page: MPage | MPageFragment) => {
|
||||
await collectIdle([page], true);
|
||||
updateStageNode(page);
|
||||
};
|
||||
|
||||
editorService.on('history-change', historyChangeHandler);
|
||||
editorService.on('root-change', rootChangeHandler);
|
||||
editorService.on('add', nodeAddHandler);
|
||||
editorService.on('remove', nodeRemoveHandler);
|
||||
editorService.on('update', nodeUpdateHandler);
|
||||
|
||||
const dataSourceAddHandler = async (config: DataSourceSchema) => {
|
||||
initDataSourceDepTarget(config);
|
||||
const app = await getTMagicApp();
|
||||
app?.dataSourceManager?.addDataSource(config);
|
||||
};
|
||||
|
||||
const dataSourceUpdateHandler = async (
|
||||
config: DataSourceSchema,
|
||||
{ changeRecords }: { changeRecords: ChangeRecord[] },
|
||||
) => {
|
||||
let needRecollectDep = false;
|
||||
let isModifyField = false;
|
||||
let isModifyMock = false;
|
||||
let isModifyMethod = false;
|
||||
for (const changeRecord of changeRecords) {
|
||||
if (!changeRecord.propPath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isModifyField =
|
||||
changeRecord.propPath === 'fields' ||
|
||||
/fields.(\d)+.name/.test(changeRecord.propPath) ||
|
||||
/fields.(\d)+$/.test(changeRecord.propPath);
|
||||
|
||||
isModifyMock = changeRecord.propPath === 'mocks';
|
||||
|
||||
isModifyMethod =
|
||||
changeRecord.propPath === 'methods' ||
|
||||
/methods.(\d)+.name/.test(changeRecord.propPath) ||
|
||||
/methods.(\d)+$/.test(changeRecord.propPath);
|
||||
|
||||
needRecollectDep = isModifyField || isModifyMock || isModifyMethod;
|
||||
|
||||
if (needRecollectDep) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const root = editorService.get('root');
|
||||
if (needRecollectDep) {
|
||||
if (Array.isArray(root?.items)) {
|
||||
depService.clearIdleTasks();
|
||||
|
||||
removeDataSourceTarget(config.id);
|
||||
initDataSourceDepTarget(config);
|
||||
|
||||
let collectIdlePromises: Promise<void[]>[] = [];
|
||||
if (isModifyField) {
|
||||
collectIdlePromises = [
|
||||
collectIdle(root.items, true, DepTargetType.DATA_SOURCE),
|
||||
collectIdle(root.items, true, DepTargetType.DATA_SOURCE_COND),
|
||||
];
|
||||
} else if (isModifyMock) {
|
||||
collectIdlePromises = [collectIdle(root.items, true, DepTargetType.DATA_SOURCE)];
|
||||
} else if (isModifyMethod) {
|
||||
collectIdlePromises = [collectIdle(root.items, true, DepTargetType.DATA_SOURCE_METHOD)];
|
||||
}
|
||||
Promise.all(collectIdlePromises).then(() => {
|
||||
updateDataSourceSchema();
|
||||
updateStageNodes(root.items);
|
||||
});
|
||||
}
|
||||
} else if (root?.dataSources) {
|
||||
const app = await getTMagicApp();
|
||||
app?.dataSourceManager?.updateSchema(root.dataSources);
|
||||
}
|
||||
};
|
||||
|
||||
const removeDataSourceTarget = (id: string) => {
|
||||
depService.removeTarget(id, DepTargetType.DATA_SOURCE);
|
||||
depService.removeTarget(id, DepTargetType.DATA_SOURCE_COND);
|
||||
depService.removeTarget(id, DepTargetType.DATA_SOURCE_METHOD);
|
||||
};
|
||||
|
||||
const dataSourceRemoveHandler = (id: string) => {
|
||||
const root = editorService.get('root');
|
||||
const nodeIds = Object.keys(root?.dataSourceDeps?.[id] || {});
|
||||
const nodes = getNodes(nodeIds, root?.items);
|
||||
|
||||
Promise.all([
|
||||
collectIdle(nodes, false, DepTargetType.DATA_SOURCE),
|
||||
collectIdle(nodes, false, DepTargetType.DATA_SOURCE_COND),
|
||||
collectIdle(nodes, false, DepTargetType.DATA_SOURCE_METHOD),
|
||||
]).then(() => {
|
||||
updateDataSourceSchema();
|
||||
updateStageNodes(nodes);
|
||||
});
|
||||
|
||||
removeDataSourceTarget(id);
|
||||
};
|
||||
|
||||
dataSourceService.on('add', dataSourceAddHandler);
|
||||
dataSourceService.on('update', dataSourceUpdateHandler);
|
||||
dataSourceService.on('remove', dataSourceRemoveHandler);
|
||||
|
||||
const codeBlockAddOrUpdateHandler = (id: Id, codeBlock: CodeBlockContent) => {
|
||||
if (depService.hasTarget(id, DepTargetType.CODE_BLOCK)) {
|
||||
depService.getTarget(id, DepTargetType.CODE_BLOCK)!.name = codeBlock.name;
|
||||
return;
|
||||
}
|
||||
|
||||
depService.addTarget(createCodeBlockTarget(id, codeBlock));
|
||||
};
|
||||
|
||||
const codeBlockRemoveHandler = (id: Id) => {
|
||||
depService.removeTarget(id, DepTargetType.CODE_BLOCK);
|
||||
};
|
||||
|
||||
codeBlockService.on('addOrUpdate', codeBlockAddOrUpdateHandler);
|
||||
codeBlockService.on('remove', codeBlockRemoveHandler);
|
||||
|
||||
const targetAddHandler = (target: Target) => {
|
||||
const root = editorService.get('root');
|
||||
if (!root) return;
|
||||
@ -340,239 +600,10 @@ export const initServiceEvents = (
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改dsl后会执行依赖收集并调用此方法
|
||||
* 所以这个方法是会被执行两次,当时updateStage应当时一次,所以通过inDeps参数来区分调用时机
|
||||
* inDeps为true是则更新依赖收集到的节点,否则则更新没有依赖的节点
|
||||
* @param nodes 需要更新的节点
|
||||
* @param inDeps 是否依赖收集完成事件中执行的
|
||||
* @returns
|
||||
*/
|
||||
const updateStage = (nodes: MNode[], inDeps = false) => {
|
||||
const root = editorService.get('root');
|
||||
if (!root) return;
|
||||
|
||||
const update = (node: MNode) =>
|
||||
stage.value?.update({
|
||||
config: cloneDeep(node),
|
||||
parentId: editorService.getParentById(node.id)?.id,
|
||||
root: cloneDeep(root),
|
||||
});
|
||||
|
||||
nodes.forEach((node) => {
|
||||
const inDepsNodeId: Id[] = [];
|
||||
const deps = Object.values(root.dataSourceDeps || {});
|
||||
deps.forEach((dep) => {
|
||||
Object.keys(dep).forEach((id) => {
|
||||
inDepsNodeId.push(id);
|
||||
});
|
||||
});
|
||||
|
||||
if (inDeps) {
|
||||
if (inDepsNodeId.includes(node.id)) {
|
||||
update(node);
|
||||
}
|
||||
} else {
|
||||
if (!inDepsNodeId.includes(node.id)) {
|
||||
update(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const dsDepCollectedHandler = async (nodes: MNode[], deep: boolean) => {
|
||||
const root = editorService.get('root');
|
||||
if (!root) return;
|
||||
const app = await getApp();
|
||||
if (app?.dsl) {
|
||||
app.dsl.dataSourceDeps = root.dataSourceDeps;
|
||||
}
|
||||
if (deep) {
|
||||
nodes.forEach((node) => {
|
||||
traverseNode<MNode>(
|
||||
node,
|
||||
(node) => {
|
||||
updateStage([node], true);
|
||||
},
|
||||
[],
|
||||
true,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
updateStage(nodes, true);
|
||||
}
|
||||
};
|
||||
|
||||
depService.on('add-target', targetAddHandler);
|
||||
depService.on('remove-target', targetRemoveHandler);
|
||||
depService.on('ds-collected', dsDepCollectedHandler);
|
||||
|
||||
const initDataSourceDepTarget = (ds: DataSourceSchema) => {
|
||||
depService.addTarget(createDataSourceTarget(ds, reactive({})));
|
||||
depService.addTarget(createDataSourceMethodTarget(ds, reactive({})));
|
||||
depService.addTarget(createDataSourceCondTarget(ds, reactive({})));
|
||||
};
|
||||
|
||||
const collectIdle = (nodes: MNode[], deep: boolean) =>
|
||||
Promise.all(
|
||||
nodes.map((node) => {
|
||||
let pageId: Id | undefined;
|
||||
|
||||
if (isPage(node)) {
|
||||
pageId = node.id;
|
||||
} else {
|
||||
const info = editorService.getNodeInfo(node.id);
|
||||
pageId = info.page?.id;
|
||||
}
|
||||
return depService.collectIdle([node], { pageId }, deep);
|
||||
}),
|
||||
);
|
||||
|
||||
// 新增节点,收集依赖
|
||||
const nodeAddHandler = (nodes: MNode[]) => {
|
||||
collectIdle(nodes, true);
|
||||
|
||||
updateStage(nodes);
|
||||
};
|
||||
|
||||
// 节点更新,收集依赖
|
||||
// 仅当修改到数据源相关的才收集
|
||||
const nodeUpdateHandler = (data: { newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }[]) => {
|
||||
const needRecollectNodes: MNode[] = [];
|
||||
const normalNodes: MNode[] = [];
|
||||
data.forEach(({ newNode, oldNode, changeRecords }) => {
|
||||
if (changeRecords?.length) {
|
||||
for (const record of changeRecords) {
|
||||
// NODE_CONDS_KEY为显示条件key
|
||||
if (
|
||||
!record.propPath ||
|
||||
new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond`).test(record.propPath) ||
|
||||
new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond.(\\d)+.value`).test(record.propPath) ||
|
||||
record.propPath === NODE_CONDS_KEY ||
|
||||
isValueIncludeDataSource(record.value)
|
||||
) {
|
||||
needRecollectNodes.push(newNode);
|
||||
} else {
|
||||
normalNodes.push(newNode);
|
||||
}
|
||||
}
|
||||
} else if (isIncludeDataSource(newNode, oldNode)) {
|
||||
needRecollectNodes.push(newNode);
|
||||
} else {
|
||||
normalNodes.push(newNode);
|
||||
}
|
||||
});
|
||||
|
||||
if (needRecollectNodes.length) {
|
||||
collectIdle(needRecollectNodes, true);
|
||||
updateStage(needRecollectNodes);
|
||||
} else if (normalNodes.length) {
|
||||
updateStage(normalNodes);
|
||||
}
|
||||
};
|
||||
|
||||
// 节点删除,清除对齐的依赖收集
|
||||
const nodeRemoveHandler = (nodes: MNode[]) => {
|
||||
depService.clear(nodes);
|
||||
};
|
||||
|
||||
// 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
|
||||
const historyChangeHandler = (page: MPage | MPageFragment) => {
|
||||
collectIdle([page], true).then(() => {
|
||||
updateDataSourceSchema();
|
||||
});
|
||||
};
|
||||
|
||||
editorService.on('history-change', historyChangeHandler);
|
||||
editorService.on('root-change', rootChangeHandler);
|
||||
editorService.on('add', nodeAddHandler);
|
||||
editorService.on('remove', nodeRemoveHandler);
|
||||
editorService.on('update', nodeUpdateHandler);
|
||||
|
||||
const codeBlockAddOrUpdateHandler = (id: Id, codeBlock: CodeBlockContent) => {
|
||||
if (depService.hasTarget(id, DepTargetType.CODE_BLOCK)) {
|
||||
depService.getTarget(id, DepTargetType.CODE_BLOCK)!.name = codeBlock.name;
|
||||
return;
|
||||
}
|
||||
|
||||
depService.addTarget(createCodeBlockTarget(id, codeBlock));
|
||||
};
|
||||
|
||||
const codeBlockRemoveHandler = (id: Id) => {
|
||||
depService.removeTarget(id, DepTargetType.CODE_BLOCK);
|
||||
};
|
||||
|
||||
codeBlockService.on('addOrUpdate', codeBlockAddOrUpdateHandler);
|
||||
codeBlockService.on('remove', codeBlockRemoveHandler);
|
||||
|
||||
const dataSourceAddHandler = async (config: DataSourceSchema) => {
|
||||
initDataSourceDepTarget(config);
|
||||
const app = await getApp();
|
||||
app?.dataSourceManager?.addDataSource(config);
|
||||
};
|
||||
|
||||
const dataSourceUpdateHandler = async (
|
||||
config: DataSourceSchema,
|
||||
{ changeRecords }: { changeRecords: ChangeRecord[] },
|
||||
) => {
|
||||
let needRecollectDep = false;
|
||||
for (const changeRecord of changeRecords) {
|
||||
if (!changeRecord.propPath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
needRecollectDep =
|
||||
changeRecord.propPath === 'fields' ||
|
||||
changeRecord.propPath === 'methods' ||
|
||||
/fields.(\d)+.name/.test(changeRecord.propPath) ||
|
||||
/fields.(\d)+$/.test(changeRecord.propPath) ||
|
||||
/methods.(\d)+.name/.test(changeRecord.propPath) ||
|
||||
/methods.(\d)+$/.test(changeRecord.propPath);
|
||||
|
||||
if (needRecollectDep) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const root = editorService.get('root');
|
||||
if (needRecollectDep) {
|
||||
if (Array.isArray(root?.items)) {
|
||||
depService.clearIdleTasks();
|
||||
|
||||
removeDataSourceTarget(config.id);
|
||||
initDataSourceDepTarget(config);
|
||||
|
||||
collectIdle(root.items, true).then(() => {
|
||||
updateDataSourceSchema();
|
||||
});
|
||||
}
|
||||
} else if (root?.dataSources) {
|
||||
const app = await getApp();
|
||||
app?.dataSourceManager?.updateSchema(root.dataSources);
|
||||
}
|
||||
};
|
||||
|
||||
const removeDataSourceTarget = (id: string) => {
|
||||
depService.removeTarget(id, DepTargetType.DATA_SOURCE);
|
||||
depService.removeTarget(id, DepTargetType.DATA_SOURCE_COND);
|
||||
depService.removeTarget(id, DepTargetType.DATA_SOURCE_METHOD);
|
||||
};
|
||||
|
||||
const dataSourceRemoveHandler = (id: string) => {
|
||||
const root = editorService.get('root');
|
||||
const nodeIds = Object.keys(root?.dataSourceDeps?.[id] || {});
|
||||
const nodes = getNodes(nodeIds, root?.items);
|
||||
collectIdle(nodes, false).then(() => {
|
||||
updateDataSourceSchema();
|
||||
});
|
||||
|
||||
removeDataSourceTarget(id);
|
||||
};
|
||||
|
||||
dataSourceService.on('add', dataSourceAddHandler);
|
||||
dataSourceService.on('update', dataSourceUpdateHandler);
|
||||
dataSourceService.on('remove', dataSourceRemoveHandler);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
depService.off('add-target', targetAddHandler);
|
||||
depService.off('remove-target', targetRemoveHandler);
|
||||
|
@ -119,10 +119,10 @@ class Dep extends BaseService {
|
||||
idleTask.once('finish', () => {
|
||||
this.emit('collected', nodes, deep);
|
||||
this.set('collecting', false);
|
||||
resolve();
|
||||
});
|
||||
idleTask.once('hight-level-finish', () => {
|
||||
this.emit('ds-collected', nodes, deep);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -130,11 +130,11 @@ class Dep extends BaseService {
|
||||
public collectNode(node: MNode, target: Target, depExtendedData: DepExtendedData = {}, deep = false) {
|
||||
// 先删除原有依赖,重新收集
|
||||
if (isPage(node)) {
|
||||
Object.entries(target.deps).forEach(([depKey, dep]) => {
|
||||
for (const [depKey, dep] of Object.entries(target.deps)) {
|
||||
if (dep.data?.pageId && dep.data.pageId === depExtendedData.pageId) {
|
||||
delete target.deps[depKey];
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.watcher.removeTargetDep(target, node);
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ export class IdleTask<T = any> extends EventEmitter {
|
||||
// 动画会占用空闲时间,当任务一直无法执行时,看看是否有动画正在播放
|
||||
// 根据空闲时间的多少来决定执行的任务数,保证页面不卡死的情况下尽量多执行任务,不然当任务数巨大时,执行时间会很久
|
||||
// 执行不完不会影响配置,但是会影响画布渲染
|
||||
while (deadline.timeRemaining() > 0 && taskList.length) {
|
||||
while (deadline.timeRemaining() > 0 && (taskList.length || hightLevelTaskList.length)) {
|
||||
const timeRemaining = deadline.timeRemaining();
|
||||
let times = 0;
|
||||
if (timeRemaining <= 5) {
|
||||
|
@ -508,7 +508,7 @@ export const traverseNode = <T extends NodeItem = NodeItem>(
|
||||
if (Array.isArray(node.items) && node.items.length) {
|
||||
parents.push(node);
|
||||
node.items.forEach((item) => {
|
||||
traverseNode(item as T, cb, [...parents]);
|
||||
traverseNode(item as T, cb, [...parents], evalCbAfter);
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user