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));
}