feat: Enhance equipment components with pin functionality and constraint management

- Added pin support to MechanicalButton, enabling pin-click events and componentId handling.
- Updated Pin component to manage constraint states and colors dynamically.
- Integrated SMT_LED with pin functionality, allowing LED state to respond to constraints.
- Enhanced Wire component to reflect constraint colors and manage wire states based on pin connections.
- Introduced wireManager for managing wire states and constraints.
- Implemented a constraints store for managing and notifying constraint state changes across components.
- Updated component configuration to remove appearance options and clarify constraint descriptions.
- Improved ProjectView to handle optional chaining for props and ensure robust data handling.
- Initialized constraint communication in main application entry point.
This commit is contained in:
alivender
2025-04-29 11:05:30 +08:00
parent 10db7c67bf
commit 1c75aa621a
12 changed files with 590 additions and 420 deletions

View File

@@ -14,16 +14,15 @@
<rect width="90" height="50" x="5" y="5" fill="#222" rx="3" ry="3" />
<!-- LED 发光部分 -->
<rect
<rect
width="70"
height="30"
x="15"
y="15"
:fill="ledColor"
:style="{ opacity: isOn ? brightness/100 : 0.2 }"
:style="{ opacity: isOn ? 1 : 0.2 }"
rx="15"
ry="15"
@click="toggleLed"
class="interactive"
/>
@@ -35,46 +34,64 @@
x="12"
y="12"
:fill="ledColor"
:style="{ opacity: brightness/100 * 0.3 }"
:style="{ opacity: 0.3 }"
rx="18"
ry="18"
filter="blur(5px)"
class="glow"
/>
</svg>
<!-- 新增数字输入引脚Pin放在LED左侧居中 -->
<div style="position:absolute;left:-18px;top:50%;transform:translateY(-50%);">
<Pin
ref="pinRef"
v-bind="props"
@pin-click="$emit('pin-click', $event)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
import { getConstraintState, onConstraintStateChange } from '../../stores/constraints';
import Pin from './Pin.vue';
// LED特有属性
interface Props {
size?: number;
color?: string;
initialOn?: boolean;
brightness?: number;
// --- 关键暴露getPinPosition代理到内部Pin ---
const pinRef = ref<any>(null);
// 从Pin组件继承属性
interface PinProps {
label?: string;
constraint?: string;
componentId?: string; // 添加componentId属性
// 这些属性被预设为固定值,但仍然包含在类型中以便完整继承
direction?: 'input' | 'output' | 'inout';
type?: 'digital' | 'analog';
}
// 组件属性定义
// LED特有属性
interface LEDProps {
size?: number;
color?: string;
}
// 组合两个接口
interface Props extends PinProps, LEDProps {}
const props = withDefaults(defineProps<Props>(), {
size: 1,
color: 'red',
initialOn: false,
brightness: 80, // 亮度默认为80%
constraint: ''
constraint: '',
label: 'LED',
componentId: ''
});
// 计算实际宽高
const width = computed(() => 100 * props.size);
const height = computed(() => 60 * props.size);
// 内部状态
const isOn = ref(props.initialOn);
const brightness = ref(props.brightness);
const isOn = ref(false);
// LED 颜色映射表
const colorMap: Record<string, string> = {
'red': '#ff3333',
'green': '#33ff33',
@@ -85,70 +102,64 @@ const colorMap: Record<string, string> = {
'purple': '#9933ff'
};
// 计算实际LED颜色
const ledColor = computed(() => {
return colorMap[props.color.toLowerCase()] || props.color;
});
// 定义组件发出的事件
const emit = defineEmits([
'toggle',
'brightness-change',
'value-change'
]);
// 监听约束状态变化
let unsubscribe: (() => void) | null = null;
// 手动切换LED状态
function toggleLed() {
isOn.value = !isOn.value;
emit('toggle', isOn.value);
emit('value-change', {
isOn: isOn.value,
brightness: brightness.value
});
}
// 设置亮度
function setBrightness(value: number) {
// 限制亮度值在0-100范围内
brightness.value = Math.max(0, Math.min(100, value));
emit('brightness-change', brightness.value);
emit('value-change', {
isOn: isOn.value,
brightness: brightness.value
});
}
// 手动设置LED开关状态
function setLedState(on: boolean) {
isOn.value = on;
emit('toggle', isOn.value);
emit('value-change', {
isOn: isOn.value,
brightness: brightness.value
});
}
// 监听props变化
watch(() => props.brightness, (newVal) => {
brightness.value = newVal;
onMounted(() => {
if (props.constraint) {
unsubscribe = onConstraintStateChange((constraint, level) => {
if (constraint === props.constraint) {
isOn.value = (level === 'high');
}
});
// 初始化LED状态
const currentState = getConstraintState(props.constraint);
isOn.value = (currentState === 'high');
}
});
watch(() => props.initialOn, (newVal) => {
isOn.value = newVal;
onUnmounted(() => {
if (unsubscribe) {
unsubscribe();
}
});
watch(() => props.constraint, (newConstraint) => {
if (unsubscribe) {
unsubscribe();
unsubscribe = null;
}
if (newConstraint) {
unsubscribe = onConstraintStateChange((constraint, level) => {
if (constraint === newConstraint) {
isOn.value = (level === 'high');
}
});
// 初始化LED状态
const currentState = getConstraintState(newConstraint);
isOn.value = (currentState === 'high');
}
});
// 向外暴露方法
defineExpose({
toggleLed,
setBrightness,
setLedState,
getInfo: () => ({
// LED特有属性
color: props.color,
isOn: isOn.value,
brightness: brightness.value,
constraint: props.constraint
})
constraint: props.constraint,
componentId: props.componentId,
direction: 'input',
type: 'digital'
}),
getPinPosition: (componentId: string) => {
if (pinRef.value && pinRef.value.getPinPosition) {
return pinRef.value.getPinPosition(componentId);
}
return null;
}
});
</script>