ow
This commit is contained in:
1 parent
7c8af2fb08
commit
c10f8347e2
31 files changed
+358
-292
No files matched your search
@@ -219,7 +219,7 @@ const requestChunk = async (
|
||||
percent: percentBefore,
|
||||
current: index,
|
||||
total: chunks.length,
|
||||
text: `网络异常,正在重试(${attempt + 1}/${retries})...`,
|
||||
text: `网络异常,正在重试(${attempt + 1}/${retries})... ${percentBefore}%`,
|
||||
});
|
||||
await sleep(props.retryDelay * Math.pow(2, attempt));
|
||||
}
|
||||
@@ -262,10 +262,11 @@ const uploadChunk = async (
|
||||
percent,
|
||||
current: index,
|
||||
total: chunks.length,
|
||||
// 单文件、多文件都统一用百分比(按字节算的整体进度),不再显示「第几片/共几片」
|
||||
text:
|
||||
progress.fileCount > 1
|
||||
? `上传中(第 ${progress.fileNo}/${progress.fileCount} 个,分片 ${index}/${chunks.length}) ${percent}%`
|
||||
: `上传中(${index}/${chunks.length})...`,
|
||||
? `上传中(第 ${progress.fileNo}/${progress.fileCount} 个) ${percent}%`
|
||||
: `上传中 ${percent}%`,
|
||||
});
|
||||
|
||||
if (index < chunks.length) {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
<template v-else-if="isVideo(record.OrderKey)">
|
||||
<div class="video-thumb">
|
||||
<img :src="record.FormattedPic" :title="record.OrgFileName" />
|
||||
<img :src="record.FormattedPic" :title="record.OrgFileName" @error="retryImage($event)" />
|
||||
<div class="play-overlay">
|
||||
<PlayCircleOutlined />
|
||||
</div>
|
||||
@@ -109,6 +109,7 @@ import {
|
||||
AppstoreOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { DmsFileUploadViewDisplayData } from "@/data/auto/dmsFileUploadViewDisplayData";
|
||||
import { retryImage } from "@/utils/imageRetry";
|
||||
|
||||
const props = defineProps<{
|
||||
datas: DmsFileUploadViewDisplayData[];
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<img
|
||||
:src="record.FormattedPic"
|
||||
:title="record.OrgFileName"
|
||||
@error="retryImage($event)"
|
||||
/>
|
||||
<div class="play-overlay">
|
||||
<PlayCircleOutlined />
|
||||
@@ -192,6 +193,7 @@ import {
|
||||
} from "@ant-design/icons-vue";
|
||||
import { FamilyDmsFileViewDisplayData } from "@/data/auto/familyDmsFileViewDisplayData";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { retryImage } from "@/utils/imageRetry";
|
||||
const props = defineProps<{
|
||||
datas: FamilyDmsFileViewDisplayData[];
|
||||
selectedKeys: FamilyDmsFileViewDisplayData[];
|
||||
|
||||
@@ -58,20 +58,20 @@
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="2" v-if="!isDirectorySelected && isSingleItem && isSingleVideo">
|
||||
<a-tooltip title="播放">
|
||||
<a-tooltip>
|
||||
<a-button class="nav-btn" @click="onPlayVideo"><cust-icon-font size="16"
|
||||
type="icon-foldervideo" /></a-button>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="2" v-if="!isDirectorySelected && isSingleItem && isSingleAudio" style="margin-left: 4px">
|
||||
<a-tooltip v-if="selectedItem.IsPlay != 'Y'" title="播放">
|
||||
<a-tooltip v-if="selectedItem.IsPlay != 'Y'">
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
@click="onPlayAudio"></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else-if="selectedItem.IsPause != 'Y'" title="暂停">
|
||||
<a-tooltip v-else-if="selectedItem.IsPause != 'Y'">
|
||||
<a-button class="nav-btn" :icon="h(PauseCircleOutlined)" @click="onPauseAudio"></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else title="继续">
|
||||
<a-tooltip v-else>
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
@click="onContinueAudio"></a-button>
|
||||
</a-tooltip>
|
||||
@@ -85,9 +85,8 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
<FileUpload v-if="canCreate" ref="fileUploadRef" :action="uploadUrl" :headers="headers"
|
||||
:resolve-file-path="resolveFilePath" :multiple="multiple" @start="onUploadStart"
|
||||
@progress="onUploadProgress" @success="onUploadSuccess" @complete="onUploadComplete"
|
||||
@interrupted="onUploadInterrupted" @error="onUploadError" />
|
||||
:resolve-file-path="resolveFilePath" :multiple="multiple" @start="onUploadStart" @progress="onUploadProgress"
|
||||
@success="onUploadSuccess" @complete="onUploadComplete" @interrupted="onUploadInterrupted" @error="onUploadError" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<a-row>
|
||||
<a-col flex="300px">
|
||||
<a-row justify="start">
|
||||
<a-col :span="3" style="margin-left: 8px">
|
||||
<a-col :span="3" style="margin-left: 8px">
|
||||
<a-tooltip title="还原">
|
||||
<a-button class="nav-btn" :icon="h(UndoOutlined)" style="color:green;"
|
||||
:disabled="!hasSelection" @click="$emit('restore', selectedItems)"></a-button>
|
||||
@@ -12,33 +12,36 @@
|
||||
</a-col>
|
||||
<a-col :span="3">
|
||||
<a-tooltip title="下载">
|
||||
<a-button class="nav-btn" :icon="h(DownloadOutlined)" :disabled="!hasSelection || isDirectorySelected || !isSingleItem"
|
||||
<a-button class="nav-btn" :icon="h(DownloadOutlined)"
|
||||
:disabled="!hasSelection || isDirectorySelected || !isSingleItem"
|
||||
@click="onDownload"></a-button>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="3" v-if="hasSelection">
|
||||
<a-col :span="3" v-if="hasSelection">
|
||||
<a-tooltip title="删除">
|
||||
<a-popconfirm title="确定是否删除?" ok-text="是" cancel-text="否" @confirm="$emit('delete', selectedItems)">
|
||||
<a-button class="nav-btn" :icon="h(DeleteOutlined)" style="color:red;"
|
||||
:disabled="!canCreate" ></a-button></a-popconfirm>
|
||||
<a-popconfirm title="确定是否删除?" ok-text="是" cancel-text="否"
|
||||
@confirm="$emit('delete', selectedItems)">
|
||||
<a-button class="nav-btn" :icon="h(DeleteOutlined)" style="color:red;"
|
||||
:disabled="!canCreate"></a-button></a-popconfirm>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="3" v-if="!isDirectorySelected && isSingleItem && isSingleVideo">
|
||||
<a-tooltip title="播放">
|
||||
<a-tooltip>
|
||||
<a-button class="nav-btn" @click="onPlayVideo"><cust-icon-font size="16"
|
||||
type="icon-foldervideo" /></a-button>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="3" v-if="!isDirectorySelected && isSingleItem && isSingleAudio" >
|
||||
<a-tooltip v-if="selectedItem.IsPlay != 'Y'" title="播放">
|
||||
<a-col :span="3" v-if="!isDirectorySelected && isSingleItem && isSingleAudio">
|
||||
<a-tooltip v-if="selectedItem.IsPlay != 'Y'">
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
@click="onPlayAudio"></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else-if="selectedItem.IsPause != 'Y'" title="暂停">
|
||||
<a-button class="nav-btn" :icon="h(PauseCircleOutlined)" @click="onPauseAudio"></a-button>
|
||||
<a-tooltip v-else-if="selectedItem.IsPause != 'Y'">
|
||||
<a-button class="nav-btn" :icon="h(PauseCircleOutlined)"
|
||||
@click="onPauseAudio"></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else title="继续">
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
<a-tooltip v-else>
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
@click="onContinueAudio"></a-button>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
@@ -182,20 +185,20 @@ const onContinueAudio = () => {
|
||||
|
||||
<style scoped>
|
||||
.nav-btn {
|
||||
width: 28px;
|
||||
height: 26px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
width: 28px;
|
||||
height: 26px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
background: #e6f4ff;
|
||||
color: #1677ff;
|
||||
background: #e6f4ff;
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
.nav-btn:disabled {
|
||||
color: #bfbfbf;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
</style>
|
||||
@@ -24,20 +24,20 @@
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="3" v-if="!isDirectorySelected && isSingleItem && isSingleVideo">
|
||||
<a-tooltip title="播放">
|
||||
<a-tooltip >
|
||||
<a-button class="nav-btn" @click="onPlayVideo"><cust-icon-font size="16"
|
||||
type="icon-foldervideo" /></a-button>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
<a-col :span="3" v-if="!isDirectorySelected && isSingleItem && isSingleAudio">
|
||||
<a-tooltip v-if="selectedItem.IsPlay != 'Y'" title="播放">
|
||||
<a-tooltip v-if="selectedItem.IsPlay != 'Y'">
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
@click="onPlayAudio"></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else-if="selectedItem.IsPause != 'Y'" title="暂停">
|
||||
<a-tooltip v-else-if="selectedItem.IsPause != 'Y'" >
|
||||
<a-button class="nav-btn" :icon="h(PauseCircleOutlined)" @click="onPauseAudio"></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else title="继续">
|
||||
<a-tooltip v-else >
|
||||
<a-button class="nav-btn" :icon="h(PlayCircleOutlined, { style: { color: 'red' } })"
|
||||
@click="onContinueAudio"></a-button>
|
||||
</a-tooltip>
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
<a-spin size="large" />
|
||||
<span>加载中…</span>
|
||||
</div>
|
||||
<button v-if="!isPlaying && !buffering" class="vp-bigplay" type="button" title="播放" @click.stop="toggle">
|
||||
<button v-if="!isPlaying && !buffering" class="vp-bigplay" type="button" aria-label="播放"
|
||||
@click.stop="toggle">
|
||||
<CaretRightFilled />
|
||||
</button>
|
||||
</div>
|
||||
@@ -107,7 +108,7 @@
|
||||
<button class="vp-ctl" type="button" title="上一个" @click="goPrev">
|
||||
<StepBackwardFilled />
|
||||
</button>
|
||||
<button class="vp-play" type="button" :title="isPlaying ? '暂停' : '播放'" @click="toggle">
|
||||
<button class="vp-play" type="button" :aria-label="isPlaying ? '暂停' : '播放'" @click="toggle">
|
||||
<PauseOutlined v-if="isPlaying" />
|
||||
<CaretRightFilled v-else />
|
||||
</button>
|
||||
@@ -161,11 +162,20 @@ import {
|
||||
/** 一个视频 */
|
||||
export type VideoItem = PublishVideoDetailDisplayData;
|
||||
|
||||
const props = withDefaults(defineProps<{ videos?: VideoItem[] }>(), { videos: () => [] });
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
videos?: VideoItem[];
|
||||
/** 打开时从第几个开始播(点列表里的某一个进来时用) */
|
||||
startIndex?: number;
|
||||
/** 挂上播放源后是否立即播放(弹窗里默认自动播) */
|
||||
autoPlay?: boolean;
|
||||
}>(),
|
||||
{ videos: () => [], startIndex: 0, autoPlay: false },
|
||||
);
|
||||
|
||||
/* ---------------- 基础状态 ---------------- */
|
||||
const videoRef = ref<HTMLVideoElement | null>(null);
|
||||
const index = ref(0);
|
||||
const index = ref(props.startIndex);
|
||||
const isPlaying = ref(false);
|
||||
const currentTime = ref(0);
|
||||
const duration = ref(0);
|
||||
@@ -589,7 +599,8 @@ const fmt = (t: number) => {
|
||||
};
|
||||
|
||||
/* ---------------- 联动 ---------------- */
|
||||
watch(current, async (t) => {
|
||||
/** 切到某个视频:重置状态 → 挂播放源 → 按需播放 */
|
||||
const prepare = async (t: VideoItem | null, play: boolean) => {
|
||||
currentTime.value = 0;
|
||||
duration.value = 0;
|
||||
bufferedEnd.value = 0;
|
||||
@@ -599,11 +610,13 @@ watch(current, async (t) => {
|
||||
ensureStageRO();
|
||||
// 重新挂接播放源:m3u8 走 hls.js,普通文件走 src(内部会销毁上一个 hls 实例)
|
||||
attachSource(t.FormattedUrl);
|
||||
if (resumeAfterSwitch) {
|
||||
if (play || props.autoPlay) {
|
||||
resumeAfterSwitch = false;
|
||||
tryPlay();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
watch(current, (t) => prepare(t, resumeAfterSwitch));
|
||||
|
||||
// 播放列表默认收起,由用户点击列表按钮展开
|
||||
watch(
|
||||
@@ -613,6 +626,17 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
// 外部指定了从第几个开始播(弹窗没销毁又换了视频时也要跟随)
|
||||
watch(
|
||||
() => props.startIndex,
|
||||
(i) => {
|
||||
if (i >= 0 && i < videos.value.length && i !== index.value) {
|
||||
resumeAfterSwitch = true;
|
||||
index.value = i;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch([volume, muted], () => {
|
||||
const v = videoRef.value;
|
||||
if (!v) return;
|
||||
@@ -625,6 +649,8 @@ watch(rate, () => {
|
||||
|
||||
let timerId = 0;
|
||||
onMounted(() => {
|
||||
// 列表在挂载时就已就绪的情况(例如弹窗里先备好数据再打开),watch 不会触发,这里补一次
|
||||
if (current.value) prepare(current.value, false);
|
||||
document.addEventListener("click", onDocClick);
|
||||
document.addEventListener("fullscreenchange", onFullscreenChange);
|
||||
timerId = window.setInterval(() => {
|
||||
|
||||
Reference in new issue
Block a user