1+ <template >
2+ <a-modal
3+ v-model:visible =" visible"
4+ title =" 选择播放器"
5+ :width =" 500"
6+ :mask-closable =" false"
7+ @ok =" handleConfirm"
8+ @cancel =" handleCancel"
9+ >
10+ <div class =" player-selector" >
11+ <div class =" player-list" >
12+ <div
13+ v-for =" player in playerTypes"
14+ :key =" player.value"
15+ class =" player-item"
16+ :class =" { active: selectedPlayer === player.value }"
17+ @click =" selectedPlayer = player.value"
18+ >
19+ <div class =" player-info" >
20+ <div class =" player-icon" >
21+ <icon-play-circle v-if =" player.value === 'art'" />
22+ <icon-code v-else-if =" player.value === 'ijk'" />
23+ <icon-mobile v-else-if =" player.value === 'exo'" />
24+ <icon-desktop v-else-if =" player.value === 'mpv'" />
25+ <icon-video-camera v-else-if =" player.value === 'vlc'" />
26+ <icon-play-arrow v-else />
27+ </div >
28+ <div class =" player-details" >
29+ <div class =" player-name" >{{ player.label }}</div >
30+ <div class =" player-desc" >{{ player.description }}</div >
31+ </div >
32+ </div >
33+ <div class =" player-check" >
34+ <icon-check-circle v-if =" selectedPlayer === player.value" class =" check-icon" />
35+ </div >
36+ </div >
37+ </div >
38+ </div >
39+ </a-modal >
40+ </template >
41+
42+ <script setup>
43+ import { ref , watch } from ' vue'
44+ import {
45+ IconPlayCircle ,
46+ IconCode ,
47+ IconMobile ,
48+ IconDesktop ,
49+ IconVideoCamera ,
50+ IconPlayArrow ,
51+ IconCheckCircle
52+ } from ' @arco-design/web-vue/es/icon'
53+
54+ const props = defineProps ({
55+ visible: {
56+ type: Boolean ,
57+ default: false
58+ },
59+ playerTypes: {
60+ type: Array ,
61+ default : () => []
62+ },
63+ currentPlayer: {
64+ type: String ,
65+ default: ' ijk'
66+ }
67+ })
68+
69+ const emit = defineEmits ([' update:visible' , ' confirm' ])
70+
71+ const visible = ref (props .visible )
72+ const selectedPlayer = ref (props .currentPlayer )
73+
74+ // 监听props变化
75+ watch (() => props .visible , (newVal ) => {
76+ visible .value = newVal
77+ })
78+
79+ watch (() => props .currentPlayer , (newVal ) => {
80+ selectedPlayer .value = newVal
81+ })
82+
83+ watch (visible, (newVal ) => {
84+ emit (' update:visible' , newVal)
85+ })
86+
87+ const handleConfirm = () => {
88+ emit (' confirm' , selectedPlayer .value )
89+ visible .value = false
90+ }
91+
92+ const handleCancel = () => {
93+ selectedPlayer .value = props .currentPlayer // 恢复原始值
94+ visible .value = false
95+ }
96+ </script >
97+
98+ <style scoped>
99+ .player-selector {
100+ padding : 16px 0 ;
101+ }
102+
103+ .player-list {
104+ display : flex ;
105+ flex-direction : column ;
106+ gap : 12px ;
107+ }
108+
109+ .player-item {
110+ display : flex ;
111+ align-items : center ;
112+ justify-content : space-between ;
113+ padding : 16px ;
114+ border : 2px solid #e5e7eb ;
115+ border-radius : 12px ;
116+ cursor : pointer ;
117+ transition : all 0.3s ease ;
118+ background : #ffffff ;
119+ }
120+
121+ .player-item :hover {
122+ border-color : #3b82f6 ;
123+ background : #f8faff ;
124+ transform : translateY (-2px );
125+ box-shadow : 0 4px 12px rgba (59 , 130 , 246 , 0.15 );
126+ }
127+
128+ .player-item.active {
129+ border-color : #3b82f6 ;
130+ background : linear-gradient (135deg , #f8faff 0% , #eff6ff 100% );
131+ box-shadow : 0 4px 16px rgba (59 , 130 , 246 , 0.2 );
132+ }
133+
134+ .player-info {
135+ display : flex ;
136+ align-items : center ;
137+ gap : 16px ;
138+ }
139+
140+ .player-icon {
141+ width : 48px ;
142+ height : 48px ;
143+ display : flex ;
144+ align-items : center ;
145+ justify-content : center ;
146+ background : linear-gradient (135deg , #667eea 0% , #764ba2 100% );
147+ border-radius : 12px ;
148+ color : white ;
149+ font-size : 24px ;
150+ }
151+
152+ .player-item.active .player-icon {
153+ background : linear-gradient (135deg , #3b82f6 0% , #1d4ed8 100% );
154+ }
155+
156+ .player-details {
157+ flex : 1 ;
158+ }
159+
160+ .player-name {
161+ font-size : 16px ;
162+ font-weight : 600 ;
163+ color : #1f2937 ;
164+ margin-bottom : 4px ;
165+ }
166+
167+ .player-desc {
168+ font-size : 14px ;
169+ color : #6b7280 ;
170+ line-height : 1.4 ;
171+ }
172+
173+ .player-check {
174+ width : 24px ;
175+ height : 24px ;
176+ display : flex ;
177+ align-items : center ;
178+ justify-content : center ;
179+ }
180+
181+ .check-icon {
182+ font-size : 24px ;
183+ color : #3b82f6 ;
184+ }
185+
186+ /* 响应式设计 */
187+ @media (max-width : 640px ) {
188+ .player-item {
189+ padding : 12px ;
190+ }
191+
192+ .player-icon {
193+ width : 40px ;
194+ height : 40px ;
195+ font-size : 20px ;
196+ }
197+
198+ .player-info {
199+ gap : 12px ;
200+ }
201+
202+ .player-name {
203+ font-size : 15px ;
204+ }
205+
206+ .player-desc {
207+ font-size : 13px ;
208+ }
209+ }
210+ </style >
0 commit comments