|
|
@@ -26,6 +26,7 @@ const videoFileList = ref<UploadFile[]>([]);
|
|
|
const thumbnailFileList = ref<UploadFile[]>([]);
|
|
|
const pdfUrl = ref<string>();
|
|
|
const videoUrl = ref<string>();
|
|
|
+const videoDuration = ref<string>();
|
|
|
const videoThumbnailUrl = ref<string>();
|
|
|
const pdfUploading = ref(false);
|
|
|
const videoUploading = ref(false);
|
|
|
@@ -49,17 +50,45 @@ function resetUploads() {
|
|
|
thumbnailFileList.value = [];
|
|
|
pdfUrl.value = void 0;
|
|
|
videoUrl.value = void 0;
|
|
|
+ videoDuration.value = void 0;
|
|
|
videoThumbnailUrl.value = void 0;
|
|
|
pdfUploading.value = false;
|
|
|
videoUploading.value = false;
|
|
|
thumbnailUploading.value = false;
|
|
|
}
|
|
|
|
|
|
+function formatDuration(totalSeconds: number) {
|
|
|
+ const hours = Math.floor(totalSeconds / 3600);
|
|
|
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
|
+ const seconds = Math.floor(totalSeconds % 60);
|
|
|
+ if (hours > 0) {
|
|
|
+ return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
|
+ }
|
|
|
+ return `${minutes}:${String(seconds).padStart(2, '0')}`;
|
|
|
+}
|
|
|
+
|
|
|
+async function readVideoDuration(file: File) {
|
|
|
+ return new Promise<string>((resolve) => {
|
|
|
+ const video = document.createElement('video');
|
|
|
+ video.preload = 'metadata';
|
|
|
+ video.addEventListener('loadedmetadata', () => {
|
|
|
+ URL.revokeObjectURL(video.src);
|
|
|
+ resolve(formatDuration(Math.floor(video.duration)));
|
|
|
+ });
|
|
|
+ video.addEventListener('error', () => {
|
|
|
+ URL.revokeObjectURL(video.src);
|
|
|
+ resolve('');
|
|
|
+ });
|
|
|
+ video.src = URL.createObjectURL(file);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
async function uploadImmediately(
|
|
|
file: File,
|
|
|
listRef: typeof pdfFileList,
|
|
|
urlRef: typeof pdfUrl,
|
|
|
uploadingRef: typeof pdfUploading,
|
|
|
+ onSuccess?: () => Promise<void> | void,
|
|
|
) {
|
|
|
const uploadFile: UploadFile = {
|
|
|
uid: `${Date.now()}`,
|
|
|
@@ -83,6 +112,7 @@ async function uploadImmediately(
|
|
|
url,
|
|
|
},
|
|
|
];
|
|
|
+ await onSuccess?.();
|
|
|
} catch {
|
|
|
urlRef.value = void 0;
|
|
|
listRef.value = [
|
|
|
@@ -104,6 +134,7 @@ const { Form, Shell } = useEditShell<MedicalCaseLibrarySubmitVO>(
|
|
|
resetUploads();
|
|
|
pdfUrl.value = model.pdfUrl;
|
|
|
videoUrl.value = model.video?.url;
|
|
|
+ videoDuration.value = model.video?.duration;
|
|
|
videoThumbnailUrl.value = model.video?.thumbnailUrl;
|
|
|
pdfFileList.value = createUploadFile(model.pdfUrl, '医案.pdf');
|
|
|
videoFileList.value = createUploadFile(model.video?.url, '讲解视频');
|
|
|
@@ -131,6 +162,10 @@ const { Form, Shell } = useEditShell<MedicalCaseLibrarySubmitVO>(
|
|
|
message.error('请上传医案PDF文件');
|
|
|
throw new Error('pdf required');
|
|
|
}
|
|
|
+ if (videoUrl.value && !videoDuration.value) {
|
|
|
+ message.error('无法获取视频时长,请重新上传视频');
|
|
|
+ throw new Error('video duration required');
|
|
|
+ }
|
|
|
|
|
|
return {
|
|
|
...values,
|
|
|
@@ -139,6 +174,7 @@ const { Form, Shell } = useEditShell<MedicalCaseLibrarySubmitVO>(
|
|
|
video: {
|
|
|
...values.video,
|
|
|
url: videoUrl.value,
|
|
|
+ duration: videoDuration.value,
|
|
|
thumbnailUrl: videoThumbnailUrl.value,
|
|
|
},
|
|
|
};
|
|
|
@@ -164,7 +200,15 @@ const beforeVideoUpload: UploadProps['beforeUpload'] = (file) => {
|
|
|
message.error('上传视频大小不超过10M');
|
|
|
return Upload.LIST_IGNORE;
|
|
|
}
|
|
|
- void uploadImmediately(file, videoFileList, videoUrl, videoUploading);
|
|
|
+ void uploadImmediately(
|
|
|
+ file,
|
|
|
+ videoFileList,
|
|
|
+ videoUrl,
|
|
|
+ videoUploading,
|
|
|
+ async () => {
|
|
|
+ videoDuration.value = await readVideoDuration(file);
|
|
|
+ },
|
|
|
+ );
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
@@ -189,6 +233,7 @@ function onPdfRemove() {
|
|
|
|
|
|
function onVideoRemove() {
|
|
|
videoUrl.value = void 0;
|
|
|
+ videoDuration.value = void 0;
|
|
|
}
|
|
|
|
|
|
function onThumbnailRemove() {
|