This commit is contained in:
itcsx committed 2026-09-21 21:31:16 +08:00
1 parent 7c8af2fb08
commit c10f8347e2
31 files changed
+358 -292

No files matched your search

+88 -38
View File
@@ -23,7 +23,8 @@
onVisibleChange: setPicVisible,
}" :src="imageSrc" />
<dmsFolder @on-submit="onReload" @submit-start="loading = true" @submit-end="loading = false"></dmsFolder>
<videoPlay></videoPlay>
<VideoPlayModal v-model:open="videoPlayModal" :videos="videoPlayList" :start-index="videoPlayIndex"
:title="videoPlayTitle" :fullscreen="width < 640" />
<dragModal v-model:open="showModalShare" width="60%" title="分享管理查询" :mask-closable="false" :fullscreen="width < 640"
@ok="handleSelectShare">
<DmsFileShareModal ref="shareEnquiry"></DmsFileShareModal>
@@ -83,7 +84,6 @@ import dmsFolder from "./DmsFolderModal.vue";
import { useLoginProfileStore } from "@/store/modules/loginProfile";
import { WebSitePolicy } from "@/policy/custom/webSitePolicy";
import { orderBy } from "lodash-es";
import VideoPlay from "./PlayVideo.vue";
import { Howl } from "howler";
import { PublishVideoEntity } from "@/data/auto/publishVideoEntity";
import publishVideoService from "@/service/master/publishVideoService";
@@ -98,6 +98,9 @@ import { PublishPhotoEntity } from "@/data/auto/publishPhotoEntity";
import MyComputer from "@/components/basic/MyComputer.vue";
import Toolbar from "@/components/basic/Toolbar.vue";
import OperatorStation from "@/components/basic/OperatorStation.vue";
import VideoPlayModal from "@/components/basic/VideoPlayModal.vue";
import type { VideoItem } from "@/components/basic/VideoPlayer.vue";
import { PublishVideoDetailDisplayData } from "@/data/auto/publishVideoDetailDisplayData";
interface BreadcrumbItem {
value: string;
@@ -163,9 +166,8 @@ const dmsFolderIsRename = ref<boolean>(false);
const dmsFolderIsMove = ref<boolean>(false);
const entity = ref<DmsFileEntity>(new DmsFileEntity());
const videoPlayModal = ref<boolean>(false);
const videoSrc = ref<string>("");
const videoPoster = ref<string>("");
const videoType = ref<string>("");
const videoPlayList = ref<VideoItem[]>([]);
const videoPlayIndex = ref<number>(0);
const videoPlayTitle = ref<string>("");
const visible = ref<boolean>(false);
@@ -198,6 +200,7 @@ const toUploadView = (r: Record<string, any>): DmsFileUploadViewDisplayData =>
onUnmounted(() => {
sound.value?.stop();
clearRefreshTimers();
});
const play = (src: string) => {
@@ -264,11 +267,6 @@ provide("dmsFolderTitle", dmsFolderTitle);
provide("dmsFolderIsRename", dmsFolderIsRename);
provide("dmsFolderIsMove", dmsFolderIsMove);
provide("DmsFileEntity", entity);
provide("videoPlayModal", videoPlayModal);
provide("videoPlayTitle", videoPlayTitle);
provide("videoSrc", videoSrc);
provide("videoPoster", videoPoster);
provide("videoType", videoType);
provide("isModalPublishVideo", showModalPublishVideo);
provide("isModalPublishAudio", showModalPublishAudio);
provide("isModalPublishPhoto", showModalPublishPhoto);
@@ -313,15 +311,32 @@ const onUploadSuccess = () => {
spinTip.value = "上传完成,等待服务端处理...";
};
/** 一批文件全部传完:给后端留点时间合并分片,文件越多等得越久 */
/** 上传后延迟刷新的定时器,离开页面/重新开始时清掉,避免野刷新 */
let refreshTimers: number[] = [];
const clearRefreshTimers = () => {
refreshTimers.forEach((t) => clearTimeout(t));
refreshTimers = [];
};
/**
* 一批文件全部传完:给后端留点时间合并分片,文件越多等得越久。
* 视频封面(jpg)由 ffmpeg 生成、可能比合并更慢,所以首刷之后再补刷两次——
* 每次查询服务端都会重新拼 ?v=,src 变了 <img> 才会重新请求,封面就能补上来。
*/
const onUploadComplete = (payload: { count?: number }) => {
const count = payload?.count ?? 1;
const sec = 2500 + (count - 1) * 1000;
spinTip.value = "加载中...";
setTimeout(() => {
onReSearch();
loading.value = false;
}, sec);
clearRefreshTimers();
refreshTimers.push(
window.setTimeout(() => {
onReSearch();
loading.value = false;
}, sec),
);
refreshTimers.push(window.setTimeout(onReSearch, sec + 3000));
refreshTimers.push(window.setTimeout(onReSearch, sec + 6000));
};
/** 中断时的断点信息,弹窗里展示用 */
@@ -395,29 +410,57 @@ const onChangeFolder = async (fvalue: string) => {
onSearchByFilePath(fvalue);
};
const onUrlVideoPlay = (url: string, title: string, poster: string) => {
/** DMS 记录 → 播放列表项(m3u8 的封面用同名 png 兜底) */
const toVideoItem = (record: DmsFileUploadViewDisplayData): VideoItem => {
const item = new PublishVideoDetailDisplayData();
item.Title = record.OrgFileName;
item.FormattedUrl = record.Url;
item.FormattedPic = (record.FormattedPic || "").replace(/\.m3u8$/, ".png");
return item;
};
/** 当前目录里已转码(有 Url)的视频,作为弹窗播放器的播放列表 */
const buildVideoList = (
records: DmsFileUploadViewDisplayData[],
): VideoItem[] =>
records
.filter(
(x) =>
x.IsDirectoryIndc != "Y" &&
fileTypePolicy.isVideo(x.OrderKey || x.OrgFileName) &&
!!x.Url,
)
.map(toVideoItem);
/** 打开视频弹窗 */
const openVideoPlay = (list: VideoItem[], index: number, title: string) => {
sound.value?.stop();
datas.value.forEach((element) => {
element.IsPlay = "";
});
videoPoster.value = poster;
videoType.value = "m3u8";
videoSrc.value = url;
videoPlayList.value = list;
videoPlayIndex.value = index < 0 ? 0 : index;
videoPlayTitle.value = title || "视频播放";
videoPlayModal.value = true;
videoPlayTitle.value = title;
};
const onVideoPlay = async (fid: number) => {
dmsFileService
.FindSourceVideoPath(fid)
.then((res) => {
videoType.value = "video/mp4";
videoSrc.value = res;
videoPlayModal.value = true;
})
.catch(() => {
videoPlayModal.value = false;
/** 未转码的视频没有 Url,直接取源片路径播放 */
const onSourceVideoPlay = async (record: DmsFileUploadViewDisplayData) => {
try {
loading.value = true;
const url = await dmsFileService.FindSourceVideoPath(record.FileId);
const item = toVideoItem(record);
item.FormattedUrl = url;
openVideoPlay([item], 0, record.OrgFileName);
} catch (error) {
notification.info({
message: "系统提示:",
description: "视频加载失败",
placement: "topRight",
});
} finally {
loading.value = false;
}
};
const onPreviewFile = async (usernameOrRecord: any, orderKey?: string) => {
@@ -626,7 +669,7 @@ const onViewPic = () => {
} else if (fileTypePolicy.isImage(keys.value[0].OrgFileName)) {
onPreviewFile(keys.value[0].CreatedBy, keys.value[0].OrderKey);
} else if (fileTypePolicy.isVideo(keys.value[0].OrgFileName)) {
onVideoPlay(keys.value[0].FileId);
onUrlVideoPlayItem(keys.value[0]);
} else {
notification.info({
message: "系统提示:",
@@ -1065,7 +1108,7 @@ const onOpenFile = (record: DmsFileUploadViewDisplayData) => {
if (fileTypePolicy.isImage(record.OrgFileName)) {
onPreviewFile(record.CreatedBy, record.OrderKey);
} else if (fileTypePolicy.isVideo(record.OrgFileName)) {
onVideoPlay(record.FileId);
onUrlVideoPlayItem(record);
} else if (fileTypePolicy.isAudio(record.OrgFileName)) {
onPlayAudio(toUploadView(record));
} else {
@@ -1135,12 +1178,19 @@ const onViewPreviewSelected = (items: DmsFileUploadViewDisplayData[]) => {
}
};
const onUrlVideoPlayItem = (record: DmsFileUploadViewDisplayData) => {
onUrlVideoPlay(
record.Url,
record.OrgFileName,
record.FormattedPic.replace(".m3u8", ".png"),
);
/** 播放视频:把当前目录的视频串成播放列表,从点中的那一个开始 */
const onUrlVideoPlayItem = async (record: DmsFileUploadViewDisplayData) => {
if (!record.Url) {
await onSourceVideoPlay(record);
return;
}
const list = buildVideoList(datas.value);
let index = list.findIndex((x) => x.FormattedUrl === record.Url);
if (index < 0) {
list.unshift(toVideoItem(record));
index = 0;
}
openVideoPlay(list, index, record.OrgFileName);
};
const onPlayAudioItem = (record: DmsFileUploadViewDisplayData) => {