Bläddra i källkod

Enhance UserListPage and AudioUpload component with voice bar duration handling

- Added state management for voice bar duration in UserListPage to track audio length.
- Updated AudioUpload component to calculate and return audio duration upon file upload.
- Modified the user data structure to include voiceBarDuration for improved user information management.
0es 1 månad sedan
förälder
incheckning
805689aef4
3 ändrade filer med 44 tillägg och 1 borttagningar
  1. 6 1
      src/app/(dashboard)/user/list/page.tsx
  2. 36 0
      src/components/AudioUpload.tsx
  3. 2 0
      src/types/api/user.ts

+ 6 - 1
src/app/(dashboard)/user/list/page.tsx

@@ -85,6 +85,9 @@ const UserListPage: React.FC = () => {
   const [editLoading, setEditLoading] = useState(false);
   const [currentEditUser, setCurrentEditUser] =
     useState<UserInfoAdminDTO | null>(null);
+  const [voiceBarDuration, setVoiceBarDuration] = useState<
+    number | undefined
+  >();
 
   // Load page data
   const loadPageData = async () => {
@@ -206,6 +209,7 @@ const UserListPage: React.FC = () => {
       cover: record.cover || "",
       voiceBar: record.voiceBar || "",
     });
+    setVoiceBarDuration(undefined);
     setEditModalVisible(true);
   };
 
@@ -229,6 +233,7 @@ const UserListPage: React.FC = () => {
         photos: values.photos || [],
         cover: values.cover || "",
         voiceBar: values.voiceBar || "",
+        voiceBarDuration: voiceBarDuration,
       };
 
       await updateUserBaseInfo(editData);
@@ -706,7 +711,7 @@ const UserListPage: React.FC = () => {
           </Form.Item>
 
           <Form.Item label="语音条" name="voiceBar">
-            <AudioUpload maxCount={1} />
+            <AudioUpload maxCount={1} onDurationChange={setVoiceBarDuration} />
           </Form.Item>
         </Form>
       </Modal>

+ 36 - 0
src/components/AudioUpload.tsx

@@ -10,6 +10,7 @@ import { getS3SimpleSign } from "@/services/upload";
 interface AudioUploadProps {
   value?: string | string[];
   onChange?: (value: string | string[]) => void;
+  onDurationChange?: (duration: number | undefined) => void;
   maxCount?: number;
   disabled?: boolean;
   dir?: string;
@@ -42,9 +43,23 @@ const getFileNameFromUrl = (url: string): string => {
   }
 };
 
+const getAudioDuration = (url: string): Promise<number> => {
+  return new Promise((resolve, reject) => {
+    const audio = new Audio();
+    audio.addEventListener("loadedmetadata", () => {
+      resolve(Math.round(audio.duration));
+    });
+    audio.addEventListener("error", () => {
+      reject(new Error("Failed to load audio metadata"));
+    });
+    audio.src = url;
+  });
+};
+
 const AudioUpload: React.FC<AudioUploadProps> = ({
   value,
   onChange,
+  onDurationChange,
   maxCount = 1,
   disabled = false,
   dir,
@@ -234,6 +249,16 @@ const AudioUpload: React.FC<AudioUploadProps> = ({
         onChange(successUrls);
       }
     }
+
+    if (onDurationChange && successUrls.length > 0) {
+      const targetUrl =
+        maxCount === 1 ? successUrls[0] : successUrls[successUrls.length - 1];
+      if (targetUrl) {
+        getAudioDuration(targetUrl)
+          .then((duration) => onDurationChange(duration))
+          .catch(() => onDurationChange(undefined));
+      }
+    }
   };
 
   // Handle file removal
@@ -253,6 +278,17 @@ const AudioUpload: React.FC<AudioUploadProps> = ({
       }
     }
 
+    if (onDurationChange) {
+      if (urls.length === 0) {
+        onDurationChange(undefined);
+      } else {
+        const targetUrl = urls[urls.length - 1];
+        getAudioDuration(targetUrl)
+          .then((duration) => onDurationChange(duration))
+          .catch(() => onDurationChange(undefined));
+      }
+    }
+
     return true;
   };
 

+ 2 - 0
src/types/api/user.ts

@@ -136,4 +136,6 @@ export interface EditPlaymateInfoAdminQuery {
   photos?: string[];
   cover?: string;
   voiceBar?: string;
+  /** Voice bar duration in seconds */
+  voiceBarDuration?: number;
 }