feat: remake most of forntend

This commit is contained in:
alivender
2025-04-26 19:59:35 +08:00
parent 4e741f9ef8
commit bc4f44ecaa
41 changed files with 84095 additions and 672 deletions

View File

@@ -0,0 +1,193 @@
<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 ? brightness/100 : 0.2 }"
rx="15"
ry="15"
@click="toggleLed"
class="interactive"
/>
<!-- LED 光晕效果 -->
<rect
v-if="isOn"
width="76"
height="36"
x="12"
y="12"
:fill="ledColor"
:style="{ opacity: brightness/100 * 0.3 }"
rx="18"
ry="18"
filter="blur(5px)"
class="glow"
/>
</svg>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
// LED特有属性
interface Props {
size?: number;
color?: string;
initialOn?: boolean;
brightness?: number;
constraint?: string;
}
// 组件属性定义
const props = withDefaults(defineProps<Props>(), {
size: 1,
color: 'red',
initialOn: false,
brightness: 80, // 亮度默认为80%
constraint: ''
});
// 计算实际宽高
const width = computed(() => 100 * props.size);
const height = computed(() => 60 * props.size);
// 内部状态
const isOn = ref(props.initialOn);
const brightness = ref(props.brightness);
// LED 颜色映射表
const colorMap: Record<string, string> = {
'red': '#ff3333',
'green': '#33ff33',
'blue': '#3333ff',
'yellow': '#ffff33',
'orange': '#ff9933',
'white': '#ffffff',
'purple': '#9933ff'
};
// 计算实际LED颜色
const ledColor = computed(() => {
return colorMap[props.color.toLowerCase()] || props.color;
});
// 定义组件发出的事件
const emit = defineEmits([
'toggle',
'brightness-change',
'value-change'
]);
// 手动切换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;
});
watch(() => props.initialOn, (newVal) => {
isOn.value = newVal;
});
// 向外暴露方法
defineExpose({
toggleLed,
setBrightness,
setLedState,
getInfo: () => ({
// LED特有属性
color: props.color,
isOn: isOn.value,
brightness: brightness.value,
constraint: props.constraint
})
});
</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>