234 lines
7.5 KiB
Vue
234 lines
7.5 KiB
Vue
<template>
|
||
<div class="property-panel">
|
||
<CollapsibleSection title="基本属性" v-model:isExpanded="propertySectionExpanded" status="default">
|
||
<PropertyEditor :componentData="componentData" :componentConfig="componentConfig" @updateProp="
|
||
(componentId, propName, value) =>
|
||
$emit('updateProp', componentId, propName, value)
|
||
" @updateDirectProp="
|
||
(componentId, propName, value) =>
|
||
$emit('updateDirectProp', componentId, propName, value)
|
||
" />
|
||
</CollapsibleSection>
|
||
|
||
<!-- 信号发生器(DDS)特殊属性编辑器 -->
|
||
<div v-if="isDDSComponent">
|
||
<DDSPropertyEditor v-model="ddsProperties" @update:modelValue="updateDDSProperties" />
|
||
</div>
|
||
|
||
<!-- 如果选中的组件有pins属性,则显示引脚配置区域 -->
|
||
<CollapsibleSection v-if="hasPinsProperty" title="引脚配置" v-model:isExpanded="pinsSectionExpanded" status="default">
|
||
<div class="space-y-4 p-2">
|
||
<!-- 显示现有的pins -->
|
||
<div v-for="(pin, index) in componentPins" :key="index" class="pin-item p-2 border rounded-md bg-base-200">
|
||
<div class="font-medium mb-2">引脚 #{{ index + 1 }}</div>
|
||
|
||
<div class="grid grid-cols-2 gap-2">
|
||
<div class="form-control">
|
||
<label class="label">
|
||
<span class="label-text text-xs">ID</span>
|
||
</label>
|
||
<input type="text" v-model="componentPins[index].pinId" class="input input-bordered input-sm w-full"
|
||
placeholder="引脚ID" @change="updatePins" />
|
||
</div>
|
||
|
||
<div class="form-control">
|
||
<label class="label">
|
||
<span class="label-text text-xs">约束条件</span>
|
||
</label>
|
||
<input type="text" v-model="componentPins[index].constraint" class="input input-bordered input-sm w-full"
|
||
placeholder="约束条件" @change="updatePins" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</CollapsibleSection>
|
||
|
||
<CollapsibleSection title="组件功能" v-model:isExpanded="componentCapsExpanded" status="default" class="mt-4">
|
||
<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>
|
||
</CollapsibleSection>
|
||
|
||
<!-- 未来可以在这里添加更多的分区 -->
|
||
<!-- 例如:
|
||
<CollapsibleSection
|
||
title="连线管理"
|
||
v-model:isExpanded="wireSectionExpanded"
|
||
status="default"
|
||
>
|
||
<div>连线管理内容</div>
|
||
</CollapsibleSection>
|
||
-->
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// 导入所需的类型和组件
|
||
import { type DiagramPart } from "@/components/LabCanvas/composable/diagramManager"; // 图表部件类型定义
|
||
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,
|
||
useTemplateRef,
|
||
} from "vue"; // Vue核心API
|
||
|
||
// 引脚接口定义
|
||
interface Pin {
|
||
pinId: string; // 引脚ID
|
||
constraint: string; // 引脚约束条件
|
||
x: number; // 引脚X坐标位置
|
||
y: number; // 引脚Y坐标位置
|
||
}
|
||
|
||
// 定义组件的输入属性
|
||
const props = defineProps<{
|
||
componentData: DiagramPart | null; // 当前选中的组件数据
|
||
componentConfig: { props: PropertyConfig[] } | null; // 组件的配置信息
|
||
}>();
|
||
|
||
// 控制各个属性分区的展开状态
|
||
const propertySectionExpanded = ref(false); // 基本属性区域默认展开
|
||
const pinsSectionExpanded = ref(false); // 引脚配置区域默认折叠
|
||
const componentCapsExpanded = ref(true); // 组件功能区域默认展开
|
||
const wireSectionExpanded = ref(false); // 连线管理区域默认折叠
|
||
|
||
const componentCaps = useTemplateRef("ComponentCapabilities");
|
||
|
||
// DDS组件特殊属性的本地状态
|
||
const ddsProperties = ref({
|
||
frequency: 1000, // 频率,默认1000Hz
|
||
phase: 0, // 相位,默认0度
|
||
waveform: "sine", // 波形类型,默认正弦波
|
||
customWaveformPoints: [], // 自定义波形点数据,默认空数组
|
||
});
|
||
|
||
// 本地维护一个pins数组副本,用于编辑操作
|
||
const componentPins = ref<Pin[]>([]);
|
||
|
||
// 监听组件pins属性变化,更新本地pins数据
|
||
watch(
|
||
() => props.componentData?.attrs?.pins,
|
||
(newPins) => {
|
||
if (newPins) {
|
||
// 深拷贝以避免直接修改原始数据
|
||
componentPins.value = JSON.parse(JSON.stringify(newPins));
|
||
} else {
|
||
componentPins.value = [];
|
||
}
|
||
},
|
||
{ deep: true, immediate: true }, // 深度监听并立即执行
|
||
);
|
||
|
||
// 监听DDS组件数据变化,更新特殊属性
|
||
watch(
|
||
() => props.componentData?.attrs,
|
||
(newAttrs) => {
|
||
if (newAttrs && isDDSComponent.value) {
|
||
// 从组件属性中提取DDS特有属性
|
||
ddsProperties.value = {
|
||
frequency: newAttrs.frequency || 1000,
|
||
phase: newAttrs.phase || 0,
|
||
waveform: newAttrs.waveform || "sine",
|
||
customWaveformPoints: newAttrs.customWaveformPoints || [],
|
||
};
|
||
}
|
||
},
|
||
{ deep: true, immediate: true }, // 深度监听并立即执行
|
||
);
|
||
|
||
// 计算属性:检查组件是否有pins属性
|
||
const hasPinsProperty = computed(() => {
|
||
if (!props.componentData || !props.componentData.attrs) {
|
||
return false;
|
||
}
|
||
|
||
// 方法1:检查配置中是否有pins属性
|
||
if (props.componentConfig && props.componentConfig.props) {
|
||
return props.componentConfig.props.some(
|
||
(prop) => prop.name === "pins" && prop.isArrayType,
|
||
);
|
||
}
|
||
|
||
// 方法2:直接检查attrs中是否有pins属性
|
||
return "pins" in props.componentData.attrs;
|
||
});
|
||
|
||
// 计算属性:检查组件是否为DDS组件
|
||
const isDDSComponent = computed(() => {
|
||
return props.componentData?.type === "DDS";
|
||
});
|
||
|
||
// 定义向父组件发送的事件
|
||
const emit = defineEmits<{
|
||
// 更新嵌套属性(如数组或对象中的属性)
|
||
(e: "updateProp", componentId: string, propName: string, value: any): void;
|
||
// 更新直接属性
|
||
(
|
||
e: "updateDirectProp",
|
||
componentId: string,
|
||
propName: string,
|
||
value: any,
|
||
): void;
|
||
}>();
|
||
|
||
// 更新pins属性的函数
|
||
function updatePins() {
|
||
if (props.componentData && props.componentData.id) {
|
||
// 将编辑后的pins数据发送给父组件
|
||
emit("updateProp", props.componentData.id, "pins", componentPins.value);
|
||
}
|
||
}
|
||
|
||
// 更新DDS特殊属性的函数
|
||
function updateDDSProperties(newProperties: any) {
|
||
// 更新本地状态
|
||
ddsProperties.value = newProperties;
|
||
if (props.componentData && props.componentData.id) {
|
||
// 将各个属性单独更新,而不是作为一个整体更新
|
||
emit(
|
||
"updateProp",
|
||
props.componentData.id,
|
||
"frequency",
|
||
newProperties.frequency,
|
||
);
|
||
emit("updateProp", props.componentData.id, "phase", newProperties.phase);
|
||
emit(
|
||
"updateProp",
|
||
props.componentData.id,
|
||
"waveform",
|
||
newProperties.waveform,
|
||
);
|
||
emit(
|
||
"updateProp",
|
||
props.componentData.id,
|
||
"customWaveformPoints",
|
||
newProperties.customWaveformPoints,
|
||
);
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.property-panel {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.pin-item {
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.pin-item:hover {
|
||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
||
}
|
||
</style>
|