129 lines
3.3 KiB
Vue
129 lines
3.3 KiB
Vue
<template>
|
|
<div class="aplayer-controller">
|
|
<v-progress
|
|
:loadProgress="loadProgress"
|
|
:playProgress="playProgress"
|
|
:theme="theme"
|
|
@dragbegin="val => $emit('dragbegin', val)"
|
|
@dragend="val => $emit('dragend', val)"
|
|
@dragging="val => $emit('dragging', val)"
|
|
/>
|
|
<div class="aplayer-time">
|
|
<div class="aplayer-time-inner">
|
|
- <span class="aplayer-ptime">{{secondToTime(stat.playedTime)}}</span> / <span
|
|
class="aplayer-dtime">{{secondToTime(stat.duration)}}</span>
|
|
</div>
|
|
<volume
|
|
v-if="!isMobile"
|
|
:volume="volume"
|
|
:theme="theme"
|
|
:muted="muted"
|
|
@togglemute="$emit('togglemute')"
|
|
@setvolume="(v: number) => $emit('setvolume', v)"
|
|
/>
|
|
<icon-button
|
|
class="aplayer-icon-mode"
|
|
icon="shuffle"
|
|
:class="{ 'inactive': !shuffle }"
|
|
@click="$emit('toggleshuffle')"
|
|
/>
|
|
<icon-button
|
|
class="aplayer-icon-mode"
|
|
:icon="repeat === 'repeat_one' ? 'repeat_one' : 'repeat_all'"
|
|
:class="{ 'inactive': repeat === 'no_repeat'}"
|
|
@click="$emit('nextmode')"
|
|
/>
|
|
<icon-button
|
|
class="aplayer-icon-menu"
|
|
icon="menu"
|
|
:class="{ 'inactive': !showList }"
|
|
@click="$emit('togglelist')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed } from 'vue'
|
|
import IconButton from './aplayer-iconbutton.vue'
|
|
import VProgress from './aplayer-controller-progress.vue'
|
|
import Volume from './aplayer-controller-volume.vue'
|
|
import { StatType } from '@/model/api/music'
|
|
|
|
const props = defineProps<{
|
|
shuffle: boolean
|
|
repeat: string
|
|
stat: StatType
|
|
theme: string
|
|
volume: number
|
|
muted: boolean
|
|
showList: boolean
|
|
isMobile: boolean
|
|
}>()
|
|
const loadProgress = computed(() => {
|
|
if (props.stat.duration === 0) return 0
|
|
return props.stat.loadedTime / props.stat.duration
|
|
})
|
|
const playProgress = computed(() => {
|
|
if (props.stat.duration === 0) return 0
|
|
return props.stat.playedTime / props.stat.duration
|
|
})
|
|
|
|
const secondToTime = (second: number) => {
|
|
if (isNaN(second)) {
|
|
return '00:00'
|
|
}
|
|
const pad0 = (num: number) => {
|
|
return num < 10 ? '0' + num : '' + num
|
|
}
|
|
|
|
const min = Math.trunc(second / 60)
|
|
const sec = Math.trunc(second - min * 60)
|
|
const hours = Math.trunc(min / 60)
|
|
const minAdjust = Math.trunc((second / 60) - (60 * Math.trunc((second / 60) / 60)))
|
|
return second >= 3600 ? pad0(hours) + ':' + pad0(minAdjust) + ':' + pad0(sec) : pad0(min) + ':' + pad0(sec)
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.aplayer-controller {
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
.aplayer-time {
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
height: 17px;
|
|
color: #999;
|
|
font-size: 11px;
|
|
padding-left: 7px;
|
|
.aplayer-volume-wrap {
|
|
margin-left: 4px;
|
|
margin-right: 4px;
|
|
}
|
|
.aplayer-icon {
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
margin-left: 4px;
|
|
&.inactive {
|
|
opacity: .3;
|
|
}
|
|
&.aplayer-icon-menu {
|
|
display: none;
|
|
}
|
|
}
|
|
.aplayer-volume-wrap + .aplayer-icon {
|
|
margin-left: 0;
|
|
}
|
|
&.aplayer-time-narrow {
|
|
.aplayer-icon-mode {
|
|
display: none;
|
|
}
|
|
.aplayer-icon-menu {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |