- 修复文件上传暂停/恢复逻辑错误,调整播放状态与上传动作的对应关系 - 为视频上传添加半透明蒙层提升用户体验 - 移除上传管理中的冗余字段和注释代码 - 调整确认框标题的padding样式 - 添加消息重发确认功能
311 lines
7.0 KiB
Vue
311 lines
7.0 KiB
Vue
<script lang="ts" setup>
|
|
import 'xgplayer/dist/index.min.css'
|
|
import { ref, nextTick, watch } from 'vue'
|
|
import { NImage, NModal, NCard, NProgress, NPopconfirm } from 'naive-ui'
|
|
import { Play, Close, Pause, Right, Attention } from '@icon-park/vue-next'
|
|
import { getImageInfo } from '@/utils/functions'
|
|
import {PauseOutline} from '@vicons/ionicons5'
|
|
import Player from 'xgplayer'
|
|
import { ITalkRecordExtraVideo, ITalkRecord } from '@/types/chat'
|
|
import { useUploadsStore } from '@/store'
|
|
// @ts-ignore
|
|
const message = window.$message
|
|
|
|
const uploadsStore = useUploadsStore()
|
|
|
|
const props = defineProps<{
|
|
extra: ITalkRecordExtraVideo
|
|
data: ITalkRecord
|
|
maxWidth?: Boolean
|
|
}>()
|
|
|
|
// const img = (src: string, width = 200) => {
|
|
// const info: any = getImageInfo(src)
|
|
|
|
// if (info.width == 0 || info.height == 0) {
|
|
// return {}
|
|
// }
|
|
|
|
// if (info.height > 300) {
|
|
// return {
|
|
// height: '300px'
|
|
// }
|
|
// }
|
|
|
|
// if (info.width < width) {
|
|
// return {
|
|
// width: `${info.width}px`,
|
|
// height: `${info.height}px`
|
|
// }
|
|
// }
|
|
|
|
// return {
|
|
// width: width + 'px',
|
|
// height: info.height / (info.width / width) + 'px'
|
|
// }
|
|
// }
|
|
|
|
const open = ref(false)
|
|
const isPaused = ref(false)
|
|
const uploadFailed = ref(false)
|
|
|
|
// 查找上传项并检查状态
|
|
const updatePauseStatus = () => {
|
|
if (props.extra.is_uploading && props.extra.upload_id) {
|
|
// 使用新的查找方法
|
|
const item = uploadsStore.findItemByClientId(props.extra.upload_id)
|
|
|
|
if (item && item.is_paused !== undefined) {
|
|
isPaused.value = item.is_paused
|
|
}
|
|
}
|
|
}
|
|
|
|
// 初始化时检查状态
|
|
updatePauseStatus()
|
|
|
|
// // 监听关键道具变化
|
|
// watch(() => props.extra.percentage, (newVal: number | undefined) => {
|
|
// // 确保进度更新时 UI 也实时更新
|
|
// // 检测上传失败状态 (-1表示上传失败)
|
|
// if (newVal === -1) {
|
|
// uploadFailed.value = true
|
|
// // 显示上传失败提示
|
|
// message.error('视频发送失败,请点击红色感叹号重试')
|
|
// } else if (newVal !== undefined && newVal > 0) {
|
|
// uploadFailed.value = false
|
|
// }
|
|
// }, { immediate: true })
|
|
|
|
async function onPlay() {
|
|
// 如果视频正在上传,不执行播放操作
|
|
if (props.extra.is_uploading) {
|
|
return
|
|
}
|
|
|
|
open.value = true
|
|
|
|
await nextTick()
|
|
|
|
new Player({
|
|
id: 'im-xgplayer',
|
|
url: props.extra.url,
|
|
fluid: true,
|
|
autoplay: true,
|
|
lang: 'zh-cn'
|
|
})
|
|
}
|
|
|
|
// 暂停上传
|
|
function pauseUpload(e) {
|
|
e.stopPropagation()
|
|
if (props.extra.is_uploading && props.extra.upload_id) {
|
|
uploadsStore.pauseUpload(props.extra.upload_id)
|
|
isPaused.value = true
|
|
}
|
|
}
|
|
|
|
// 继续上传
|
|
function resumeUpload(e) {
|
|
console.log('resumeUpload')
|
|
e.stopPropagation()
|
|
if (props.extra.is_uploading && props.extra.upload_id) {
|
|
uploadsStore.resumeUpload(props.extra.upload_id)
|
|
isPaused.value = false
|
|
}
|
|
}
|
|
|
|
// 重新上传视频
|
|
// function retryUpload(e) {
|
|
// e.stopPropagation()
|
|
// if (props.extra.upload_id) {
|
|
// // 重置失败状态
|
|
// uploadFailed.value = false
|
|
|
|
// // 恢复上传
|
|
// uploadsStore.resumeUpload(props.extra.upload_id)
|
|
// message.success('正在重新上传视频...')
|
|
// }
|
|
// }
|
|
</script>
|
|
<template>
|
|
<section
|
|
class="im-message-video"
|
|
:class="{ left: data.float === 'left' }"
|
|
@click="onPlay"
|
|
>
|
|
|
|
<!-- <n-image :src="extra.cover" preview-disabled /> -->
|
|
<video :src="props.extra.url" :controls="false"></video>
|
|
<!-- 上传进度时的黑色半透明蒙层 -->
|
|
<div v-if="extra.is_uploading && !uploadFailed" class="upload-mask"></div>
|
|
<!-- 上传进度显示 -->
|
|
<div v-if="extra.is_uploading && !uploadFailed" class="upload-progress">
|
|
<n-progress
|
|
|
|
type="circle"
|
|
:percentage="Math.round(extra.percentage || 0)"
|
|
:show-indicator="false"
|
|
:stroke-width="6"
|
|
color="#fff"
|
|
rail-color="#E3E3E3"
|
|
/>
|
|
|
|
<!-- 暂停/继续按钮移到圆圈内部 -->
|
|
<div class="upload-control" @click.stop>
|
|
<n-icon
|
|
v-if="!isPaused"
|
|
class="control-btn"
|
|
:component="PauseOutline"
|
|
size="20"
|
|
@click="pauseUpload"
|
|
/>
|
|
<div v-else class="w-15px h-15px bg-#fff rounded-4px" @click="resumeUpload" >
|
|
|
|
</div>
|
|
<!-- <n-icon
|
|
v-else
|
|
class="control-btn"
|
|
:component="Right"
|
|
size="20"
|
|
@click="resumeUpload"
|
|
/> -->
|
|
</div>
|
|
</div>
|
|
<!-- 播放按钮,仅在视频不是上传状态且未失败时显示 -->
|
|
<div v-if="!extra.is_uploading && !uploadFailed" class="btn-video">
|
|
<n-icon :component="Play" size="40" />
|
|
</div>
|
|
|
|
<n-modal v-model:show="open">
|
|
<n-card
|
|
style="width: 800px; min-height: 300px; background-color: #ffffff; position: relative"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
>
|
|
<div id="im-xgplayer"></div>
|
|
<div class="im-xgplayer-close" @click="open = false">
|
|
<n-icon :component="Close" size="18" />
|
|
</div>
|
|
</n-card>
|
|
</n-modal>
|
|
</section>
|
|
</template>
|
|
<style lang="less" scoped>
|
|
.im-message-video {
|
|
overflow: hidden;
|
|
padding: 5px;
|
|
border-radius: 5px;
|
|
background: var(--im-message-left-bg-color);
|
|
min-width: 30px;
|
|
min-height: 30px;
|
|
display: inline-flex;
|
|
position: relative;
|
|
height:149px;
|
|
width: 225px;
|
|
&.left {
|
|
background: var(--im-message-right-bg-color);
|
|
}
|
|
|
|
video {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 5px;
|
|
object-fit: cover;
|
|
background-color: #333; /* 添加背景色,避免默认显示为灰色 */
|
|
}
|
|
|
|
.btn-video {
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
position: absolute;
|
|
cursor: pointer;
|
|
color: #ffffff;
|
|
}
|
|
|
|
&:hover {
|
|
.btn-video {
|
|
color: #03a9f4;
|
|
}
|
|
}
|
|
}
|
|
|
|
.im-xgplayer-close {
|
|
position: absolute;
|
|
height: 35px;
|
|
width: 35px;
|
|
background-color: #f5f5f5;
|
|
right: -45px;
|
|
top: -45px;
|
|
cursor: pointer;
|
|
border-radius: 50%;
|
|
color: #000;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.upload-mask {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.45);
|
|
z-index: 1;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.upload-progress {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 40px;
|
|
height: 40px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 2;
|
|
|
|
.upload-control {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
|
|
.control-btn {
|
|
color: white;
|
|
z-index: 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 上传失败样式 */
|
|
.upload-failed {
|
|
position: absolute;
|
|
left: 10px;
|
|
bottom: 10px;
|
|
z-index: 2;
|
|
|
|
.failed-icon {
|
|
width: 30px;
|
|
height: 30px;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
border-radius: 50%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
|
|
&:hover {
|
|
background-color: rgba(0, 0, 0, 0.9);
|
|
}
|
|
}
|
|
}
|
|
</style>
|