lcw
This commit is contained in:
@ -73,6 +73,13 @@ const searchConfiger = ref([
|
||||
placeholder: "请输入题目",
|
||||
showType: "input"
|
||||
},
|
||||
{
|
||||
label: "题目类型",
|
||||
prop: "type",
|
||||
placeholder: "请选择题目类型",
|
||||
showType: "select",
|
||||
options: D_BAXX_KTLX
|
||||
},
|
||||
]);
|
||||
|
||||
const queryFrom = ref({});
|
||||
@ -132,11 +139,11 @@ const getList = () => {
|
||||
let data = { ...pageData.pageConfiger, ...queryFrom.value };
|
||||
qcckPost(data, "/mosty-base/baxx/tkgl/page").then((res) => {
|
||||
console.log(res);
|
||||
|
||||
let arr = res.records || []
|
||||
arr.forEach(item => {
|
||||
item.correctAnswer = item.correctAnswer.split(',')
|
||||
item.correctAnswer =item.correctAnswer&&Array.isArray(item.correctAnswer) ? item.correctAnswer.join(',') : item.correctAnswer
|
||||
});
|
||||
console.log(arr);
|
||||
pageData.tableData = arr;
|
||||
pageData.total = res.total;
|
||||
pageData.tableConfiger.loading = false;
|
||||
|
||||
@ -0,0 +1,335 @@
|
||||
<template>
|
||||
<el-dialog v-model="modelValue" width="50%" :show-close="false" center :fullscreen="fullscreen">
|
||||
<!-- 使用title插槽替代header插槽,Element Plus中通常使用title插槽自定义标题 -->
|
||||
<template #title>
|
||||
<div class="dialog-header-content">
|
||||
<div class="dialog-title">{{ videoTitle }}</div>
|
||||
<div class="dialog-header-actions">
|
||||
<el-icon class="header-icon" @click="zoomBox"><FullScreen /></el-icon>
|
||||
<el-icon class="header-icon" @click="handleClose"><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="video-container">
|
||||
<!-- 视频播放区域 -->
|
||||
<div
|
||||
v-if="modelValue"
|
||||
ref="videoPlayerRef"
|
||||
class="video-player"
|
||||
:style="{ height: playerHeight }"
|
||||
>
|
||||
<video
|
||||
ref="videoRef"
|
||||
class="video-element"
|
||||
:src="url"
|
||||
controls
|
||||
autoplay
|
||||
muted
|
||||
playsinline
|
||||
preload="auto"
|
||||
@loadeddata="handleVideoLoaded"
|
||||
@error="handleVideoError"
|
||||
@stalled="handleVideoStalled"
|
||||
>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, onBeforeUnmount, nextTick, computed } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Loading } from '@element-plus/icons-vue';
|
||||
import {downFiles} from '@/api/instructCenter'
|
||||
// 定义组件属性
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 父组件传递的视频信息
|
||||
listQuery: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 视频标题
|
||||
videoTitle: {
|
||||
type: String,
|
||||
default: '测试'
|
||||
}
|
||||
});
|
||||
|
||||
// 定义组件事件
|
||||
const emit = defineEmits(['update:modelValue', 'close']);
|
||||
|
||||
// 响应式数据
|
||||
const videoPlayerRef = ref(null);
|
||||
const videoRef = ref(null);
|
||||
const player = ref(null);
|
||||
const loading = ref(false);
|
||||
const playing = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const playerHeight = ref('60vh');
|
||||
const fullscreen=ref(false);
|
||||
const videoMuted = ref(true);
|
||||
const url=ref('')
|
||||
// 计算属性:获取安全的视频源URL
|
||||
const getVideoSrc = () => {
|
||||
// 确保listQuery.fjid是字符串类型
|
||||
const fjid = JSON.parse(props.listQuery.fjid)?.map(item => item.id).join(',') || '';
|
||||
downFiles(fjid).then(res => {
|
||||
url.value=res.url
|
||||
});
|
||||
}
|
||||
// 监听对话框显示状态
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
if (newVal) {
|
||||
getVideoSrc()
|
||||
} else {
|
||||
// 对话框关闭时,销毁播放器
|
||||
destroyPlayer();
|
||||
}
|
||||
});
|
||||
|
||||
const zoomBox = () => {
|
||||
fullscreen.value = !fullscreen.value;
|
||||
playerHeight.value = fullscreen.value ? '89vh' : '60vh';
|
||||
};
|
||||
|
||||
|
||||
// 停止播放
|
||||
const stopPlay = () => {
|
||||
try {
|
||||
if (player.value) {
|
||||
// 实际项目中这里应该是播放器的停止方法
|
||||
// player.value.stop();
|
||||
playing.value = false;
|
||||
ElMessage.info('视频已停止');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('停止播放失败:', error);
|
||||
ElMessage.error('停止播放失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 销毁播放器
|
||||
const destroyPlayer = () => {
|
||||
try {
|
||||
if (player.value) {
|
||||
// 实际项目中这里应该是播放器的销毁方法
|
||||
// player.value.destroy();
|
||||
player.value = null;
|
||||
playing.value = false;
|
||||
loading.value = false;
|
||||
errorMessage.value = '';
|
||||
console.log('播放器已销毁');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('销毁播放器失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
stopPlay();
|
||||
emit('update:modelValue', false);
|
||||
emit('close');
|
||||
};
|
||||
|
||||
// 视频加载完成后的处理
|
||||
const handleVideoLoaded = () => {
|
||||
console.log('视频数据加载完成');
|
||||
if (videoRef.value) {
|
||||
// 尝试播放视频
|
||||
videoRef.value.play().then(() => {
|
||||
console.log('视频播放成功');
|
||||
playing.value = true;
|
||||
}).catch(error => {
|
||||
console.error('视频加载后自动播放失败:', error);
|
||||
// 显示用户提示
|
||||
ElMessage.warning('视频需要点击播放按钮开始播放');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 视频错误处理
|
||||
const handleVideoError = (event) => {
|
||||
console.error('视频加载错误:', event.target.error);
|
||||
errorMessage.value = `视频加载失败: ${getErrorMessage(event.target.error.code)}`;
|
||||
loading.value = false;
|
||||
ElMessage.error('视频加载失败,请检查网络或视频链接');
|
||||
};
|
||||
|
||||
// 视频卡顿处理
|
||||
const handleVideoStalled = () => {
|
||||
console.warn('视频加载卡顿,尝试重新加载');
|
||||
if (videoRef.value) {
|
||||
// 尝试重新加载视频
|
||||
videoRef.value.load();
|
||||
}
|
||||
};
|
||||
|
||||
// 获取错误消息
|
||||
const getErrorMessage = (errorCode) => {
|
||||
const errorMessages = {
|
||||
1: '用户中止了获取过程',
|
||||
2: '网络错误导致获取过程失败',
|
||||
3: '解码过程出错',
|
||||
4: '媒体格式不支持',
|
||||
5: '其他未知错误'
|
||||
};
|
||||
return errorMessages[errorCode] || '未知错误';
|
||||
};
|
||||
|
||||
// 切换静音状态
|
||||
const toggleMute = () => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.muted = !videoRef.value.muted;
|
||||
videoMuted.value = videoRef.value.muted;
|
||||
}
|
||||
};
|
||||
|
||||
// 组件卸载前清理
|
||||
onBeforeUnmount(() => {
|
||||
destroyPlayer();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
|
||||
padding: 12px 24px;
|
||||
margin: 0;
|
||||
border-bottom: 2px solid #409eff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 16px 24px 24px;
|
||||
background-color: #0a0a0a;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
// 头部内容样式
|
||||
.dialog-header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// 标题样式
|
||||
.dialog-title {
|
||||
color: #0b0b0b;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
// 头部操作按钮容器
|
||||
.dialog-header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
// 头部图标样式
|
||||
.header-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: #000000;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #409eff;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.video-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.video-player {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
border-radius: 8px;
|
||||
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
// 视频元素样式
|
||||
.video-element {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
background-color: #000;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
// 全屏状态下的样式增强
|
||||
:deep(.el-dialog--fullscreen) {
|
||||
.el-dialog__header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
margin-top: 60px; // 为固定头部留出空间
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.video-controls {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-top: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -24,6 +24,7 @@
|
||||
<el-link type="primary" link @click="addEdit('edit', row)">编辑</el-link>
|
||||
<el-link type="primary" link @click="addEdit('detail', row)">详情</el-link>
|
||||
<el-link type="danger" link @click="handleDelete([row.id])">删除</el-link>
|
||||
<el-link type="primary" @click="videoDisplays(row)">视频播放</el-link>
|
||||
</template>
|
||||
</MyTable>
|
||||
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
|
||||
@ -34,10 +35,12 @@
|
||||
<!-- 详情 -->
|
||||
<DetailForm ref="detailDiloag" @refresh="getList" />
|
||||
</div>
|
||||
<VideoDisplay v-model="showVideoDisplay" :videoTitle="videoTitle" :listQuery="videoDisplayData"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import PageTitle from "@/components/aboutTable/PageTitle.vue";
|
||||
import VideoDisplay from "./components/videoDisplay.vue";
|
||||
import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||
import Pages from "@/components/aboutTable/Pages.vue";
|
||||
import Search from "@/components/aboutTable/Search.vue";
|
||||
@ -45,6 +48,7 @@ import DetailForm from "./components/detailForm.vue";
|
||||
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
|
||||
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const showVideoDisplay = ref(false)
|
||||
const detailDiloag = ref();
|
||||
const searchBox = ref(); //搜索框
|
||||
const baseUrl = 'data:image/jpeg;base64,'
|
||||
@ -137,6 +141,14 @@ const tabHeightFn = () => {
|
||||
tabHeightFn();
|
||||
};
|
||||
};
|
||||
const videoDisplayData = ref();
|
||||
const videoTitle=ref('');
|
||||
// 视频播放
|
||||
const videoDisplays = (val) => {
|
||||
// videoTitle.value=val.spbt
|
||||
showVideoDisplay.value = true
|
||||
videoDisplayData.value = val
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user