Browse Source

🎨 refactor(ui): scope table scrolling to console cards & refine overall layout

Summary
Implement a dedicated, reusable scrolling mechanism for all console-table pages while keeping header and sidebar fixed, plus related layout improvements.

Key Changes
• Added `.table-scroll-card` utility class
 – Provides flex column layout and internal vertical scrolling
 – Desktop height: `calc(100vh - 110px)`; Mobile (<768 px) height: `calc(100vh - 77px)`
 – Hides scrollbars cross-browser (`-ms-overflow-style`, `scrollbar-width`, `::-webkit-scrollbar`)
• Replaced global `.semi-card` scrolling rules with `.table-scroll-card` to avoid affecting non-table cards
• Updated table components (Channels, Tokens, Users, Logs, MjLogs, TaskLogs, Redemptions) to use the new class
• PageLayout
 – Footer is now suppressed for all `/console` routes
 – Confirmed only central content area scrolls; header & sidebar remain fixed
• Restored hidden scrollbar rules for `.semi-layout-content` and removed unnecessary global overrides
• Minor CSS cleanup & comment improvements for readability

Result
Console table pages now fill the viewport with smooth, internal scrolling and no visible scrollbars, while other cards and pages remain unaffected.
t0ng7u 7 months ago
parent
commit
218ad6bbe0

+ 1 - 1
web/src/components/auth/LoginForm.js

@@ -523,7 +523,7 @@ const LoginForm = () => {
       {/* 背景模糊晕染球 */}
       {/* 背景模糊晕染球 */}
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
-      <div className="w-full max-w-sm mt-[64px]">
+      <div className="w-full max-w-sm mt-[60px]">
         {showEmailLogin || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth)
         {showEmailLogin || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth)
           ? renderEmailLoginForm()
           ? renderEmailLoginForm()
           : renderOAuthOptions()}
           : renderOAuthOptions()}

+ 1 - 1
web/src/components/auth/PasswordResetConfirm.js

@@ -82,7 +82,7 @@ const PasswordResetConfirm = () => {
       {/* 背景模糊晕染球 */}
       {/* 背景模糊晕染球 */}
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
-      <div className="w-full max-w-sm mt-[64px]">
+      <div className="w-full max-w-sm mt-[60px]">
         <div className="flex flex-col items-center">
         <div className="flex flex-col items-center">
           <div className="w-full max-w-md">
           <div className="w-full max-w-md">
             <div className="flex items-center justify-center mb-6 gap-2">
             <div className="flex items-center justify-center mb-6 gap-2">

+ 1 - 1
web/src/components/auth/PasswordResetForm.js

@@ -82,7 +82,7 @@ const PasswordResetForm = () => {
       {/* 背景模糊晕染球 */}
       {/* 背景模糊晕染球 */}
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
-      <div className="w-full max-w-sm mt-[64px]">
+      <div className="w-full max-w-sm mt-[60px]">
         <div className="flex flex-col items-center">
         <div className="flex flex-col items-center">
           <div className="w-full max-w-md">
           <div className="w-full max-w-md">
             <div className="flex items-center justify-center mb-6 gap-2">
             <div className="flex items-center justify-center mb-6 gap-2">

+ 1 - 1
web/src/components/auth/RegisterForm.js

@@ -540,7 +540,7 @@ const RegisterForm = () => {
       {/* 背景模糊晕染球 */}
       {/* 背景模糊晕染球 */}
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-indigo" style={{ top: '-80px', right: '-80px', transform: 'none' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
       <div className="blur-ball blur-ball-teal" style={{ top: '50%', left: '-120px' }} />
-      <div className="w-full max-w-sm mt-[64px]">
+      <div className="w-full max-w-sm mt-[60px]">
         {showEmailRegister || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth)
         {showEmailRegister || !(status.github_oauth || status.oidc_enabled || status.wechat_login || status.linuxdo_oauth || status.telegram_oauth)
           ? renderEmailRegisterForm()
           ? renderEmailRegisterForm()
           : renderOAuthOptions()}
           : renderOAuthOptions()}

+ 1 - 1
web/src/components/layout/PageLayout.js

@@ -23,7 +23,7 @@ const PageLayout = () => {
   const { i18n } = useTranslation();
   const { i18n } = useTranslation();
   const location = useLocation();
   const location = useLocation();
 
 
-  const shouldHideFooter = location.pathname === '/console/playground' || location.pathname.startsWith('/console/chat');
+  const shouldHideFooter = location.pathname.startsWith('/console');
 
 
   const shouldInnerPadding = location.pathname.includes('/console') &&
   const shouldInnerPadding = location.pathname.includes('/console') &&
     !location.pathname.startsWith('/console/chat') &&
     !location.pathname.startsWith('/console/chat') &&

+ 1 - 1
web/src/components/settings/PersonalSetting.js

@@ -379,7 +379,7 @@ const PersonalSetting = () => {
   };
   };
 
 
   return (
   return (
-    <div className="bg-gray-50 mt-[64px]">
+    <div className="bg-gray-50 mt-[60px]">
       <div className="flex justify-center">
       <div className="flex justify-center">
         <div className="w-full">
         <div className="w-full">
           {/* 主卡片容器 */}
           {/* 主卡片容器 */}

+ 1 - 1
web/src/components/table/ChannelsTable.js

@@ -1902,7 +1902,7 @@ const ChannelsTable = () => {
       />
       />
 
 
       <Card
       <Card
-        className="!rounded-2xl"
+        className="table-scroll-card !rounded-2xl"
         title={renderHeader()}
         title={renderHeader()}
         shadows='always'
         shadows='always'
         bordered={false}
         bordered={false}

+ 1 - 1
web/src/components/table/LogsTable.js

@@ -1202,7 +1202,7 @@ const LogsTable = () => {
     <>
     <>
       {renderColumnSelector()}
       {renderColumnSelector()}
       <Card
       <Card
-        className='!rounded-2xl mb-4'
+        className='table-scroll-card !rounded-2xl mb-4'
         title={
         title={
           <div className='flex flex-col w-full'>
           <div className='flex flex-col w-full'>
             <Spin spinning={loadingStat}>
             <Spin spinning={loadingStat}>

+ 1 - 1
web/src/components/table/MjLogsTable.js

@@ -799,7 +799,7 @@ const LogsTable = () => {
       {renderColumnSelector()}
       {renderColumnSelector()}
       <Layout>
       <Layout>
         <Card
         <Card
-          className="!rounded-2xl mb-4"
+          className="table-scroll-card !rounded-2xl mb-4"
           title={
           title={
             <div className="flex flex-col w-full">
             <div className="flex flex-col w-full">
               <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">

+ 1 - 1
web/src/components/table/RedemptionsTable.js

@@ -574,7 +574,7 @@ const RedemptionsTable = () => {
       ></EditRedemption>
       ></EditRedemption>
 
 
       <Card
       <Card
-        className="!rounded-2xl"
+        className="table-scroll-card !rounded-2xl"
         title={renderHeader()}
         title={renderHeader()}
         shadows='always'
         shadows='always'
         bordered={false}
         bordered={false}

+ 1 - 1
web/src/components/table/TaskLogsTable.js

@@ -649,7 +649,7 @@ const LogsTable = () => {
       {renderColumnSelector()}
       {renderColumnSelector()}
       <Layout>
       <Layout>
         <Card
         <Card
-          className="!rounded-2xl mb-4"
+          className="table-scroll-card !rounded-2xl mb-4"
           title={
           title={
             <div className="flex flex-col w-full">
             <div className="flex flex-col w-full">
               <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">

+ 1 - 1
web/src/components/table/TokensTable.js

@@ -872,7 +872,7 @@ const TokensTable = () => {
       ></EditToken>
       ></EditToken>
 
 
       <Card
       <Card
-        className="!rounded-2xl"
+        className="table-scroll-card !rounded-2xl"
         title={renderHeader()}
         title={renderHeader()}
         shadows='always'
         shadows='always'
         bordered={false}
         bordered={false}

+ 1 - 1
web/src/components/table/UsersTable.js

@@ -639,7 +639,7 @@ const UsersTable = () => {
       ></EditUser>
       ></EditUser>
 
 
       <Card
       <Card
-        className="!rounded-2xl"
+        className="table-scroll-card !rounded-2xl"
         title={renderHeader()}
         title={renderHeader()}
         shadows='always'
         shadows='always'
         bordered={false}
         bordered={false}

+ 28 - 7
web/src/index.css

@@ -14,22 +14,16 @@
 }
 }
 
 
 /* ==================== 全局基础样式 ==================== */
 /* ==================== 全局基础样式 ==================== */
-/* 侧边栏宽度相关的 CSS 变量,配合 .sidebar-collapsed 类和媒体查询实现响应式布局 */
 :root {
 :root {
   --sidebar-width: 180px;
   --sidebar-width: 180px;
-  /* 展开时宽度 */
-  --sidebar-width-collapsed: 60px;  /* 折叠后宽度,显示图标栏 */
-  /* 折叠后宽度 */
+  --sidebar-width-collapsed: 60px;
   --sidebar-current-width: var(--sidebar-width);
   --sidebar-current-width: var(--sidebar-width);
 }
 }
 
 
-/* 当 body 上存在 .sidebar-collapsed 类时,使用折叠宽度 */
 body.sidebar-collapsed {
 body.sidebar-collapsed {
   --sidebar-current-width: var(--sidebar-width-collapsed);
   --sidebar-current-width: var(--sidebar-width-collapsed);
 }
 }
 
 
-/* 移除了在移动端强制设为 0 的限制,改由 React 控制是否渲染侧边栏以实现显示/隐藏 */
-
 body {
 body {
   font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei', sans-serif;
   font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei', sans-serif;
   color: var(--semi-color-text-0);
   color: var(--semi-color-text-0);
@@ -615,4 +609,31 @@ html:not(.dark) .blur-ball-indigo {
 
 
 html:not(.dark) .blur-ball-teal {
 html:not(.dark) .blur-ball-teal {
   opacity: 0.2;
   opacity: 0.2;
+}
+
+/* ==================== 表格卡片滚动设置 ==================== */
+.table-scroll-card {
+  display: flex;
+  flex-direction: column;
+  height: calc(100vh - 110px);
+  max-height: calc(100vh - 110px);
+}
+
+.table-scroll-card .semi-card-body {
+  flex: 1 1 auto;
+  overflow-y: auto;
+
+  -ms-overflow-style: none;
+  scrollbar-width: none;
+}
+
+.table-scroll-card .semi-card-body::-webkit-scrollbar {
+  display: none;
+}
+
+@media (max-width: 767px) {
+  .table-scroll-card {
+    height: calc(100vh - 77px);
+    max-height: calc(100vh - 77px);
+  }
 }
 }

+ 1 - 1
web/src/pages/About/index.js

@@ -105,7 +105,7 @@ const About = () => {
   );
   );
 
 
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       {aboutLoaded && about === '' ? (
       {aboutLoaded && about === '' ? (
         <div className="flex justify-center items-center h-screen p-8">
         <div className="flex justify-center items-center h-screen p-8">
           <Empty
           <Empty

+ 1 - 1
web/src/pages/Channel/index.js

@@ -3,7 +3,7 @@ import ChannelsTable from '../../components/table/ChannelsTable';
 
 
 const File = () => {
 const File = () => {
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       <ChannelsTable />
       <ChannelsTable />
     </div>
     </div>
   );
   );

+ 1 - 1
web/src/pages/Chat/index.js

@@ -42,7 +42,7 @@ const ChatPage = () => {
       allow='camera;microphone'
       allow='camera;microphone'
     />
     />
   ) : (
   ) : (
-    <div className="fixed inset-0 w-screen h-screen flex items-center justify-center bg-white/80 z-[1000] mt-[64px]">
+    <div className="fixed inset-0 w-screen h-screen flex items-center justify-center bg-white/80 z-[1000] mt-[60px]">
       <div className="flex flex-col items-center">
       <div className="flex flex-col items-center">
         <Spin
         <Spin
           size="large"
           size="large"

+ 1 - 1
web/src/pages/Chat2Link/index.js

@@ -17,7 +17,7 @@ const chat2page = () => {
   }
   }
 
 
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       <h3>正在加载,请稍候...</h3>
       <h3>正在加载,请稍候...</h3>
     </div>
     </div>
   );
   );

+ 1 - 1
web/src/pages/Detail/index.js

@@ -1120,7 +1120,7 @@ const Detail = (props) => {
   }, []);
   }, []);
 
 
   return (
   return (
-    <div className="bg-gray-50 h-full mt-[64px] px-2">
+    <div className="bg-gray-50 h-full mt-[60px] px-2">
       <div className="flex items-center justify-between mb-4">
       <div className="flex items-center justify-between mb-4">
         <h2
         <h2
           className="text-2xl font-semibold text-gray-800 transition-opacity duration-1000 ease-in-out"
           className="text-2xl font-semibold text-gray-800 transition-opacity duration-1000 ease-in-out"

+ 1 - 1
web/src/pages/Home/index.js

@@ -274,7 +274,7 @@ const Home = () => {
               className="w-full h-screen border-none"
               className="w-full h-screen border-none"
             />
             />
           ) : (
           ) : (
-            <div className="mt-[64px]" dangerouslySetInnerHTML={{ __html: homePageContent }} />
+            <div className="mt-[60px]" dangerouslySetInnerHTML={{ __html: homePageContent }} />
           )}
           )}
         </div>
         </div>
       )}
       )}

+ 1 - 1
web/src/pages/Log/index.js

@@ -2,7 +2,7 @@ import React from 'react';
 import LogsTable from '../../components/table/LogsTable';
 import LogsTable from '../../components/table/LogsTable';
 
 
 const Token = () => (
 const Token = () => (
-  <div className="mt-[64px] px-2">
+  <div className="mt-[60px] px-2">
     <LogsTable />
     <LogsTable />
   </div>
   </div>
 );
 );

+ 1 - 1
web/src/pages/Midjourney/index.js

@@ -2,7 +2,7 @@ import React from 'react';
 import MjLogsTable from '../../components/table/MjLogsTable';
 import MjLogsTable from '../../components/table/MjLogsTable';
 
 
 const Midjourney = () => (
 const Midjourney = () => (
-  <div className="mt-[64px] px-2">
+  <div className="mt-[60px] px-2">
     <MjLogsTable />
     <MjLogsTable />
   </div>
   </div>
 );
 );

+ 1 - 1
web/src/pages/NotFound/index.js

@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
 const NotFound = () => {
 const NotFound = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
   return (
   return (
-    <div className="flex justify-center items-center h-screen p-8 mt-[64px]">
+    <div className="flex justify-center items-center h-screen p-8 mt-[60px]">
       <Empty
       <Empty
         image={<IllustrationNotFound style={{ width: 250, height: 250 }} />}
         image={<IllustrationNotFound style={{ width: 250, height: 250 }} />}
         darkModeImage={<IllustrationNotFoundDark style={{ width: 250, height: 250 }} />}
         darkModeImage={<IllustrationNotFoundDark style={{ width: 250, height: 250 }} />}

+ 1 - 1
web/src/pages/Playground/index.js

@@ -352,7 +352,7 @@ const Playground = () => {
   }, [setMessage, saveMessagesImmediately]);
   }, [setMessage, saveMessagesImmediately]);
 
 
   return (
   return (
-    <div className="h-full bg-gray-50 mt-[64px]">
+    <div className="h-full bg-gray-50 mt-[60px]">
       <Layout style={{ height: '100%', background: 'transparent' }} className="flex flex-col md:flex-row">
       <Layout style={{ height: '100%', background: 'transparent' }} className="flex flex-col md:flex-row">
         {(showSettings || !isMobile) && (
         {(showSettings || !isMobile) && (
           <Layout.Sider
           <Layout.Sider

+ 1 - 1
web/src/pages/Pricing/index.js

@@ -2,7 +2,7 @@ import React from 'react';
 import ModelPricing from '../../components/table/ModelPricing.js';
 import ModelPricing from '../../components/table/ModelPricing.js';
 
 
 const Pricing = () => (
 const Pricing = () => (
-  <div className="mt-[64px] px-2">
+  <div className="mt-[60px] px-2">
     <ModelPricing />
     <ModelPricing />
   </div>
   </div>
 );
 );

+ 1 - 1
web/src/pages/Redemption/index.js

@@ -3,7 +3,7 @@ import RedemptionsTable from '../../components/table/RedemptionsTable';
 
 
 const Redemption = () => {
 const Redemption = () => {
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       <RedemptionsTable />
       <RedemptionsTable />
     </div>
     </div>
   );
   );

+ 1 - 1
web/src/pages/Setting/index.js

@@ -150,7 +150,7 @@ const Setting = () => {
     }
     }
   }, [location.search]);
   }, [location.search]);
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       <Layout>
       <Layout>
         <Layout.Content>
         <Layout.Content>
           <Tabs
           <Tabs

+ 1 - 1
web/src/pages/Setup/index.js

@@ -133,7 +133,7 @@ const Setup = () => {
   };
   };
 
 
   return (
   return (
-    <div className="bg-gray-50 mt-[64px]">
+    <div className="bg-gray-50 mt-[60px]">
       <Layout>
       <Layout>
         <Layout.Content>
         <Layout.Content>
           <div className="flex justify-center px-4 py-8">
           <div className="flex justify-center px-4 py-8">

+ 1 - 1
web/src/pages/Task/index.js

@@ -2,7 +2,7 @@ import React from 'react';
 import TaskLogsTable from '../../components/table/TaskLogsTable.js';
 import TaskLogsTable from '../../components/table/TaskLogsTable.js';
 
 
 const Task = () => (
 const Task = () => (
-  <div className="mt-[64px] px-2">
+  <div className="mt-[60px] px-2">
     <TaskLogsTable />
     <TaskLogsTable />
   </div>
   </div>
 );
 );

+ 1 - 1
web/src/pages/Token/index.js

@@ -3,7 +3,7 @@ import TokensTable from '../../components/table/TokensTable';
 
 
 const Token = () => {
 const Token = () => {
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       <TokensTable />
       <TokensTable />
     </div>
     </div>
   );
   );

+ 1 - 1
web/src/pages/TopUp/index.js

@@ -382,7 +382,7 @@ const TopUp = () => {
   };
   };
 
 
   return (
   return (
-    <div className='mx-auto relative min-h-screen lg:min-h-0 mt-[64px]'>
+    <div className='mx-auto relative min-h-screen lg:min-h-0 mt-[60px]'>
       {/* 划转模态框 */}
       {/* 划转模态框 */}
       <Modal
       <Modal
         title={
         title={

+ 1 - 1
web/src/pages/User/index.js

@@ -3,7 +3,7 @@ import UsersTable from '../../components/table/UsersTable';
 
 
 const User = () => {
 const User = () => {
   return (
   return (
-    <div className="mt-[64px] px-2">
+    <div className="mt-[60px] px-2">
       <UsersTable />
       <UsersTable />
     </div>
     </div>
   );
   );