feat: remake most of forntend
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
// filepath: c:\_Project\FPGA_WebLab\FPGA_WebLab\src\components\equipments\Switch.vue
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" :width="props.width" :height="props.height" viewBox="0 0 16 16">
|
||||
<def>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
:width="width"
|
||||
:height="height"
|
||||
:viewBox="`4 6 ${props.switchCount + 2} 4`"
|
||||
class="dip-switch"
|
||||
>
|
||||
<defs>
|
||||
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feFlood result="flood" flood-color="#f08a5d" flood-opacity="1"></feFlood>
|
||||
<feComposite in="flood" result="mask" in2="SourceGraphic" operator="in"></feComposite>
|
||||
@@ -15,49 +22,130 @@
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</def>
|
||||
</defs>
|
||||
|
||||
<g>
|
||||
<rect width="8" height="4" x="4" y="6" fill="#c01401" rx="0.1" />
|
||||
<text fill="white" font-size="0.7" x="4.25" y="6.75">ON</text>
|
||||
<!-- 红色背景随开关数量变化宽度 -->
|
||||
<rect :width="props.switchCount + 2" height="4" x="4" y="6" fill="#c01401" rx="0.1" />
|
||||
<text v-if="props.showLabels" fill="white" font-size="0.7" x="4.25" y="6.75">ON</text>
|
||||
|
||||
<g>
|
||||
<rect class="glow" @click="toggleBtnStatus(0)" width="0.7" height="2" fill="#68716f" x="5.15" y="7" rx="0.1" />
|
||||
<rect class="glow" @click="toggleBtnStatus(1)" width="0.7" height="2" fill="#68716f" x="6.15" y="7" rx="0.1" />
|
||||
<rect class="glow" @click="toggleBtnStatus(2)" width="0.7" height="2" fill="#68716f" x="7.15" y="7" rx="0.1" />
|
||||
<rect class="glow" @click="toggleBtnStatus(3)" width="0.7" height="2" fill="#68716f" x="8.15" y="7" rx="0.1" />
|
||||
<rect class="glow" @click="toggleBtnStatus(4)" width="0.7" height="2" fill="#68716f" x="9.15" y="7" rx="0.1" />
|
||||
<rect class="glow" @click="toggleBtnStatus(5)" width="0.7" height="2" fill="#68716f" x="10.15" y="7" rx="0.1" />
|
||||
<template v-for="(_, index) in Array(props.switchCount)" :key="index">
|
||||
<rect
|
||||
class="glow interactive"
|
||||
@click="toggleBtnStatus(index)"
|
||||
width="0.7"
|
||||
height="2"
|
||||
fill="#68716f"
|
||||
:x="5.15 + index"
|
||||
y="7"
|
||||
rx="0.1"
|
||||
/>
|
||||
<text
|
||||
v-if="props.showLabels"
|
||||
:x="5.5 + index"
|
||||
y="9.5"
|
||||
font-size="0.4"
|
||||
text-anchor="middle"
|
||||
fill="#444"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
</template>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<rect @click="toggleBtnStatus(0)" width="0.65" height="0.65" fill="white" x="5.175" :y="btnLocation[0]" rx="0.1"
|
||||
opacity="1" />
|
||||
<rect @click="toggleBtnStatus(1)" width="0.65" height="0.65" fill="white" x="6.175" :y="btnLocation[1]" rx="0.1"
|
||||
opacity="1" />
|
||||
<rect @click="toggleBtnStatus(2)" width="0.65" height="0.65" fill="white" x="7.175" :y="btnLocation[2]" rx="0.1"
|
||||
opacity="1" />
|
||||
<rect @click="toggleBtnStatus(3)" width="0.65" height="0.65" fill="white" x="8.175" :y="btnLocation[3]" rx="0.1"
|
||||
opacity="1" />
|
||||
<rect @click="toggleBtnStatus(4)" width="0.65" height="0.65" fill="white" x="9.175" :y="btnLocation[4]" rx="0.1"
|
||||
opacity="1" />
|
||||
<rect @click="toggleBtnStatus(5)" width="0.65" height="0.65" fill="white" x="10.175" :y="btnLocation[5]"
|
||||
rx="0.1" opacity="1" />
|
||||
<template v-for="(location, index) in btnLocation" :key="`btn-${index}`">
|
||||
<rect
|
||||
class="interactive"
|
||||
@click="toggleBtnStatus(index)"
|
||||
width="0.65"
|
||||
height="0.65"
|
||||
fill="white"
|
||||
:x="5.175 + index"
|
||||
:y="location"
|
||||
rx="0.1"
|
||||
opacity="1"
|
||||
/>
|
||||
</template>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
|
||||
interface Props {
|
||||
width?: string | number;
|
||||
height?: string | number;
|
||||
size?: number;
|
||||
switchCount?: number;
|
||||
// 新增属性
|
||||
initialValues?: boolean[] | string; // 开关的初始状态,可以是布尔数组或逗号分隔的字符串
|
||||
showLabels?: boolean; // 是否显示标签
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
width: 160,
|
||||
height: 160,
|
||||
size: 1,
|
||||
switchCount: 6,
|
||||
initialValues: () => [],
|
||||
showLabels: true
|
||||
});
|
||||
|
||||
// 计算实际宽高
|
||||
const width = computed(() => {
|
||||
// 每个开关占用25px宽度,再加上两侧边距(20px)
|
||||
return (props.switchCount * 25 + 20) * props.size;
|
||||
});
|
||||
const height = computed(() => 85 * props.size); // 高度保持固定比例
|
||||
|
||||
// 定义发出的事件
|
||||
const emit = defineEmits(['change', 'switch-toggle']);
|
||||
|
||||
// 解析初始值,支持字符串和数组两种格式
|
||||
const parseInitialValues = () => {
|
||||
if (Array.isArray(props.initialValues)) {
|
||||
return [...props.initialValues].slice(0, props.switchCount);
|
||||
} else if (typeof props.initialValues === 'string' && props.initialValues.trim() !== '') {
|
||||
// 将逗号分隔的字符串转换为布尔数组
|
||||
const values = props.initialValues.split(',')
|
||||
.map(val => val.trim() === '1' || val.trim().toLowerCase() === 'true')
|
||||
.slice(0, props.switchCount);
|
||||
|
||||
// 如果数组长度小于开关数量,用 false 填充
|
||||
while (values.length < props.switchCount) {
|
||||
values.push(false);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
// 默认返回全部为 false 的数组
|
||||
return Array(props.switchCount).fill(false);
|
||||
};
|
||||
|
||||
// 初始化按钮状态
|
||||
const btnStatus = ref(parseInitialValues());
|
||||
|
||||
// 监听 switchCount 变化,调整开关状态数组
|
||||
watch(() => props.switchCount, (newCount) => {
|
||||
if (newCount !== btnStatus.value.length) {
|
||||
// 如果新数量大于当前数量,则扩展数组
|
||||
if (newCount > btnStatus.value.length) {
|
||||
btnStatus.value = [
|
||||
...btnStatus.value,
|
||||
...Array(newCount - btnStatus.value.length).fill(false)
|
||||
];
|
||||
} else {
|
||||
// 如果新数量小于当前数量,则截断数组
|
||||
btnStatus.value = btnStatus.value.slice(0, newCount);
|
||||
}
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 监听 initialValues 变化,更新开关状态
|
||||
watch(() => props.initialValues, () => {
|
||||
btnStatus.value = parseInitialValues();
|
||||
});
|
||||
|
||||
const btnStatus = ref([false, false, false, false, false, false]);
|
||||
const btnLocation = computed(() => {
|
||||
return btnStatus.value.map((status) => {
|
||||
return status ? 7.025 : 8.325;
|
||||
@@ -65,20 +153,58 @@ const btnLocation = computed(() => {
|
||||
});
|
||||
|
||||
function setBtnStatus(btnNum: number, isOn: boolean): void {
|
||||
btnStatus.value[btnNum] = isOn;
|
||||
if (btnNum >= 0 && btnNum < btnStatus.value.length) {
|
||||
btnStatus.value[btnNum] = isOn;
|
||||
emit('change', { index: btnNum, value: isOn, states: [...btnStatus.value] });
|
||||
}
|
||||
}
|
||||
|
||||
function toggleBtnStatus(btnNum: number): void {
|
||||
btnStatus.value[btnNum] = !btnStatus.value[btnNum];
|
||||
if (btnNum >= 0 && btnNum < btnStatus.value.length) {
|
||||
btnStatus.value[btnNum] = !btnStatus.value[btnNum];
|
||||
emit('switch-toggle', {
|
||||
index: btnNum,
|
||||
value: btnStatus.value[btnNum],
|
||||
states: [...btnStatus.value]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 一次性设置所有开关状态
|
||||
function setAllStates(states: boolean[]): void {
|
||||
const newStates = states.slice(0, props.switchCount);
|
||||
while (newStates.length < props.switchCount) {
|
||||
newStates.push(false);
|
||||
}
|
||||
btnStatus.value = newStates;
|
||||
emit('change', { states: [...btnStatus.value] });
|
||||
}
|
||||
|
||||
// 暴露组件方法和状态
|
||||
defineExpose({
|
||||
setBtnStatus,
|
||||
toggleBtnStatus,
|
||||
setAllStates,
|
||||
getBtnStatus: () => [...btnStatus.value]
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
.dip-switch {
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 0; /* 移除行高导致的额外间距 */
|
||||
font-size: 0; /* 防止文本节点造成的间距 */
|
||||
box-sizing: content-box;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
rect {
|
||||
transition: all 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.glow:hover {
|
||||
filter: url(#glow);
|
||||
.interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user