99
1010 <!-- 3个扇形区域(作为可点击的 path) -->
1111 <path v-for =" (part, idx) in encoderParts" :key =" `sector-${idx}`" :d =" getSectorPath(idx)"
12- :class =" ['encoder-sector', `encoder-sector-${idx}`, { selected: selectedIndex === part.index }]"
12+ :class =" ['encoder-sector', `encoder-sector-${idx}`, { selected: selectedIndex === part.index, 'test-active': testActiveSet.has(part.index), 'test-pulse': testPulseIndex === part.index }]"
1313 @click.stop =" !disabled && handlePartClick(part.index)" />
1414 </svg >
1515
1616 <!-- 标签和徽章(在 SVG 上方) -->
1717 <div v-for =" (part, idx) in encoderParts" :key =" `label-${idx}`" class =" encoder-label-container"
18- :class =" { selected: selectedIndex === part.index }" :style =" getLabelContainerStyle(idx)"
18+ :class =" { selected: selectedIndex === part.index, 'test-active': testActiveSet.has(part.index), 'test-pulse': testPulseIndex === part.index }" :style =" getLabelContainerStyle(idx)"
1919 @click.stop =" !disabled && handlePartClick(part.index)" >
2020 <span class =" encoder-part-label" >{{ part.label }}</span >
2121 <span v-if =" part.actionBadge" class =" encoder-part-badge" >{{ part.actionBadge }}</span >
@@ -49,6 +49,10 @@ const props = defineProps<{
4949 };
5050 /** 是否禁用 */
5151 disabled? : boolean ;
52+ /** 测试模式: 当前按下的旋钮虚拟键索引 */
53+ testActiveIndices? : number [];
54+ /** 测试模式: 最近触发的旋钮虚拟键索引 */
55+ testPulseIndex? : number | null ;
5256}>();
5357
5458const emit = defineEmits <{
@@ -74,6 +78,8 @@ const anySelected = computed(() => {
7478 props .selectedIndex === props .encoderIndices .ccw ;
7579});
7680
81+ const testActiveSet = computed (() => new Set (props .testActiveIndices ?? []));
82+
7783/** 旋钮的3个部分 */
7884const encoderParts = computed (() => {
7985 return [
@@ -282,6 +288,15 @@ function getActionBadge(action: KeyAction): string | null {
282288 opacity : 1 ;
283289}
284290
291+ .encoder-sector.test-active {
292+ fill : rgba (74 , 222 , 128 , 0.38 );
293+ opacity : 1 ;
294+ }
295+
296+ .encoder-sector.test-pulse :not (.test-active ) {
297+ animation : encoder-test-pulse 520ms ease-out ;
298+ }
299+
285300.encoder-label-container {
286301 display : flex ;
287302 flex-direction : column ;
@@ -299,6 +314,11 @@ function getActionBadge(action: KeyAction): string | null {
299314 text-shadow : 0 1px 3px rgba (59 , 130 , 246 , 0.5 );
300315}
301316
317+ .encoder-label-container.test-active {
318+ color : var (--c-success );
319+ text-shadow : 0 1px 4px rgba (74 , 222 , 128 , 0.45 );
320+ }
321+
302322.encoder-label-container :hover {
303323 color : var (--c-text-primary );
304324 transform : scale (1.1 );
@@ -317,4 +337,9 @@ function getActionBadge(action: KeyAction): string | null {
317337 user-select : none ;
318338 font-weight : 600 ;
319339}
340+
341+ @keyframes encoder-test-pulse {
342+ 0% { fill : rgba (74 , 222 , 128 , 0.45 ); }
343+ 100% { fill : rgba (255 , 255 , 255 , 0.05 ); }
344+ }
320345 </style >
0 commit comments