feat: Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex-1 min-w-[60%] bg-base-200 relative overflow-hidden diagram-container" ref="canvasContainer"
|
||||
<div class="flex-1 h-full w-full bg-base-200 relative overflow-hidden diagram-container" ref="canvasContainer"
|
||||
@mousedown="handleCanvasMouseDown"
|
||||
@mousedown.middle.prevent="startMiddleDrag"
|
||||
@wheel.prevent="onZoom"
|
||||
@@ -38,9 +38,8 @@
|
||||
<div
|
||||
ref="canvas"
|
||||
class="diagram-canvas"
|
||||
:style="{ transform: `translate(${position.x}px, ${position.y}px) scale(${scale})` }">
|
||||
<!-- 渲染连线 -->
|
||||
<svg class="wires-layer" width="4000" height="4000">
|
||||
:style="{ transform: `translate(${position.x}px, ${position.y}px) scale(${scale})` }"> <!-- 渲染连线 -->
|
||||
<svg class="wires-layer" width="10000" height="10000">
|
||||
<!-- 已完成的连线 -->
|
||||
<WireComponent
|
||||
v-for="(wire, index) in wireItems"
|
||||
@@ -77,33 +76,25 @@
|
||||
|
||||
<!-- 渲染画布上的组件 -->
|
||||
<div v-for="component in diagramParts" :key="component.id"
|
||||
class="component-wrapper"
|
||||
:class="{
|
||||
class="component-wrapper" :class="{
|
||||
'component-hover': hoveredComponent === component.id,
|
||||
'component-selected': selectedComponentId === component.id,
|
||||
'component-disabled': component.isOn,
|
||||
'component-hidden': component.hide
|
||||
}"
|
||||
:style="{
|
||||
'component-disabled': !component.isOn,
|
||||
'component-hidepins': component.hidepins
|
||||
}" :style="{
|
||||
top: component.y + 'px',
|
||||
left: component.x + 'px',
|
||||
zIndex: selectedComponentId === component.id ? 999 : 1,
|
||||
zIndex: component.index ?? 0,
|
||||
transform: component.rotate ? `rotate(${component.rotate}deg)` : 'none',
|
||||
opacity: component.isOn ? 0.6 : 1,
|
||||
display: component.hide ? 'none' : 'block'
|
||||
opacity: component.isOn ? 1 : 0.6,
|
||||
display: 'block'
|
||||
}"
|
||||
@mousedown.left.stop="startComponentDrag($event, component)"
|
||||
@mouseover="hoveredComponent = component.id"
|
||||
@mouseleave="hoveredComponent = null"> <!-- 动态渲染组件 -->
|
||||
<component :is="getComponentDefinition(component.type)"
|
||||
v-if="props.componentModules[component.type]"
|
||||
v-bind="prepareComponentProps(component.attrs || {}, component.id)" @update:bindKey="(value: string) => updateComponentProp(component.id, 'bindKey', value)"
|
||||
@pin-click="(pinInfo: any) => handlePinClick(component.id, pinInfo, pinInfo.originalEvent)"
|
||||
:ref="(el: any) => {
|
||||
if (el && componentRefs.value) {
|
||||
componentRefs.value[component.id] = el;
|
||||
}
|
||||
}"
|
||||
v-bind="prepareComponentProps(component.attrs || {}, component.id)" @update:bindKey="(value: string) => updateComponentProp(component.id, 'bindKey', value)" @pin-click="(pinInfo: any) => handlePinClick(component.id, pinInfo, pinInfo.originalEvent)" :ref="(el: any) => setComponentRef(component.id, el)"
|
||||
/>
|
||||
|
||||
<!-- Fallback if component module not loaded yet -->
|
||||
@@ -191,9 +182,18 @@ const diagramData = ref<DiagramData>({
|
||||
// 组件引用跟踪
|
||||
const componentRefs = ref<Record<string, any>>({});
|
||||
|
||||
// 计算属性:从 diagramData 中提取组件列表
|
||||
// 计算属性:从 diagramData 中提取组件列表,并按index属性排序
|
||||
const diagramParts = computed<DiagramPart[]>(() => {
|
||||
return diagramData.value.parts;
|
||||
// 克隆原始数组以避免直接修改原始数据
|
||||
const parts = [...diagramData.value.parts];
|
||||
|
||||
// 按照index属性进行排序,index值大的排在后面(显示在上层)
|
||||
// 如果没有定义index则默认为0
|
||||
return parts.sort((a, b) => {
|
||||
const indexA = a.index ?? 0;
|
||||
const indexB = b.index ?? 0;
|
||||
return indexA - indexB;
|
||||
});
|
||||
});
|
||||
|
||||
// 计算属性:转换连接为 WireItem 列表以供渲染
|
||||
@@ -219,14 +219,20 @@ const wireItems = computed<WireItem[]>(() => {
|
||||
// 如果找到组件,设置连线端点位置
|
||||
if (startComp) {
|
||||
startPos.x = startComp.x;
|
||||
startPos.y = startComp.y; // 尝试获取引脚精确位置(如果有实现)
|
||||
startPos.y = startComp.y;
|
||||
|
||||
// 尝试获取引脚精确位置(如果有实现)
|
||||
const startCompRef = componentRefs.value?.[startCompId];
|
||||
if (startCompRef && typeof startCompRef.getPinPosition === 'function') {
|
||||
try {
|
||||
const pinPos = startCompRef.getPinPosition(startPinId);
|
||||
console.log(`线路${index} - 起点引脚位置(来自${startCompId}):`, pinPos);
|
||||
|
||||
if (pinPos) {
|
||||
startPos.x = pinPos.x;
|
||||
startPos.y = pinPos.y;
|
||||
// 正确合并组件位置与引脚相对位置
|
||||
startPos.x = startComp.x + pinPos.x;
|
||||
startPos.y = startComp.y + pinPos.y;
|
||||
console.log(`线路${index} - 计算后的起点位置:`, startPos);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`获取引脚位置出错:`, error);
|
||||
@@ -243,9 +249,13 @@ const wireItems = computed<WireItem[]>(() => {
|
||||
if (endCompRef && typeof endCompRef.getPinPosition === 'function') {
|
||||
try {
|
||||
const pinPos = endCompRef.getPinPosition(endPinId);
|
||||
console.log(`线路${index} - 终点引脚位置(来自${endCompId}):`, pinPos);
|
||||
|
||||
if (pinPos) {
|
||||
endPos.x = pinPos.x;
|
||||
endPos.y = pinPos.y;
|
||||
// 正确合并组件位置与引脚相对位置
|
||||
endPos.x = endComp.x + pinPos.x;
|
||||
endPos.y = endComp.y + pinPos.y;
|
||||
console.log(`线路${index} - 计算后的终点位置:`, endPos);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`获取引脚位置出错:`, error);
|
||||
@@ -282,7 +292,7 @@ const fileInput = ref<HTMLInputElement | null>(null);
|
||||
|
||||
// --- 缩放功能 ---
|
||||
const MIN_SCALE = 0.2;
|
||||
const MAX_SCALE = 3.0;
|
||||
const MAX_SCALE = 10.0;
|
||||
|
||||
function onZoom(e: WheelEvent) {
|
||||
e.preventDefault();
|
||||
@@ -341,6 +351,22 @@ function prepareComponentProps(attrs: Record<string, any>, componentId?: string)
|
||||
return result;
|
||||
}
|
||||
|
||||
// 设置组件引用
|
||||
function setComponentRef(componentId: string, el: any) {
|
||||
if (componentRefs.value) {
|
||||
if (el) {
|
||||
componentRefs.value[componentId] = el;
|
||||
} else {
|
||||
delete componentRefs.value[componentId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重置组件引用缓存
|
||||
function resetComponentRefs() {
|
||||
componentRefs.value = {};
|
||||
}
|
||||
|
||||
// 加载组件模块
|
||||
async function loadComponentModule(type: string) {
|
||||
if (!props.componentModules[type]) {
|
||||
@@ -567,39 +593,74 @@ function handlePinClick(componentId: string, pinInfo: any, event: MouseEvent) {
|
||||
// 获取引脚ID
|
||||
const pinId = pinInfo.label;
|
||||
|
||||
console.log('----引脚点击详情开始----');
|
||||
console.log('组件ID:', componentId);
|
||||
console.log('引脚ID:', pinId);
|
||||
console.log('引脚原始信息:', pinInfo);
|
||||
console.log('鼠标位置:', mousePosition);
|
||||
|
||||
if (!isCreatingWire.value) {
|
||||
// 开始创建连线
|
||||
const containerRect = canvasContainer.value.getBoundingClientRect();
|
||||
// 获取引脚位置 - 优先使用pinInfo中传递的position
|
||||
// 获取初始位置信息
|
||||
let pinPosition = pinInfo.position;
|
||||
console.log(pinInfo);
|
||||
console.log('引脚位置:', pinPosition);
|
||||
console.log('Pin信息:', pinInfo);
|
||||
console.log('Pin初始位置:', pinPosition);
|
||||
console.log('组件ID:', componentId);
|
||||
console.log('引脚ID:', pinId);
|
||||
console.log('组件引用:', componentRefs);
|
||||
console.log('组件引用:', componentRefs.value[componentId]);
|
||||
|
||||
// 从组件引用中获取组件实例
|
||||
const component = componentRefs.value[componentId];
|
||||
if (component && typeof component.getPinPosition === 'function') {
|
||||
console.log('组件引用:', component);
|
||||
|
||||
// 查找组件部件对象以获取组件位置
|
||||
const componentPart = diagramParts.value.find(p => p.id === componentId);
|
||||
if (!componentPart) {
|
||||
console.error('找不到组件部件对象:', componentId);
|
||||
}
|
||||
|
||||
// 重新设置引脚位置(初始化)
|
||||
pinPosition = { x: 0, y: 0 };
|
||||
|
||||
// 如果组件实例存在且有 getPinPosition 方法
|
||||
if (component && typeof component.getPinPosition === 'function' && componentPart) {
|
||||
try {
|
||||
console.log('从组件获取引脚位置:', componentId, pinId);
|
||||
pinPosition += component.getPinPosition(pinId);
|
||||
console.log('尝试从组件获取引脚位置');
|
||||
console.log('组件部件位置:', componentPart.x, componentPart.y);
|
||||
const pinRelativePos = component.getPinPosition(pinId);
|
||||
console.log('组件返回的引脚相对位置:', pinRelativePos);
|
||||
|
||||
if (pinRelativePos) {
|
||||
// 计算引脚的绝对位置 = 组件位置 + 引脚相对位置
|
||||
pinPosition = {
|
||||
x: componentPart.x + pinRelativePos.x,
|
||||
y: componentPart.y + pinRelativePos.y
|
||||
};
|
||||
console.log('计算的引脚绝对位置:', pinPosition);
|
||||
} else {
|
||||
// 如果没有找到引脚位置,使用组件位置
|
||||
pinPosition = {
|
||||
x: componentPart.x,
|
||||
y: componentPart.y
|
||||
};
|
||||
console.log('使用组件位置:', pinPosition);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`获取引脚位置出错:`, error);
|
||||
}
|
||||
}
|
||||
// 如果还是没有position,使用默认位置
|
||||
if (!pinPosition) {
|
||||
console.warn('无法获取引脚位置,使用默认值');
|
||||
pinPosition = { x: 0, y: 0 };
|
||||
} else if (componentPart) {
|
||||
// 如果组件不存在或没有 getPinPosition 方法,使用组件的位置
|
||||
pinPosition = {
|
||||
x: componentPart.x,
|
||||
y: componentPart.y
|
||||
};
|
||||
console.log('使用组件位置:', pinPosition);
|
||||
}
|
||||
|
||||
console.log('最终的引脚位置:', pinPosition);
|
||||
console.log('最终使用的引脚位置:', pinPosition);
|
||||
|
||||
// 计算引脚在画布坐标系中的位置
|
||||
const pinCanvasX = (pinPosition.x - containerRect.left - position.x) / scale.value;
|
||||
const pinCanvasY = (pinPosition.y - containerRect.top - position.y) / scale.value;
|
||||
|
||||
setWireCreationStart(pinCanvasX, pinCanvasY, componentId, pinId, pinInfo.constraint);
|
||||
// 使用最终的引脚位置作为连线起点
|
||||
setWireCreationStart(pinPosition.x, pinPosition.y, componentId, pinId, pinInfo.constraint);
|
||||
document.addEventListener('mousemove', onCreatingWireMouseMove);
|
||||
} else {
|
||||
// 完成连线创建
|
||||
@@ -609,6 +670,48 @@ function handlePinClick(componentId: string, pinInfo: any, event: MouseEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取终点引脚位置
|
||||
let endPosition = { x: 0, y: 0 };
|
||||
const componentPart = diagramParts.value.find(p => p.id === componentId);
|
||||
const endComponent = componentRefs.value[componentId];
|
||||
|
||||
console.log('终点组件部件:', componentPart);
|
||||
console.log('终点组件引用:', endComponent);
|
||||
|
||||
// 如果找到组件,设置终点位置
|
||||
if (componentPart) {
|
||||
endPosition.x = componentPart.x;
|
||||
endPosition.y = componentPart.y;
|
||||
|
||||
// 如果组件实现了getPinPosition方法,使用它
|
||||
if (endComponent && typeof endComponent.getPinPosition === 'function') {
|
||||
try {
|
||||
const pinPos = endComponent.getPinPosition(pinId);
|
||||
console.log('终点组件返回的引脚位置:', pinPos);
|
||||
|
||||
if (pinPos) {
|
||||
// 正确合并组件位置与引脚相对位置
|
||||
endPosition = {
|
||||
x: componentPart.x + pinPos.x,
|
||||
y: componentPart.y + pinPos.x
|
||||
};
|
||||
console.log('终点引脚位置(来自组件方法):', endPosition);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`获取终点引脚位置出错:`, error);
|
||||
}
|
||||
} else {
|
||||
// 对于没有提供引脚精确位置的组件,使用组件位置
|
||||
console.log('终点组件没有提供引脚位置方法,使用组件位置');
|
||||
}
|
||||
} else {
|
||||
console.error('找不到终点组件部件对象:', componentId);
|
||||
}
|
||||
|
||||
console.log('最终使用的终点位置:', endPosition);
|
||||
console.log('线路从', creatingWireStartInfo, '到', { componentId, pinId });
|
||||
console.log('----引脚点击详情结束----');
|
||||
|
||||
// 创建新的连线
|
||||
const newConnection: ConnectionArray = [
|
||||
`${creatingWireStartInfo.componentId}:${creatingWireStartInfo.pinId}`,
|
||||
@@ -822,6 +925,9 @@ function showToast(message: string, type: 'success' | 'error' | 'info' = 'info',
|
||||
|
||||
// --- 生命周期钩子 ---
|
||||
onMounted(async () => {
|
||||
// 重置组件引用
|
||||
resetComponentRefs();
|
||||
|
||||
// 加载图表数据
|
||||
try {
|
||||
diagramData.value = await loadDiagramData();
|
||||
@@ -843,12 +949,11 @@ onMounted(async () => {
|
||||
} catch (error) {
|
||||
console.error('加载图表数据失败:', error);
|
||||
}
|
||||
|
||||
// 初始化中心位置
|
||||
// 初始化中心位置
|
||||
if (canvasContainer.value) {
|
||||
// 修改为将画布中心点放在容器中心点
|
||||
position.x = canvasContainer.value.clientWidth / 2 - 2000; // 画布宽度的一半
|
||||
position.y = canvasContainer.value.clientHeight / 2 - 2000; // 画布高度的一半
|
||||
position.x = canvasContainer.value.clientWidth / 2 - 5000; // 画布宽度的一半
|
||||
position.y = canvasContainer.value.clientHeight / 2 - 5000; // 画布高度的一半
|
||||
}
|
||||
|
||||
// 添加键盘事件监听器
|
||||
@@ -858,7 +963,7 @@ onMounted(async () => {
|
||||
// 处理键盘事件
|
||||
function handleKeyDown(e: KeyboardEvent) {
|
||||
// 如果当前有选中的组件,并且按下了Delete键
|
||||
if (selectedComponentId.value && (e.key === 'Delete' || e.key === 'Backspace')) {
|
||||
if (selectedComponentId.value && (e.key === 'Delete')) {
|
||||
// 触发删除组件事件
|
||||
deleteComponent(selectedComponentId.value);
|
||||
}
|
||||
@@ -961,6 +1066,11 @@ defineExpose({
|
||||
watch(diagramData, (newData) => {
|
||||
saveDiagramData(newData);
|
||||
}, { deep: true });
|
||||
|
||||
// 当组件模块加载完成后,确保组件引用正确建立
|
||||
watch(() => props.componentModules, () => {
|
||||
// 这里不需要特别处理,Vue 会自动通过 setComponentRef 函数更新引用
|
||||
}, { deep: true });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -969,23 +1079,20 @@ watch(diagramData, (newData) => {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
/* background-image:
|
||||
linear-gradient(to right, rgba(100, 100, 100, 0.1) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, rgba(100, 100, 100, 0.1) 1px, transparent 1px),
|
||||
linear-gradient(to right, rgba(80, 80, 80, 0.2) 100px, transparent 100px),
|
||||
linear-gradient(to bottom, rgba(80, 80, 80, 0.2) 100px, transparent 100px); */
|
||||
background-size: 20px 20px, 20px 20px, 100px 100px, 100px 100px;
|
||||
background-position: 0 0;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.diagram-canvas {
|
||||
position: relative;
|
||||
width: 4000px;
|
||||
height: 4000px;
|
||||
width: 10000px;
|
||||
height: 10000px;
|
||||
transform-origin: 0 0;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
@@ -1002,6 +1109,7 @@ watch(diagramData, (newData) => {
|
||||
height: 100%;
|
||||
pointer-events: auto; /* 修复:允许线被点击 */
|
||||
z-index: 50;
|
||||
overflow: visible; /* 确保超出SVG范围的内容也能显示 */
|
||||
}
|
||||
|
||||
.wires-layer path {
|
||||
@@ -1035,7 +1143,6 @@ watch(diagramData, (newData) => {
|
||||
outline: 3px dashed;
|
||||
outline-color: #e74c3c #f39c12 #3498db #2ecc71;
|
||||
outline-offset: 3px;
|
||||
z-index: 999 !important; /* 使用更高的z-index确保始终在顶层 */
|
||||
}
|
||||
|
||||
/* 禁用状态 */
|
||||
@@ -1044,6 +1151,11 @@ watch(diagramData, (newData) => {
|
||||
filter: grayscale(70%);
|
||||
}
|
||||
|
||||
/* 隐藏引脚状态 */
|
||||
.component-hidepins :deep([data-pin-wrapper]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 为黑暗模式设置不同的网格线颜色 */
|
||||
/* :root[data-theme="dark"] .diagram-container {
|
||||
background-image:
|
||||
|
||||
Reference in New Issue
Block a user