refactor: 给Canvas解耦合
This commit is contained in:
@@ -83,7 +83,8 @@
|
||||
}
|
||||
">
|
||||
<!-- 动态渲染组件 -->
|
||||
<component :is="getComponentDefinition(component.type)" v-if="props.componentModules[component.type]"
|
||||
<component :is="getComponentDefinition(component.type)"
|
||||
v-if="props.componentModules[component.type] && getComponentDefinition(component.type)"
|
||||
v-bind="prepareComponentProps(component.attrs || {}, component.id)" @update:bindKey="
|
||||
(value: string) =>
|
||||
updateComponentProp(component.id, 'bindKey', value)
|
||||
@@ -98,6 +99,7 @@
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="loading loading-spinner loading-xs mb-1"></div>
|
||||
<span>Loading {{ component.type }}...</span>
|
||||
<small class="mt-1 text-xs">{{ props.componentModules[component.type] ? 'Module loaded but invalid' : 'Module not found' }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -159,6 +161,7 @@ import type {
|
||||
} from "./diagramManager";
|
||||
|
||||
import { CanvasCurrentSelectedComponentID } from "../InjectKeys";
|
||||
import { useComponentManager } from "./componentManager";
|
||||
|
||||
// 右键菜单处理函数
|
||||
function handleContextMenu(e: MouseEvent) {
|
||||
@@ -168,13 +171,9 @@ function handleContextMenu(e: MouseEvent) {
|
||||
// 定义组件发出的事件
|
||||
const emit = defineEmits([
|
||||
"diagram-updated",
|
||||
"component-selected",
|
||||
"component-moved",
|
||||
"component-delete",
|
||||
"toggle-doc-panel",
|
||||
"wire-created",
|
||||
"wire-deleted",
|
||||
"load-component-module",
|
||||
"open-components",
|
||||
]);
|
||||
|
||||
@@ -184,6 +183,12 @@ const props = defineProps<{
|
||||
showDocPanel?: boolean; // 添加属性接收文档面板的显示状态
|
||||
}>();
|
||||
|
||||
// 获取componentManager实例
|
||||
const componentManager = useComponentManager();
|
||||
if (!componentManager) {
|
||||
throw new Error("DiagramCanvas must be used within a component manager provider");
|
||||
}
|
||||
|
||||
// --- 画布状态 ---
|
||||
const canvasContainer = ref<HTMLElement | null>(null);
|
||||
const canvas = ref<HTMLElement | null>(null);
|
||||
@@ -365,7 +370,13 @@ function onZoom(e: WheelEvent) {
|
||||
// --- 动态组件渲染 ---
|
||||
const getComponentDefinition = (type: string) => {
|
||||
const module = props.componentModules[type];
|
||||
if (!module) return null;
|
||||
|
||||
if (!module) {
|
||||
console.warn(`No module found for component type: ${type}`);
|
||||
// 尝试异步加载组件模块
|
||||
loadComponentModule(type);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确保我们返回一个有效的组件定义
|
||||
if (module.default) {
|
||||
@@ -414,8 +425,12 @@ function resetComponentRefs() {
|
||||
async function loadComponentModule(type: string) {
|
||||
if (!props.componentModules[type]) {
|
||||
try {
|
||||
// 通知父组件需要加载此类型的组件
|
||||
emit("load-component-module", type);
|
||||
// 直接通过componentManager加载组件模块
|
||||
if (componentManager) {
|
||||
await componentManager.loadComponentModule(type);
|
||||
// 强制更新当前组件,确保新加载的模块能被识别
|
||||
console.log(`Component module ${type} loaded successfully`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to request component module ${type}:`, error);
|
||||
}
|
||||
@@ -428,7 +443,10 @@ function handleCanvasMouseDown(e: MouseEvent) {
|
||||
if (e.target === canvasContainer.value || e.target === canvas.value) {
|
||||
if (selectedComponentId.value !== null) {
|
||||
selectedComponentId.value = null;
|
||||
emit("component-selected", null);
|
||||
// 直接通过componentManager选择组件
|
||||
if (componentManager) {
|
||||
componentManager.selectComponent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +523,10 @@ function startComponentDrag(e: MouseEvent, component: DiagramPart) {
|
||||
// 仍然选中组件,无论是否为交互元素
|
||||
if (selectedComponentId.value !== component.id) {
|
||||
selectedComponentId.value = component.id;
|
||||
emit("component-selected", component);
|
||||
// 直接通过componentManager选择组件
|
||||
if (componentManager) {
|
||||
componentManager.selectComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果组件锁定位置或是交互元素,则不启动拖拽
|
||||
@@ -600,12 +621,14 @@ function onComponentDrag(e: MouseEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
// 通知父组件位置已更新
|
||||
emit("component-moved", {
|
||||
id: draggingComponentId.value,
|
||||
x: Math.round(newX),
|
||||
y: Math.round(newY),
|
||||
});
|
||||
// 通知componentManager位置已更新
|
||||
if (componentManager) {
|
||||
componentManager.moveComponent({
|
||||
id: draggingComponentId.value,
|
||||
x: Math.round(newX),
|
||||
y: Math.round(newY),
|
||||
});
|
||||
}
|
||||
|
||||
// 通知图表已更新
|
||||
emit("diagram-updated", diagramData.value);
|
||||
@@ -634,14 +657,20 @@ function updateComponentProp(
|
||||
propName: string,
|
||||
value: any,
|
||||
) {
|
||||
diagramData.value = updatePartAttribute(
|
||||
diagramData.value,
|
||||
componentId,
|
||||
propName,
|
||||
value,
|
||||
);
|
||||
emit("diagram-updated", diagramData.value);
|
||||
saveDiagramData(diagramData.value);
|
||||
// 直接通过componentManager更新组件属性
|
||||
if (componentManager) {
|
||||
componentManager.updateComponentProp(componentId, propName, value);
|
||||
} else {
|
||||
// 后备方案:直接更新数据
|
||||
diagramData.value = updatePartAttribute(
|
||||
diagramData.value,
|
||||
componentId,
|
||||
propName,
|
||||
value,
|
||||
);
|
||||
emit("diagram-updated", diagramData.value);
|
||||
saveDiagramData(diagramData.value);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 连线操作 ---
|
||||
@@ -871,7 +900,10 @@ function deleteWire(wireIndex: number) {
|
||||
// 删除组件
|
||||
function deleteComponent(componentId: string) {
|
||||
diagramData.value = deletePart(diagramData.value, componentId);
|
||||
emit("component-delete", componentId);
|
||||
// 直接通过componentManager删除组件
|
||||
if (componentManager) {
|
||||
componentManager.deleteComponent(componentId);
|
||||
}
|
||||
emit("diagram-updated", diagramData.value);
|
||||
saveDiagramData(diagramData.value);
|
||||
|
||||
@@ -1024,6 +1056,24 @@ onMounted(async () => {
|
||||
// 重置组件引用
|
||||
resetComponentRefs();
|
||||
|
||||
// 设置componentManager的画布引用
|
||||
if (componentManager) {
|
||||
// 创建一个包含必要方法的画布API对象
|
||||
const canvasAPI = {
|
||||
getDiagramData: () => diagramData.value,
|
||||
updateDiagramDataDirectly: (data: DiagramData) => {
|
||||
diagramData.value = data;
|
||||
saveDiagramData(data);
|
||||
emit("diagram-updated", data);
|
||||
},
|
||||
getCanvasPosition: () => ({ x: position.x, y: position.y }),
|
||||
getScale: () => scale.value,
|
||||
$el: canvasContainer.value,
|
||||
showToast
|
||||
};
|
||||
componentManager.setCanvasRef(canvasAPI);
|
||||
}
|
||||
|
||||
// 加载图表数据
|
||||
try {
|
||||
diagramData.value = await loadDiagramData();
|
||||
@@ -1039,12 +1089,10 @@ onMounted(async () => {
|
||||
Array.from(componentTypes),
|
||||
);
|
||||
|
||||
// 通知父组件需要加载组件模块
|
||||
componentTypes.forEach((type) => {
|
||||
if (!props.componentModules[type]) {
|
||||
emit("load-component-module", type);
|
||||
}
|
||||
});
|
||||
// 直接通过componentManager预加载组件模块
|
||||
if (componentManager) {
|
||||
await componentManager.preloadComponentModules(Array.from(componentTypes));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载图表数据失败:", error);
|
||||
}
|
||||
@@ -1115,7 +1163,7 @@ function updateDiagramDataDirectly(data: DiagramData) {
|
||||
emit("diagram-updated", data);
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
// 暴露方法给父组件 - 简化版本,主要用于数据访问
|
||||
defineExpose({
|
||||
// 基本数据操作
|
||||
getDiagramData: () => diagramData.value,
|
||||
@@ -1154,23 +1202,6 @@ defineExpose({
|
||||
});
|
||||
},
|
||||
|
||||
// 文件操作
|
||||
openDiagramFileSelector,
|
||||
exportDiagram,
|
||||
|
||||
// 组件操作
|
||||
getSelectedComponent: () => {
|
||||
if (!selectedComponentId.value) return null;
|
||||
return (
|
||||
diagramParts.value.find((p) => p.id === selectedComponentId.value) || null
|
||||
);
|
||||
},
|
||||
deleteSelectedComponent: () => {
|
||||
if (selectedComponentId.value) {
|
||||
deleteComponent(selectedComponentId.value);
|
||||
}
|
||||
},
|
||||
|
||||
// 画布状态
|
||||
getCanvasPosition: () => ({ x: position.x, y: position.y }),
|
||||
getScale: () => scale.value,
|
||||
|
||||
Reference in New Issue
Block a user