1768 lines
58 KiB
Vue
1768 lines
58 KiB
Vue
<script setup>
|
||
import { RouterLink, RouterView } from "vue-router"
|
||
import { nextTick, onMounted, ref } from "vue"
|
||
|
||
import { getQrcode, getList, monitorState, Generate, monitorMusic, getDetails, lyricsGenerateHttp, lyricsMonitorHttp, quitLoginHttp, likeDetailsHttp } from "./utils/api"
|
||
import { ElMessage } from "element-plus"
|
||
import triangleIcon from "@/components/triangle-icon.vue"
|
||
|
||
onMounted(() => {
|
||
// getLoginQrcode()
|
||
getListData()
|
||
})
|
||
|
||
let list = ref([])
|
||
let listIndex = ref(null) // 列表选中的 Index
|
||
|
||
const getListData = () => {
|
||
getList().then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
return
|
||
}
|
||
|
||
if (res.code != 200) return
|
||
const data = res.data || []
|
||
let isNeedMonitor = false
|
||
data.forEach(element => {
|
||
if (element.status != "complete") {
|
||
isNeedMonitor = true
|
||
}
|
||
})
|
||
|
||
if (isNeedMonitor) {
|
||
monitorMusicState()
|
||
}
|
||
|
||
// data[0].audio_url = "./21be5d73-221f-4e7b-82f0-26c7c71b797e.mp3"
|
||
|
||
islogin.value = true
|
||
list.value = data || []
|
||
})
|
||
}
|
||
|
||
let wxloginVisible = ref(false) // 登录弹窗显示状态
|
||
let wxloginQrcodeLose = ref(false) // 登录二维码失效状态
|
||
let islogin = ref(false) // 登录状态
|
||
let token = ""
|
||
let qrcode = ref("")
|
||
|
||
// 获取二维码
|
||
const getLoginQrcode = () => {
|
||
getQrcode().then(res => {
|
||
if (res.code != 200) return
|
||
|
||
const data = res.data || {}
|
||
token = data.token || ""
|
||
qrcode.value = data.qrcode || ""
|
||
wxloginVisible.value = true
|
||
|
||
monitorLogin()
|
||
})
|
||
}
|
||
|
||
// 监听扫码状态
|
||
let monitorTimer = null
|
||
const monitorLogin = () => {
|
||
monitorTimer = setInterval(() => {
|
||
monitorState({ token: token }).then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
return
|
||
}
|
||
|
||
// code 200 为登录成功 400 是等待 201 是失效
|
||
if (res.code == 400) return
|
||
|
||
clearInterval(monitorTimer)
|
||
|
||
if (res.code == 201) {
|
||
wxloginQrcodeLose.value = true
|
||
}
|
||
|
||
if (res.code == 200) {
|
||
ElMessage({
|
||
showClose: true,
|
||
message: res.message,
|
||
type: "success",
|
||
})
|
||
wxloginVisible.value = false
|
||
getListData()
|
||
localStorage.setItem("token", res.data?.token)
|
||
}
|
||
})
|
||
}, 3000)
|
||
}
|
||
|
||
const handleClose = () => {
|
||
wxloginVisible.value = false
|
||
wxloginQrcodeLose.value = false
|
||
clearInterval(monitorTimer)
|
||
}
|
||
|
||
let options = ref([
|
||
{
|
||
label: "V2 (老款模型,最长生成1分钟左右)",
|
||
value: "chirp-v2-xxl-alpha",
|
||
},
|
||
{
|
||
label: "V3 (广泛、多才多艺,最多生成2分钟)",
|
||
value: "chirp-v3-0",
|
||
},
|
||
{
|
||
label: "V3.5 (最新模型,更好的歌曲结构,最长生成4分钟)",
|
||
value: "chirp-v3-5",
|
||
},
|
||
])
|
||
|
||
let type = ref("inspiration") // inspiration 灵感 custom 自定义
|
||
|
||
const cutType = key => {
|
||
// 恢复默认值
|
||
obj.value = Object.assign({}, obj.value, {
|
||
"has_vocal": true,
|
||
"prompt": "",
|
||
"gpt_description_prompt": "",
|
||
"mv": "chirp-v3-5",
|
||
"tags": "",
|
||
})
|
||
|
||
// console.log(obj.value)
|
||
type.value = key
|
||
}
|
||
|
||
let obj = ref({
|
||
"gpt_description_prompt": "", // 描述
|
||
"mv": "chirp-v3-5",
|
||
"make_instrumental": false,
|
||
"tags": "", // 标签
|
||
"prompt": "", // 提示
|
||
"history": null,
|
||
"concat_history": null,
|
||
"type": "gen",
|
||
"duration": null, // 持续时间
|
||
"refund_credits": null, // 优惠
|
||
"stream": true, // 流派
|
||
"infill": null, // 填充物
|
||
"has_vocal": true, // 是否有声音
|
||
"error_type": null,
|
||
"error_message": null,
|
||
})
|
||
|
||
// 点击创建音乐
|
||
const creativeMusic = () => {
|
||
Generate({ ...obj.value }).then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
return
|
||
}
|
||
if (res.code != 200) {
|
||
ElMessage({
|
||
showClose: true,
|
||
message: res.message,
|
||
type: "error",
|
||
})
|
||
return
|
||
}
|
||
const data = res.data || {}
|
||
list.value = data.list.concat(list.value)
|
||
// list.value = list.value.unshift()
|
||
|
||
monitorMusicState(data.metadataid)
|
||
ElMessage({
|
||
showClose: true,
|
||
message: "提交成功",
|
||
type: "success",
|
||
})
|
||
})
|
||
}
|
||
|
||
// let styleVisible = ref(true) // 风格弹窗状态
|
||
// bass, drum, guitar, rock, pop, electro, electronic, metal, heavy metal, heavy metal, heavy metal, heavy metal
|
||
let stylelist = ["bass", "drum", "guitar", "rock", "pop", "electro", "electronic", "metal", "heavy metal", "Subscribe", "heavy metal", "beat", "synth", "hard rock", "rap", "catchy", "powerful", "indie pop"]
|
||
|
||
const addStyle = item => {
|
||
obj.value.tags = obj.value.tags.trim()
|
||
if (obj.value.tags) obj.value.tags += ","
|
||
|
||
obj.value.tags += item
|
||
}
|
||
|
||
const handleMusicList = index => {
|
||
let targetlist = list.value || []
|
||
let target = targetlist[index]
|
||
listIndex.value = index
|
||
|
||
// console.log(target.metadataid)
|
||
if (target.status !== "complete") {
|
||
monitorMusicState(target.metadataid || "没有metadataid")
|
||
}
|
||
getMusicDetails(target.id)
|
||
}
|
||
|
||
let monitorMusicTimer = null
|
||
// 监听音乐的生成状态
|
||
const monitorMusicState = metadataid => {
|
||
clearTimeout(monitorMusicTimer)
|
||
monitorMusicTimer = setTimeout(() => {
|
||
monitorMusic({ metadataid }).then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
return
|
||
}
|
||
if (res.code != 200) return
|
||
const data = res.data || {}
|
||
const dataList = data.list || []
|
||
|
||
if (data.status != "complete") {
|
||
monitorMusicState(metadataid)
|
||
}
|
||
|
||
let obj = {}
|
||
// let isnoneed = 0 // isnoneed > 0 需要继续监听的意思 submitted streaming 代表生产中
|
||
dataList.forEach((element, index) => {
|
||
// if (element.status != "complete") isnoneed++
|
||
// 打开详情并且 已经生成成功后刷新详情
|
||
if (element.status == "complete" && songInfo.value.sid == element.sid) {
|
||
getMusicDetails(element.id)
|
||
}
|
||
obj[element.sid] = index
|
||
})
|
||
|
||
// if (isnoneed > 0) {
|
||
// monitorMusicState(metadataid)
|
||
// }
|
||
|
||
let targetlist = list.value || []
|
||
targetlist.forEach((element, index) => {
|
||
if (obj[element.sid] >= 0) {
|
||
targetlist[index] = dataList[obj[element.sid]]
|
||
delete obj[element.sid]
|
||
}
|
||
})
|
||
|
||
for (const key in obj) {
|
||
targetlist.unshift(dataList[obj[key]])
|
||
}
|
||
list.value = targetlist
|
||
})
|
||
}, 10000)
|
||
}
|
||
|
||
let songInfo = ref({}) // 歌详情
|
||
|
||
const getMusicDetails = id => {
|
||
getDetails({ id }).then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
return
|
||
}
|
||
if (res.code != 200) {
|
||
ElMessage({
|
||
showClose: true,
|
||
message: res.message,
|
||
})
|
||
return
|
||
}
|
||
|
||
songInfo.value = res.data
|
||
|
||
previewState.value = true
|
||
})
|
||
}
|
||
|
||
const audio = ref(null)
|
||
const isPlaying = ref(false)
|
||
let audioSrc = ref("")
|
||
|
||
let previewState = ref(false)
|
||
const closeInfo = () => {
|
||
// previewState.value = false
|
||
songInfo.value = {}
|
||
}
|
||
|
||
const playAudio = index => {
|
||
if (index == undefined) {
|
||
index = listIndex.value || 0
|
||
}
|
||
let targetlist = list.value || []
|
||
let target = targetlist[index] || {}
|
||
const url = target.audio_url || ""
|
||
if (audioSrc.value != url) {
|
||
audio.value.src = url
|
||
currentTime.value = 0
|
||
}
|
||
audio.value.play()
|
||
listIndex.value = index
|
||
}
|
||
|
||
const togglePlayPause = () => {
|
||
if (isPlaying.value) {
|
||
pauseAudio()
|
||
} else {
|
||
playAudio()
|
||
}
|
||
}
|
||
|
||
const updatePlayStatus = () => {
|
||
isPlaying.value = !audio.value.paused
|
||
audioSrc.value = audio.value.src || ""
|
||
}
|
||
|
||
const pauseAudio = () => {
|
||
audio.value.pause()
|
||
}
|
||
|
||
const nextAudio = () => {
|
||
if (listIndex.value == null) return
|
||
let targetlist = list.value || []
|
||
let index = listIndex.value
|
||
index = (index + 1) % targetlist.length
|
||
let target = targetlist[index]
|
||
audio.value.src = target.audio_url
|
||
audio.value.play()
|
||
|
||
listIndex.value = index
|
||
}
|
||
|
||
const prevAudio = () => {
|
||
if (listIndex.value == null) return
|
||
|
||
let targetlist = list.value || []
|
||
let index = listIndex.value
|
||
index = (index - 1 + targetlist.length) % targetlist.length
|
||
|
||
let target = targetlist[index]
|
||
audio.value.src = target.audio_url
|
||
audio.value.play()
|
||
|
||
listIndex.value = index
|
||
}
|
||
|
||
const currentTime = ref(0)
|
||
const duration = ref(0)
|
||
|
||
const updateCurrentTime = () => {
|
||
// console.log("4454545")
|
||
currentTime.value = audio.value.currentTime
|
||
}
|
||
|
||
const updateDuration = () => {
|
||
duration.value = audio.value.duration
|
||
}
|
||
|
||
const seekAudio = value => {
|
||
if (value >= 0) {
|
||
audio.value.currentTime = value
|
||
}
|
||
// console.log(value)
|
||
|
||
if (isNaN(value)) {
|
||
currentTime.value = 0
|
||
// console.log(currentTime.value)
|
||
}
|
||
}
|
||
|
||
const formatTime = time => {
|
||
if (isNaN(time)) return "0:00"
|
||
if (time == Infinity) {
|
||
return "-- : --"
|
||
}
|
||
const minutes = Math.floor(time / 60)
|
||
const seconds = Math.floor(time % 60)
|
||
return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`
|
||
}
|
||
|
||
// 生成类似
|
||
const generatingSimilar = index => {
|
||
let target = list.value[index]
|
||
|
||
// 判断是显示哪个模式
|
||
if (target.metadata.prompt) {
|
||
cutType("custom")
|
||
} else {
|
||
cutType("inspiration")
|
||
}
|
||
|
||
// console.log("target", target)
|
||
|
||
nextTick(() => {
|
||
// console.log("target.model_name", target.model_name)
|
||
obj.value = { ...target.metadata, mv: target.model_name, title: target.title }
|
||
})
|
||
}
|
||
|
||
// 判断风格是否已经在输入框了
|
||
const judgingExistence = item => {
|
||
const tags = obj.value?.tags || ""
|
||
return !tags.includes(item)
|
||
}
|
||
|
||
// 生成歌词
|
||
const lyricsGenerating = () => {
|
||
if (lyricsMonitorState.value) return
|
||
const prompt = obj.value.prompt || ""
|
||
lyricsMonitorState.value = true
|
||
lyricsGenerateHttp({ prompt })
|
||
.then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
lyricsMonitorState.value = false
|
||
return
|
||
}
|
||
|
||
if (res.code != 200) {
|
||
ElMessage({
|
||
showClose: true,
|
||
message: res.message,
|
||
type: "error",
|
||
})
|
||
lyricsMonitorState.value = false
|
||
return
|
||
}
|
||
const data = res.data
|
||
// console.log("data", data)
|
||
lyricsMonitor(data.id)
|
||
})
|
||
.catch(() => {
|
||
lyricsMonitorState.value = false
|
||
})
|
||
}
|
||
|
||
let lyricsMonitorTimer = null
|
||
let lyricsMonitorState = ref(false) // 生成状态
|
||
// 监听歌词生成
|
||
const lyricsMonitor = id => {
|
||
setTimeout(() => {
|
||
lyricsMonitorHttp({ id })
|
||
.then(res => {
|
||
if (res.code == 401) {
|
||
getLoginQrcode()
|
||
return
|
||
}
|
||
|
||
const data = res.data
|
||
|
||
if (data.status == "complete") {
|
||
obj.value.prompt = data.text
|
||
obj.value.title = data.title
|
||
lyricsMonitorState.value = false
|
||
} else {
|
||
lyricsMonitor(id)
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.log("err", err)
|
||
lyricsMonitor(id)
|
||
})
|
||
}, 3000)
|
||
}
|
||
|
||
// 退出登录
|
||
const logOut = () => {
|
||
localStorage.setItem("token", "")
|
||
islogin.value = false
|
||
quitLoginHttp()
|
||
songInfo.value = {}
|
||
list.value = []
|
||
}
|
||
|
||
// 登录
|
||
const register = () => {
|
||
getLoginQrcode()
|
||
}
|
||
|
||
// 点击列表 点赞
|
||
const handlelike = index => {
|
||
let targetlist = list.value || []
|
||
let target = targetlist[index] || {}
|
||
|
||
likeDetailsHttp({ id: target.id }).then(res => {
|
||
if (res.code != 200) {
|
||
ElMessage({
|
||
showClose: true,
|
||
message: res.message,
|
||
type: "error",
|
||
})
|
||
return
|
||
}
|
||
const data = res.data || {}
|
||
list.value[index]["is_upvote"] = data.is_upvote || 0
|
||
// 判断 详情预览和点赞的是不是同一首
|
||
if (target.sid == songInfo.value.sid) {
|
||
songInfo.value["is_upvote"] = data.is_upvote || 0
|
||
}
|
||
})
|
||
|
||
// target.is_liked = 1
|
||
}
|
||
|
||
// 切换纯音乐
|
||
const switchchange = value => {
|
||
// 当切换到纯音乐时去掉歌词
|
||
if (!value) {
|
||
obj.value.prompt = ""
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div>
|
||
<!-- <div class="flexflex" style="height: calc(100vh - 69px); overflow: auto;"> -->
|
||
<div class="flexflex">
|
||
<div class="left-box">
|
||
<img class="left-bj left-bj1" src="./assets/img/left-bj1.png" />
|
||
<img class="left-bj left-bj2" src="./assets/img/left-bj2.png" />
|
||
<img class="left-bj left-bj3" src="./assets/img/left-bj1.png" />
|
||
<img class="hemisphere-icon" src="./assets/img/hemisphere-icon.png" />
|
||
<img class="logo" src="./assets/img/logo-icon.png" />
|
||
<img class="star" src="./assets/img/star-icon.png" />
|
||
|
||
<div class="tab-box">
|
||
<div class="tab-item" :class="{ 'sel': type == 'inspiration' }" @click="cutType('inspiration')">灵感模式</div>
|
||
<div class="tab-item" :class="{ 'sel': type == 'custom' }" @click="cutType('custom')">自定义模式</div>
|
||
</div>
|
||
<template v-if="type == 'inspiration'">
|
||
<div class="description">
|
||
<div class="title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
歌曲描述
|
||
<el-popover placement="right" :width="300" trigger="click" content='描述你想要的音乐风格和主题(例如"关于假日")。使用流派和氛围,而不是特定的艺术家和歌曲。' popper-class="popper-description">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
<div class="title-right"></div>
|
||
</div>
|
||
<el-input v-model="obj.gpt_description_prompt" class="description-input" style="width: 100%;" type="textarea" placeholder="请输入您的歌曲描述,例如:一首关于青春的冷酷的电子歌曲" maxlength="200" show-word-limit autosize resize="none" />
|
||
</div>
|
||
<div class="toggle-switch title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
<el-switch v-model="obj.has_vocal" class="ml-2" style="--el-switch-on-color: #fbd38d; --el-switch-off-color: #ffffff3d;" :active-value="false" :inactive-value="true" />
|
||
纯音乐
|
||
<el-popover placement="right" :width="150" trigger="click" content="没有歌词的音乐。">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
<div class="section model">
|
||
<div class="title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
音乐模型
|
||
<el-popover placement="right" :width="150" trigger="click" content="官方suno音乐模型">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
|
||
<el-select v-model="obj.mv" placeholder="选择模型" size="large" popper-class="model-select" :popper-append-to-body="false" :suffix-icon="triangleIcon">
|
||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</div>
|
||
<div class="creation-btn flexcenter" @click="creativeMusic()">创作</div>
|
||
</template>
|
||
<template v-else>
|
||
<div class="toggle-switch title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
<el-switch v-model="obj.has_vocal" style="--el-switch-on-color: #fbd38d; --el-switch-off-color: #ffffff3d;" :active-value="false" :inactive-value="true" @change="switchchange" />
|
||
纯音乐
|
||
<el-popover placement="right" :width="150" trigger="click" content="没有歌词的音乐。">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="lyric" v-if="obj.has_vocal">
|
||
<div class="title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
歌词
|
||
<el-popover placement="right" :width="300" trigger="click" content="随机生成歌词,自己写,或者从Al那里得到一些帮助。使用两首诗(8行)获得最佳效果。">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
<div class="title-right flexacenter">
|
||
<!-- <el-popover popper-class="type-popover" placement="right" :width="280" trigger="click" :teleported="false">
|
||
<div class="lyric-type flexflex">
|
||
<div class="lyric-type-item flexcenter" v-for="item in 7" :key="item">主歌</div>
|
||
</div>
|
||
<template #reference>
|
||
<div class="meta-tags flexcenter">添加元标签</div>
|
||
</template>
|
||
</el-popover> -->
|
||
</div>
|
||
</div>
|
||
|
||
<div class="lyric-content">
|
||
<el-input v-model="obj.prompt" class="lyric-input" maxlength="3000" style="width: 100%;" :rows="4" type="textarea" placeholder="请输入你的歌词" autosize resize="none" />
|
||
<div class="random-btn flexcenter" @click="lyricsGenerating()">
|
||
<img v-if="lyricsMonitorState" class="loading-icon" src="./assets/img/loading-icon.svg" />
|
||
<template v-else>{{ obj.prompt ? "AI优化歌词" : "生成歌词" }}</template>
|
||
</div>
|
||
<div class="numberwords">{{ obj.prompt.length }}/3000</div>
|
||
</div>
|
||
</div>
|
||
<div class="style">
|
||
<div class="title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
音乐风格
|
||
<el-popover placement="right" :width="300" trigger="click" content="描述你想要的音乐风格 例如:流行、摇滚、史诗。Suno的模型无法识别具体的艺人名称,但能理解音乐类型和氛围。">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
<div class="style-content">
|
||
<el-input v-model="obj.tags" class="style-input" maxlength="2000" style="width: 100%;" :rows="4" type="textarea" placeholder="输入音乐风格(英文)" autosize resize="none" />
|
||
<!-- <div class="random-btn flexcenter">选择音乐风格</div> -->
|
||
<div class="style-list">
|
||
<template v-for="item in stylelist">
|
||
<div :key="item" class="style-item" v-if="judgingExistence(item)" @click="addStyle(item)">{{ item }}</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="name">
|
||
<div class="title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
歌曲名称
|
||
<el-popover placement="right" trigger="click" content="为你的歌曲命名">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
|
||
<el-input class="name-input" v-model="obj.title" style="width: 300px;" maxlength="50" placeholder="请输入歌曲名称" />
|
||
</div>
|
||
<div class="section model">
|
||
<div class="title-box flexacenter">
|
||
<div class="title-left flexacenter">
|
||
音乐模型
|
||
<el-popover placement="right" :width="150" trigger="click" content="官方suno音乐模型">
|
||
<template #reference>
|
||
<img class="question-icon" src="./assets/img/question-icon.svg" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
|
||
<el-select v-model="obj.mv" placeholder="选择模型" size="large" style="width: 100%;" popper-class="model-select" :suffix-icon="triangleIcon">
|
||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</div>
|
||
<div class="creation-btn flexcenter" @click="creativeMusic()">创作</div>
|
||
</template>
|
||
<!-- <div class="flex1"></div> -->
|
||
<!-- <div class="user-box" v-if="islogin"> -->
|
||
<div class="user-box" v-if="false">
|
||
<img class="user-img" src="https://cdn1.suno.ai/defaultPink.jpg" />
|
||
<div class="user-text flex1">微信用户</div>
|
||
|
||
<el-popover popper-class="user-popover" placement="top" :width="300" trigger="click">
|
||
<div class="user-btn flexcenter" @click.stop="logOut()">退出登录</div>
|
||
<template #reference>
|
||
<div class="user-dot flexcenter">
|
||
<img class="user-dot-icon" src="./assets/img/dot.svg" />
|
||
</div>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
<div class="middle-box flex1">
|
||
<template v-if="list.length == 0">
|
||
<div class="nodata">暂无数据</div>
|
||
</template>
|
||
<template v-else>
|
||
<div class="list">
|
||
<div class="item flexflex" :class="{ 'sel': listIndex == index, 'playing': audioSrc == item.audio_url }" v-for="(item, index) in list" :key="index" @click="handleMusicList(index)">
|
||
<div class="progress-bar" v-if="item.status != 'complete'">生成中...</div>
|
||
<div class="img-box" @click="isPlaying && audioSrc == item.audio_url ? pauseAudio() : playAudio(index)">
|
||
<img v-if="item.image_url" class="img" :src="item.image_url" />
|
||
<img v-else class="img" src="https://suno.ansnid.com/attachment/Zvt57TuJSUvkyhw-xG7avCGHpt5oNTyM1Nwws44-UqaPEyOpLewjBmkLTe6SsJ5o8oxYDW_C7QrwtE0o7mQElMUC3lm6UrpsPr3ey21qvjUeOOPrNv6_QpsEVrOxyJ36niqc_cWN6UYoEk7POhf2DtewNDQyOQ~~" />
|
||
<div class="play flexcenter">
|
||
<img v-if="audioSrc == item.audio_url && isPlaying" class="suspend-btn" src="./assets/img/suspend.png" />
|
||
<img v-else class="play-btn" src="./assets/img/play-icon.png" />
|
||
</div>
|
||
</div>
|
||
<div class="content flexflex flex1">
|
||
<div class="name">{{ item.title }}</div>
|
||
<div class="desc">{{ item.tags || item?.metadata?.tags }}</div>
|
||
</div>
|
||
|
||
<div class="like-box flexcenter" @click.stop="handlelike(index)">
|
||
<img v-if="item.is_upvote == 1" class="like-icon" src="./assets/img/like-c-icon.png" />
|
||
<img v-else class="like-icon" src="./assets/img/like-icon.png" />
|
||
</div>
|
||
|
||
<el-popover popper-class="dot-popover" placement="bottom" :width="220" trigger="click" :teleported="false">
|
||
<div class="dot-list" @click.stop="">
|
||
<!-- <a class="dot-item" target="_parent" v-if="item.audio_url" :href="item.audio_url" :download="item.title + '.mp3'">下载MP3</a> -->
|
||
<a class="dot-item" target="_blank" v-if="item.audio_url" :href="item.audio_url">下载MP3</a>
|
||
<a class="dot-item" target="_blank" v-if="item.video_url" :href="item.video_url">下载视频</a>
|
||
<div class="dot-item" @click="generatingSimilar(index)">生成类似</div>
|
||
</div>
|
||
<template #reference>
|
||
<div class="dot flexcenter" @click.stop="">
|
||
<img class="dot-icon" src="./assets/img/dot.svg" />
|
||
</div>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
<!-- <div class="right-box" v-if="previewState"> -->
|
||
<div class="right-box flexflex">
|
||
<template v-if="JSON.stringify(songInfo) === '{}'">
|
||
<div class="nosong">选择要预览的歌曲。</div>
|
||
</template>
|
||
<template v-else>
|
||
<div class="song-info-box">
|
||
<div class="close flexcenter" @click="closeInfo()">
|
||
<img class="close-icon" src="./assets/img/icon12.svg" />
|
||
</div>
|
||
<img class="song-picture" :src="songInfo.image_large_url" />
|
||
<div class="song-info">
|
||
<div class="name">{{ songInfo.title }}</div>
|
||
<div class="desc" v-html="songInfo?.metadata?.tags"></div>
|
||
<div class="like-box flexcenter" @click.stop="handlelike(listIndex)">
|
||
<img v-if="songInfo.is_upvote == 0" class="like-icon" src="./assets/img/like-icon.png" />
|
||
<img v-else class="like-icon" src="./assets/img/like-c-icon.png" />
|
||
</div>
|
||
<div class="desc" v-html="songInfo?.metadata?.prompt"></div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<div class="register-box flexacenter" v-if="islogin">
|
||
<div class="register-text">Welcome!</div>
|
||
<div class="register-btn" @click.stop="logOut()">[退出登录]</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="base-bottom flexflex">
|
||
<div class="base-middle flexflex">
|
||
<div class="btn flexacenter">
|
||
<div class="btn-item btn-left flexcenter" @click="prevAudio()">
|
||
<img class="btn-icon" src="./assets/img/arrows-icon.svg" />
|
||
</div>
|
||
<div class="btn-item btn-centre flexcenter" @click="togglePlayPause()">
|
||
<img v-if="isPlaying" class="suspend" src="./assets/img/suspend-icon.svg" />
|
||
<img v-else class="suspend" src="./assets/img/play-icon.svg" />
|
||
</div>
|
||
<div class="btn-item btn-right flexcenter" @click="nextAudio()">
|
||
<img class="btn-icon" src="./assets/img/arrows-icon.svg" />
|
||
</div>
|
||
</div>
|
||
<div class="audio-box flexacenter">
|
||
<div class="time">{{ formatTime(currentTime) }}</div>
|
||
<el-slider class="progress-box" :show-tooltip="false" v-model="currentTime" :min="0" :max="duration" @change="seekAudio" />
|
||
<div class="time time-right">{{ formatTime(duration) }}</div>
|
||
</div>
|
||
<!-- <img class="cyclical-icon" src="./assets/img/loop.png" />
|
||
<img class="cyclical-icon" src="./assets/img/single.png" /> -->
|
||
</div>
|
||
</div>
|
||
|
||
<el-dialog class="wxlogin" v-model="wxloginVisible" width="480" :before-close="handleClose" align-center="true" :show-close="false">
|
||
<div class="wxlogin-box">
|
||
<div class="close-box">
|
||
<img class="close-icon" src="" />
|
||
</div>
|
||
<div class="wxlogin-title">微信登录</div>
|
||
<div class="qrcode-box flexcenter">
|
||
<img class="qrcode-img" :src="qrcode" />
|
||
<div class="lose-box flexcenter" v-if="wxloginQrcodeLose" @click="getLoginQrcode()">
|
||
二维码失效,点击重新获取
|
||
</div>
|
||
</div>
|
||
<div class="hint">扫码关注【SunoAI音乐创作工具】即可登录</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<audio ref="audio" @timeupdate="updateCurrentTime" @loadedmetadata="updateDuration" @ended="nextAudio" @play="updatePlayStatus" @pause="updatePlayStatus"></audio>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped lang="less">
|
||
audio {
|
||
display: none;
|
||
}
|
||
body {
|
||
background-color: #000;
|
||
}
|
||
|
||
.left-box {
|
||
width: 320px;
|
||
// height: calc(100vh - 69px);
|
||
height: 100vh;
|
||
overflow: auto;
|
||
padding: 10px;
|
||
background-color: #000;
|
||
// background-image: url("./assets/img/left-bj.svg");
|
||
background: -webkit-linear-gradient(289.179008025811deg, rgba(107, 77, 229, 1) 0%, rgba(144, 91, 212, 1) 38%, rgba(83, 37, 142, 1) 70%, rgba(47, 51, 145, 1) 100%);
|
||
background: -moz-linear-gradient(160.820991974189deg, rgba(107, 77, 229, 1) 0%, rgba(144, 91, 212, 1) 38%, rgba(83, 37, 142, 1) 70%, rgba(47, 51, 145, 1) 100%);
|
||
background: linear-gradient(160.820991974189deg, rgba(107, 77, 229, 1) 0%, rgba(144, 91, 212, 1) 38%, rgba(83, 37, 142, 1) 70%, rgba(47, 51, 145, 1) 100%);
|
||
// border-right: 1px solid #252323;
|
||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||
// height: calc(100vh - 69px);
|
||
position: relative;
|
||
z-index: 1;
|
||
// display: flex;
|
||
// flex-direction: column;
|
||
|
||
.left-bj {
|
||
&.left-bj1 {
|
||
top: 0;
|
||
height: 341px;
|
||
}
|
||
&.left-bj2 {
|
||
top: 341px;
|
||
height: 551px;
|
||
transform: rotate(180deg);
|
||
}
|
||
&.left-bj3 {
|
||
top: 892px;
|
||
}
|
||
position: fixed;
|
||
left: 0;
|
||
width: 319px;
|
||
// height: 440px;
|
||
z-index: -1;
|
||
}
|
||
|
||
.hemisphere-icon {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 80px;
|
||
height: 83px;
|
||
}
|
||
.logo {
|
||
width: 131px;
|
||
height: 32px;
|
||
margin: 20px auto 44px;
|
||
display: block;
|
||
}
|
||
.star {
|
||
z-index: -1;
|
||
position: absolute;
|
||
bottom: 10px;
|
||
left: 0;
|
||
width: 154px;
|
||
height: 158px;
|
||
left: 34px;
|
||
bottom: 63px;
|
||
}
|
||
.user-box {
|
||
display: flex;
|
||
align-items: center;
|
||
// padding: 4px;
|
||
padding-left: 10px;
|
||
margin-top: 10px;
|
||
margin-bottom: 10px;
|
||
.user-img {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
}
|
||
.user-text {
|
||
color: #fff;
|
||
font-size: 14px;
|
||
padding-left: 7px;
|
||
}
|
||
|
||
.user-dot {
|
||
padding: 0 12px;
|
||
min-width: 32px;
|
||
height: 32px;
|
||
cursor: pointer;
|
||
border-radius: 6px;
|
||
.user-dot-icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tab-box {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 5px;
|
||
height: 46px;
|
||
border: 1px solid rgba(255, 255, 255, 0.196078);
|
||
background: rgba(255, 255, 255, 0.0980392);
|
||
border-radius: 10px;
|
||
color: #adadad;
|
||
margin-bottom: 24px;
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
font-size: 18px;
|
||
height: 36px;
|
||
line-height: 36px;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
&:first-of-type {
|
||
margin-right: 5px;
|
||
}
|
||
&.sel {
|
||
color: #000;
|
||
background: -webkit-linear-gradient(344.577838681261deg, rgba(254, 233, 125, 1) 0%, rgba(231, 194, 91, 1) 49%, rgba(254, 140, 125, 1) 100%);
|
||
background: -moz-linear-gradient(105.422161318739deg, rgba(254, 233, 125, 1) 0%, rgba(231, 194, 91, 1) 49%, rgba(254, 140, 125, 1) 100%);
|
||
background: linear-gradient(105.422161318739deg, rgba(254, 233, 125, 1) 0%, rgba(231, 194, 91, 1) 49%, rgba(254, 140, 125, 1) 100%);
|
||
border: none;
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.description {
|
||
margin-bottom: 24px;
|
||
.title {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.description-input {
|
||
/deep/ .el-textarea__inner {
|
||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.196078) inset !important;
|
||
background: rgba(255, 255, 255, 0.0980392);
|
||
border-radius: 10px;
|
||
|
||
color: #fff;
|
||
min-height: 180px !important;
|
||
// max-height: 300px;
|
||
padding: 16px 13px;
|
||
}
|
||
/deep/ .el-input__count {
|
||
font-size: 13px;
|
||
color: rgba(255, 255, 255, 0.498039215686275);
|
||
background: transparent;
|
||
}
|
||
// min-height: 31px;
|
||
min-height: 94px;
|
||
width: 100%;
|
||
color: #ffffffeb;
|
||
line-height: 1.5;
|
||
border-radius: 4px;
|
||
}
|
||
}
|
||
|
||
.toggle-switch {
|
||
color: #fff;
|
||
font-size: 14px;
|
||
.el-switch {
|
||
margin-right: 10px;
|
||
}
|
||
margin-bottom: 24px !important;
|
||
}
|
||
|
||
.title-box {
|
||
margin-bottom: 10px;
|
||
justify-content: space-between;
|
||
|
||
.title-left {
|
||
font-size: 16px;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
.question-icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-left: 10px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/deep/ .el-popper {
|
||
font-size: 12px;
|
||
color: #fff;
|
||
}
|
||
}
|
||
.title-right {
|
||
.meta-tags {
|
||
width: 80px;
|
||
height: 28px;
|
||
color: rgb(204 204 204);
|
||
background-color: rgb(26 26 26);
|
||
font-size: 12px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
|
||
.model {
|
||
margin-bottom: 24px;
|
||
.title {
|
||
margin-bottom: 10px;
|
||
}
|
||
/deep/ .el-select__wrapper {
|
||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.196078) inset !important;
|
||
background: rgba(255, 255, 255, 0.0980392);
|
||
height: 40px;
|
||
line-height: 40px;
|
||
border-radius: 10px;
|
||
|
||
.el-select__selected-item {
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
// /deep/ .el-popper {
|
||
// .el-select-dropdown.model-select {
|
||
// .el-select-dropdown__item {
|
||
// color: #606266;
|
||
// &.is-selected {
|
||
// color: #fff;
|
||
// }
|
||
// &.is-hovering {
|
||
// background: #232426 !important;
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
}
|
||
|
||
.creation-btn {
|
||
padding: 0 16px;
|
||
cursor: pointer;
|
||
min-height: 44px;
|
||
height: 50px;
|
||
background: -webkit-linear-gradient(350.537677791974deg, rgba(254, 233, 125, 1) 0%, rgba(231, 194, 91, 1) 49%, rgba(254, 140, 125, 1) 100%);
|
||
background: -moz-linear-gradient(99.4623222080256deg, rgba(254, 233, 125, 1) 0%, rgba(231, 194, 91, 1) 49%, rgba(254, 140, 125, 1) 100%);
|
||
background: linear-gradient(99.4623222080256deg, rgba(254, 233, 125, 1) 0%, rgba(231, 194, 91, 1) 49%, rgba(254, 140, 125, 1) 100%);
|
||
border: none;
|
||
border-radius: 10px;
|
||
font-weight: 650;
|
||
font-size: 24px;
|
||
color: #000000;
|
||
}
|
||
|
||
.lyric {
|
||
.title-box {
|
||
.el-popper.type-popover {
|
||
.lyric-type {
|
||
justify-content: space-between;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
padding: 10px;
|
||
.lyric-type-item {
|
||
width: 72px;
|
||
height: 24px;
|
||
color: rgb(170 170 170);
|
||
cursor: pointer;
|
||
border-radius: 9999px;
|
||
border: 1px solid #aaa;
|
||
&:hover {
|
||
border-color: #ddd;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.lyric-content {
|
||
/deep/ .lyric-input {
|
||
.el-textarea__inner {
|
||
background: transparent;
|
||
box-shadow: none;
|
||
color: #fff;
|
||
min-height: 107px !important;
|
||
max-height: 300px;
|
||
padding: 16px 13px;
|
||
}
|
||
|
||
.el-input__count {
|
||
background: transparent;
|
||
}
|
||
}
|
||
padding-bottom: 7px;
|
||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.196078) inset !important;
|
||
// border: 1px solid rgba(255, 255, 255, 0.196078);
|
||
background: rgba(255, 255, 255, 0.0980392);
|
||
|
||
border-radius: 10px;
|
||
color: #adadad;
|
||
margin-bottom: 24px;
|
||
|
||
position: relative;
|
||
.numberwords {
|
||
position: absolute;
|
||
bottom: 6px;
|
||
right: 13px;
|
||
font-size: 13px;
|
||
color: rgba(255, 255, 255, 0.498039215686275);
|
||
}
|
||
}
|
||
}
|
||
|
||
.style {
|
||
.style-content {
|
||
/deep/ .style-input {
|
||
.el-textarea__inner {
|
||
background: transparent;
|
||
box-shadow: none;
|
||
min-height: 100px !important;
|
||
color: #fff;
|
||
max-height: 300px;
|
||
padding: 16px 13px;
|
||
}
|
||
}
|
||
padding-bottom: 5px;
|
||
// box-shadow: 0 0 0 1px #252323 inset !important;
|
||
// margin-bottom: 10px;
|
||
border: 1px solid rgba(255, 255, 255, 0.196078);
|
||
background: rgba(255, 255, 255, 0.0980392);
|
||
margin-bottom: 24px;
|
||
border-radius: 10px;
|
||
|
||
.style-list {
|
||
width: calc(100% - 12px);
|
||
display: flex;
|
||
overflow: auto;
|
||
white-space: pre;
|
||
margin: 0 6px;
|
||
box-sizing: border-box;
|
||
|
||
.style-item {
|
||
padding: 0 8px;
|
||
font-size: 14px;
|
||
color: #000000;
|
||
cursor: pointer;
|
||
border-radius: 10px;
|
||
height: 26px;
|
||
line-height: 26px;
|
||
background-color: rgba(255, 255, 255, 0.6);
|
||
margin-bottom: 8px;
|
||
|
||
&:not(:last-of-type) {
|
||
margin-right: 6px;
|
||
}
|
||
}
|
||
|
||
&::-webkit-scrollbar {
|
||
width: 13px;
|
||
height: 13px;
|
||
background-color: rgba(255, 255, 255, 0.6);
|
||
border-radius: 10px;
|
||
}
|
||
|
||
&::-webkit-scrollbar-thumb {
|
||
border-radius: 10px;
|
||
background-color: rgba(255, 255, 255, 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.random-btn {
|
||
// background: rgba(255, 255, 255, 0.16);
|
||
// width: 120px;
|
||
margin-left: 7px;
|
||
cursor: pointer;
|
||
// padding: 0 12px;
|
||
// min-width: 32px;
|
||
// height: 32px;
|
||
// border-radius: 6px;
|
||
// color: #fff;
|
||
// font-size: 12px;
|
||
width: 109px;
|
||
height: 36px;
|
||
background-color: rgba(255, 255, 255, 0.6);
|
||
// border: none;
|
||
border-radius: 10px;
|
||
font-size: 16px;
|
||
color: #000000;
|
||
.loading-icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
animation: rotate 1s linear infinite;
|
||
@keyframes rotate {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
100% {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.name {
|
||
margin-bottom: 24px;
|
||
|
||
.name-input {
|
||
/deep/ .el-input__wrapper {
|
||
// background: none;
|
||
// box-shadow: 0 0 0 1px #252323 inset !important;
|
||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.196078) inset !important;
|
||
background: rgba(255, 255, 255, 0.0980392);
|
||
height: 40px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
/deep/ .el-input__inner {
|
||
color: #fff;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/deep/ .el-popper {
|
||
background: rgb(25, 25, 26) !important;
|
||
border: none !important;
|
||
box-shadow: 0 0 0 1px #252323 inset !important;
|
||
|
||
&.is-light .el-popper__arrow:before {
|
||
border-color: #252323 !important;
|
||
background: rgb(25, 25, 26) !important;
|
||
}
|
||
}
|
||
|
||
.right-box {
|
||
width: 294px;
|
||
height: 100vh;
|
||
overflow: auto;
|
||
// height: calc(100vh - 69px);
|
||
overflow: auto;
|
||
position: relative;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
.song-info-box {
|
||
height: calc(100vh - 40px);
|
||
overflow: auto;
|
||
}
|
||
.nosong {
|
||
color: #a0aec0;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
padding-top: 40px;
|
||
}
|
||
|
||
.close {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 10px;
|
||
background-color: #fff3;
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.song-picture {
|
||
width: 100%;
|
||
}
|
||
.song-info {
|
||
font-size: 14px;
|
||
padding: 10px;
|
||
color: #fff;
|
||
overflow: auto;
|
||
|
||
.name {
|
||
line-height: 24px;
|
||
font-size: 14px;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.desc {
|
||
white-space: pre-line;
|
||
line-height: 24px;
|
||
// margin-bottom: 40px;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.like-box {
|
||
padding: 0 10px;
|
||
width: fit-content;
|
||
height: 32px;
|
||
cursor: pointer;
|
||
margin-bottom: 20px;
|
||
|
||
&:hover {
|
||
border-radius: 5px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
.like-icon {
|
||
width: 17px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.register-box {
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
height: 40px;
|
||
padding: 0 15px;
|
||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||
background-color: rgba(51, 51, 51, 1);
|
||
|
||
.register-text {
|
||
font-weight: 650;
|
||
font-size: 20px;
|
||
color: #8080ff;
|
||
}
|
||
|
||
.register-btn {
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
color: rgba(255, 255, 255, 0.498039215686275);
|
||
}
|
||
}
|
||
}
|
||
|
||
.middle-box {
|
||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||
// height: calc(100vh - 69px);
|
||
height: 100vh;
|
||
overflow: auto;
|
||
padding-top: 10px;
|
||
padding-bottom: 120px;
|
||
.nodata {
|
||
color: #a0aec0;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
padding-top: 40px;
|
||
}
|
||
|
||
.list {
|
||
.item {
|
||
padding-left: 30px;
|
||
padding-right: 30px;
|
||
margin-bottom: 10px;
|
||
cursor: pointer;
|
||
align-items: center;
|
||
&.sel,
|
||
&:hover {
|
||
background: radial-gradient(3010.06% 152.11% at 27.33% 38.98%, rgba(61, 58, 58, 0.43) 0%, rgba(25, 24, 24, 0.57) 100%) !important;
|
||
}
|
||
|
||
&.playing {
|
||
.img-box {
|
||
.play {
|
||
display: flex;
|
||
}
|
||
}
|
||
.content {
|
||
.name {
|
||
color: #e7c25b;
|
||
}
|
||
}
|
||
}
|
||
|
||
.img-box {
|
||
position: relative;
|
||
width: 80px;
|
||
height: 80px;
|
||
margin-right: 20px;
|
||
border-radius: 6px;
|
||
|
||
.img {
|
||
width: 80px;
|
||
height: 80px;
|
||
border-radius: 6px;
|
||
}
|
||
&:hover {
|
||
.play {
|
||
display: flex;
|
||
}
|
||
}
|
||
.suspend-box,
|
||
.play {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
.play-btn {
|
||
width: 36px;
|
||
}
|
||
|
||
.suspend-btn {
|
||
width: 46px;
|
||
}
|
||
}
|
||
|
||
.play {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
position: relative;
|
||
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(270deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0.8));
|
||
background-size: 300% 100%;
|
||
animation: gradientAnimation 5s linear infinite;
|
||
}
|
||
|
||
@keyframes gradientAnimation {
|
||
0% {
|
||
background-position: 0% 50%;
|
||
}
|
||
50% {
|
||
background-position: 100% 50%;
|
||
}
|
||
100% {
|
||
background-position: 0% 50%;
|
||
}
|
||
}
|
||
|
||
.content {
|
||
font-size: 14px;
|
||
line-height: 21px;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
margin-right: 10px;
|
||
.name {
|
||
font-weight: 700;
|
||
color: #fff;
|
||
word-break: break-word;
|
||
font-size: 18px;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
margin-bottom: 6px;
|
||
}
|
||
.desc {
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
word-break: break-all;
|
||
word-wrap: break-word;
|
||
white-space: normal;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.like-box {
|
||
padding: 0 10px;
|
||
height: 32px;
|
||
cursor: pointer;
|
||
&:hover {
|
||
border-radius: 5px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
.like-icon {
|
||
width: 17px;
|
||
}
|
||
}
|
||
|
||
.dot {
|
||
padding: 0 10px;
|
||
min-width: 32px;
|
||
height: 32px;
|
||
cursor: pointer;
|
||
&:hover {
|
||
border-radius: 5px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
.dot-icon {
|
||
widows: 16px;
|
||
height: 16px;
|
||
}
|
||
}
|
||
|
||
/deep/ .dot-popover {
|
||
padding: 0;
|
||
|
||
.dot-list {
|
||
padding: 5px 0;
|
||
.dot-item {
|
||
padding-left: 10px;
|
||
padding-right: 10px;
|
||
line-height: 30px;
|
||
cursor: pointer;
|
||
height: 30px;
|
||
font-size: 14px;
|
||
color: #fff;
|
||
display: block;
|
||
text-decoration: none;
|
||
&:hover {
|
||
background: radial-gradient(3010.06% 152.11% at 27.33% 38.98%, rgba(61, 58, 58, 0.43) 0%, rgba(25, 24, 24, 0.57) 100%);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.base-bottom {
|
||
background-color: rgb(22 22 22);
|
||
border: 1px solid rgba(255, 255, 255, 0.19);
|
||
// border-top: 1px solid #222222;
|
||
padding-left: 24px;
|
||
padding-right: 24px;
|
||
// padding-top: 24px;
|
||
height: 68px;
|
||
display: flex;
|
||
justify-content: center;
|
||
// align-items: center;
|
||
position: fixed;
|
||
bottom: 10px;
|
||
width: 540px;
|
||
height: 96px;
|
||
border-radius: 10px;
|
||
z-index: 10;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
|
||
.base-middle {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding-top: 18px;
|
||
margin-bottom: 6px;
|
||
.btn {
|
||
// margin-right: 24px;
|
||
|
||
.btn-item {
|
||
width: 36px;
|
||
height: 36px;
|
||
background: inherit;
|
||
background-color: rgba(255, 255, 255, 0.8);
|
||
border: none;
|
||
border-radius: 18px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
// &:hover {
|
||
// .el-icon {
|
||
// font-size: 30px;
|
||
// }
|
||
// }
|
||
|
||
.btn-icon {
|
||
width: 15px;
|
||
height: 16px;
|
||
}
|
||
|
||
&.btn-left {
|
||
.btn-icon {
|
||
transform: rotate(180deg);
|
||
}
|
||
}
|
||
|
||
&.btn-centre {
|
||
margin-left: 20px;
|
||
margin-right: 20px;
|
||
// background-color: #fbd38d;
|
||
background: transparent;
|
||
img {
|
||
width: 36px;
|
||
height: 36px;
|
||
// width: 20px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.audio-box {
|
||
position: relative;
|
||
margin-left: 16px;
|
||
margin-right: 16px;
|
||
.time {
|
||
top: -17px;
|
||
left: 0;
|
||
position: absolute;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-size: 14px;
|
||
&.time-right {
|
||
right: 0;
|
||
left: auto;
|
||
}
|
||
}
|
||
|
||
.progress-box {
|
||
width: 500px;
|
||
|
||
/deep/ .el-slider__runway {
|
||
height: 6px;
|
||
background-color: rgba(255, 255, 255, 0.803921568627451);
|
||
.el-slider__bar {
|
||
background: rgba(128, 128, 255, 1);
|
||
height: 6px;
|
||
}
|
||
}
|
||
/deep/ .el-slider__button {
|
||
border: none;
|
||
height: 16px;
|
||
width: 16px;
|
||
background: rgba(128, 128, 255, 1);
|
||
}
|
||
}
|
||
}
|
||
.cyclical-icon {
|
||
height: 14px;
|
||
margin-right: 5px;
|
||
margin: 0 12px;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
|
||
/deep/ .el-dialog {
|
||
border-radius: 10px;
|
||
color: #fff !important;
|
||
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||
background: rgb(25, 25, 26) !important;
|
||
padding: 16px;
|
||
.el-dialog__header {
|
||
display: none;
|
||
}
|
||
|
||
&.wxlogin {
|
||
.el-dialog__body {
|
||
.wxlogin-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
position: relative;
|
||
|
||
.close-box {
|
||
width: 0;
|
||
height: 0;
|
||
position: absolute;
|
||
top: 15px;
|
||
right: 15px;
|
||
}
|
||
|
||
.wxlogin-title {
|
||
color: #969595;
|
||
padding: 0 20px;
|
||
height: 40px;
|
||
margin-bottom: 10px;
|
||
line-height: 40px;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.qrcode-box {
|
||
width: 300px;
|
||
height: 300px;
|
||
position: relative;
|
||
.qrcode-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.lose-box {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
.hint {
|
||
margin-top: 20px;
|
||
margin-bottom: 20px;
|
||
color: rgb(204 204 204);
|
||
text-align: center;
|
||
}
|
||
|
||
.remark {
|
||
text-align: center;
|
||
font-size: 12px;
|
||
color: rgb(180 185 191);
|
||
a {
|
||
color: rgb(88 101 242);
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<style lang="less">
|
||
.el-popper {
|
||
background: rgb(25, 25, 26) !important;
|
||
border: none !important;
|
||
box-shadow: 0 0 0 1px #252323 inset !important;
|
||
font-size: 12px !important;
|
||
color: #fff !important;
|
||
|
||
&.is-light .el-popper__arrow:before {
|
||
border-color: #252323 !important;
|
||
background: rgb(25, 25, 26) !important;
|
||
border-left-color: transparent !important;
|
||
border-top-color: transparent !important;
|
||
}
|
||
}
|
||
|
||
.el-popper.model-select {
|
||
.el-select-dropdown__item {
|
||
color: #606266;
|
||
&.is-selected {
|
||
color: #fff;
|
||
}
|
||
&.is-hovering {
|
||
background: #232426 !important;
|
||
}
|
||
}
|
||
}
|
||
.user-popover {
|
||
.user-btn {
|
||
width: 100%;
|
||
height: 40px;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
margin-top: 12px;
|
||
margin-bottom: 8px;
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
.el-switch {
|
||
.el-switch__core {
|
||
height: 24px;
|
||
min-width: 48px;
|
||
border-radius: 48px;
|
||
.el-switch__action {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
}
|
||
|
||
&.is-checked .el-switch__core {
|
||
background: -webkit-linear-gradient(350.53767779deg, #fee97d 0%, #e7c25b 49%, #fe8c7d 100%);
|
||
background: -moz-linear-gradient(99.46232221deg, #fee97d 0%, #e7c25b 49%, #fe8c7d 100%);
|
||
background: linear-gradient(99.46232221deg, #fee97d 0%, #e7c25b 49%, #fe8c7d 100%);
|
||
border: none;
|
||
.el-switch__action {
|
||
left: calc(100% - 21px);
|
||
}
|
||
}
|
||
}
|
||
</style>
|