feat: dplayer
This commit is contained in:
@@ -6,7 +6,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"proxy": "node proxy.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.12.0",
|
"axios": "^1.12.0",
|
||||||
|
|||||||
73
proxy.js
73
proxy.js
@@ -8,6 +8,8 @@ const port = 3000;
|
|||||||
// 允许跨域请求
|
// 允许跨域请求
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
res.header('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Range');
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -18,22 +20,35 @@ app.get('/proxy', async (req, res) => {
|
|||||||
const targetUrl = req.query.url;
|
const targetUrl = req.query.url;
|
||||||
console.log('Fetching data from:', targetUrl);
|
console.log('Fetching data from:', targetUrl);
|
||||||
if (!targetUrl) {
|
if (!targetUrl) {
|
||||||
return res.status(400).send('URL parameter is required');
|
return res.status(400).json({ error: 'URL parameter is required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 设置请求头
|
// 设置请求头
|
||||||
const headers = {};
|
const headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||||||
|
};
|
||||||
if (req.headers.range) {
|
if (req.headers.range) {
|
||||||
headers['Range'] = req.headers.range; // 转发 Range 请求头
|
headers['Range'] = req.headers.range; // 转发 Range 请求头,支持视频分段加载
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向目标 URL 发起请求
|
// 向目标 URL 发起请求
|
||||||
const response = await fetch(targetUrl, { headers });
|
const response = await fetch(targetUrl, { headers });
|
||||||
|
|
||||||
|
// 检查响应状态
|
||||||
|
if (!response.ok) {
|
||||||
|
return res.status(response.status).json({
|
||||||
|
error: `Failed to fetch: ${response.statusText}`,
|
||||||
|
status: response.status
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 设置响应头
|
// 设置响应头
|
||||||
response.headers.forEach((value, key) => {
|
response.headers.forEach((value, key) => {
|
||||||
if (key !== 'content-encoding') { // 避免某些头信息导致问题
|
// 跳过一些可能导致问题的头信息
|
||||||
|
if (key.toLowerCase() !== 'content-encoding' &&
|
||||||
|
key.toLowerCase() !== 'transfer-encoding' &&
|
||||||
|
key.toLowerCase() !== 'connection') {
|
||||||
res.setHeader(key, value);
|
res.setHeader(key, value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -44,19 +59,55 @@ app.get('/proxy', async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将响应体直接流式传输给客户端
|
// 将响应体直接流式传输给客户端
|
||||||
response.body.pipe(res, { end: true });
|
if (response.body) {
|
||||||
|
response.body.pipe(res, { end: true });
|
||||||
|
|
||||||
// 错误处理
|
// 错误处理
|
||||||
response.body.on('error', (err) => {
|
response.body.on('error', (err) => {
|
||||||
console.error('Error during data transfer:', err);
|
console.error('Error during data transfer:', err);
|
||||||
res.status(500).send('Error during data transfer');
|
if (!res.headersSent) {
|
||||||
});
|
res.status(500).json({ error: 'Error during data transfer' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.status(500).json({ error: 'No response body' });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error('Error fetching data:', error);
|
||||||
res.status(500).send('Error fetching data');
|
|
||||||
|
// 根据错误类型返回更具体的错误信息
|
||||||
|
let errorMessage = 'Error fetching data';
|
||||||
|
let statusCode = 500;
|
||||||
|
let hostname = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
hostname = new URL(targetUrl).hostname;
|
||||||
|
} catch (e) {
|
||||||
|
hostname = 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.code === 'ENOTFOUND') {
|
||||||
|
errorMessage = `DNS解析失败:无法解析域名 "${hostname}"。请检查URL是否正确,或网络连接是否正常。`;
|
||||||
|
statusCode = 502;
|
||||||
|
} else if (error.code === 'ECONNREFUSED') {
|
||||||
|
errorMessage = `连接被拒绝:无法连接到目标服务器 "${hostname}"。`;
|
||||||
|
statusCode = 502;
|
||||||
|
} else if (error.code === 'ETIMEDOUT') {
|
||||||
|
errorMessage = `请求超时:目标服务器 "${hostname}" 响应时间过长。`;
|
||||||
|
statusCode = 504;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.status(statusCode).json({
|
||||||
|
error: errorMessage,
|
||||||
|
code: error.code,
|
||||||
|
targetUrl: targetUrl
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Proxy server running at http://localhost:${port}`);
|
console.log(`Proxy server running at http://localhost:${port}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
67
src/api/playroom.ts
Normal file
67
src/api/playroom.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { userInfoStore } from "@/store/user";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const userinfo = userInfoStore();
|
||||||
|
|
||||||
|
|
||||||
|
export const searchPlayRoom = async (inputValue: string) => {
|
||||||
|
const response = await axios.post('/api/playroom/search',{
|
||||||
|
r_name: inputValue
|
||||||
|
},{
|
||||||
|
headers:{
|
||||||
|
'Authorization': "Bearer " + userinfo.token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(response.data.code === "200"){
|
||||||
|
return response.data.data.records
|
||||||
|
} else {
|
||||||
|
console.error(response.data.msg)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createPlayroom = async (room_name: string) => {
|
||||||
|
const response = await axios.post('/api/playroom/create',{
|
||||||
|
r_name: room_name
|
||||||
|
},{
|
||||||
|
headers:{
|
||||||
|
'Authorization': "Bearer " + userinfo.token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(response.data.code === "200"){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPlayrooms = async ()=> {
|
||||||
|
const response = await axios.get('/api/playroom/get',{
|
||||||
|
headers:{
|
||||||
|
'Authorization' : `Bearer ${userinfo.token}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(response.data.code === "200"){
|
||||||
|
return response.data.data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const joinPlayroom = async (r_id: number) => {
|
||||||
|
const response = await axios.post('/api/inviting/playroom',{
|
||||||
|
inviter: userinfo.user.id,
|
||||||
|
target: userinfo.user.id,
|
||||||
|
status: 0,
|
||||||
|
room: r_id,
|
||||||
|
},{
|
||||||
|
headers:{
|
||||||
|
'Authorization': "Bearer " + userinfo.token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(response.data.code === "200"){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { userInfoStore } from "@/store/user";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const userinfo = userInfoStore();
|
|
||||||
|
|
||||||
|
|
||||||
export const searchPlayRoom = async (inputValue: string) => {
|
|
||||||
const response = await axios.post('/api/playroom/search',{
|
|
||||||
r_name: inputValue
|
|
||||||
},{
|
|
||||||
headers:{
|
|
||||||
'Authorization': "Bearer " + userinfo.token
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if(response.data.code === "200"){
|
|
||||||
return response.data.data
|
|
||||||
} else {
|
|
||||||
console.error(response.data.msg)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,8 @@ import DPlayer from 'dplayer';
|
|||||||
import Hls from 'hls.js';
|
import Hls from 'hls.js';
|
||||||
|
|
||||||
const videoRef = ref(null);
|
const videoRef = ref(null);
|
||||||
|
const player = ref(null);
|
||||||
|
const hlsInstance = ref(null);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
autoplay: { type: Boolean, default: false },
|
autoplay: { type: Boolean, default: false },
|
||||||
@@ -15,75 +17,208 @@ const props = defineProps({
|
|||||||
danmaku: { type: Object, default: () => ({}) }
|
danmaku: { type: Object, default: () => ({}) }
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
// 判断是否为 HLS 格式
|
||||||
const playerOptions = {
|
const isHlsUrl = (url) => {
|
||||||
|
return url.includes('.m3u8') || url.includes('hls') || url.includes('application/x-mpegURL');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清理 HLS 实例
|
||||||
|
const cleanupHls = () => {
|
||||||
|
if (hlsInstance.value) {
|
||||||
|
try {
|
||||||
|
hlsInstance.value.destroy();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('清理 HLS 实例时出错:', e);
|
||||||
|
}
|
||||||
|
hlsInstance.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建播放器配置
|
||||||
|
const createPlayerOptions = (url) => {
|
||||||
|
const proxyUrl = `/proxy?url=${encodeURIComponent(url)}`;
|
||||||
|
const isHls = isHlsUrl(url);
|
||||||
|
|
||||||
|
console.log('视频 URL:', url);
|
||||||
|
console.log('是否为 HLS 格式:', isHls);
|
||||||
|
console.log('代理 URL:', proxyUrl);
|
||||||
|
|
||||||
|
const options = {
|
||||||
container: videoRef.value,
|
container: videoRef.value,
|
||||||
autoplay: props.autoplay,
|
autoplay: props.autoplay,
|
||||||
video: {
|
video: {},
|
||||||
url: `/proxy?url=${encodeURIComponent(props.videoUrl)}`,
|
danmaku: props.danmaku
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isHls && Hls.isSupported()) {
|
||||||
|
// HLS 格式使用 customHls
|
||||||
|
options.video = {
|
||||||
|
url: proxyUrl,
|
||||||
type: 'customHls',
|
type: 'customHls',
|
||||||
customType: {
|
customType: {
|
||||||
customHls: function (video, player) {
|
customHls: function (video, player) {
|
||||||
if (Hls.isSupported()) {
|
cleanupHls(); // 清理旧的实例
|
||||||
const hls = new Hls();
|
|
||||||
hls.loadSource(video.src);
|
const hls = new Hls({
|
||||||
hls.attachMedia(video);
|
maxBufferLength: 20,
|
||||||
hls.config.maxBufferLength = 60; // 设置最大缓冲时间为60秒
|
maxMaxBufferLength: 60,
|
||||||
hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
enableWorker: true,
|
||||||
video.play();
|
lowLatencyMode: false
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
hlsInstance.value = hls;
|
||||||
|
|
||||||
|
hls.loadSource(video.src);
|
||||||
|
hls.attachMedia(video);
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||||
|
console.error('HLS 错误:', data);
|
||||||
|
if (data.fatal) {
|
||||||
|
switch (data.type) {
|
||||||
|
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||||
|
console.error('网络错误,尝试恢复...');
|
||||||
|
hls.startLoad();
|
||||||
|
break;
|
||||||
|
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||||
|
console.error('媒体错误,尝试恢复...');
|
||||||
|
hls.recoverMediaError();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('致命错误,无法恢复');
|
||||||
|
hls.destroy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
|
console.log('HLS 清单解析完成');
|
||||||
|
if (props.autoplay) {
|
||||||
|
video.play().catch(err => {
|
||||||
|
console.warn('自动播放失败:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
danmaku: props.danmaku
|
} else {
|
||||||
|
// 普通视频格式(MP4等)
|
||||||
|
options.video = {
|
||||||
|
url: proxyUrl,
|
||||||
|
type: 'auto' // 让 DPlayer 自动检测类型
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
onMounted(() => {
|
||||||
|
try {
|
||||||
|
const playerOptions = createPlayerOptions(props.videoUrl);
|
||||||
|
player.value = new DPlayer(playerOptions);
|
||||||
|
|
||||||
console.log(`/proxy?url=${encodeURIComponent(props.videoUrl)}`)
|
player.value.on('play', () => {
|
||||||
const player = new DPlayer(playerOptions);
|
console.log('播放:', props.videoUrl);
|
||||||
|
});
|
||||||
|
|
||||||
player.on('play', () => {
|
player.value.on('pause', () => {
|
||||||
console.log("播放...")
|
console.log('暂停');
|
||||||
})
|
});
|
||||||
player.on('pause', () => {
|
|
||||||
console.log("暂停...")
|
|
||||||
})
|
|
||||||
player.on('ended', () => {
|
|
||||||
console.log("结束...")
|
|
||||||
})
|
|
||||||
player.on('error', () => {
|
|
||||||
console.log("出错...")
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(() => props.videoUrl, (newUrl) => {
|
player.value.on('ended', () => {
|
||||||
if (player) {
|
console.log('播放结束');
|
||||||
console.log("切换视频...")
|
});
|
||||||
player.switchVideo({
|
|
||||||
url: `/proxy?url=${encodeURIComponent(newUrl)}`,
|
player.value.on('error', (error) => {
|
||||||
type: 'customHls',
|
console.error('播放器错误:', error);
|
||||||
customType: {
|
});
|
||||||
customHls: function (video, player) {
|
|
||||||
if (Hls.isSupported()) {
|
player.value.on('loadstart', () => {
|
||||||
const hls = new Hls();
|
console.log('开始加载视频');
|
||||||
|
});
|
||||||
|
|
||||||
|
player.value.on('canplay', () => {
|
||||||
|
console.log('视频可以播放');
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化播放器失败:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => props.videoUrl, (newUrl) => {
|
||||||
|
if (player.value && newUrl) {
|
||||||
|
console.log('切换视频到:', newUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
cleanupHls(); // 清理旧的 HLS 实例
|
||||||
|
|
||||||
|
const isHls = isHlsUrl(newUrl);
|
||||||
|
const proxyUrl = `/proxy?url=${encodeURIComponent(newUrl)}`;
|
||||||
|
|
||||||
|
if (isHls && Hls.isSupported()) {
|
||||||
|
// HLS 格式切换
|
||||||
|
player.value.switchVideo({
|
||||||
|
url: proxyUrl,
|
||||||
|
type: 'customHls',
|
||||||
|
customType: {
|
||||||
|
customHls: function (video, player) {
|
||||||
|
cleanupHls();
|
||||||
|
|
||||||
|
const hls = new Hls({
|
||||||
|
maxBufferLength: 20,
|
||||||
|
maxMaxBufferLength: 60,
|
||||||
|
enableWorker: true
|
||||||
|
});
|
||||||
|
|
||||||
|
hlsInstance.value = hls;
|
||||||
hls.loadSource(video.src);
|
hls.loadSource(video.src);
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
|
||||||
video.play();
|
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||||
|
console.error('HLS 错误:', data);
|
||||||
|
if (data.fatal) {
|
||||||
|
switch (data.type) {
|
||||||
|
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||||
|
hls.startLoad();
|
||||||
|
break;
|
||||||
|
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||||
|
hls.recoverMediaError();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hls.destroy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
})
|
} else {
|
||||||
|
// 普通视频格式切换
|
||||||
|
player.value.switchVideo({
|
||||||
|
url: proxyUrl,
|
||||||
|
type: 'auto'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('切换视频失败:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
});
|
||||||
|
|
||||||
// 销毁时清理播放器
|
// 销毁时清理播放器和 HLS 实例
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
player.destroy();
|
cleanupHls();
|
||||||
});
|
if (player.value) {
|
||||||
|
try {
|
||||||
|
player.value.destroy();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('销毁播放器时出错:', e);
|
||||||
|
}
|
||||||
|
player.value = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
38
src/store/playroom.ts
Normal file
38
src/store/playroom.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { ref } from "vue";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
interface PlayroomState {
|
||||||
|
id: number
|
||||||
|
r_id: number;
|
||||||
|
r_name: string;
|
||||||
|
r_introduction: string;
|
||||||
|
r_avatar: string;
|
||||||
|
role: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const PlayroomStore = defineStore("PlayroomStore",
|
||||||
|
() =>{
|
||||||
|
const currentPlayroom = ref<PlayroomState>();
|
||||||
|
const currentUrl = ref<string>("");
|
||||||
|
|
||||||
|
const setCurrentPlayroom = (playroom: PlayroomState) => {
|
||||||
|
currentPlayroom.value = playroom;
|
||||||
|
}
|
||||||
|
|
||||||
|
const setCurrentUrl = (url: string) => {
|
||||||
|
currentUrl.value = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearPlayroom = () => {
|
||||||
|
currentPlayroom.value = undefined;
|
||||||
|
currentUrl.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentPlayroom,
|
||||||
|
setCurrentPlayroom,
|
||||||
|
setCurrentUrl,
|
||||||
|
clearPlayroom,
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { ref } from "vue";
|
|
||||||
import { defineStore } from "pinia";
|
|
||||||
|
|
||||||
export const roomStore = defineStore("room",{
|
|
||||||
state: () => ({
|
|
||||||
r_id: '',
|
|
||||||
r_name: '',
|
|
||||||
r_avatar: '',
|
|
||||||
inroomTag: '',
|
|
||||||
currentURL: '',
|
|
||||||
}),
|
|
||||||
actions:{
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<el-table-column label="简介" prop="r_introduction"></el-table-column>
|
<el-table-column label="简介" prop="r_introduction"></el-table-column>
|
||||||
<el-table-column label="">
|
<el-table-column label="">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button @click="goToRoom(scope.row.r_id)">进入房间</el-button>
|
<el-button @click="goToRoom(scope.row)">进入房间</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<el-dialog v-model="createWindow" title="创建房间" style="width: 400px;height: 300px;">
|
<el-dialog v-model="createWindow" title="创建房间" style="width: 400px;height: 300px;">
|
||||||
<el-form ref="form" :model="formData" label-width="80px" @submit.prevent="createRoom">
|
<el-form ref="form" :model="formData" label-width="80px" @submit.prevent="createroom">
|
||||||
<el-form-item label="房间名" prop="roomName">
|
<el-form-item label="房间名" prop="roomName">
|
||||||
<el-input v-model="formData.roomName" placeholder="请输入房间名" clearable></el-input>
|
<el-input v-model="formData.roomName" placeholder="请输入房间名" clearable></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -39,14 +39,11 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
import { roomStore } from '@/store/room';
|
import { PlayroomStore } from '@/store/playroom';
|
||||||
import axios from 'axios';
|
|
||||||
import { userInfoStore } from '@/store/store';
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { getPlayrooms, createPlayroom } from '@/api/playroom';
|
||||||
|
|
||||||
const userinfo = userInfoStore()
|
const roominfo = PlayroomStore()
|
||||||
const roominfo = roomStore()
|
|
||||||
|
|
||||||
const createWindow = ref(false)
|
const createWindow = ref(false)
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
roomName: ''
|
roomName: ''
|
||||||
@@ -54,65 +51,45 @@ const formData = reactive({
|
|||||||
|
|
||||||
const rooms = ref([])
|
const rooms = ref([])
|
||||||
|
|
||||||
const goToRoom = (r_id) => {
|
const goToRoom = (r) => {
|
||||||
console.log(r_id)
|
roominfo.setCurrentPlayroom(r);
|
||||||
roominfo.r_id = r_id
|
|
||||||
// 跳转到房间页面
|
// 跳转到房间页面
|
||||||
const baseUrl = window.location.origin;
|
const baseUrl = window.location.origin;
|
||||||
const targetUrl = `${baseUrl}/room`; // 替换为你的目标路由
|
const targetUrl = `${baseUrl}/room`; // 替换为你的目标路由
|
||||||
window.open(targetUrl, "room");
|
window.open(targetUrl, "room");
|
||||||
};
|
};
|
||||||
|
|
||||||
const createRoom = async () => {
|
const createroom = async () => {
|
||||||
if (!formData.roomName || formData.roomName.trim() === '') {
|
if (!formData.roomName || formData.roomName.trim() === '') {
|
||||||
ElMessage.error('房间名不能为空')
|
ElMessage.error('房间名不能为空')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await axios.post('/api/room/create',{
|
if(await createPlayroom(formData.roomName)){
|
||||||
r_name: formData.roomName
|
ElMessage.success('创建成功')
|
||||||
},{
|
}else{
|
||||||
headers: {
|
ElMessage.error('创建失败')
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': userinfo.token
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if (response.data.code === 200) {
|
|
||||||
console.log(formData.roomName + '创建成功')
|
|
||||||
} else {
|
|
||||||
console.log(response.data.msg)
|
|
||||||
}
|
}
|
||||||
formData.roomName = ''
|
formData.roomName = ''
|
||||||
createWindow.value = false
|
createWindow.value = false
|
||||||
getRooms()
|
rooms.value = await getPlayrooms()
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRooms = async () => {
|
const getrooms = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/room/getrooms',{
|
rooms.value = await getPlayrooms()
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': userinfo.token
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if (response.data.code === 200) {
|
|
||||||
console.log(response.data.data)
|
|
||||||
rooms.value = response.data.data
|
|
||||||
} else {
|
|
||||||
console.log(response.data.msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.log(error)
|
ElMessage.error('获取房间列表失败' + error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getRooms()
|
getrooms()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<el-table-column prop="r_introduction" label="个性签名" width="200"></el-table-column>
|
<el-table-column prop="r_introduction" label="个性签名" width="200"></el-table-column>
|
||||||
<el-table-column>
|
<el-table-column>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button @click="joinRoom(scope.row.r_id)">加入房间</el-button>
|
<el-button @click="joinroom(scope.row.r_id)">加入房间</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -69,7 +69,7 @@ import { userInfoStore } from '@/store/user'
|
|||||||
import { onlineSocketStore } from '@/store/Online'
|
import { onlineSocketStore } from '@/store/Online'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { searchFriend,addFriend } from '@/api/friend'
|
import { searchFriend,addFriend } from '@/api/friend'
|
||||||
import { searchPlayRoom } from '@/api/room'
|
import { searchPlayRoom, joinPlayroom } from '@/api/playroom'
|
||||||
|
|
||||||
const socket = onlineSocketStore()
|
const socket = onlineSocketStore()
|
||||||
const inputValue = ref('')
|
const inputValue = ref('')
|
||||||
@@ -123,26 +123,16 @@ const addfriend = async (f_id) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//加入房间申请逻辑
|
//加入房间申请逻辑
|
||||||
const joinRoom = (r_id) => {
|
const joinroom = (r_id) => {
|
||||||
axios({
|
try{
|
||||||
headers: {
|
if(joinPlayroom(r_id)){
|
||||||
'Authorization': userinfo.token,
|
ElMessage.success("请求发送成功,请耐心等待审核")
|
||||||
},
|
return
|
||||||
url: '/api/inviting/sendinviting',
|
}
|
||||||
method: 'POST',
|
}catch(error){
|
||||||
data: {
|
ElMessage.error("加入房间失败:",error)
|
||||||
inviter: userinfo.user.u_id,
|
}
|
||||||
target: userinfo.user.u_id,
|
|
||||||
room: r_id
|
|
||||||
}
|
|
||||||
}).then((response) => {
|
|
||||||
if (response.data.code === 200) {
|
|
||||||
ElMessage.success("请求发送成功,请耐心等待审核")
|
|
||||||
}
|
|
||||||
else if (response.data.code === 500) {
|
|
||||||
ElMessage.error("请勿重复发送!")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<video-player :autoplay="false" :videoUrl="videoUrl" />
|
<video-player :autoplay="false" :videoUrl="currentURL" />
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-row style="height: 50%">
|
<el-row style="height: 50%">
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
<el-dialog title="设置/替换视频流" v-model="dialogVisibleVideo">
|
<el-dialog title="设置/替换视频流" v-model="dialogVisibleVideo">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="20">
|
||||||
<el-input v-model="curruentRoomInfo.currentURL" placeholder="请输入视频流地址"></el-input>
|
<el-input v-model="changingVideoUrl" placeholder="请输入视频流地址"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-button>测试</el-button>
|
<el-button>测试</el-button>
|
||||||
@@ -159,12 +159,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watchEffect } from 'vue';
|
import { onMounted, ref, watchEffect } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { userInfoStore } from '@/store/store';
|
import { userInfoStore } from '@/store/user';
|
||||||
import videoPlayer from '@/components/videoPlayer.vue';
|
import videoPlayer from '@/components/videoPlayer.vue';
|
||||||
import { roomStore } from '@/store/room';
|
import { PlayroomStore } from '@/store/playroom';
|
||||||
|
|
||||||
//import audioPlayer from '@/components/audioPlayer.vue'; // 假设你有一个音频播放组件
|
//import audioPlayer from '@/components/audioPlayer.vue'; // 假设你有一个音频播放组件
|
||||||
|
|
||||||
const curruentRoomInfo = roomStore();
|
const curruentRoomInfo = PlayroomStore();
|
||||||
const userinfo = userInfoStore();
|
const userinfo = userInfoStore();
|
||||||
|
|
||||||
const dialogVisibleCode = ref(false)
|
const dialogVisibleCode = ref(false)
|
||||||
@@ -175,6 +176,8 @@ const drawer = ref(false);
|
|||||||
const role = ref(null);
|
const role = ref(null);
|
||||||
const invitingCode = ref('666666')
|
const invitingCode = ref('666666')
|
||||||
|
|
||||||
|
const changingVideoUrl = ref('')
|
||||||
|
|
||||||
const currentURL = ref('https://www.5dm.link/api/dd.php?vid=ccccxhndnys1&cid=ccccxhndnys1&xid=0&pid=55293&tid=1742788904&t=616d5131b6ade51a0e20814466b13515&ext=.mp4')
|
const currentURL = ref('https://www.5dm.link/api/dd.php?vid=ccccxhndnys1&cid=ccccxhndnys1&xid=0&pid=55293&tid=1742788904&t=616d5131b6ade51a0e20814466b13515&ext=.mp4')
|
||||||
const avatar = ref(null)
|
const avatar = ref(null)
|
||||||
const avatarPreview = ref('')
|
const avatarPreview = ref('')
|
||||||
@@ -333,7 +336,7 @@ const getInvitingCode = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const replaceURL = () => {
|
const replaceURL = () => {
|
||||||
currentURL.value = curruentRoomInfo.currentURL;
|
currentURL.value = changingVideoUrl.value;
|
||||||
dialogVisibleVideo.value = false;
|
dialogVisibleVideo.value = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -365,7 +368,7 @@ onMounted(() => {
|
|||||||
//测试代码
|
//测试代码
|
||||||
curruentRoomInfo.r_id = '123456';
|
curruentRoomInfo.r_id = '123456';
|
||||||
curruentRoomInfo.r_name = '弹幕聊天室';
|
curruentRoomInfo.r_name = '弹幕聊天室';
|
||||||
curruentRoomInfo.currentURL = 'https://www.5dm.link/api/dd.php?vid=ccccxhndnys1&cid=ccccxhndnys1&xid=0&pid=55293&tid=1742788904&t=616d5131b6ade51a0e20814466b13515&ext=.mp4';
|
curruentRoomInfo.setCurrentUrl('https://www.5dm.link/api/dd.php?vid=ccccxhndnys1&cid=ccccxhndnys1&xid=0&pid=55293&tid=1742788904&t=616d5131b6ade51a0e20814466b13515&ext=.mp4')
|
||||||
curruentRoomInfo.r_avatar = 'https://merlin.xin/avatars/avatar';
|
curruentRoomInfo.r_avatar = 'https://merlin.xin/avatars/avatar';
|
||||||
role.value = 0;
|
role.value = 0;
|
||||||
avatarPreview.value = curruentRoomInfo.r_avatar;
|
avatarPreview.value = curruentRoomInfo.r_avatar;
|
||||||
|
|||||||
Reference in New Issue
Block a user