fix(ai): 补全音乐播放器进度交互
- 音乐列表改用 typed provide/inject + MusicSong - audioBar 绑定真实 audio 元数据,支持进度显示、拖动 seek 与切歌重载 - 同步适配 web-antd、web-ele、web-antdv-next 对齐 Vue3 管理后台 0970806dcmigration
parent
1a3de7e97a
commit
c2707a499a
|
|
@ -1,17 +1,22 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject, reactive, ref } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { computed, inject, nextTick, reactive, ref, watch } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { formatPast } from '@vben/utils';
|
||||
|
||||
import { Image, Slider } from 'ant-design-vue';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicAudioBarIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
const currentAudioUrl = computed(() => currentSong.value.audioUrl || undefined);
|
||||
|
||||
const audioRef = ref<HTMLAudioElement | null>(null);
|
||||
const audioProgress = ref(0);
|
||||
const audioDuration = ref(0);
|
||||
const audioProps = reactive<any>({
|
||||
autoplay: true,
|
||||
paused: false,
|
||||
|
|
@ -21,6 +26,17 @@ const audioProps = reactive<any>({
|
|||
volume: 50,
|
||||
}); // 音频相关属性https://www.runoob.com/tags/ref-av-dom.html
|
||||
|
||||
function formatAudioTime(seconds: number) {
|
||||
if (!Number.isFinite(seconds)) {
|
||||
return '00:00';
|
||||
}
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = Math.floor(seconds % 60);
|
||||
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds
|
||||
.toString()
|
||||
.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function toggleStatus(type: string) {
|
||||
audioProps[type] = !audioProps[type];
|
||||
if (type === 'paused' && audioRef.value) {
|
||||
|
|
@ -33,9 +49,40 @@ function toggleStatus(type: string) {
|
|||
}
|
||||
|
||||
/** 更新播放位置 */
|
||||
function audioTimeUpdate(args: any) {
|
||||
audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss');
|
||||
function audioTimeUpdate() {
|
||||
if (!audioRef.value) {
|
||||
return;
|
||||
}
|
||||
audioProgress.value = audioRef.value.currentTime;
|
||||
audioProps.currentTime = formatAudioTime(audioRef.value.currentTime);
|
||||
}
|
||||
|
||||
function audioLoadedMetadata() {
|
||||
if (!audioRef.value) {
|
||||
return;
|
||||
}
|
||||
audioDuration.value = audioRef.value.duration;
|
||||
audioProps.duration = formatAudioTime(audioRef.value.duration);
|
||||
}
|
||||
|
||||
function handleProgressChange(value: number | [number, number]) {
|
||||
if (!audioRef.value || Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
audioRef.value.currentTime = value;
|
||||
audioProgress.value = value;
|
||||
audioProps.currentTime = formatAudioTime(value);
|
||||
}
|
||||
|
||||
watch(currentAudioUrl, () => {
|
||||
audioProgress.value = 0;
|
||||
audioDuration.value = 0;
|
||||
audioProps.currentTime = '00:00';
|
||||
audioProps.duration = '00:00';
|
||||
nextTick(() => {
|
||||
audioRef.value?.load();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -49,8 +96,10 @@ function audioTimeUpdate(args: any) {
|
|||
:width="45"
|
||||
/>
|
||||
<div>
|
||||
<div>{{ currentSong.name }}</div>
|
||||
<div class="text-xs text-gray-400">{{ currentSong.singer }}</div>
|
||||
<div>{{ currentSong.title || '暂无音乐' }}</div>
|
||||
<div class="text-xs text-gray-400">
|
||||
{{ currentSong.singer || currentSong.desc }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 音频controls -->
|
||||
|
|
@ -74,19 +123,26 @@ function audioTimeUpdate(args: any) {
|
|||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<span>{{ audioProps.currentTime }}</span>
|
||||
<Slider v-model:value="audioProgress" color="#409eff" class="!w-40" />
|
||||
<Slider
|
||||
v-model:value="audioProgress"
|
||||
:max="audioDuration"
|
||||
color="#409eff"
|
||||
class="!w-40"
|
||||
@change="handleProgressChange"
|
||||
/>
|
||||
<span>{{ audioProps.duration }}</span>
|
||||
</div>
|
||||
<!-- 音频 -->
|
||||
<audio
|
||||
v-bind="audioProps"
|
||||
:src="currentAudioUrl"
|
||||
:autoplay="audioProps.autoplay"
|
||||
:muted="audioProps.muted"
|
||||
ref="audioRef"
|
||||
controls
|
||||
v-show="!audioProps"
|
||||
@timeupdate="audioTimeUpdate"
|
||||
>
|
||||
<!-- <source :src="audioUrl" /> -->
|
||||
</audio>
|
||||
@loadedmetadata="audioLoadedMetadata"
|
||||
></audio>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<IconifyIcon
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
import type { MusicSong } from './types';
|
||||
|
||||
import { provide, ref } from 'vue';
|
||||
|
||||
|
|
@ -8,14 +9,15 @@ import { Col, Empty, Row, TabPane, Tabs } from 'ant-design-vue';
|
|||
import audioBar from './audioBar/index.vue';
|
||||
import songCard from './songCard/index.vue';
|
||||
import songInfo from './songInfo/index.vue';
|
||||
import { currentSongKey } from './types';
|
||||
|
||||
defineOptions({ name: 'AiMusicListIndex' });
|
||||
|
||||
const currentType = ref('mine');
|
||||
const loading = ref(false); // loading 状态
|
||||
const currentSong = ref({}); // 当前音乐
|
||||
const mySongList = ref<Recordable<any>[]>([]);
|
||||
const squareSongList = ref<Recordable<any>[]>([]);
|
||||
const currentSong = ref<MusicSong>({}); // 当前音乐
|
||||
const mySongList = ref<MusicSong[]>([]);
|
||||
const squareSongList = ref<MusicSong[]>([]);
|
||||
|
||||
function generateMusic(_formData: Recordable<any>) {
|
||||
loading.value = true;
|
||||
|
|
@ -45,7 +47,7 @@ function generateMusic(_formData: Recordable<any>) {
|
|||
}, 3000);
|
||||
}
|
||||
|
||||
function setCurrentSong(music: Recordable<any>) {
|
||||
function setCurrentSong(music: MusicSong) {
|
||||
currentSong.value = music;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ defineExpose({
|
|||
generateMusic,
|
||||
});
|
||||
|
||||
provide('currentSong', currentSong);
|
||||
provide(currentSongKey, currentSong);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { inject, ref } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Image } from 'ant-design-vue';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongCardIndex' });
|
||||
|
||||
defineProps({
|
||||
songInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
withDefaults(defineProps<{ songInfo?: MusicSong }>(), {
|
||||
songInfo: () => ({}),
|
||||
});
|
||||
|
||||
const emits = defineEmits(['play']);
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
|
||||
function playSong() {
|
||||
emits('play');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { inject, ref } from 'vue';
|
||||
|
||||
import { Button, Card, Image } from 'ant-design-vue';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongInfoIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject, reactive, ref } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { computed, inject, nextTick, reactive, ref, watch } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { formatPast } from '@vben/utils';
|
||||
|
||||
import { Image, Slider } from 'antdv-next';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicAudioBarIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
const currentAudioUrl = computed(() => currentSong.value.audioUrl || undefined);
|
||||
|
||||
const audioRef = ref<HTMLAudioElement | null>(null);
|
||||
const audioProgress = ref(0);
|
||||
const audioDuration = ref(0);
|
||||
const audioProps = reactive<any>({
|
||||
autoplay: true,
|
||||
paused: false,
|
||||
|
|
@ -21,6 +26,17 @@ const audioProps = reactive<any>({
|
|||
volume: 50,
|
||||
}); // 音频相关属性https://www.runoob.com/tags/ref-av-dom.html
|
||||
|
||||
function formatAudioTime(seconds: number) {
|
||||
if (!Number.isFinite(seconds)) {
|
||||
return '00:00';
|
||||
}
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = Math.floor(seconds % 60);
|
||||
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds
|
||||
.toString()
|
||||
.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function toggleStatus(type: string) {
|
||||
audioProps[type] = !audioProps[type];
|
||||
if (type === 'paused' && audioRef.value) {
|
||||
|
|
@ -33,9 +49,40 @@ function toggleStatus(type: string) {
|
|||
}
|
||||
|
||||
/** 更新播放位置 */
|
||||
function audioTimeUpdate(args: any) {
|
||||
audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss');
|
||||
function audioTimeUpdate() {
|
||||
if (!audioRef.value) {
|
||||
return;
|
||||
}
|
||||
audioProgress.value = audioRef.value.currentTime;
|
||||
audioProps.currentTime = formatAudioTime(audioRef.value.currentTime);
|
||||
}
|
||||
|
||||
function audioLoadedMetadata() {
|
||||
if (!audioRef.value) {
|
||||
return;
|
||||
}
|
||||
audioDuration.value = audioRef.value.duration;
|
||||
audioProps.duration = formatAudioTime(audioRef.value.duration);
|
||||
}
|
||||
|
||||
function handleProgressChange(value: number | [number, number]) {
|
||||
if (!audioRef.value || Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
audioRef.value.currentTime = value;
|
||||
audioProgress.value = value;
|
||||
audioProps.currentTime = formatAudioTime(value);
|
||||
}
|
||||
|
||||
watch(currentAudioUrl, () => {
|
||||
audioProgress.value = 0;
|
||||
audioDuration.value = 0;
|
||||
audioProps.currentTime = '00:00';
|
||||
audioProps.duration = '00:00';
|
||||
nextTick(() => {
|
||||
audioRef.value?.load();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -49,8 +96,10 @@ function audioTimeUpdate(args: any) {
|
|||
:width="45"
|
||||
/>
|
||||
<div>
|
||||
<div>{{ currentSong.name }}</div>
|
||||
<div class="text-xs text-gray-400">{{ currentSong.singer }}</div>
|
||||
<div>{{ currentSong.title || '暂无音乐' }}</div>
|
||||
<div class="text-xs text-gray-400">
|
||||
{{ currentSong.singer || currentSong.desc }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 音频controls -->
|
||||
|
|
@ -74,19 +123,26 @@ function audioTimeUpdate(args: any) {
|
|||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<span>{{ audioProps.currentTime }}</span>
|
||||
<Slider v-model:value="audioProgress" color="#409eff" class="!w-40" />
|
||||
<Slider
|
||||
v-model:value="audioProgress"
|
||||
:max="audioDuration"
|
||||
color="#409eff"
|
||||
class="!w-40"
|
||||
@change="handleProgressChange"
|
||||
/>
|
||||
<span>{{ audioProps.duration }}</span>
|
||||
</div>
|
||||
<!-- 音频 -->
|
||||
<audio
|
||||
v-bind="audioProps"
|
||||
:src="currentAudioUrl"
|
||||
:autoplay="audioProps.autoplay"
|
||||
:muted="audioProps.muted"
|
||||
ref="audioRef"
|
||||
controls
|
||||
v-show="!audioProps"
|
||||
@timeupdate="audioTimeUpdate"
|
||||
>
|
||||
<!-- <source :src="audioUrl" /> -->
|
||||
</audio>
|
||||
@loadedmetadata="audioLoadedMetadata"
|
||||
></audio>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<IconifyIcon
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
import type { MusicSong } from './types';
|
||||
|
||||
import { provide, ref } from 'vue';
|
||||
|
||||
|
|
@ -8,14 +9,15 @@ import { Col, Empty, Row, TabPane, Tabs } from 'antdv-next';
|
|||
import audioBar from './audioBar/index.vue';
|
||||
import songCard from './songCard/index.vue';
|
||||
import songInfo from './songInfo/index.vue';
|
||||
import { currentSongKey } from './types';
|
||||
|
||||
defineOptions({ name: 'AiMusicListIndex' });
|
||||
|
||||
const currentType = ref('mine');
|
||||
const loading = ref(false); // loading 状态
|
||||
const currentSong = ref({}); // 当前音乐
|
||||
const mySongList = ref<Recordable<any>[]>([]);
|
||||
const squareSongList = ref<Recordable<any>[]>([]);
|
||||
const currentSong = ref<MusicSong>({}); // 当前音乐
|
||||
const mySongList = ref<MusicSong[]>([]);
|
||||
const squareSongList = ref<MusicSong[]>([]);
|
||||
|
||||
function generateMusic(_formData: Recordable<any>) {
|
||||
loading.value = true;
|
||||
|
|
@ -45,7 +47,7 @@ function generateMusic(_formData: Recordable<any>) {
|
|||
}, 3000);
|
||||
}
|
||||
|
||||
function setCurrentSong(music: Recordable<any>) {
|
||||
function setCurrentSong(music: MusicSong) {
|
||||
currentSong.value = music;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ defineExpose({
|
|||
generateMusic,
|
||||
});
|
||||
|
||||
provide('currentSong', currentSong);
|
||||
provide(currentSongKey, currentSong);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { inject, ref } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Image } from 'antdv-next';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongCardIndex' });
|
||||
|
||||
defineProps({
|
||||
songInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
withDefaults(defineProps<{ songInfo?: MusicSong }>(), {
|
||||
songInfo: () => ({}),
|
||||
});
|
||||
|
||||
const emits = defineEmits(['play']);
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
|
||||
function playSong() {
|
||||
emits('play');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { inject, ref } from 'vue';
|
||||
|
||||
import { Button, Card, Image } from 'antdv-next';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongInfoIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject, reactive, ref } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { computed, inject, nextTick, reactive, ref, watch } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { formatPast } from '@vben/utils';
|
||||
|
||||
import { ElImage, ElSlider } from 'element-plus';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicAudioBarIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
const currentAudioUrl = computed(() => currentSong.value.audioUrl || undefined);
|
||||
|
||||
const audioRef = ref<HTMLAudioElement | null>(null);
|
||||
const audioProgress = ref(0);
|
||||
const audioDuration = ref(0);
|
||||
const audioProps = reactive<any>({
|
||||
autoplay: true,
|
||||
paused: false,
|
||||
|
|
@ -21,6 +26,17 @@ const audioProps = reactive<any>({
|
|||
volume: 50,
|
||||
}); // 音频相关属性https://www.runoob.com/tags/ref-av-dom.html
|
||||
|
||||
function formatAudioTime(seconds: number) {
|
||||
if (!Number.isFinite(seconds)) {
|
||||
return '00:00';
|
||||
}
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = Math.floor(seconds % 60);
|
||||
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds
|
||||
.toString()
|
||||
.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function toggleStatus(type: string) {
|
||||
audioProps[type] = !audioProps[type];
|
||||
if (type === 'paused' && audioRef.value) {
|
||||
|
|
@ -33,9 +49,40 @@ function toggleStatus(type: string) {
|
|||
}
|
||||
|
||||
/** 更新播放位置 */
|
||||
function audioTimeUpdate(args: any) {
|
||||
audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss');
|
||||
function audioTimeUpdate() {
|
||||
if (!audioRef.value) {
|
||||
return;
|
||||
}
|
||||
audioProgress.value = audioRef.value.currentTime;
|
||||
audioProps.currentTime = formatAudioTime(audioRef.value.currentTime);
|
||||
}
|
||||
|
||||
function audioLoadedMetadata() {
|
||||
if (!audioRef.value) {
|
||||
return;
|
||||
}
|
||||
audioDuration.value = audioRef.value.duration;
|
||||
audioProps.duration = formatAudioTime(audioRef.value.duration);
|
||||
}
|
||||
|
||||
function handleProgressChange(value: number | number[]) {
|
||||
if (!audioRef.value || Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
audioRef.value.currentTime = value;
|
||||
audioProgress.value = value;
|
||||
audioProps.currentTime = formatAudioTime(value);
|
||||
}
|
||||
|
||||
watch(currentAudioUrl, () => {
|
||||
audioProgress.value = 0;
|
||||
audioDuration.value = 0;
|
||||
audioProps.currentTime = '00:00';
|
||||
audioProps.duration = '00:00';
|
||||
nextTick(() => {
|
||||
audioRef.value?.load();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -49,8 +96,10 @@ function audioTimeUpdate(args: any) {
|
|||
class="!w-[45px]"
|
||||
/>
|
||||
<div>
|
||||
<div>{{ currentSong.name }}</div>
|
||||
<div class="text-xs text-gray-400">{{ currentSong.singer }}</div>
|
||||
<div>{{ currentSong.title || '暂无音乐' }}</div>
|
||||
<div class="text-xs text-gray-400">
|
||||
{{ currentSong.singer || currentSong.desc }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 音频controls -->
|
||||
|
|
@ -74,19 +123,26 @@ function audioTimeUpdate(args: any) {
|
|||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<span>{{ audioProps.currentTime }}</span>
|
||||
<ElSlider v-model="audioProgress" color="#409eff" class="!w-40" />
|
||||
<ElSlider
|
||||
v-model="audioProgress"
|
||||
:max="audioDuration"
|
||||
color="#409eff"
|
||||
class="!w-40"
|
||||
@change="handleProgressChange"
|
||||
/>
|
||||
<span>{{ audioProps.duration }}</span>
|
||||
</div>
|
||||
<!-- 音频 -->
|
||||
<audio
|
||||
v-bind="audioProps"
|
||||
:src="currentAudioUrl"
|
||||
:autoplay="audioProps.autoplay"
|
||||
:muted="audioProps.muted"
|
||||
ref="audioRef"
|
||||
controls
|
||||
v-show="!audioProps"
|
||||
@timeupdate="audioTimeUpdate"
|
||||
>
|
||||
<!-- <source :src="audioUrl" /> -->
|
||||
</audio>
|
||||
@loadedmetadata="audioLoadedMetadata"
|
||||
></audio>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<IconifyIcon
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
import type { MusicSong } from './types';
|
||||
|
||||
import { provide, ref } from 'vue';
|
||||
|
||||
|
|
@ -8,14 +9,15 @@ import { ElCol, ElEmpty, ElRow, ElTabPane, ElTabs } from 'element-plus';
|
|||
import audioBar from './audioBar/index.vue';
|
||||
import songCard from './songCard/index.vue';
|
||||
import songInfo from './songInfo/index.vue';
|
||||
import { currentSongKey } from './types';
|
||||
|
||||
defineOptions({ name: 'AiMusicListIndex' });
|
||||
|
||||
const currentType = ref('mine');
|
||||
const loading = ref(false); // loading 状态
|
||||
const currentSong = ref({}); // 当前音乐
|
||||
const mySongList = ref<Recordable<any>[]>([]);
|
||||
const squareSongList = ref<Recordable<any>[]>([]);
|
||||
const currentSong = ref<MusicSong>({}); // 当前音乐
|
||||
const mySongList = ref<MusicSong[]>([]);
|
||||
const squareSongList = ref<MusicSong[]>([]);
|
||||
|
||||
function generateMusic(_formData: Recordable<any>) {
|
||||
loading.value = true;
|
||||
|
|
@ -45,7 +47,7 @@ function generateMusic(_formData: Recordable<any>) {
|
|||
}, 3000);
|
||||
}
|
||||
|
||||
function setCurrentSong(music: Recordable<any>) {
|
||||
function setCurrentSong(music: MusicSong) {
|
||||
currentSong.value = music;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ defineExpose({
|
|||
generateMusic,
|
||||
});
|
||||
|
||||
provide('currentSong', currentSong);
|
||||
provide(currentSongKey, currentSong);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { inject, ref } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { ElImage } from 'element-plus';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongCardIndex' });
|
||||
|
||||
defineProps({
|
||||
songInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
withDefaults(defineProps<{ songInfo?: MusicSong }>(), {
|
||||
songInfo: () => ({}),
|
||||
});
|
||||
|
||||
const emits = defineEmits(['play']);
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
|
||||
function playSong() {
|
||||
emits('play');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
import type { MusicSong } from '../types';
|
||||
|
||||
import { inject, ref } from 'vue';
|
||||
|
||||
import { ElButton, ElCard, ElImage } from 'element-plus';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongInfoIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue