Selaa lähdekoodia

fix(@six/wisdom-legacy): 成果管理 - 医案库页面接口修改

cmj 2 päivää sitten
vanhempi
commit
03e5c421b2

+ 3 - 0
apps/wisdom-legacy/src/api/outcome/medical-case-library.schema.ts

@@ -62,6 +62,7 @@ export interface MedicalCaseLibraryVO extends AuditRecordVO {
   firstVisitDate: string;
   pdfUrl?: string;
   video?: {
+    duration?: string;
     name?: string;
     thumbnailUrl?: string;
     url?: string;
@@ -149,6 +150,7 @@ export function decodeMedicalCaseLibrary(
       name: dto.videoName,
       url: dto.videoUrl,
       thumbnailUrl: dto.videoFirstUrl,
+      duration: dto.duration,
     },
     isHaveLinkVideo: dto.isHaveLinkVideo ?? !!dto.videoUrl,
   };
@@ -182,6 +184,7 @@ export function encodeMedicalCaseLibrary(
     videoName: vo.video?.name,
     videoUrl,
     videoFirstUrl: vo.video?.thumbnailUrl,
+    duration: videoUrl ? vo.video?.duration : void 0,
     isHaveLinkVideo: !!videoUrl,
   };
 }

+ 8 - 8
apps/wisdom-legacy/src/views/outcome/MedicalCaseLibraryList.vue

@@ -27,13 +27,12 @@ const { Grid, Edit, actions, grid } = useGridPage(medicalCaseLibraryGrid, {
   params: { workroomId: () => workroomId.value },
   edit: editModal(MedicalCaseLibraryEdit),
   delete: deleteMedicalCaseLibraryMethod,
-  view: ({ row }: { row: MedicalCaseLibraryVO }) => {
+  view: (row: MedicalCaseLibraryVO) => {
     if (row.pdfUrl) {
       window.open(row.pdfUrl, '_blank');
     } else {
       message.warning('暂无PDF文件');
     }
-    return void 0;
   },
 });
 
@@ -62,12 +61,13 @@ function hasLinkedVideo(row: MedicalCaseLibraryVO) {
       </template>
 
       <template #patientInfo="{ row }">
-        <div class="text-left leading-5">
-          <div>{{ maskPatientName(row.patient?.name) }}</div>
-          <div class="text-xs text-gray-400">
-            {{ formatPatientInfo({ row }) }}
-          </div>
-        </div>
+        <span class="whitespace-nowrap">
+          {{
+            [maskPatientName(row.patient?.name), formatPatientInfo({ row })]
+              .filter(Boolean)
+              .join(' / ')
+          }}
+        </span>
       </template>
 
       <template #linkedVideo="{ row }">

+ 1 - 1
apps/wisdom-legacy/src/views/outcome/medical-case-library.data.ts

@@ -58,7 +58,7 @@ export const medicalCaseLibraryGrid = defineGrid<MedicalCaseLibraryVO>({
       field: 'patient.name',
       title: '患者信息',
       minWidth: 140,
-      align: 'left',
+      align: 'center',
       slots: { default: 'patientInfo' },
     },
     {

+ 46 - 1
apps/wisdom-legacy/src/views/outcome/modules/MedicalCaseLibraryEdit.vue

@@ -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() {