263 lines
5.9 KiB
Vue
263 lines
5.9 KiB
Vue
<template>
|
|
<div class="led-container" :style="{ width: width + 'px', height: height + 'px', position: 'relative' }">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
:width="width"
|
|
:height="height"
|
|
viewBox="0 0 100 60"
|
|
class="smt-led"
|
|
>
|
|
<!-- LED 基座 -->
|
|
<rect width="100" height="60" x="0" y="0" fill="#333" rx="5" ry="5" />
|
|
|
|
<!-- LED 主体 -->
|
|
<rect width="90" height="50" x="5" y="5" fill="#222" rx="3" ry="3" />
|
|
|
|
<!-- LED 发光部分 -->
|
|
<rect
|
|
width="70"
|
|
height="30"
|
|
x="15"
|
|
y="15"
|
|
:fill="ledColor"
|
|
:style="{ opacity: isOn ? 1 : 0.2 }"
|
|
rx="15"
|
|
ry="15"
|
|
class="interactive"
|
|
/>
|
|
|
|
<!-- LED 光晕效果 -->
|
|
<rect
|
|
v-if="isOn"
|
|
width="76"
|
|
height="36"
|
|
x="12"
|
|
y="12"
|
|
:fill="ledColor"
|
|
:style="{ opacity: 0.3 }"
|
|
rx="18"
|
|
ry="18"
|
|
filter="blur(5px)"
|
|
class="glow"
|
|
/> </svg>
|
|
<!-- 渲染自定义引脚数组 -->
|
|
<div v-for="pin in props.pins" :key="pin.pinId"
|
|
:style="{
|
|
position: 'absolute',
|
|
left: `${pin.x * props.size}px`,
|
|
top: `${pin.y * props.size}px`,
|
|
transform: 'translate(-50%, -50%)'
|
|
}"
|
|
:data-pin-wrapper="`${pin.pinId}`"
|
|
:data-pin-x="`${pin.x * props.size}`"
|
|
:data-pin-y="`${pin.y * props.size}`">
|
|
<Pin
|
|
:ref="el => { if(el) pinRefs[pin.pinId] = el }"
|
|
:label="pin.pinId"
|
|
:constraint="pin.constraint"
|
|
:pinId="pin.pinId"
|
|
@pin-click="$emit('pin-click', $event)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
|
|
import { useConstraintsStore } from '../../stores/constraints';
|
|
import Pin from './Pin.vue';
|
|
|
|
const {getConstraintState, onConstraintStateChange} = useConstraintsStore();
|
|
|
|
// 存储多个Pin引用
|
|
const pinRefs = ref<Record<string, any>>({});
|
|
|
|
// LED特有属性
|
|
interface LEDProps {
|
|
size?: number;
|
|
color?: string;
|
|
brightness?: number;
|
|
pins?: {
|
|
pinId: string;
|
|
constraint: string;
|
|
x: number;
|
|
y: number;
|
|
}[];
|
|
}
|
|
|
|
const props = withDefaults(defineProps<LEDProps>(), {
|
|
size: 1,
|
|
color: 'red',
|
|
brightness: 80,
|
|
pins: () => [
|
|
{
|
|
pinId: 'LED',
|
|
constraint: '',
|
|
x: 50,
|
|
y: 30
|
|
}
|
|
]
|
|
});
|
|
|
|
const width = computed(() => 100 * props.size);
|
|
const height = computed(() => 60 * props.size);
|
|
|
|
const isOn = ref(false);
|
|
|
|
const colorMap: Record<string, string> = {
|
|
'red': '#ff3333',
|
|
'green': '#33ff33',
|
|
'blue': '#3333ff',
|
|
'yellow': '#ffff33',
|
|
'orange': '#ff9933',
|
|
'white': '#ffffff',
|
|
'purple': '#9933ff'
|
|
};
|
|
|
|
const ledColor = computed(() => {
|
|
return colorMap[props.color.toLowerCase()] || props.color;
|
|
});
|
|
|
|
// 获取LED的constraint值
|
|
const ledConstraint = computed(() => {
|
|
if (props.pins && props.pins.length > 0) {
|
|
return props.pins[0].constraint;
|
|
}
|
|
return '';
|
|
});
|
|
|
|
// 监听约束状态变化
|
|
let unsubscribe: (() => void) | null = null;
|
|
|
|
onMounted(() => {
|
|
if (ledConstraint.value) {
|
|
unsubscribe = onConstraintStateChange((constraint, level) => {
|
|
if (constraint === ledConstraint.value) {
|
|
isOn.value = (level === 'high');
|
|
}
|
|
});
|
|
// 初始化LED状态
|
|
const currentState = getConstraintState(ledConstraint.value);
|
|
isOn.value = (currentState === 'high');
|
|
}
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (unsubscribe) {
|
|
unsubscribe();
|
|
}
|
|
});
|
|
|
|
watch(() => ledConstraint.value, (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({
|
|
getInfo: () => ({
|
|
color: props.color,
|
|
isOn: isOn.value,
|
|
constraint: ledConstraint.value,
|
|
direction: 'input',
|
|
type: 'digital',
|
|
pins: props.pins
|
|
}),
|
|
getPinPosition: (pinId: string) => {
|
|
// 如果是自定义的引脚ID
|
|
if (props.pins && props.pins.length > 0) {
|
|
console.log('SMT_LED查找Pin ID:', pinId);
|
|
console.log('SMT_LED组件尺寸:', props.size, '宽高:', width.value, 'x', height.value);
|
|
const customPin = props.pins.find(p => p.pinId === pinId);
|
|
console.log('找到的引脚配置:', customPin);
|
|
|
|
if (customPin) {
|
|
// 考虑组件尺寸的缩放
|
|
const scaledX = customPin.x * props.size;
|
|
const scaledY = customPin.y * props.size;
|
|
|
|
console.log('使用Pin缩放后的坐标:', scaledX, scaledY);
|
|
return {
|
|
x: scaledX,
|
|
y: scaledY
|
|
};
|
|
}
|
|
console.log('未找到匹配的引脚');
|
|
return null;
|
|
}
|
|
console.log('没有引脚配置');
|
|
return null;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
// 添加一个静态方法来获取默认props
|
|
export function getDefaultProps() {
|
|
return {
|
|
size: 1,
|
|
color: 'red',
|
|
brightness: 80,
|
|
pins: [
|
|
{
|
|
pinId: 'LED',
|
|
constraint: '',
|
|
x: 50,
|
|
y: 30
|
|
}
|
|
]
|
|
};
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.led-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
position: relative;
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
}
|
|
|
|
.smt-led {
|
|
display: block;
|
|
padding: 0;
|
|
margin: 0;
|
|
line-height: 0;
|
|
font-size: 0;
|
|
box-sizing: content-box;
|
|
overflow: visible;
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
}
|
|
|
|
.interactive {
|
|
cursor: pointer;
|
|
transition: all 0.2s ease-in-out;
|
|
}
|
|
|
|
.interactive:hover {
|
|
filter: brightness(1.2);
|
|
}
|
|
|
|
.glow {
|
|
pointer-events: none;
|
|
}
|
|
</style>
|