Files
PC-official/static/js/index.js
DESKTOP-RQ919RC\Pc 0e0d977c3b style(css): 优化播放按钮和标签的样式设计
简化播放按钮的样式实现,移除冗余的伪元素,改用box-shadow实现边框效果
统一标签的圆角半径和背景色,移除注释掉的代码
调整播放按钮点击逻辑,当playurl不存在时自动获取播放链接
2025-09-19 19:18:28 +08:00

517 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { createApp, ref, onMounted, nextTick, onUnmounted, computed } = Vue;
const search = createApp({
setup() {
const trait = [
{
icon: "./static/img/headset-icon.png",
title: "音乐创作",
text: "朴见潮音2024 年成立于广州,是专注 AI 音乐领域的创新工作室。短短一年便跻身于AI音乐浪潮先锋品牌",
},
{
icon: "./static/img/mv-icon.png",
title: "MV创作",
text: "以 AI 技术为核心整合音乐创作、MV 制作、教学培训、发行级重制等业务,为创作者和爱好者打造一站式平台。",
},
{
icon: "./static/img/train-icon.png",
title: "教学培训",
text: "工作室运用多种 AI 工具,突破传统创作局限,支持流行、摇滚等多元风格创作,满足个性化需求。",
},
{
icon: "./static/img/remake-icon.png",
title: "发行级重制",
text: "构建全流程服务体系,从 AI 音乐创作、MV 视觉呈现,到零基础教学,再到发行级重制提升品质,实现作品价值最大化。",
},
];
const audioPlayer = ref(null);
const progress = ref(0); // 播放进度百分比
// 响应式变量存储当前播放时间和总时长
const currentTimeFormatted = ref("00:00");
const durationFormatted = ref("00:00");
// 格式化时间函数:将秒数转换为 MM:SS 格式
const formatTime = (seconds) => {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
};
// 更新进度的函数
const getProgress = () => {
if (!audioPlayer.value) return;
const currentTime = audioPlayer.value.currentTime || 0;
const duration = audioPlayer.value.duration || 0;
const p = duration > 0 ? (currentTime / duration) * 100 : 0;
setProgress(p, audioPlayer.value.src);
progress.value = p;
// 更新时间显示
currentTimeFormatted.value = formatTime(currentTime);
durationFormatted.value = formatTime(duration);
};
const setProgress = (val, src) => {
awardAudioList.value.forEach((item) => {
if (item.playurl == src) item.progress = val;
});
customList.value.forEach((item) => {
if (item.playurl == src) item.progress = val;
});
studentList.value.forEach((item) => {
if (item.playurl == src) item.progress = val;
});
if (zeroOrderStudents.value?.playurl == src) {
zeroOrderStudents.value["progress"] = val;
}
};
const introduceRef = ref(null);
const worksRef = ref(null);
const customRef = ref(null);
const studentRef = ref(null);
let pointerIndex = ref(0);
const albumBoxRef = ref(null);
// 点击侧边栏
const changePointer = (index) => {
albumBoxRef.value.scrollTo({ top: 448 * index, behavior: "smooth" });
pointerIndex.value = index;
};
// 向上滚动到上一页
const scrollToPrevious = () => {
let index = pointerIndex.value - 1;
if (index < 0) return;
changePointer(index);
};
// 向下滚动到下一页
const scrollToNext = () => {
let index = pointerIndex.value + 1;
if (index > bannerList.value.length) return;
changePointer(index);
};
// 获取当前在可视窗口中的元素ref
const visibleRef = computed(() => {
const visibleElement = elements.value.find((el) => el.isVisible);
return visibleElement ? visibleElement.ref : null;
});
let bannerList = ref([]);
let awardMVList = ref([]);
let awardAudioList = ref([]);
const init = () => {
ajax("https://pujianchaoyin.com/api/getHomeData").then((res) => {
// ajax("https://pujianchaoyin.com/index/api").then((res) => {
if (res.code != 200) return;
const data = res.data;
console.log("data", data);
bannerList.value = data.banner;
awardMVList.value = data.awardMVList;
data.awardAudioList.forEach((item, index) => {
item["playurl"] = `https://app.gter.net/image/miniApp/mp3/${index + 1}.mp3`;
});
awardAudioList.value = data.awardAudioList;
customList.value = data.customAudioList;
studentList.value = data.studentList || [];
studentList.value.forEach((item, index) => {
item["order"] = index;
});
zeroOrderStudents.value = studentList.value[0];
nextTick(() => bannerSwiper());
});
};
let bannerSwiperTimer = null;
// 头部轮播图 定时器
const bannerSwiper = () => {
clearTimeout(bannerSwiperTimer);
bannerSwiperTimer = setTimeout(() => {
let index = pointerIndex.value + 1;
if (index > bannerList.value.length - 1) index = 0;
changePointer(index);
bannerSwiper();
}, 3000);
};
// 头部轮播图 - 切换 定时器
const changeInterval = (type) => {
if (type) clearTimeout(bannerSwiperTimer);
else bannerSwiper();
};
onMounted(() => {
init();
// 添加进度更新事件监听器
if (audioPlayer.value) {
volume.value = audioPlayer.value.volume * 100;
audioPlayer.value.addEventListener("timeupdate", getProgress);
audioPlayer.value.addEventListener("loadedmetadata", getProgress);
}
});
// 组件卸载时清理事件监听器
onUnmounted(() => {
audioPlayer?.value?.removeEventListener("timeupdate", getProgress);
audioPlayer?.value?.removeEventListener("loadedmetadata", getProgress);
});
// 播放 组件状态
let previewState = ref(false);
let art = null;
// 开启播放 MV
const openPreview = (id) => {
closeAll();
ajax("https://pujianchaoyin.com/api/getMvDetail", {
id,
}).then((res) => {
if (res.code != 200) return;
const data = res.data;
previewState.value = true;
nextTick(() => {
art = new Artplayer({
container: ".artplayer-app",
url: data.playurl,
autoplay: true,
poster: data.img || "",
fullscreen: true,
});
art.play();
});
});
};
// 关闭播放 MV
const closePreview = () => {
previewState.value = false;
art?.destroy();
art = null;
};
// 快进 和 后退 10秒
const fastForward = (type = "fast") => {
if (!audioPlayer.value) return;
const src = playData.value?.playurl || "";
const area = playData.value?.area || "";
if (audioPlayer.value.src != src) {
manageAudio(src, area);
return;
}
let currentTime = audioPlayer.value.currentTime || 0;
const duration = audioPlayer.value.duration || 0;
let newTime = 0;
if (type == "fast") newTime = Math.min(currentTime + 10, duration);
else newTime = Math.max(currentTime - 10, 0);
audioPlayer.value.currentTime = newTime;
getProgress();
};
// 播放 组件数据
let playData = ref(null);
// 管理音频播放
const manageAudio = (src, area) => {
const audio = audioPlayer.value;
closeAll();
setTimeout(() => {
if (audio?.src != src) audio.src = src;
audio.play().then(() => {
if (area == "works") {
awardAudioList.value.forEach((item) => {
if (item.playurl == src) {
item["state"] = true;
playData.value = { ...item, area };
}
});
}
if (area == "custom") {
customList.value.forEach((item) => {
if (item.playurl == src) {
item["state"] = true;
playData.value = { ...item, area };
}
});
}
if (area == "student") {
zeroOrderStudents.value["state"] = true;
playData.value = { ...zeroOrderStudents.value, area };
}
});
}, 500);
};
// 重新播放
const rePlay = () => {
if (!playData.value) return;
const { playurl, area } = playData.value;
manageAudio(playurl, area);
};
// 关闭所有播放
const closeAll = () => {
audioPlayer.value.pause();
awardAudioList.value.forEach((item) => {
item["state"] = false;
});
customList.value.forEach((item) => {
item["state"] = false;
});
zeroOrderStudents.value["state"] = false;
playData.value && (playData.value.state = false);
};
// 定制音乐 数据
let customList = ref([]);
let studentList = ref([]); // 学生数据
let studentIndex = ref(0); // 学生下标
let zeroOrderStudents = ref({}); // 学生 选中播放 数据
// 切换学生 播放
const cutStudent = (index) => {
// 找到目标元素和第一个元素
const [target, first] = [studentList.value[index], studentList.value.find((item) => item.order == 0)];
// 交换order值
if (target && first && target !== first) [target.order, first.order] = [first.order, target.order];
zeroOrderStudents.value = target;
studentIndex.value = index;
target.playurl ? manageAudio(target.playurl, "student") : getPlayUrl(0, "student");
};
// 切换学生 歌曲 上\下一首
const cutSong = (type) => {
const listLength = studentList.value.length;
const index = studentIndex.value;
let newIndex = 0;
if (type === "up") newIndex = index - 1 < 0 ? listLength - 1 : index - 1;
else if (type === "down") newIndex = index + 1 >= listLength ? 0 : index + 1;
cutStudent(newIndex);
};
// 响应式数据:音量值、是否静音
let volume = ref(100);
// 计算并设置音量百分比
const setVolumePercentage = (percentage) => {
const volumePercent = Math.max(0, Math.min(100, percentage));
volume.value = Math.abs(~~volumePercent);
// 设置音频元素的音量范围是0-1
if (audioPlayer.value) audioPlayer.value.volume = volume.value / 100;
};
// 处理音量进度条点击
const handleVolumeClick = (event) => {
// 获取进度条元素
const progressBar = event.currentTarget;
const rect = progressBar.getBoundingClientRect();
const clickPosition = rect.bottom - event.clientY;
const percentage = (clickPosition / rect.height) * 100;
setVolumePercentage(percentage);
};
let volumeShow = ref(false);
// 处理音量进度条拖拽
let isDragging = false;
const startDrag = (event) => {
isDragging = true;
handleVolumeDrag(event);
// 添加事件监听器
document.addEventListener("mousemove", handleVolumeDrag);
document.addEventListener("mouseup", stopDrag);
};
const handleVolumeDrag = (event) => {
if (!isDragging) return;
// 获取音量进度条元素
const progressBar = document.querySelector(".sound-control .progress");
if (!progressBar) return;
const rect = progressBar.getBoundingClientRect();
// 计算拖拽位置相对于进度条的比例
let dragPosition = rect.bottom - event.clientY;
// 限制在进度条范围内
dragPosition = Math.max(0, Math.min(dragPosition, rect.height));
const percentage = (dragPosition / rect.height) * 100;
setVolumePercentage(percentage);
};
const stopDrag = () => {
isDragging = false;
document.removeEventListener("mousemove", handleVolumeDrag);
document.removeEventListener("mouseup", stopDrag);
};
const handleVolumeShow = () => (volumeShow.value = true);
const handleVolumeHide = () => (volumeShow.value = false);
onUnmounted(() => {
// 确保移除所有拖拽相关事件
document.removeEventListener("mousemove", handleVolumeDrag);
document.removeEventListener("mouseup", stopDrag);
document.removeEventListener("mousemove", handleBarDragBottomDrag);
document.removeEventListener("mouseup", stopBarDragBottom);
});
const ajax = (url, data = {}) => {
if (["localhost", "127.0.0.1"].includes(location.hostname)) data["authorization"] = "3338bf6a2e53dda872da3664a2560b25";
return new Promise(function (resolve, reject) {
axios
.post(url, data, {
emulateJSON: true,
withCredentials: true,
})
.then(function (res) {
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
resolve(data);
});
});
};
const ajaxget = (url, data) => {
if (!data) data = {};
if (["localhost", "127.0.0.1"].includes(location.hostname)) data["authorization"] = "3338bf6a2e53dda872da3664a2560b25";
return new Promise((resolve, reject) => {
axios
.get(url, {
emulateJSON: true,
withCredentials: true,
})
.then((res) => {
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
resolve(data);
});
});
};
// 处理音量进度条拖拽
let isBarBottomDragging = false;
const startBarDragBottom = (event) => {
isBarBottomDragging = true;
handleBarDragBottomDrag(event);
// 添加事件监听器
document.addEventListener("mousemove", handleBarDragBottomDrag);
document.addEventListener("mouseup", stopBarDragBottom);
};
const stopBarDragBottom = () => {
isBarBottomDragging = false;
document.removeEventListener("mousemove", handleBarDragBottomDrag);
document.removeEventListener("mouseup", stopBarDragBottom);
};
// 直接点击进度条 跳转
const handleBarDragBottomClick = (event) => {
// 获取进度条元素
const progressBar = event.currentTarget;
const rect = progressBar.getBoundingClientRect();
const clickPosition = event.clientX - rect.left;
const percentage = clickPosition / rect.width;
// 限制百分比在0-100之间
const clampedPercentage = Math.max(0, Math.min(100, percentage));
updatePlay(clampedPercentage);
};
const handleBarDragBottomDrag = (event) => {
if (!isBarBottomDragging) return;
// 获取音量进度条元素
const progressBar = document.querySelector(".bottom-play .middle .progress-bar");
if (!progressBar) return;
const rect = progressBar.getBoundingClientRect();
// 计算拖拽位置相对于进度条的比例
let dragPosition = event.clientX - rect.left;
// 限制在进度条范围内
dragPosition = Math.max(0, Math.min(dragPosition, rect.width));
const percentage = dragPosition / rect.width;
updatePlay(percentage);
};
const updatePlay = (percentage) => {
if (!audioPlayer.value) return;
const duration = audioPlayer.value.duration || 0;
let newTime = duration * percentage;
newTime = Math.max(0, Math.min(duration, newTime));
audioPlayer.value.currentTime = newTime;
getProgress();
};
const getPlayUrl = (index, area) => {
let id = null;
if (area == "student") {
const item = zeroOrderStudents.value;
id = item.id;
}
if (area == "custom") {
const item = customList.value[index];
id = item.id;
}
ajax("https://pujianchaoyin.com/api/getMusicDetail", {
id,
}).then((res) => {
if (res.code != 200) return;
const data = res.data;
if (area == "student") {
zeroOrderStudents.value = { ...data, ...zeroOrderStudents.value };
manageAudio(data.playurl, area);
}
if (area == "custom") {
customList.value[index] = { ...data, ...customList.value[index] };
manageAudio(data.playurl, area);
}
});
};
return { cutSong, getPlayUrl, handleBarDragBottomClick, startBarDragBottom, volumeShow, handleVolumeHide, handleVolumeShow, zeroOrderStudents, rePlay, playData, awardAudioList, changeInterval, awardMVList, bannerList, albumBoxRef, volume, handleVolumeClick, handleVolumeDrag, startDrag, stopDrag, volume, cutStudent, studentList, studentIndex, scrollToPrevious, scrollToNext, changePointer, pointerIndex, visibleRef, studentRef, customRef, formatTime, currentTimeFormatted, durationFormatted, worksRef, introduceRef, customList, closeAll, manageAudio, progress, closePreview, openPreview, previewState, audioPlayer, trait, fastForward };
},
}).mount("#appIndex");