فهرست منبع

✨ feat(ui): Replace Spin with animated Skeleton in UsageLogsActions

Summary
• Swapped out the obsolete `<Spin>` loader for a modern, animated Semi-UI `<Skeleton>` implementation in `UsageLogsActions.jsx`.

Details
1. Added animated Skeleton placeholders mirroring real Tag sizes (108 × 26, 65 × 26, 64 × 26).
2. Introduced `showSkeleton` state with 500 ms minimum display to eliminate flicker.
3. Leveraged existing `showStat` flag to decide when real data is ready.
4. Ensured only the three Tags are under loading state - `CompactModeToggle` renders immediately.
5. Adopted CardTable‐style `Skeleton` pattern (`loading` + `placeholder`) for consistency.
6. Removed all references to the original `Spin` component.

Outcome
A smoother and more consistent loading experience across devices, aligning UI behaviour with the project’s latest Skeleton standards.
t0ng7u 10 ماه پیش
والد
کامیت
4fccaf3284
1فایلهای تغییر یافته به همراه41 افزوده شده و 11 حذف شده
  1. 41 11
      web/src/components/table/usage-logs/UsageLogsActions.jsx

+ 41 - 11
web/src/components/table/usage-logs/UsageLogsActions.jsx

@@ -17,21 +17,51 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 For commercial licensing, please contact support@quantumnous.com
 */
 
-import React from 'react';
-import { Tag, Space, Spin } from '@douyinfe/semi-ui';
+import React, { useState, useEffect, useRef } from 'react';
+import { Tag, Space, Skeleton } from '@douyinfe/semi-ui';
 import { renderQuota } from '../../../helpers';
 import CompactModeToggle from '../../common/ui/CompactModeToggle';
 
 const LogsActions = ({
   stat,
   loadingStat,
+  showStat,
   compactMode,
   setCompactMode,
   t,
 }) => {
+  const [showSkeleton, setShowSkeleton] = useState(loadingStat);
+  const needSkeleton = !showStat || showSkeleton;
+  const loadingStartRef = useRef(Date.now());
+
+  useEffect(() => {
+    if (loadingStat) {
+      loadingStartRef.current = Date.now();
+      setShowSkeleton(true);
+    } else {
+      const elapsed = Date.now() - loadingStartRef.current;
+      const remaining = Math.max(0, 500 - elapsed);
+      if (remaining === 0) {
+        setShowSkeleton(false);
+      } else {
+        const timer = setTimeout(() => setShowSkeleton(false), remaining);
+        return () => clearTimeout(timer);
+      }
+    }
+  }, [loadingStat]);
+
+  // Skeleton placeholder layout (three tag-size blocks)
+  const placeholder = (
+    <Space>
+      <Skeleton.Title style={{ width: 108, height: 26, borderRadius: 6 }} />
+      <Skeleton.Title style={{ width: 65, height: 26, borderRadius: 6 }} />
+      <Skeleton.Title style={{ width: 64, height: 26, borderRadius: 6 }} />
+    </Space>
+  );
+
   return (
-    <Spin spinning={loadingStat}>
-      <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full">
+    <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full">
+      <Skeleton loading={needSkeleton} active placeholder={placeholder}>
         <Space>
           <Tag
             color='blue'
@@ -68,14 +98,14 @@ const LogsActions = ({
             TPM: {stat.tpm}
           </Tag>
         </Space>
+      </Skeleton>
 
-        <CompactModeToggle
-          compactMode={compactMode}
-          setCompactMode={setCompactMode}
-          t={t}
-        />
-      </div>
-    </Spin>
+      <CompactModeToggle
+        compactMode={compactMode}
+        setCompactMode={setCompactMode}
+        t={t}
+      />
+    </div>
   );
 };