feat: 添加歌单管理功能
- 新增歌单管理界面,支持添加和删除歌单 - 在MusicLibModel中添加musicCount字段显示歌曲数量 - 优化歌词编辑界面,添加加载状态提示 - 优化UI细节和路由视图加载时机 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
265ce0c6c7
commit
b68de2e9bf
@ -16,6 +16,7 @@ export interface MusicLibModel {
|
|||||||
_id: string
|
_id: string
|
||||||
name: string // 歌单名称
|
name: string // 歌单名称
|
||||||
path: string // 歌单文件路径
|
path: string // 歌单文件路径
|
||||||
|
musicCount: number // 歌曲数量
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MusicLyricModel {
|
export interface MusicLyricModel {
|
||||||
|
|||||||
@ -152,7 +152,6 @@ html, body, #app, .layout {
|
|||||||
.search-btn {
|
.search-btn {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,8 +40,8 @@
|
|||||||
<el-tab-pane v-for="tab in store.state.tabs" :key="tab.name" :label="tab.title" :name="tab.path" closable></el-tab-pane>
|
<el-tab-pane v-for="tab in store.state.tabs" :key="tab.name" :label="tab.title" :name="tab.path" closable></el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-content" v-if="mainViewReady">
|
<div class="layout-content">
|
||||||
<router-view class="main-view" v-slot="{ Component }">
|
<router-view class="main-view" v-slot="{ Component }" v-if="mainViewReady">
|
||||||
<keep-alive :include="keepViews">
|
<keep-alive :include="keepViews">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
<div class="btn-container">
|
<div class="btn-container">
|
||||||
<el-button type="success" plain icon="VideoPlay" @click="playMusic">播放</el-button>
|
<el-button type="success" plain icon="VideoPlay" @click="playMusic">播放</el-button>
|
||||||
<el-button type="primary" icon="Upload" @click="openUploadModal">上传音乐</el-button>
|
<el-button type="primary" icon="Upload" @click="openUploadModal">上传音乐</el-button>
|
||||||
|
<el-button type="warning" plain icon="Notebook" @click="libDrawerVisible = true">歌单管理</el-button>
|
||||||
<div class="search-btn">
|
<div class="search-btn">
|
||||||
<el-button type="primary" @click="loadDataBase(true)" icon="Search">搜索</el-button>
|
<el-button type="primary" @click="loadDataBase(true)" icon="Search">搜索</el-button>
|
||||||
<el-button @click="reset" icon="RefreshLeft">重置</el-button>
|
<el-button @click="reset" icon="RefreshLeft">重置</el-button>
|
||||||
@ -85,7 +86,7 @@
|
|||||||
</el-pagination>
|
</el-pagination>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog v-model="modifyLyricModal" title="编辑歌词" :width="600" >
|
<el-dialog v-model="modifyLyricModal" title="编辑歌词" :width="600" >
|
||||||
<el-form ref="lyricForm" :model="lyricFormData" :rules="lyricRuleValidate" :label-width="120">
|
<el-form v-loading="lyricLoading" ref="lyricForm" :model="lyricFormData" :rules="lyricRuleValidate" :label-width="120">
|
||||||
<el-form-item label="网易云ID" prop="cloudId">
|
<el-form-item label="网易云ID" prop="cloudId">
|
||||||
<el-input v-model="lyricFormData.cloudId" />
|
<el-input v-model="lyricFormData.cloudId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -139,6 +140,31 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-drawer v-model="libDrawerVisible" title="歌单管理" size="900px">
|
||||||
|
<el-button type="primary" icon="Plus" @click="addLibRow" style="margin-bottom: 12px">添加歌单</el-button>
|
||||||
|
<el-table :data="libTableData" stripe>
|
||||||
|
<el-table-column prop="name" label="名称">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="scope.row._isNew" v-model="scope.row.name" placeholder="歌单名称" />
|
||||||
|
<span v-else>{{ scope.row.name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="path" label="路径">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="scope.row._isNew" v-model="scope.row.path" placeholder="music/歌单名/" />
|
||||||
|
<span v-else>{{ scope.row.path }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="musicCount" label="歌曲数量" width="100" />
|
||||||
|
<el-table-column label="操作" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button v-if="scope.row._isNew" link type="primary" icon="Check" @click="saveLib(scope.row)" :loading="libSaving">保存</el-button>
|
||||||
|
<el-button v-if="scope.row._isNew" link icon="Close" @click="cancelAddLib">取消</el-button>
|
||||||
|
<el-button v-if="!scope.row._isNew" link type="danger" icon="Delete" @click="removeLib(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-drawer>
|
||||||
<el-drawer v-model="musicPlaying" :close-on-click-modal="false" size="40%" title="播放音乐">
|
<el-drawer v-model="musicPlaying" :close-on-click-modal="false" size="40%" title="播放音乐">
|
||||||
<a-player v-if="musicPlaying" ref="player" autoplay showLrc :list="musicList" v-model:music="currentMusic" @play="musicPlay"/>
|
<a-player v-if="musicPlaying" ref="player" autoplay showLrc :list="musicList" v-model:music="currentMusic" @play="musicPlay"/>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
@ -190,6 +216,10 @@ const currentMusic = ref<MusicPlayerItem>()
|
|||||||
const lyricForm = ref<VForm>()
|
const lyricForm = ref<VForm>()
|
||||||
const musicUpload = ref<UploadInstance>()
|
const musicUpload = ref<UploadInstance>()
|
||||||
const player = ref<any>()
|
const player = ref<any>()
|
||||||
|
const lyricLoading = ref(false)
|
||||||
|
const libDrawerVisible = ref(false)
|
||||||
|
const libTableData = ref<(MusicLibModel & { _isNew?: boolean })[]>([])
|
||||||
|
const libSaving = ref(false)
|
||||||
|
|
||||||
const lyricRuleValidate = {
|
const lyricRuleValidate = {
|
||||||
cloudId: [
|
cloudId: [
|
||||||
@ -266,13 +296,17 @@ function remove(row: MusicModel) {
|
|||||||
}
|
}
|
||||||
async function updateLyric(row: MusicModel) {
|
async function updateLyric(row: MusicModel) {
|
||||||
currentRow.value = { ...row }
|
currentRow.value = { ...row }
|
||||||
|
lyricFormData.value = {}
|
||||||
modifyLyricModal.value = true
|
modifyLyricModal.value = true
|
||||||
if (row.lyricId) {
|
if (row.lyricId) {
|
||||||
const data = (await http.get<any, any>('/api/v2/music/lyric/get', {params: {lyricId: row.lyricId}}))
|
lyricLoading.value = true
|
||||||
data.cloudId = data.cloudId ? data.cloudId.toString() : null
|
try {
|
||||||
lyricFormData.value = data
|
const data = await http.get<any, any>('/api/v2/music/lyric/get', {params: {lyricId: row.lyricId}})
|
||||||
} else {
|
data.cloudId = data.cloudId ? data.cloudId.toString() : null
|
||||||
lyricFormData.value = {}
|
lyricFormData.value = data
|
||||||
|
} finally {
|
||||||
|
lyricLoading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function saveLyric() {
|
async function saveLyric() {
|
||||||
@ -350,9 +384,43 @@ function musicPlay() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadLibs() {
|
||||||
|
return http.get<never, any>('/api/v2/music/lib/list').then(data => {
|
||||||
|
musicLibs.value = data
|
||||||
|
libTableData.value = data.map((item: MusicLibModel) => ({ ...item }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function addLibRow() {
|
||||||
|
if (libTableData.value.some(item => (item as any)._isNew)) return
|
||||||
|
libTableData.value.unshift({ _id: '', name: '', path: '', musicCount: 0, _isNew: true })
|
||||||
|
}
|
||||||
|
function cancelAddLib() {
|
||||||
|
libTableData.value = libTableData.value.filter(item => !(item as any)._isNew)
|
||||||
|
}
|
||||||
|
async function saveLib(row: MusicLibModel & { _isNew?: boolean }) {
|
||||||
|
if (!row.name || !row.path) {
|
||||||
|
ElMessage.warning('请输入歌单名称和路径')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
libSaving.value = true
|
||||||
|
try {
|
||||||
|
await http.post<any, any>('/api/v2/music/lib/add', { name: row.name, path: row.path })
|
||||||
|
ElMessage.success('歌单创建成功')
|
||||||
|
await loadLibs()
|
||||||
|
} finally {
|
||||||
|
libSaving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function removeLib(row: MusicLibModel) {
|
||||||
|
ElMessageBox.confirm(`是否确认删除歌单「${row.name}」?`, '确认删除', { type: 'warning' }).then(async () => {
|
||||||
|
await http.delete<any, any>('/api/v2/music/lib/delete', { params: { id: row._id } })
|
||||||
|
ElMessage.success('歌单删除成功')
|
||||||
|
await loadLibs()
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
// created
|
// created
|
||||||
http.get<never, any>('/api/v2/music/lib/list').then(data => {
|
loadLibs().then(() => {
|
||||||
musicLibs.value = data
|
|
||||||
loadData()
|
loadData()
|
||||||
})
|
})
|
||||||
http.get<never, any>('/api/v2/music/listExts').then(data => {
|
http.get<never, any>('/api/v2/music/listExts').then(data => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user