- 在 PlaylistDTO 和 SingerDTO 中添加 collectCount 和 commentCount 字段 - 更新前端 Singer 组件,使用 getSingerById API 获取歌手信息
854 lines
20 KiB
Vue
854 lines
20 KiB
Vue
<script setup>
|
||
import { ref, onMounted, computed } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import { getSingerList, addSinger as apiAddSinger, updateSinger, deleteSinger, getSingerById } from '../../api/singer'
|
||
import { getSingerTypeList } from '../../api/admin/type'
|
||
import { getMusicList } from '../../api/music'
|
||
import { addMusicToSinger, removeMusicFromSinger } from '../../api/singer'
|
||
|
||
// 歌手列表
|
||
const singerList = ref([])
|
||
|
||
// 加载状态
|
||
const loading = ref(false)
|
||
|
||
// 分页信息
|
||
const pagination = ref({
|
||
currentPage: 1,
|
||
pageSize: 5,
|
||
total: 0
|
||
})
|
||
|
||
// 搜索关键字
|
||
const searchKeyword = ref('')
|
||
|
||
// 类型筛选
|
||
const selectedType = ref('')
|
||
|
||
// 类型列表
|
||
const typeList = ref([])
|
||
|
||
// 添加/编辑对话框
|
||
const dialogVisible = ref(false)
|
||
|
||
// 对话框标题
|
||
const dialogTitle = ref('添加歌手')
|
||
|
||
// 当前编辑的歌手
|
||
const currentSinger = ref(null)
|
||
|
||
// 表单数据
|
||
const form = ref({
|
||
name: '',
|
||
typeId: '',
|
||
introduction: '',
|
||
avatar: null
|
||
})
|
||
|
||
// 获取歌手列表
|
||
const fetchSingerList = async () => {
|
||
loading.value = true
|
||
try {
|
||
const params = {
|
||
page: pagination.value.currentPage,
|
||
size: pagination.value.pageSize,
|
||
keyword: searchKeyword.value,
|
||
typeId: selectedType.value || null
|
||
}
|
||
|
||
const res = await getSingerList(params.page, params.size, params.keyword, params.typeId)
|
||
|
||
if (res.code === 200) {
|
||
singerList.value = res.data.list
|
||
console.log(66666,singerList.value)
|
||
pagination.value.total = res.data.total
|
||
} else {
|
||
ElMessage.error(res.message || '获取歌手列表失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取歌手列表错误:', error)
|
||
ElMessage.error('获取歌手列表失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 获取类型列表
|
||
const fetchTypeList = async () => {
|
||
try {
|
||
const res = await getSingerTypeList()
|
||
if (res.code === 200) {
|
||
typeList.value = res.data
|
||
} else {
|
||
ElMessage.error(res.message || '获取歌手类型列表失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取歌手类型列表错误:', error)
|
||
ElMessage.error('获取歌手类型列表失败')
|
||
}
|
||
}
|
||
|
||
// 处理页码变化
|
||
const handleCurrentChange = (page) => {
|
||
pagination.value.currentPage = page
|
||
fetchSingerList()
|
||
}
|
||
|
||
// 处理每页条数变化
|
||
const handleSizeChange = (size) => {
|
||
pagination.value.pageSize = size
|
||
pagination.value.currentPage = 1
|
||
fetchSingerList()
|
||
}
|
||
|
||
// 搜索歌手
|
||
const searchSinger = () => {
|
||
pagination.value.currentPage = 1
|
||
fetchSingerList()
|
||
}
|
||
|
||
// 重置搜索
|
||
const resetSearch = () => {
|
||
searchKeyword.value = ''
|
||
selectedType.value = ''
|
||
pagination.value.currentPage = 1
|
||
fetchSingerList()
|
||
}
|
||
|
||
// 添加歌手
|
||
const addSinger = () => {
|
||
dialogTitle.value = '添加歌手'
|
||
currentSinger.value = null
|
||
form.value = {
|
||
name: '',
|
||
typeId: '',
|
||
introduction: '',
|
||
avatar: null
|
||
}
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
// 编辑歌手
|
||
const editSinger = (row) => {
|
||
dialogTitle.value = '编辑歌手'
|
||
currentSinger.value = row
|
||
form.value = {
|
||
name: row.name,
|
||
typeId: row.type ? row.type.id : row.typeId,
|
||
introduction: row.introduction || '',
|
||
avatar: null
|
||
}
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
// 删除歌手
|
||
const handleDeleteSinger = (row) => {
|
||
ElMessageBox.confirm(`确定要删除歌手 ${row.name} 吗?此操作不可恢复`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(async () => {
|
||
try {
|
||
const res = await deleteSinger(row.id)
|
||
if (res.code === 200) {
|
||
ElMessage.success(res.message || '删除成功')
|
||
// 刷新歌手列表
|
||
fetchSingerList()
|
||
} else {
|
||
ElMessage.error(res.message || '删除失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('删除歌手错误:', error)
|
||
ElMessage.error('删除歌手失败')
|
||
}
|
||
}).catch(() => {})
|
||
}
|
||
|
||
// 管理音乐对话框相关状态
|
||
const musicDialogVisible = ref(false)
|
||
const currentSingerId = ref(null)
|
||
const currentSingerName = ref('')
|
||
const musicList = ref([])
|
||
const selectedMusicIds = ref([])
|
||
const musicSearchKeyword = ref('')
|
||
const musicLoading = ref(false)
|
||
|
||
// 获取音乐列表
|
||
const fetchMusicList = async () => {
|
||
musicLoading.value = true
|
||
try {
|
||
const res = await getMusicList(1, 100, musicSearchKeyword.value)
|
||
if (res.code === 200) {
|
||
musicList.value = res.data.list || res.data.records || []
|
||
} else {
|
||
ElMessage.error(res.message || '获取音乐列表失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取音乐列表失败:', error)
|
||
ElMessage.error('获取音乐列表失败')
|
||
} finally {
|
||
musicLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 获取歌手关联的音乐
|
||
const fetchSingerMusic = async (singerId) => {
|
||
try {
|
||
const res = await getSingerById(singerId)
|
||
if (res.code === 200 && res.data.musics) {
|
||
selectedMusicIds.value = res.data.musics.map(m => m.id)
|
||
}
|
||
} catch (error) {
|
||
console.error('获取歌手音乐失败:', error)
|
||
}
|
||
}
|
||
|
||
// 管理歌手音乐
|
||
const manageSingerMusic = async (row) => {
|
||
currentSingerId.value = row.id
|
||
currentSingerName.value = row.name
|
||
musicSearchKeyword.value = ''
|
||
musicDialogVisible.value = true
|
||
|
||
// 加载音乐列表和已选音乐
|
||
await Promise.all([
|
||
fetchMusicList(),
|
||
fetchSingerMusic(row.id)
|
||
])
|
||
}
|
||
|
||
// 添加音乐到歌手
|
||
const addMusicToSingerLocal = async (musicId) => {
|
||
try {
|
||
const res = await addMusicToSinger(currentSingerId.value, musicId)
|
||
if (res.code === 200) {
|
||
ElMessage.success('添加成功')
|
||
await fetchSingerMusic(currentSingerId.value)
|
||
} else {
|
||
ElMessage.error(res.message || '添加失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('添加音乐失败:', error)
|
||
ElMessage.error('添加失败')
|
||
}
|
||
}
|
||
|
||
// 从歌手移除音乐
|
||
const removeMusicFromSingerLocal = async (musicId) => {
|
||
try {
|
||
const res = await removeMusicFromSinger(currentSingerId.value, musicId)
|
||
if (res.code === 200) {
|
||
ElMessage.success('移除成功')
|
||
await fetchSingerMusic(currentSingerId.value)
|
||
} else {
|
||
ElMessage.error(res.message || '移除失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('移除音乐失败:', error)
|
||
ElMessage.error('移除失败')
|
||
}
|
||
}
|
||
|
||
// 搜索音乐
|
||
const searchMusic = () => {
|
||
fetchMusicList()
|
||
}
|
||
|
||
// 提交表单
|
||
const submitForm = async () => {
|
||
try {
|
||
// 构建歌手数据
|
||
const singerData = {
|
||
name: form.value.name,
|
||
introduction: form.value.introduction,
|
||
type: form.value.typeId ? { id: form.value.typeId } : null
|
||
}
|
||
|
||
let res
|
||
if (currentSinger.value) {
|
||
// 编辑歌手
|
||
res = await updateSinger(currentSinger.value.id, singerData, form.value.avatar)
|
||
} else {
|
||
// 添加歌手
|
||
res = await apiAddSinger(singerData, form.value.avatar)
|
||
}
|
||
|
||
if (res.code === 200) {
|
||
ElMessage.success(res.message || (currentSinger.value ? '编辑成功' : '添加成功'))
|
||
dialogVisible.value = false
|
||
// 刷新歌手列表
|
||
fetchSingerList()
|
||
} else {
|
||
ElMessage.error(res.message || '操作失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('提交歌手表单错误:', error)
|
||
ElMessage.error('操作失败')
|
||
}
|
||
}
|
||
|
||
// 格式化类型
|
||
const formatType = (typeId) => {
|
||
const type = typeList.value.find(t => t.id === typeId)
|
||
return type ? type.name : '-'
|
||
}
|
||
|
||
// 格式化粉丝数
|
||
const formatFans = (count) => {
|
||
if (count < 10000) {
|
||
return count.toString()
|
||
} else if (count < 100000000) {
|
||
return (count / 10000).toFixed(1) + '万'
|
||
} else {
|
||
return (count / 100000000).toFixed(1) + '亿'
|
||
}
|
||
}
|
||
|
||
// 处理头像上传
|
||
const handleAvatarChange = (file) => {
|
||
if (file && file.raw) {
|
||
// 验证文件类型
|
||
const isImage = file.raw.type.startsWith('image/')
|
||
if (!isImage) {
|
||
ElMessage.error('只能上传图片文件!')
|
||
return
|
||
}
|
||
|
||
// 验证文件大小
|
||
const isLt2M = file.raw.size / 1024 / 1024 < 2
|
||
if (!isLt2M) {
|
||
ElMessage.error('图片大小不能超过 2MB!')
|
||
return
|
||
}
|
||
|
||
form.value.avatar = file.raw
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
fetchSingerList()
|
||
fetchTypeList()
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="admin-singer-container">
|
||
<!-- 搜索栏 -->
|
||
<div class="search-bar">
|
||
<el-input
|
||
v-model="searchKeyword"
|
||
placeholder="请输入歌手名称/简介"
|
||
clearable
|
||
@clear="resetSearch"
|
||
@keyup.enter="searchSinger"
|
||
class="search-input"
|
||
>
|
||
<template #append>
|
||
<el-button @click="searchSinger">
|
||
<el-icon><search /></el-icon>
|
||
搜索
|
||
</el-button>
|
||
</template>
|
||
</el-input>
|
||
|
||
<el-select
|
||
v-model="selectedType"
|
||
placeholder="选择类型"
|
||
clearable
|
||
@change="searchSinger"
|
||
class="type-select"
|
||
>
|
||
<el-option
|
||
v-for="type in typeList"
|
||
:key="type.id"
|
||
:label="type.name"
|
||
:value="type.id"
|
||
/>
|
||
</el-select>
|
||
|
||
<el-button type="primary" @click="addSinger">
|
||
<el-icon><plus /></el-icon>
|
||
添加歌手
|
||
</el-button>
|
||
</div>
|
||
|
||
<!-- 歌手列表 -->
|
||
<el-table
|
||
:data="singerList"
|
||
stripe
|
||
style="width: 100%"
|
||
v-loading="loading"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||
|
||
<el-table-column label="头像" width="80" align="center">
|
||
<template #default="scope">
|
||
<img
|
||
:src="scope.row.avatar"
|
||
:alt="scope.row.name"
|
||
class="singer-avatar"
|
||
>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column prop="name" label="歌手名称" min-width="150"></el-table-column>
|
||
|
||
<el-table-column label="类型" width="120">
|
||
<template #default="scope">
|
||
{{ formatType(scope.row.type ? scope.row.type.id : scope.row.typeId) }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column prop="introduction" label="简介" min-width="200">
|
||
<template #default="scope">
|
||
<el-tooltip
|
||
:content="scope.row.introduction"
|
||
placement="top"
|
||
:show-after="500"
|
||
>
|
||
<div class="introduction-text">{{ scope.row.introduction }}</div>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column prop="musicCount" label="单曲数" width="80" align="center"></el-table-column>
|
||
|
||
<el-table-column prop="fansCount" label="粉丝数" width="100" align="center">
|
||
<template #default="scope">
|
||
{{ formatFans(scope.row.fansCount || 0) }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column prop="createTime" label="创建时间" width="120"></el-table-column>
|
||
|
||
<el-table-column label="操作" width="200" fixed="right">
|
||
<template #default="scope">
|
||
<el-button
|
||
size="small"
|
||
@click="manageSingerMusic(scope.row)"
|
||
>
|
||
管理音乐
|
||
</el-button>
|
||
|
||
<el-button
|
||
size="small"
|
||
type="primary"
|
||
@click="editSinger(scope.row)"
|
||
>
|
||
编辑
|
||
</el-button>
|
||
|
||
<el-button
|
||
size="small"
|
||
type="danger"
|
||
@click="handleDeleteSinger(scope.row)"
|
||
>
|
||
删除
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<div class="pagination">
|
||
<el-pagination
|
||
v-model:current-page="pagination.currentPage"
|
||
v-model:page-size="pagination.pageSize"
|
||
:page-sizes="[5, 10, 15, 20]"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="pagination.total"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 添加/编辑对话框 -->
|
||
<el-dialog
|
||
v-model="dialogVisible"
|
||
:title="dialogTitle"
|
||
width="600px"
|
||
>
|
||
<el-form
|
||
:model="form"
|
||
label-width="100px"
|
||
>
|
||
<el-form-item label="歌手名称" required>
|
||
<el-input v-model="form.name" placeholder="请输入歌手名称" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="类型" required>
|
||
<el-select
|
||
v-model="form.typeId"
|
||
placeholder="请选择歌手类型"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="type in typeList"
|
||
:key="type.id"
|
||
:label="type.name"
|
||
:value="type.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="简介">
|
||
<el-input
|
||
v-model="form.introduction"
|
||
type="textarea"
|
||
:rows="3"
|
||
placeholder="请输入歌手简介"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="头像">
|
||
<!-- 当前头像预览 -->
|
||
<div v-if="currentSinger && currentSinger.avatar" class="current-avatar">
|
||
<el-image
|
||
:src="currentSinger.avatar"
|
||
fit="cover"
|
||
class="avatar-preview"
|
||
:preview-src-list="[currentSinger.avatar]"
|
||
:initial-index="0"
|
||
preview-teleported
|
||
/>
|
||
<div class="avatar-tip">当前头像</div>
|
||
</div>
|
||
|
||
<el-upload
|
||
action="#"
|
||
:auto-upload="false"
|
||
:on-change="handleAvatarChange"
|
||
:limit="1"
|
||
list-type="picture-card"
|
||
>
|
||
<el-icon><plus /></el-icon>
|
||
</el-upload>
|
||
<div class="el-upload__tip">
|
||
点击上传新头像,不上传则保持原头像
|
||
</div>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 管理音乐对话框 -->
|
||
<el-dialog
|
||
v-model="musicDialogVisible"
|
||
:title="`管理歌手 ${currentSingerName} 的音乐`"
|
||
width="800px"
|
||
>
|
||
<div class="music-management-container">
|
||
<!-- 搜索栏 -->
|
||
<div class="search-bar">
|
||
<el-input
|
||
v-model="musicSearchKeyword"
|
||
placeholder="搜索音乐名称"
|
||
clearable
|
||
@keyup.enter="searchMusic"
|
||
class="search-input"
|
||
>
|
||
<template #append>
|
||
<el-button @click="searchMusic">
|
||
<el-icon><search /></el-icon>
|
||
搜索
|
||
</el-button>
|
||
</template>
|
||
</el-input>
|
||
</div>
|
||
|
||
<!-- 音乐列表 -->
|
||
<div class="music-list-container">
|
||
<el-table
|
||
:data="musicList"
|
||
stripe
|
||
style="width: 100%"
|
||
v-loading="musicLoading"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||
<el-table-column prop="name" label="音乐名称" min-width="150"></el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template #default="scope">
|
||
<el-button
|
||
size="small"
|
||
type="primary"
|
||
@click="addMusicToSingerLocal(scope.row.id)"
|
||
:disabled="selectedMusicIds.includes(scope.row.id)"
|
||
>
|
||
{{ selectedMusicIds.includes(scope.row.id) ? '已添加' : '添加' }}
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<!-- 已添加音乐 -->
|
||
<div class="selected-music-container">
|
||
<h3>已添加的音乐</h3>
|
||
<el-table
|
||
:data="musicList.filter(m => selectedMusicIds.includes(m.id))"
|
||
stripe
|
||
style="width: 100%"
|
||
empty-text="暂无音乐"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||
<el-table-column prop="name" label="音乐名称" min-width="150"></el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template #default="scope">
|
||
<el-button
|
||
size="small"
|
||
type="danger"
|
||
@click="removeMusicFromSingerLocal(scope.row.id)"
|
||
>
|
||
移除
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="musicDialogVisible = false">关闭</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.music-management-container {
|
||
padding: 10px;
|
||
}
|
||
|
||
.search-bar {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.search-input {
|
||
width: 300px;
|
||
}
|
||
|
||
.music-list-container,
|
||
.selected-music-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.selected-music-container h3 {
|
||
margin-bottom: 10px;
|
||
color: #606266;
|
||
}
|
||
</style>
|
||
|
||
<style scoped>
|
||
.admin-singer-container {
|
||
padding: 20px;
|
||
background: linear-gradient(135deg, #e1f5fe 0%, #b3e5fc 100%);
|
||
}
|
||
|
||
.search-bar {
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: center;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
padding: 15px;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.search-input {
|
||
width: 300px;
|
||
}
|
||
|
||
.search-input :deep(.el-input__inner) {
|
||
border-radius: 8px;
|
||
border: 1px solid #b3e5fc;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.search-input :deep(.el-input__inner):focus {
|
||
border-color: #4dd0e1;
|
||
box-shadow: 0 0 0 2px rgba(77, 208, 225, 0.2);
|
||
}
|
||
|
||
.type-select {
|
||
width: 150px;
|
||
}
|
||
|
||
.type-select :deep(.el-input__inner) {
|
||
border-radius: 8px;
|
||
border: 1px solid #b3e5fc;
|
||
}
|
||
|
||
.el-button {
|
||
border-radius: 8px !important;
|
||
font-weight: bold !important;
|
||
transition: all 0.3s !important;
|
||
}
|
||
|
||
.el-button--primary {
|
||
background: linear-gradient(135deg, #4dd0e1 0%, #26c6da 100%) !important;
|
||
border: none !important;
|
||
}
|
||
|
||
.el-button--primary:hover {
|
||
transform: translateY(-2px) !important;
|
||
box-shadow: 0 4px 8px rgba(38, 198, 218, 0.3) !important;
|
||
}
|
||
|
||
.pagination {
|
||
margin-top: 20px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
padding: 15px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.singer-avatar {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.singer-avatar:hover {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.introduction-text {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 200px;
|
||
}
|
||
|
||
.el-table {
|
||
--el-table-border-color: #b3e5fc;
|
||
--el-table-header-bg-color: #e1f5fe;
|
||
--el-table-row-hover-bg-color: #b3e5fc;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.el-table th.el-table__cell {
|
||
background-color: #e1f5fe !important;
|
||
color: #0d47a1 !important;
|
||
font-weight: bold !important;
|
||
}
|
||
|
||
.el-table .el-table__row {
|
||
background-color: rgba(255, 255, 255, 0.9) !important;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.el-table .el-table__row:hover {
|
||
background-color: #b3e5fc !important;
|
||
transform: scale(1.01);
|
||
}
|
||
|
||
.el-table :deep(.el-button) {
|
||
margin-left: 0;
|
||
margin-right: 5px;
|
||
padding: 4px 8px;
|
||
border-radius: 8px !important;
|
||
}
|
||
|
||
.el-dialog {
|
||
border-radius: 16px !important;
|
||
}
|
||
|
||
.el-dialog :deep(.el-dialog__header) {
|
||
background: linear-gradient(135deg, #e1f5fe 0%, #b3e5fc 100%);
|
||
border-radius: 16px 16px 0 0 !important;
|
||
padding: 15px 20px;
|
||
}
|
||
|
||
.el-dialog :deep(.el-dialog__title) {
|
||
color: #0d47a1;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.el-form-item :deep(.el-form-item__label) {
|
||
color: #4a4a4a;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.el-input :deep(.el-input__inner) {
|
||
border-radius: 8px;
|
||
border: 1px solid #b3e5fc;
|
||
}
|
||
|
||
.el-input :deep(.el-input__inner):focus {
|
||
border-color: #4dd0e1;
|
||
box-shadow: 0 0 0 2px rgba(77, 208, 225, 0.2);
|
||
}
|
||
|
||
.current-avatar {
|
||
margin-bottom: 10px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.avatar-preview {
|
||
width: 100px;
|
||
height: 100px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
margin-bottom: 5px;
|
||
border: 1px solid #b3e5fc;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.avatar-preview:hover {
|
||
transform: scale(1.05);
|
||
}
|
||
|
||
.avatar-tip {
|
||
font-size: 12px;
|
||
color: #4a4a4a;
|
||
}
|
||
|
||
.el-upload :deep(.el-upload--picture-card) {
|
||
border-radius: 8px;
|
||
border: 1px dashed #b3e5fc;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.el-upload :deep(.el-upload--picture-card:hover) {
|
||
border-color: #4dd0e1;
|
||
}
|
||
|
||
.music-management-container {
|
||
padding: 10px;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.music-management-container .search-bar {
|
||
background: transparent;
|
||
padding: 0;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.music-list-container,
|
||
.selected-music-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.selected-music-container h3 {
|
||
margin-bottom: 10px;
|
||
color: #4a4a4a;
|
||
}
|
||
</style>
|