From c152b5aa2f46cf713d0772811db8aa0cd67ce3d0 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 2 Jul 2026 02:37:43 +0800 Subject: [PATCH] style: apply legacy shell across student pages --- apps/taro/src/app.tsx | 20 +- .../src/components/StudentLegacyShell.css | 250 ++++++++++++++++++ .../src/components/StudentLegacyShell.tsx | 68 +++++ apps/taro/src/pages/student/home/index.css | 243 +---------------- apps/taro/src/pages/student/home/index.tsx | 44 +-- apps/taro/src/pages/student/student.css | 27 +- 6 files changed, 366 insertions(+), 286 deletions(-) create mode 100644 apps/taro/src/components/StudentLegacyShell.css create mode 100644 apps/taro/src/components/StudentLegacyShell.tsx diff --git a/apps/taro/src/app.tsx b/apps/taro/src/app.tsx index 526b8ea0..70483456 100644 --- a/apps/taro/src/app.tsx +++ b/apps/taro/src/app.tsx @@ -1,6 +1,7 @@ import { PropsWithChildren, useEffect, useState } from 'react'; import { Text, View } from '@tarojs/components'; import 'katex/dist/katex.min.css'; +import { StudentLegacyShell } from '@/components/StudentLegacyShell'; import { appEnv, isH5Runtime } from '@/env'; import { currentPagePath, guardCurrentRoute, shouldGuardPath } from '@/services/routeGuard'; import './app.css'; @@ -43,12 +44,23 @@ function installH5RouteListener(callback: () => void) { }; } +function shouldUseStudentShell(path: string) { + if (appEnv.portal !== 'student') return false; + if (!path.startsWith('/pages/student/')) return false; + return ![ + '/pages/student/login/index', + '/pages/student/region/index', + ].includes(path); +} + export default function App({ children }: PropsWithChildren) { const [routeReady, setRouteReady] = useState(() => !shouldGuardPath(currentPagePath())); + const [path, setPath] = useState(() => currentPagePath()); function verifyCurrentRoute() { - const path = currentPagePath(); - const protectedRoute = shouldGuardPath(path); + const nextPath = currentPagePath(); + setPath(nextPath); + const protectedRoute = shouldGuardPath(nextPath); setRouteReady(!protectedRoute); guardCurrentRoute() .then(ok => setRouteReady(Boolean(ok))) @@ -102,5 +114,9 @@ export default function App({ children }: PropsWithChildren) { ); } + if (shouldUseStudentShell(path)) { + return {children}; + } + return children; } diff --git a/apps/taro/src/components/StudentLegacyShell.css b/apps/taro/src/components/StudentLegacyShell.css new file mode 100644 index 00000000..37b4fbb1 --- /dev/null +++ b/apps/taro/src/components/StudentLegacyShell.css @@ -0,0 +1,250 @@ +.student-legacy-layout { + position: relative; + min-height: 100vh; +} + +.student-legacy-main { + min-width: 0; +} + +.student-legacy-main .student-page { + padding-bottom: 132px; +} + +.legacy-student-sidebar { + display: none; +} + +.legacy-mobile-dock { + position: fixed; + right: 18px; + bottom: 18px; + left: 18px; + z-index: 30; + display: flex; + justify-content: space-around; + gap: 4px; + padding: 14px 12px; + border: 1px solid rgba(255, 255, 255, 0.6); + border-radius: 28px; + background: rgba(255, 255, 255, 0.94); + box-shadow: 0 14px 34px rgba(15, 23, 42, 0.18); +} + +.legacy-dock-item { + display: flex; + flex: 1; + min-width: 0; + flex-direction: column; + align-items: center; + gap: 5px; + color: #9ca3af; +} + +.legacy-dock-item.active { + color: var(--tiku-primary); +} + +.legacy-dock-dot { + display: flex; + align-items: center; + justify-content: center; + width: 42px; + height: 42px; + border-radius: 16px; + background: #f1f5f9; + font-size: 21px; + font-weight: 900; + line-height: 42px; +} + +.legacy-dock-item.active .legacy-dock-dot { + background: var(--tiku-primary); + color: #fff; + box-shadow: 0 8px 18px rgba(17, 82, 212, 0.24); +} + +.legacy-dock-text { + display: block; + font-size: 18px; + font-weight: 760; + line-height: 1.2; +} + +@media (min-width: 900px) { + .student-legacy-layout { + display: grid; + grid-template-columns: 260px minmax(0, 1fr); + gap: 28px; + min-height: 100vh; + padding: 24px; + } + + .legacy-student-sidebar { + position: sticky; + top: 24px; + display: flex; + height: calc(100vh - 48px); + flex-direction: column; + padding: 22px; + border: 1px solid rgba(226, 232, 240, 0.9); + border-radius: 30px; + background: rgba(255, 255, 255, 0.92); + box-shadow: 0 16px 34px rgba(15, 23, 42, 0.08); + } + + .legacy-brand-block { + display: flex; + align-items: center; + gap: 14px; + min-width: 0; + padding: 6px 4px 24px; + } + + .legacy-brand-icon { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 48px; + width: 48px; + height: 48px; + border-radius: 16px; + background: var(--tiku-primary); + box-shadow: 0 10px 20px rgba(17, 82, 212, 0.26); + } + + .legacy-brand-mark { + color: #fff; + font-size: 26px; + font-weight: 950; + } + + .legacy-brand-copy { + min-width: 0; + } + + .legacy-brand-name { + display: block; + color: #111827; + font-size: 19px; + font-weight: 950; + line-height: 1.25; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .legacy-brand-sub { + display: block; + margin-top: 3px; + color: var(--tiku-primary); + font-size: 14px; + font-weight: 850; + } + + .legacy-nav-list { + display: flex; + flex: 1; + flex-direction: column; + gap: 8px; + padding-top: 8px; + border-top: 1px solid #f1f5f9; + } + + .legacy-nav-item { + display: flex; + align-items: center; + gap: 12px; + min-height: 52px; + padding: 0 14px; + border-radius: 16px; + color: #64748b; + } + + .legacy-nav-item.active { + background: #111827; + color: #fff; + box-shadow: 0 8px 20px rgba(15, 23, 42, 0.16); + } + + .legacy-nav-dot { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 10px; + background: #f1f5f9; + color: inherit; + font-size: 16px; + font-weight: 900; + } + + .legacy-nav-item.active .legacy-nav-dot { + background: rgba(255, 255, 255, 0.16); + } + + .legacy-nav-text { + font-size: 18px; + font-weight: 850; + } + + .legacy-sidebar-user { + display: flex; + align-items: center; + gap: 12px; + padding-top: 18px; + border-top: 1px solid #f1f5f9; + } + + .legacy-mini-avatar { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 44px; + width: 44px; + height: 44px; + border-radius: 999px; + background: linear-gradient(135deg, #1152d4, #60a5fa); + color: #fff; + } + + .legacy-mini-avatar-mark { + color: #fff; + font-size: 20px; + font-weight: 900; + } + + .legacy-sidebar-user-copy { + min-width: 0; + } + + .legacy-sidebar-user-name { + display: block; + color: #334155; + font-size: 16px; + font-weight: 850; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .legacy-sidebar-user-tag { + display: inline-flex; + margin-top: 4px; + padding: 2px 8px; + border-radius: 999px; + background: linear-gradient(90deg, #fef3c7, #fde68a); + color: #92400e; + font-size: 13px; + font-weight: 850; + } + + .legacy-mobile-dock { + display: none; + } + + .student-legacy-main .student-page { + padding-bottom: 48px; + } +} diff --git a/apps/taro/src/components/StudentLegacyShell.tsx b/apps/taro/src/components/StudentLegacyShell.tsx new file mode 100644 index 00000000..fb7579f7 --- /dev/null +++ b/apps/taro/src/components/StudentLegacyShell.tsx @@ -0,0 +1,68 @@ +import { PropsWithChildren } from 'react'; +import Taro from '@tarojs/taro'; +import { Text, View } from '@tarojs/components'; +import { getTenantContext } from '@/services/api'; +import { currentPagePath } from '@/services/routeGuard'; +import './StudentLegacyShell.css'; + +const navItems = [ + { name: '首页', path: '/pages/student/home/index' }, + { name: '背单词', path: '/pages/student/vocabulary/index' }, + { name: '知识手册', path: '/pages/student/handbook/index' }, + { name: '购买', path: '/pages/student/checkout/index' }, + { name: '分数线', path: '/pages/student/scoreline/index' }, + { name: '我的', path: '/pages/student/profile/index' }, +]; + +function isActivePath(currentPath: string, itemPath: string) { + if (itemPath === '/pages/student/home/index') return currentPath === itemPath; + return currentPath.startsWith(itemPath); +} + +export function StudentLegacyShell({ children }: PropsWithChildren) { + const tenant = getTenantContext(); + const currentPath = currentPagePath(); + const brandName = tenant?.branding.brandName || tenant?.branding.shortName || '工学题库'; + + return ( + + + + + + + + {brandName} + 专升本刷题宝 + + + + {navItems.map(item => ( + Taro.navigateTo({ url: item.path })}> + {item.name.slice(0, 1)} + {item.name} + + ))} + + + + + + + 学习账号 + SVIP + + + + {children} + + {navItems.slice(0, 5).map(item => ( + Taro.navigateTo({ url: item.path })}> + {item.name.slice(0, 1)} + {item.name} + + ))} + + + ); +} diff --git a/apps/taro/src/pages/student/home/index.css b/apps/taro/src/pages/student/home/index.css index 8a71774a..08e13c9b 100644 --- a/apps/taro/src/pages/student/home/index.css +++ b/apps/taro/src/pages/student/home/index.css @@ -1,72 +1,6 @@ -.student-home-layout { - position: relative; - min-height: 100vh; -} - .student-page { min-height: 100vh; padding: 28px; - padding-bottom: 132px; -} - -.legacy-student-sidebar { - display: none; -} - -.legacy-mobile-dock { - position: fixed; - right: 18px; - bottom: 18px; - left: 18px; - z-index: 30; - display: flex; - justify-content: space-around; - gap: 4px; - padding: 14px 12px; - border: 1px solid rgba(255, 255, 255, 0.6); - border-radius: 28px; - background: rgba(255, 255, 255, 0.94); - box-shadow: 0 14px 34px rgba(15, 23, 42, 0.18); -} - -.legacy-dock-item { - display: flex; - flex: 1; - min-width: 0; - flex-direction: column; - align-items: center; - gap: 5px; - color: #9ca3af; -} - -.legacy-dock-item.active { - color: var(--tiku-primary); -} - -.legacy-dock-dot { - display: flex; - align-items: center; - justify-content: center; - width: 42px; - height: 42px; - border-radius: 16px; - background: #f1f5f9; - font-size: 21px; - font-weight: 900; - line-height: 42px; -} - -.legacy-dock-item.active .legacy-dock-dot { - background: var(--tiku-primary); - color: #fff; - box-shadow: 0 8px 18px rgba(17, 82, 212, 0.24); -} - -.legacy-dock-text { - display: block; - font-size: 18px; - font-weight: 760; - line-height: 1.2; } .topbar { @@ -391,180 +325,9 @@ } @media (min-width: 900px) { - .student-home-layout { - display: grid; - grid-template-columns: 260px minmax(0, 1fr); - gap: 28px; - min-height: 100vh; - padding: 24px; - } - - .legacy-student-sidebar { - position: sticky; - top: 24px; - display: flex; - height: calc(100vh - 48px); - flex-direction: column; - padding: 22px; - border: 1px solid rgba(226, 232, 240, 0.9); - border-radius: 30px; - background: rgba(255, 255, 255, 0.92); - box-shadow: 0 16px 34px rgba(15, 23, 42, 0.08); - } - - .legacy-brand-block { - display: flex; - align-items: center; - gap: 14px; - min-width: 0; - padding: 6px 4px 24px; - } - - .legacy-brand-icon { - display: flex; - align-items: center; - justify-content: center; - flex: 0 0 48px; - width: 48px; - height: 48px; - border-radius: 16px; - background: var(--tiku-primary); - box-shadow: 0 10px 20px rgba(17, 82, 212, 0.26); - } - - .legacy-brand-mark { - color: #fff; - font-size: 26px; - font-weight: 950; - } - - .legacy-brand-copy { - min-width: 0; - } - - .legacy-brand-name { - display: block; - color: #111827; - font-size: 19px; - font-weight: 950; - line-height: 1.25; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .legacy-brand-sub { - display: block; - margin-top: 3px; - color: var(--tiku-primary); - font-size: 14px; - font-weight: 850; - } - - .legacy-nav-list { - display: flex; - flex: 1; - flex-direction: column; - gap: 8px; - padding-top: 8px; - border-top: 1px solid #f1f5f9; - } - - .legacy-nav-item { - display: flex; - align-items: center; - gap: 12px; - min-height: 52px; - padding: 0 14px; - border-radius: 16px; - color: #64748b; - } - - .legacy-nav-item.active { - background: #111827; - color: #fff; - box-shadow: 0 8px 20px rgba(15, 23, 42, 0.16); - } - - .legacy-nav-dot { - display: flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; - border-radius: 10px; - background: #f1f5f9; - color: inherit; - font-size: 16px; - font-weight: 900; - } - - .legacy-nav-item.active .legacy-nav-dot { - background: rgba(255, 255, 255, 0.16); - } - - .legacy-nav-text { - font-size: 18px; - font-weight: 850; - } - - .legacy-sidebar-user { - display: flex; - align-items: center; - gap: 12px; - padding-top: 18px; - border-top: 1px solid #f1f5f9; - } - - .legacy-mini-avatar { - display: flex; - align-items: center; - justify-content: center; - flex: 0 0 44px; - width: 44px; - height: 44px; - border-radius: 999px; - background: linear-gradient(135deg, #1152d4, #60a5fa); - color: #fff; - } - - .legacy-mini-avatar-mark { - color: #fff; - font-size: 20px; - font-weight: 900; - } - - .legacy-sidebar-user-copy { - min-width: 0; - } - - .legacy-sidebar-user-name { - display: block; - color: #334155; - font-size: 16px; - font-weight: 850; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .legacy-sidebar-user-tag { - display: inline-flex; - margin-top: 4px; - padding: 2px 8px; - border-radius: 999px; - background: linear-gradient(90deg, #fef3c7, #fde68a); - color: #92400e; - font-size: 13px; - font-weight: 850; - } - - .legacy-mobile-dock { - display: none; - } - .student-page { - max-width: 980px; + width: 100%; + max-width: 1180px; margin: 0 auto; padding: 36px; padding-bottom: 48px; @@ -580,7 +343,7 @@ } .entry-grid { - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(4, minmax(0, 1fr)); } } diff --git a/apps/taro/src/pages/student/home/index.tsx b/apps/taro/src/pages/student/home/index.tsx index 2bdbd829..31e89129 100644 --- a/apps/taro/src/pages/student/home/index.tsx +++ b/apps/taro/src/pages/student/home/index.tsx @@ -40,42 +40,9 @@ export default function StudentHomePage() { { name: '消息通知', path: '/pages/student/notifications/index', meta: '通知 / 待办', tone: 'orange' }, { name: '个人中心', path: '/pages/student/profile/index', meta: '会员 / 订单', tone: 'slate' }, ]; - const navItems = [ - { name: '首页', path: '/pages/student/home/index', active: true }, - { name: '背单词', path: '/pages/student/vocabulary/index' }, - { name: '知识手册', path: '/pages/student/handbook/index' }, - { name: '购买', path: '/pages/student/checkout/index' }, - { name: '分数线', path: '/pages/student/scoreline/index' }, - { name: '我的', path: '/pages/student/profile/index' }, - ]; return ( - - - - - - {brandName} - 专升本刷题宝 - - - - {navItems.map(item => ( - Taro.navigateTo({ url: item.path })}> - {item.name.slice(0, 1)} - {item.name} - - ))} - - - {(userName || '同').slice(0, 1)} - - {userName || '同学'} - SVIP - - - - + @@ -149,15 +116,6 @@ export default function StudentHomePage() { ))} - - - {navItems.slice(0, 5).map(item => ( - Taro.navigateTo({ url: item.path })}> - {item.name.slice(0, 1)} - {item.name} - - ))} - ); } diff --git a/apps/taro/src/pages/student/student.css b/apps/taro/src/pages/student/student.css index 4981780c..2271b31a 100644 --- a/apps/taro/src/pages/student/student.css +++ b/apps/taro/src/pages/student/student.css @@ -1372,7 +1372,8 @@ @media (min-width: 900px) { .student-page { - max-width: 900px; + width: 100%; + max-width: 1180px; margin: 0 auto; padding: 36px; } @@ -1385,6 +1386,30 @@ font-size: 42px; } + .student-topbar { + padding: 24px 28px; + border: 1px solid rgba(226, 232, 240, 0.9); + border-radius: 28px; + background: rgba(255, 255, 255, 0.88); + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.05); + } + + .student-page > .toolbar, + .student-page > .section-block > .toolbar { + padding: 14px; + border: 1px solid var(--tiku-border); + border-radius: 24px; + background: #fff; + box-shadow: var(--tiku-shadow); + } + + .quiet-panel, + .report-panel, + .scoreline-filter-panel, + .asset-preview-panel { + border-radius: 28px; + } + .answer-sheet { grid-template-columns: repeat(10, minmax(0, 1fr)); }