|
1 | 1 | <template> |
2 | | - <n-space |
3 | | - v-if="loadingBuffer" |
4 | | - justify="center" |
5 | | - align="center" |
6 | | - size="small" |
7 | | - w-full |
8 | | - h-full |
9 | | - pos-absolute |
10 | | - z-9999 |
11 | | - > |
12 | | - <n-spin :show="loadingBuffer"> |
13 | | - <template #description> {{ t('parsing') }} </template> |
14 | | - </n-spin> |
15 | | - </n-space> |
16 | | - <div id="guacamolePlayer" w-full style="height: 90%"></div> |
17 | | - <n-flex align="center" :wrap="false" w-full px-10px style="height: 10%"> |
18 | | - <n-flex :wrap="false" w-160px align="center"> |
19 | | - <n-button |
20 | | - v-if="!isPlaying" |
21 | | - :disabled="isProcessing" |
22 | | - text |
23 | | - cursor-pointer |
24 | | - @click="handleVideoPlay" |
25 | | - > |
26 | | - <n-icon :component="PlayCircleOutline" size="30" text-base /> |
27 | | - </n-button> |
28 | | - <n-button v-else :disabled="isProcessing" text cursor-pointer @click="handleVideoPlay"> |
29 | | - <n-icon :component="StopCircleOutline" size="30" text-base /> |
30 | | - </n-button> |
31 | | - <n-text text-base> {{ currentPosition }} / {{ totalDuration }} </n-text> |
32 | | - </n-flex> |
33 | | - <n-slider |
34 | | - v-model:value="currentPercent" |
35 | | - :max="max" |
36 | | - :disabled="isProcessing" |
37 | | - :format-tooltip="formatTooltip" |
38 | | - @update:value="handleSliderChange" |
39 | | - /> |
40 | | - <n-flex :wrap="false" w-200px align="center" justify="end"> |
41 | | - <n-button-group> |
42 | | - <n-button size="small" @click="handleZoomOut" :disabled="scale <= 0.1"> |
43 | | - <n-icon :component="RemoveOutline" size="16" /> |
| 2 | + <div class="gua-player-root"> |
| 3 | + <n-space v-if="loadingBuffer" justify="center" align="center" size="small" class="loading-mask"> |
| 4 | + <n-spin :show="loadingBuffer"> |
| 5 | + <template #description>{{ t('parsing') }}</template> |
| 6 | + </n-spin> |
| 7 | + </n-space> |
| 8 | + |
| 9 | + <div id="guacamolePlayer" class="player-area"></div> |
| 10 | + |
| 11 | + <div class="controls"> |
| 12 | + <div class="controls-left"> |
| 13 | + <n-button v-if="!isPlaying" :disabled="isProcessing" text @click="handleVideoPlay"> |
| 14 | + <n-icon :component="PlayCircleOutline" size="30" /> |
44 | 15 | </n-button> |
45 | | - <n-button size="small" @click="handleZoomReset"> |
46 | | - <n-text style="font-size: 12px">{{ Math.round(scale * 100) }}%</n-text> |
| 16 | + <n-button v-else :disabled="isProcessing" text @click="handleVideoPlay"> |
| 17 | + <n-icon :component="StopCircleOutline" size="30" /> |
47 | 18 | </n-button> |
48 | | - <n-button size="small" @click="handleZoomIn" :disabled="scale >= 2.0"> |
49 | | - <n-icon :component="AddOutline" size="16" /> |
50 | | - </n-button> |
51 | | - </n-button-group> |
52 | | - </n-flex> |
53 | | - </n-flex> |
| 19 | + <n-text class="time-text">{{ currentPosition }} / {{ totalDuration }}</n-text> |
| 20 | + </div> |
| 21 | + |
| 22 | + <div class="controls-slider"> |
| 23 | + <n-slider |
| 24 | + v-model:value="currentPercent" |
| 25 | + :max="max" |
| 26 | + :disabled="isProcessing" |
| 27 | + :format-tooltip="formatTooltip" |
| 28 | + @update:value="handleSliderChange" |
| 29 | + /> |
| 30 | + </div> |
| 31 | + |
| 32 | + <div class="controls-right"> |
| 33 | + <n-button-group> |
| 34 | + <n-button size="small" @click="handleZoomOut" :disabled="scale <= 0.1"> |
| 35 | + <n-icon :component="RemoveOutline" size="16" /> |
| 36 | + </n-button> |
| 37 | + <n-button size="small" @click="handleZoomReset"> |
| 38 | + <n-text class="scale-text">{{ Math.round(scale * 100) }}%</n-text> |
| 39 | + </n-button> |
| 40 | + <n-button size="small" @click="handleZoomIn" :disabled="scale >= 2.0"> |
| 41 | + <n-icon :component="AddOutline" size="16" /> |
| 42 | + </n-button> |
| 43 | + </n-button-group> |
| 44 | + </div> |
| 45 | + </div> |
| 46 | + </div> |
54 | 47 | </template> |
55 | 48 |
|
56 | 49 | <script setup lang="ts"> |
@@ -198,9 +191,7 @@ const initRecordingEvent = (record, el: HTMLElement) => { |
198 | 191 | max.value = record.getDuration(); |
199 | 192 | totalDuration.value = formatTime(record.getDuration()); |
200 | 193 | }, 100); |
201 | | -
|
202 | | - }) |
203 | | -
|
| 194 | + }); |
204 | 195 |
|
205 | 196 | const parentEl = el.parentElement as HTMLElement; |
206 | 197 |
|
@@ -663,3 +654,74 @@ onUnmounted(() => { |
663 | 654 | isPlaying.value = false; |
664 | 655 | }); |
665 | 656 | </script> |
| 657 | + |
| 658 | +<style scoped lang="scss"> |
| 659 | +.gua-player-root { |
| 660 | + position: relative; |
| 661 | + display: flex; |
| 662 | + flex-direction: column; |
| 663 | + height: 100%; |
| 664 | + min-height: 0; |
| 665 | + width: 100%; |
| 666 | +} |
| 667 | +
|
| 668 | +.loading-mask { |
| 669 | + position: absolute; |
| 670 | + inset: 0; |
| 671 | + z-index: 10; |
| 672 | +} |
| 673 | +
|
| 674 | +.player-area { |
| 675 | + flex: 1 1 auto; |
| 676 | + min-height: 0; |
| 677 | + width: 100%; |
| 678 | + overflow: hidden; |
| 679 | +} |
| 680 | +
|
| 681 | +.controls { |
| 682 | + flex: 0 0 auto; |
| 683 | + display: flex; |
| 684 | + align-items: center; |
| 685 | + gap: 8px; |
| 686 | + padding: 8px 10px; |
| 687 | + width: 100%; |
| 688 | + box-sizing: border-box; |
| 689 | +} |
| 690 | +
|
| 691 | +.controls-left { |
| 692 | + flex: 0 0 auto; |
| 693 | + display: flex; |
| 694 | + align-items: center; |
| 695 | + gap: 8px; |
| 696 | + width: 180px; |
| 697 | +} |
| 698 | +
|
| 699 | +.time-text { |
| 700 | + font-size: 14px; |
| 701 | +} |
| 702 | +
|
| 703 | +.controls-slider { |
| 704 | + flex: 1 1 auto; |
| 705 | + min-width: 0; |
| 706 | +} |
| 707 | +
|
| 708 | +.controls-right { |
| 709 | + flex: 0 0 auto; |
| 710 | + display: flex; |
| 711 | + align-items: center; |
| 712 | + justify-content: flex-end; |
| 713 | + width: 200px; |
| 714 | +} |
| 715 | +
|
| 716 | +.scale-text { |
| 717 | + font-size: 12px; |
| 718 | +} |
| 719 | +
|
| 720 | +:deep(.n-slider) { |
| 721 | + width: 100%; |
| 722 | +} |
| 723 | +
|
| 724 | +:deep(.n-slider-rail) { |
| 725 | + margin: 0; |
| 726 | +} |
| 727 | +</style> |
0 commit comments