fix: Component awlays reset

This commit is contained in:
SikongJueluo 2025-05-17 17:32:16 +08:00
parent c7907b4253
commit 7aff4f3f02
No known key found for this signature in database
7 changed files with 48 additions and 161 deletions

View File

@ -112,7 +112,15 @@
</template> </template>
<script setup lang="ts"> <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"; import WireComponent from "./equipments/Wire.vue";
// diagram // diagram
@ -122,10 +130,7 @@ import {
updatePartPosition, updatePartPosition,
updatePartAttribute, updatePartAttribute,
deletePart, deletePart,
addConnection,
deleteConnection, deleteConnection,
findConnectionsByPart,
moveGroupComponents,
parseConnectionPin, parseConnectionPin,
connectionArrayToWireItem, connectionArrayToWireItem,
validateDiagramData, validateDiagramData,
@ -137,7 +142,8 @@ import type {
ConnectionArray, ConnectionArray,
WireItem, WireItem,
} from "./diagramManager"; } from "./diagramManager";
import { toString } from "lodash";
import { CanvasCurrentSelectedComponentID } from "./InjectKeys";
// //
function handleContextMenu(e: MouseEvent) { function handleContextMenu(e: MouseEvent) {
@ -174,6 +180,9 @@ const hoveredComponent = ref<string | null>(null);
const draggingComponentId = ref<string | null>(null); const draggingComponentId = ref<string | null>(null);
const componentDragOffset = reactive({ x: 0, y: 0 }); const componentDragOffset = reactive({ x: 0, y: 0 });
// Provide and Inject
provide(CanvasCurrentSelectedComponentID, selectedComponentId);
// Diagram // Diagram
const diagramData = ref<DiagramData>({ const diagramData = ref<DiagramData>({
version: 1, version: 1,
@ -244,7 +253,7 @@ const wireItems = computed<WireItem[]>(() => {
console.log(`线路${index} - 计算后的起点位置:`, startPos); console.log(`线路${index} - 计算后的起点位置:`, startPos);
} }
} catch (error) { } catch (error) {
console.error(`获取引脚位置出错:`, error); // console.error(`:`, error);
} }
} }
} }
@ -490,7 +499,7 @@ function startComponentDrag(e: MouseEvent, component: DiagramPart) {
// //
e.stopPropagation(); e.stopPropagation();
console.debug(`Start Drag Component: ${component.type}:${component.id}`) console.debug(`Start Drag Component: ${component.type}:${component.id}`);
// //
draggingComponentId.value = component.id; draggingComponentId.value = component.id;

View File

@ -0,0 +1,4 @@
import type { InjectionKey, Ref } from "vue";
export const CanvasCurrentSelectedComponentID = Symbol() as InjectionKey<Ref<string | null>>

View File

@ -44,11 +44,13 @@
</CollapsibleSection> </CollapsibleSection>
<CollapsibleSection title="组件功能" v-model:isExpanded="componentCapsExpanded" status="default" class="mt-4"> <CollapsibleSection title="组件功能" v-model:isExpanded="componentCapsExpanded" status="default" class="mt-4">
<div v-if="componentData && componentData.type"> <div id="ComponentCapabilities" ref="ComponentCapabilities"></div>
<component v-if="capabilityComponent" :is="capabilityComponent" v-bind="componentData.attrs" /> <div v-if="!(componentData && componentData.type)" class="text-gray-400">
<div v-else class="text-gray-400">该组件没有提供特殊功能</div> 选择元件以查看其功能
</div>
<div v-else-if="!componentCaps?.hasChildNodes()" class="text-gray-400">
该组件没有提供特殊功能
</div> </div>
<div v-else class="text-gray-400">选择元件以查看其功能</div>
</CollapsibleSection> </CollapsibleSection>
<!-- 未来可以在这里添加更多的分区 --> <!-- 未来可以在这里添加更多的分区 -->
@ -71,9 +73,12 @@ import { type PropertyConfig } from "@/components/equipments/componentConfig"; /
import CollapsibleSection from "./CollapsibleSection.vue"; // import CollapsibleSection from "./CollapsibleSection.vue"; //
import PropertyEditor from "./PropertyEditor.vue"; // import PropertyEditor from "./PropertyEditor.vue"; //
import DDSPropertyEditor from "./equipments/DDSPropertyEditor.vue"; // DDS import DDSPropertyEditor from "./equipments/DDSPropertyEditor.vue"; // DDS
import { ref, computed, watch, shallowRef, markRaw, h, createApp } from "vue"; // VueAPI import {
import { isNull, isUndefined } from "lodash"; ref,
import type { JSX } from "vue/jsx-runtime"; computed,
watch,
useTemplateRef,
} from "vue"; // VueAPI
// //
interface Pin { interface Pin {
@ -95,6 +100,8 @@ const pinsSectionExpanded = ref(false); // 引脚配置区域默认折叠
const componentCapsExpanded = ref(true); // const componentCapsExpanded = ref(true); //
const wireSectionExpanded = ref(false); // 线 const wireSectionExpanded = ref(false); // 线
const componentCaps = useTemplateRef("ComponentCapabilities");
// DDS // DDS
const ddsProperties = ref({ const ddsProperties = ref({
frequency: 1000, // 1000Hz 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> </script>
<style scoped> <style scoped>

View File

@ -1,5 +1,3 @@
import type { JSX } from "vue/jsx-runtime";
// 定义 diagram.json 的类型结构 // 定义 diagram.json 的类型结构
export interface DiagramData { export interface DiagramData {
version: number; version: number;
@ -17,7 +15,6 @@ export interface DiagramPart {
x: number; x: number;
y: number; y: number;
attrs: Record<string, any>; attrs: Record<string, any>;
capsPage?: JSX.Element;
rotate: number; rotate: number;
group: string; group: string;
positionlock: boolean; positionlock: boolean;

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="motherboard-container" :style="{ <div class="motherboard-container" v-bind="$attrs" :style="{
width: width + 'px', width: width + 'px',
height: height + 'px', height: height + 'px',
position: 'relative', position: 'relative',
@ -9,21 +9,31 @@
<image href="../equipments/svg/motherboard.svg" width="100%" height="100%" preserveAspectRatio="xMidYMid meet" /> <image href="../equipments/svg/motherboard.svg" width="100%" height="100%" preserveAspectRatio="xMidYMid meet" />
</svg> </svg>
</div> </div>
<Teleport to="#ComponentCapabilities" v-if="selectecComponentID === props.componentId">
<MotherBoardCaps :jtagAddr="eqps.boardAddr" :jtagPort="eqps.boardPort.toString()" />
</Teleport>
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
import MotherBoardCaps from "./MotherBoardCaps.vue"; import MotherBoardCaps from "./MotherBoardCaps.vue";
import { useEquipments } from "@/stores/equipments"; 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 { export interface MotherBoardProps {
size?: number; size?: number;
boardAddr?: string; boardAddr?: string;
boardPort?: string; boardPort?: string;
componentId?: string;
} }
const emit = defineEmits<{
(e: "pinClick", pinId: string): void;
}>();
const props = withDefaults(defineProps<MotherBoardProps>(), getDefaultProps()); const props = withDefaults(defineProps<MotherBoardProps>(), getDefaultProps());
const selectecComponentID = inject(CanvasCurrentSelectedComponentID, ref(null));
// //
const width = computed(() => 800 * props.size); const width = computed(() => 800 * props.size);
@ -34,9 +44,6 @@ const eqps = useEquipments();
const bitstreamFile = ref<File | null>(); const bitstreamFile = ref<File | null>();
watchEffect(() => { watchEffect(() => {
console.trace(
`board监听改动: ${props.size} ${props.boardAddr}:${props.boardPort}`,
);
eqps.setAddr(props.boardAddr); eqps.setAddr(props.boardAddr);
eqps.setPort(props.boardPort); eqps.setPort(props.boardPort);
}); });
@ -49,20 +56,6 @@ defineExpose({
}), }),
// getPinPosition // getPinPosition
getPinPosition: () => null, getPinPosition: () => null,
getCapabilities: () => {
// JSX
return defineComponent({
name: "MotherBoardCaps",
setup() {
return () => (
<MotherBoardCaps
jtagAddr={eqps.boardAddr}
jtagPort={eqps.boardPort.toString()}
/>
);
},
});
},
}); });
</script> </script>
@ -73,6 +66,7 @@ export function getDefaultProps(): MotherBoardProps {
size: 1, size: 1,
boardAddr: "127.0.0.1", boardAddr: "127.0.0.1",
boardPort: "1234", boardPort: "1234",
componentId: "DefaultMotherBoardID",
}; };
} }
</script> </script>

View File

@ -217,7 +217,6 @@ async function handleAddComponent(componentData: {
x: Math.round(position.x + offsetX), x: Math.round(position.x + offsetX),
y: Math.round(position.y + offsetY), y: Math.round(position.y + offsetY),
attrs: componentData.props, attrs: componentData.props,
capsPage: capsPage, //
rotate: 0, rotate: 0,
group: "", group: "",
positionlock: false, positionlock: false,