fix: Component awlays reset
This commit is contained in:
parent
c7907b4253
commit
7aff4f3f02
|
@ -112,7 +112,15 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, onUnmounted, computed, watch } from "vue";
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
computed,
|
||||
watch,
|
||||
provide,
|
||||
} from "vue";
|
||||
import WireComponent from "./equipments/Wire.vue";
|
||||
|
||||
// 导入 diagram 管理器
|
||||
|
@ -122,10 +130,7 @@ import {
|
|||
updatePartPosition,
|
||||
updatePartAttribute,
|
||||
deletePart,
|
||||
addConnection,
|
||||
deleteConnection,
|
||||
findConnectionsByPart,
|
||||
moveGroupComponents,
|
||||
parseConnectionPin,
|
||||
connectionArrayToWireItem,
|
||||
validateDiagramData,
|
||||
|
@ -137,7 +142,8 @@ import type {
|
|||
ConnectionArray,
|
||||
WireItem,
|
||||
} from "./diagramManager";
|
||||
import { toString } from "lodash";
|
||||
|
||||
import { CanvasCurrentSelectedComponentID } from "./InjectKeys";
|
||||
|
||||
// 右键菜单处理函数
|
||||
function handleContextMenu(e: MouseEvent) {
|
||||
|
@ -174,6 +180,9 @@ const hoveredComponent = ref<string | null>(null);
|
|||
const draggingComponentId = ref<string | null>(null);
|
||||
const componentDragOffset = reactive({ x: 0, y: 0 });
|
||||
|
||||
// Provide and Inject
|
||||
provide(CanvasCurrentSelectedComponentID, selectedComponentId);
|
||||
|
||||
// Diagram 数据
|
||||
const diagramData = ref<DiagramData>({
|
||||
version: 1,
|
||||
|
@ -244,7 +253,7 @@ const wireItems = computed<WireItem[]>(() => {
|
|||
console.log(`线路${index} - 计算后的起点位置:`, startPos);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`获取引脚位置出错:`, error);
|
||||
// console.error(`获取引脚位置出错:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,7 +499,7 @@ function startComponentDrag(e: MouseEvent, component: DiagramPart) {
|
|||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
|
||||
console.debug(`Start Drag Component: ${component.type}:${component.id}`)
|
||||
console.debug(`Start Drag Component: ${component.type}:${component.id}`);
|
||||
|
||||
// 设置拖拽状态
|
||||
draggingComponentId.value = component.id;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import type { InjectionKey, Ref } from "vue";
|
||||
|
||||
export const CanvasCurrentSelectedComponentID = Symbol() as InjectionKey<Ref<string | null>>
|
||||
|
|
@ -44,11 +44,13 @@
|
|||
</CollapsibleSection>
|
||||
|
||||
<CollapsibleSection title="组件功能" v-model:isExpanded="componentCapsExpanded" status="default" class="mt-4">
|
||||
<div v-if="componentData && componentData.type">
|
||||
<component v-if="capabilityComponent" :is="capabilityComponent" v-bind="componentData.attrs" />
|
||||
<div v-else class="text-gray-400">该组件没有提供特殊功能</div>
|
||||
<div id="ComponentCapabilities" ref="ComponentCapabilities"></div>
|
||||
<div v-if="!(componentData && componentData.type)" class="text-gray-400">
|
||||
选择元件以查看其功能
|
||||
</div>
|
||||
<div v-else-if="!componentCaps?.hasChildNodes()" class="text-gray-400">
|
||||
该组件没有提供特殊功能
|
||||
</div>
|
||||
<div v-else class="text-gray-400">选择元件以查看其功能</div>
|
||||
</CollapsibleSection>
|
||||
|
||||
<!-- 未来可以在这里添加更多的分区 -->
|
||||
|
@ -71,9 +73,12 @@ import { type PropertyConfig } from "@/components/equipments/componentConfig"; /
|
|||
import CollapsibleSection from "./CollapsibleSection.vue"; // 可折叠区域组件
|
||||
import PropertyEditor from "./PropertyEditor.vue"; // 属性编辑器组件
|
||||
import DDSPropertyEditor from "./equipments/DDSPropertyEditor.vue"; // DDS专用属性编辑器组件
|
||||
import { ref, computed, watch, shallowRef, markRaw, h, createApp } from "vue"; // Vue核心API
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
import type { JSX } from "vue/jsx-runtime";
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
watch,
|
||||
useTemplateRef,
|
||||
} from "vue"; // Vue核心API
|
||||
|
||||
// 引脚接口定义
|
||||
interface Pin {
|
||||
|
@ -95,6 +100,8 @@ const pinsSectionExpanded = ref(false); // 引脚配置区域默认折叠
|
|||
const componentCapsExpanded = ref(true); // 组件功能区域默认展开
|
||||
const wireSectionExpanded = ref(false); // 连线管理区域默认折叠
|
||||
|
||||
const componentCaps = useTemplateRef("ComponentCapabilities");
|
||||
|
||||
// DDS组件特殊属性的本地状态
|
||||
const ddsProperties = ref({
|
||||
frequency: 1000, // 频率,默认1000Hz
|
||||
|
@ -207,129 +214,6 @@ function updateDDSProperties(newProperties: any) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 存储当前选中组件的能力组件
|
||||
const capabilityComponent = shallowRef<JSX.Element>();
|
||||
|
||||
// 获取组件实例上暴露的方法
|
||||
async function getExposedCapabilities(componentType: string) {
|
||||
try {
|
||||
// 动态导入组件
|
||||
const module = await import(`./equipments/${componentType}.vue`);
|
||||
const Component = module.default;
|
||||
|
||||
// 创建一个临时div作为挂载点
|
||||
const tempDiv = document.createElement("div");
|
||||
|
||||
// 创建临时应用实例并挂载组件
|
||||
let exposedMethods: any = null;
|
||||
const app = createApp({
|
||||
render() {
|
||||
return h(Component, {
|
||||
ref: (el: any) => {
|
||||
if (el) {
|
||||
// 获取组件实例暴露的方法
|
||||
exposedMethods = el;
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// 挂载应用
|
||||
const vm = app.mount(tempDiv);
|
||||
|
||||
// 确保实例已创建并获取到暴露的方法
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
// 检查是否有getCapabilities方法
|
||||
if (
|
||||
exposedMethods &&
|
||||
typeof exposedMethods.getCapabilities === "function"
|
||||
) {
|
||||
// 获取能力组件定义
|
||||
const CapabilityComponent = exposedMethods.getCapabilities();
|
||||
|
||||
// 卸载应用,清理DOM
|
||||
app.unmount();
|
||||
tempDiv.remove();
|
||||
|
||||
return CapabilityComponent;
|
||||
}
|
||||
|
||||
// 卸载应用,清理DOM
|
||||
app.unmount();
|
||||
tempDiv.remove();
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error(`获取${componentType}能力页面失败:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 监听选中组件变化,动态加载能力组件
|
||||
watch(
|
||||
() => props.componentData,
|
||||
async (newComponentData) => {
|
||||
if (newComponentData && newComponentData.type) {
|
||||
try {
|
||||
// 首先尝试从实例中获取暴露的方法
|
||||
let capsComponent = null;
|
||||
if (!isUndefined( newComponentData.capsPage ) && !isNull(newComponentData.capsPage)) {
|
||||
capsComponent = newComponentData.capsPage;
|
||||
capabilityComponent.value = markRaw(capsComponent);
|
||||
}
|
||||
else
|
||||
capsComponent = await getExposedCapabilities(newComponentData.type);
|
||||
|
||||
if (capsComponent) {
|
||||
capabilityComponent.value = markRaw(capsComponent);
|
||||
newComponentData.capsPage = capsComponent;
|
||||
console.log(`已从实例加载${newComponentData.type}组件的能力页面`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果实例方法获取失败,回退到模块导出方法
|
||||
const module = await import(
|
||||
`./equipments/${newComponentData.type}.vue`
|
||||
);
|
||||
|
||||
if (
|
||||
(module.default &&
|
||||
typeof module.default.getCapabilities === "function") ||
|
||||
typeof module.getCapabilities === "function"
|
||||
) {
|
||||
const getCapsFn =
|
||||
typeof module.getCapabilities === "function"
|
||||
? module.getCapabilities
|
||||
: module.default.getCapabilities;
|
||||
|
||||
const moduleCapComponent = getCapsFn();
|
||||
if (moduleCapComponent) {
|
||||
capabilityComponent.value = markRaw(moduleCapComponent);
|
||||
console.log(`已从模块加载${newComponentData.type}组件的能力页面`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
capabilityComponent.value = null;
|
||||
console.log(`组件${newComponentData.type}没有提供getCapabilities方法`);
|
||||
} catch (error) {
|
||||
console.error(`加载组件${newComponentData.type}能力页面失败:`, error);
|
||||
capabilityComponent.value = null;
|
||||
}
|
||||
} else {
|
||||
capabilityComponent.value = null;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 修改hasComponentCaps计算属性
|
||||
const hasComponentCaps = computed(() => {
|
||||
return capabilityComponent.value !== null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import type { JSX } from "vue/jsx-runtime";
|
||||
|
||||
// 定义 diagram.json 的类型结构
|
||||
export interface DiagramData {
|
||||
version: number;
|
||||
|
@ -17,7 +15,6 @@ export interface DiagramPart {
|
|||
x: number;
|
||||
y: number;
|
||||
attrs: Record<string, any>;
|
||||
capsPage?: JSX.Element;
|
||||
rotate: number;
|
||||
group: string;
|
||||
positionlock: boolean;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="motherboard-container" :style="{
|
||||
<div class="motherboard-container" v-bind="$attrs" :style="{
|
||||
width: width + 'px',
|
||||
height: height + 'px',
|
||||
position: 'relative',
|
||||
|
@ -9,21 +9,31 @@
|
|||
<image href="../equipments/svg/motherboard.svg" width="100%" height="100%" preserveAspectRatio="xMidYMid meet" />
|
||||
</svg>
|
||||
</div>
|
||||
<Teleport to="#ComponentCapabilities" v-if="selectecComponentID === props.componentId">
|
||||
<MotherBoardCaps :jtagAddr="eqps.boardAddr" :jtagPort="eqps.boardPort.toString()" />
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import MotherBoardCaps from "./MotherBoardCaps.vue";
|
||||
import { useEquipments } from "@/stores/equipments";
|
||||
import { ref, computed, defineComponent, watchEffect } from "vue";
|
||||
import { ref, computed, watchEffect, inject } from "vue";
|
||||
import { CanvasCurrentSelectedComponentID } from "../InjectKeys";
|
||||
|
||||
// 主板特有属性
|
||||
export interface MotherBoardProps {
|
||||
size?: number;
|
||||
boardAddr?: string;
|
||||
boardPort?: string;
|
||||
componentId?: string;
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "pinClick", pinId: string): void;
|
||||
}>();
|
||||
|
||||
const props = withDefaults(defineProps<MotherBoardProps>(), getDefaultProps());
|
||||
const selectecComponentID = inject(CanvasCurrentSelectedComponentID, ref(null));
|
||||
|
||||
// 计算实际宽高
|
||||
const width = computed(() => 800 * props.size);
|
||||
|
@ -34,9 +44,6 @@ const eqps = useEquipments();
|
|||
const bitstreamFile = ref<File | null>();
|
||||
|
||||
watchEffect(() => {
|
||||
console.trace(
|
||||
`board监听改动: ${props.size} ${props.boardAddr}:${props.boardPort}`,
|
||||
);
|
||||
eqps.setAddr(props.boardAddr);
|
||||
eqps.setPort(props.boardPort);
|
||||
});
|
||||
|
@ -49,20 +56,6 @@ defineExpose({
|
|||
}),
|
||||
// 主板没有引脚,但为了接口一致性,提供一个空的getPinPosition方法
|
||||
getPinPosition: () => null,
|
||||
getCapabilities: () => {
|
||||
// 返回组件定义而不是直接返回JSX
|
||||
return defineComponent({
|
||||
name: "MotherBoardCaps",
|
||||
setup() {
|
||||
return () => (
|
||||
<MotherBoardCaps
|
||||
jtagAddr={eqps.boardAddr}
|
||||
jtagPort={eqps.boardPort.toString()}
|
||||
/>
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -73,6 +66,7 @@ export function getDefaultProps(): MotherBoardProps {
|
|||
size: 1,
|
||||
boardAddr: "127.0.0.1",
|
||||
boardPort: "1234",
|
||||
componentId: "DefaultMotherBoardID",
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -217,7 +217,6 @@ async function handleAddComponent(componentData: {
|
|||
x: Math.round(position.x + offsetX),
|
||||
y: Math.round(position.y + offsetY),
|
||||
attrs: componentData.props,
|
||||
capsPage: capsPage, // 设置组件的能力页面
|
||||
rotate: 0,
|
||||
group: "",
|
||||
positionlock: false,
|
||||
|
|
Loading…
Reference in New Issue