import { ref, shallowRef, computed } from "vue"; import { createInjectionState } from "@vueuse/core"; import type { DiagramData, DiagramPart } from "./diagramManager"; import type { PropertyConfig } from "@/components/equipments/componentConfig"; import { generatePropertyConfigs, generatePropsFromDefault, generatePropsFromAttrs, } from "@/components/equipments/componentConfig"; // 存储动态导入的组件模块 interface ComponentModule { default: any; getDefaultProps?: () => Record; config?: { props?: Array; }; __esModule?: boolean; // 添加 __esModule 属性 } // 定义组件管理器的状态和方法 const [useProvideComponentManager, useComponentManager] = createInjectionState( () => { // --- 状态管理 --- const componentModules = ref>({}); const selectedComponentId = ref(null); const selectedComponentConfig = shallowRef<{ props: PropertyConfig[] } | null>(null); const diagramCanvas = ref(null); const componentRefs = ref>({}); // 计算当前选中的组件数据 const selectedComponentData = computed(() => { if (!diagramCanvas.value || !selectedComponentId.value) return null; const canvasInstance = diagramCanvas.value as any; if (canvasInstance && canvasInstance.getDiagramData) { const data = canvasInstance.getDiagramData(); return data.parts.find((p: DiagramPart) => p.id === selectedComponentId.value) || null; } return null; }); // --- 组件模块管理 --- /** * 动态加载组件模块 */ async function loadComponentModule(type: string) { console.log(`尝试加载组件模块: ${type}`); console.log(`当前已加载的模块:`, Object.keys(componentModules.value)); if (!componentModules.value[type]) { try { console.log(`正在动态导入模块: @/components/equipments/${type}.vue`); const module = await import(`@/components/equipments/${type}.vue`); console.log(`成功导入模块 ${type}:`, module); // 直接设置新的对象引用以触发响应性 componentModules.value = { ...componentModules.value, [type]: module, }; console.log(`模块 ${type} 已添加到 componentModules`); console.log(`更新后的模块列表:`, Object.keys(componentModules.value)); } catch (error) { console.error(`Failed to load component module ${type}:`, error); return null; } } else { console.log(`模块 ${type} 已经存在`); } return componentModules.value[type]; } /** * 预加载所有组件模块 */ async function preloadComponentModules(componentTypes: string[]) { console.log("Preloading component modules:", componentTypes); await Promise.all( componentTypes.map((type) => loadComponentModule(type)) ); console.log("All component modules loaded"); } // --- 组件操作 --- /** * 添加新组件到画布 */ async function addComponent(componentData: { type: string; name: string; props: Record; }) { console.log("=== 开始添加组件 ==="); console.log("组件数据:", componentData); const canvasInstance = diagramCanvas.value as any; if (!canvasInstance) { console.error("没有可用的画布实例"); return; } // 预加载组件模块,确保组件能正常渲染 console.log(`预加载组件模块: ${componentData.type}`); const componentModule = await loadComponentModule(componentData.type); if (!componentModule) { console.error(`无法加载组件模块: ${componentData.type}`); return; } console.log(`组件模块加载成功: ${componentData.type}`, componentModule); // 获取画布位置信息 let position = { x: 100, y: 100 }; let scale = 1; try { if (canvasInstance.getCanvasPosition && canvasInstance.getScale) { position = canvasInstance.getCanvasPosition(); scale = canvasInstance.getScale(); const canvasContainer = canvasInstance.$el as HTMLElement; if (canvasContainer) { const viewportWidth = canvasContainer.clientWidth; const viewportHeight = canvasContainer.clientHeight; position.x = (viewportWidth / 2 - position.x) / scale; position.y = (viewportHeight / 2 - position.y) / scale; } } } catch (error) { console.error("获取画布位置时出错:", error); } // 添加随机偏移 const offsetX = Math.floor(Math.random() * 100) - 50; const offsetY = Math.floor(Math.random() * 100) - 50; // 获取组件能力页面 let capsPage = null; if ( componentModule && componentModule.default && typeof componentModule.default.getCapabilities === "function" ) { try { capsPage = componentModule.default.getCapabilities(); console.log(`获取到${componentData.type}组件的能力页面`); } catch (error) { console.error(`获取${componentData.type}组件能力页面失败:`, error); } } // 创建新组件 const newComponent: DiagramPart = { id: `component-${Date.now()}`, type: componentData.type, x: Math.round(position.x + offsetX), y: Math.round(position.y + offsetY), attrs: componentData.props, rotate: 0, group: "", positionlock: false, hidepins: true, isOn: true, index: 0, }; // 通过画布实例添加组件 if (canvasInstance.getDiagramData && canvasInstance.updateDiagramDataDirectly) { const currentData = canvasInstance.getDiagramData(); currentData.parts.push(newComponent); // 使用 updateDiagramDataDirectly 避免触发加载状态 canvasInstance.updateDiagramDataDirectly(currentData); console.log("组件添加完成:", newComponent); // 等待Vue的下一个tick,确保组件模块已经更新 await new Promise(resolve => setTimeout(resolve, 50)); } } /** * 添加模板到画布 */ async function addTemplate(templateData: { id: string; name: string; template: any; }) { console.log("添加模板:", templateData); const canvasInstance = diagramCanvas.value as any; if (!canvasInstance?.getDiagramData || !canvasInstance?.updateDiagramDataDirectly) { console.error("没有可用的画布实例添加模板"); return; } const currentData = canvasInstance.getDiagramData(); console.log("=== 当前图表组件数量:", currentData.parts.length); // 生成唯一ID前缀 const idPrefix = `template-${Date.now()}-`; if (templateData.template?.parts) { // 获取视口中心位置 let viewportCenter = { x: 300, y: 200 }; try { if (canvasInstance.getCanvasPosition && canvasInstance.getScale) { const position = canvasInstance.getCanvasPosition(); const scale = canvasInstance.getScale(); const canvasContainer = canvasInstance.$el as HTMLElement; if (canvasContainer) { const viewportWidth = canvasContainer.clientWidth; const viewportHeight = canvasContainer.clientHeight; viewportCenter.x = (viewportWidth / 2 - position.x) / scale; viewportCenter.y = (viewportHeight / 2 - position.y) / scale; } } } catch (error) { console.error("获取视口中心位置时出错:", error); } const mainPart = templateData.template.parts[0]; // 创建新组件 const newParts = await Promise.all( templateData.template.parts.map(async (part: any) => { const newPart = JSON.parse(JSON.stringify(part)); newPart.id = `${idPrefix}${part.id}`; // 加载组件模块并获取能力页面 try { const componentModule = await loadComponentModule(part.type); if ( componentModule?.default && typeof componentModule.default.getCapabilities === "function" ) { newPart.capsPage = componentModule.default.getCapabilities(); console.log(`加载模板组件${part.type}组件的能力页面成功`); } } catch (error) { console.error(`加载模板组件${part.type}的能力页面失败:`, error); } // 计算新位置 if (typeof newPart.x === "number" && typeof newPart.y === "number") { const relativeX = part.x - mainPart.x; const relativeY = part.y - mainPart.y; newPart.x = viewportCenter.x + relativeX; newPart.y = viewportCenter.y + relativeY; } return newPart; }) ); currentData.parts.push(...newParts); // 处理连接关系 if (templateData.template.connections) { const idMap: Record = {}; templateData.template.parts.forEach((part: any) => { idMap[part.id] = `${idPrefix}${part.id}`; }); const newConnections = templateData.template.connections.map((conn: any) => { if (Array.isArray(conn)) { const [from, to, type, path] = conn; const fromParts = from.split(":"); const toParts = to.split(":"); if (fromParts.length === 2 && toParts.length === 2) { const fromComponentId = fromParts[0]; const fromPinId = fromParts[1]; const toComponentId = toParts[0]; const toPinId = toParts[1]; const newFrom = `${idMap[fromComponentId] || fromComponentId}:${fromPinId}`; const newTo = `${idMap[toComponentId] || toComponentId}:${toPinId}`; return [newFrom, newTo, type, path]; } } return conn; }); currentData.connections.push(...newConnections); } canvasInstance.updateDiagramDataDirectly(currentData); console.log("=== 更新图表数据完成,新组件数量:", currentData.parts.length); return { success: true, message: `已添加 ${templateData.name} 模板` }; } else { console.error("模板格式错误,缺少parts数组"); return { success: false, message: "模板格式错误" }; } } /** * 删除组件 */ function deleteComponent(componentId: string) { const canvasInstance = diagramCanvas.value as any; if (!canvasInstance?.getDiagramData || !canvasInstance?.updateDiagramDataDirectly) { return; } const currentData = canvasInstance.getDiagramData(); const component = currentData.parts.find((p: DiagramPart) => p.id === componentId); if (!component) return; const componentsToDelete: string[] = [componentId]; // 处理组件组 if (component.group && component.group !== "") { const groupMembers = currentData.parts.filter( (p: DiagramPart) => p.group === component.group && p.id !== componentId ); componentsToDelete.push(...groupMembers.map((p: DiagramPart) => p.id)); console.log(`删除组件 ${componentId} 及其组 ${component.group} 中的 ${groupMembers.length} 个组件`); } // 删除组件 currentData.parts = currentData.parts.filter( (p: DiagramPart) => !componentsToDelete.includes(p.id) ); // 删除相关连接 currentData.connections = currentData.connections.filter((connection: any) => { for (const id of componentsToDelete) { if (connection[0].startsWith(`${id}:`) || connection[1].startsWith(`${id}:`)) { return false; } } return true; }); // 清除选中状态 if (selectedComponentId.value && componentsToDelete.includes(selectedComponentId.value)) { selectedComponentId.value = null; selectedComponentConfig.value = null; } canvasInstance.updateDiagramDataDirectly(currentData); } /** * 选中组件 */ async function selectComponent(componentData: DiagramPart | null) { selectedComponentId.value = componentData ? componentData.id : null; selectedComponentConfig.value = null; if (componentData) { const moduleRef = await loadComponentModule(componentData.type); if (moduleRef) { try { const propConfigs: PropertyConfig[] = []; const addedProps = new Set(); // 从 getDefaultProps 方法获取默认配置 if (typeof moduleRef.getDefaultProps === "function") { const defaultProps = moduleRef.getDefaultProps(); const defaultPropConfigs = generatePropsFromDefault(defaultProps); defaultPropConfigs.forEach((config) => { propConfigs.push(config); addedProps.add(config.name); }); } // 添加组件直接属性 const directPropConfigs = generatePropertyConfigs(componentData); const newDirectProps = directPropConfigs.filter( (config) => !addedProps.has(config.name) ); propConfigs.push(...newDirectProps); // 添加 attrs 中的属性 if (componentData.attrs) { const attrPropConfigs = generatePropsFromAttrs(componentData.attrs); attrPropConfigs.forEach((attrConfig) => { const existingIndex = propConfigs.findIndex( (p) => p.name === attrConfig.name ); if (existingIndex >= 0) { propConfigs[existingIndex] = attrConfig; } else { propConfigs.push(attrConfig); } }); } selectedComponentConfig.value = { props: propConfigs }; console.log(`Built config for ${componentData.type}:`, selectedComponentConfig.value); } catch (error) { console.error(`Error building config for ${componentData.type}:`, error); selectedComponentConfig.value = { props: [] }; } } else { console.warn(`Module for component ${componentData.type} not found.`); selectedComponentConfig.value = { props: [] }; } } } /** * 更新组件属性 */ function updateComponentProp(componentId: string, propName: string, value: any) { const canvasInstance = diagramCanvas.value as any; if (!canvasInstance?.getDiagramData || !canvasInstance?.updateDiagramDataDirectly) { console.error("没有可用的画布实例进行属性更新"); return; } // 检查值格式 if (value !== null && typeof value === "object" && "value" in value) { value = value.value; } const currentData = canvasInstance.getDiagramData(); const part = currentData.parts.find((p: DiagramPart) => p.id === componentId); if (part) { if (propName in part) { (part as any)[propName] = value; } else { if (!part.attrs) { part.attrs = {}; } part.attrs[propName] = value; } canvasInstance.updateDiagramDataDirectly(currentData); console.log(`更新组件${componentId}的属性${propName}为:`, value, typeof value); } } /** * 更新组件直接属性 */ function updateComponentDirectProp(componentId: string, propName: string, value: any) { const canvasInstance = diagramCanvas.value as any; if (!canvasInstance?.getDiagramData || !canvasInstance?.updateDiagramDataDirectly) { console.error("没有可用的画布实例进行属性更新"); return; } const currentData = canvasInstance.getDiagramData(); const part = currentData.parts.find((p: DiagramPart) => p.id === componentId); if (part) { (part as any)[propName] = value; canvasInstance.updateDiagramDataDirectly(currentData); console.log(`更新组件${componentId}的直接属性${propName}为:`, value, typeof value); } } /** * 移动组件 */ function moveComponent(moveData: { id: string; x: number; y: number }) { const canvasInstance = diagramCanvas.value as any; if (!canvasInstance?.getDiagramData || !canvasInstance?.updateDiagramDataDirectly) { return; } const currentData = canvasInstance.getDiagramData(); const part = currentData.parts.find((p: DiagramPart) => p.id === moveData.id); if (part) { part.x = moveData.x; part.y = moveData.y; canvasInstance.updateDiagramDataDirectly(currentData); } } /** * 设置画布实例引用 */ function setCanvasRef(canvasRef: any) { diagramCanvas.value = canvasRef; } /** * 设置组件DOM引用 */ function setComponentRef(componentId: string, el: any) { if (el) { componentRefs.value[componentId] = el; } else { delete componentRefs.value[componentId]; } } /** * 获取组件DOM引用 */ function getComponentRef(componentId: string) { return componentRefs.value[componentId]; } /** * 获取当前图表数据 */ function getDiagramData() { const canvasInstance = diagramCanvas.value; if (canvasInstance && canvasInstance.getDiagramData) { return canvasInstance.getDiagramData(); } return { parts: [], connections: [], version: 1, author: "admin", editor: "me" }; } /** * 更新图表数据 */ function updateDiagramData(data: any) { const canvasInstance = diagramCanvas.value; if (canvasInstance && canvasInstance.updateDiagramDataDirectly) { canvasInstance.updateDiagramDataDirectly(data); } } /** * 获取画布位置和缩放信息 */ function getCanvasInfo() { const canvasInstance = diagramCanvas.value; if (!canvasInstance) return { position: { x: 0, y: 0 }, scale: 1 }; const position = canvasInstance.getCanvasPosition ? canvasInstance.getCanvasPosition() : { x: 0, y: 0 }; const scale = canvasInstance.getScale ? canvasInstance.getScale() : 1; return { position, scale }; } /** * 显示通知 */ function showToast(message: string, type: "success" | "error" | "info" = "info") { const canvasInstance = diagramCanvas.value; if (canvasInstance && canvasInstance.showToast) { canvasInstance.showToast(message, type); } } /** * 获取组件定义 */ function getComponentDefinition(type: string) { const module = componentModules.value[type]; if (!module) { console.warn(`No module found for component type: ${type}`); // 尝试异步加载组件模块 loadComponentModule(type); return null; } // 确保我们返回一个有效的组件定义 if (module.default) { return module.default; } else if (module.__esModule && module.default) { // 有时 Vue 的动态导入会将默认导出包装在 __esModule 属性下 return module.default; } else { console.warn( `Module for ${type} found but default export is missing`, module, ); return null; } } /** * 准备组件属性 */ function prepareComponentProps( attrs: Record, componentId?: string, ): Record { const result: Record = { ...attrs }; if (componentId) { result.componentId = componentId; } return result; } /** * 初始化组件管理器 */ async function initialize() { const canvasInstance = diagramCanvas.value as any; if (canvasInstance?.getDiagramData) { const diagramData = canvasInstance.getDiagramData(); // 收集所有组件类型 const componentTypes = new Set(); diagramData.parts.forEach((part: DiagramPart) => { componentTypes.add(part.type); }); // 预加载组件模块 await preloadComponentModules(Array.from(componentTypes)); } } return { // 状态 componentModules, selectedComponentId, selectedComponentData, selectedComponentConfig, componentRefs, // 方法 loadComponentModule, preloadComponentModules, addComponent, addTemplate, deleteComponent, selectComponent, updateComponentProp, updateComponentDirectProp, moveComponent, setCanvasRef, setComponentRef, getComponentRef, getDiagramData, updateDiagramData, getCanvasInfo, showToast, getComponentDefinition, prepareComponentProps, initialize, }; } ); export { useProvideComponentManager, useComponentManager };