feat(移动端): 优化教师端课表与统计排版

- 课表周视图支持横向滚动,避免在小屏下被压缩

- 阅读任务统计卡与筛选区在移动端改为网格/堆叠布局

- 课程反馈头部统计与搜索栏在移动端重排,防止文字截断

- 我的班级标题卡在小屏下自适应左对齐并防止横向溢出

Made-with: Cursor
This commit is contained in:
zhonghua 2026-03-04 14:31:32 +08:00
parent ca361d6d2b
commit 73b7f10d56
4 changed files with 292 additions and 65 deletions

View File

@ -1,27 +1,27 @@
<template>
<div class="min-h-[calc(100vh-120px)] bg-[linear-gradient(180deg,#FFF8F0_0%,#FFFFFF_100%)] p-6 rounded-2xl">
<div class="class-list-view min-h-[calc(100vh-120px)] bg-[linear-gradient(180deg,#FFF8F0_0%,#FFFFFF_100%)] p-4 md:p-6 rounded-2xl overflow-x-hidden min-w-0">
<!-- 页面标题区域 -->
<div class="relative bg-[linear-gradient(135deg,#FF8C42_0%,#FFB347_100%)] rounded-2xl py-6 px-8 mb-6 overflow-hidden flex justify-between items-center">
<div class="class-list-header relative bg-[linear-gradient(135deg,#FF8C42_0%,#FFB347_100%)] rounded-2xl py-6 px-6 md:px-8 mb-6 overflow-hidden flex flex-wrap justify-between items-center gap-4">
<div class="absolute top-0 right-0 w-[200px] h-full pointer-events-none">
<div class="absolute rounded-full opacity-15 bg-white w-[120px] h-[120px] -top-[30px] right-5 c1"></div>
<div class="absolute rounded-full opacity-15 bg-white w-20 h-20 top-10 right-20 c2"></div>
<div class="absolute rounded-full opacity-15 bg-white w-10 h-10 bottom-2.5 right-10 c3"></div>
</div>
<div class="flex items-center relative z-1">
<div class="header-left flex items-center relative z-1 min-w-0">
<div class="w-14 h-14 rounded-[14px] flex items-center justify-center text-[26px] mr-4 flex-shrink-0 bg-white/25 text-white icon-wrapper orange"><HomeOutlined /></div>
<div class="text-white header-text">
<h1 class="text-[28px] font-700 m-0 text-white page-title">我的班级</h1>
<div class="text-white header-text min-w-0">
<h1 class="text-[22px] md:text-[28px] font-700 m-0 text-white page-title">我的班级</h1>
<p class="text-sm mt-1 mb-0 opacity-90 text-white page-subtitle">管理您的班级开启精彩的阅读课堂</p>
</div>
</div>
<div class="flex items-center gap-5 relative z-1">
<div class="text-center text-white stats-item">
<span class="block text-[32px] font-700 leading-tight stats-value">{{ classes.length }}</span>
<div class="class-list-header-stats flex items-center gap-4 md:gap-5 relative z-1 flex-shrink-0">
<div class="text-center text-white stats-item min-w-[4rem]">
<span class="block text-[28px] md:text-[32px] font-700 leading-tight stats-value">{{ classes.length }}</span>
<span class="text-[13px] opacity-85 stats-label">个班级</span>
</div>
<div class="w-px h-10 bg-white/30 stats-divider"></div>
<div class="text-center text-white stats-item">
<span class="block text-[32px] font-700 leading-tight stats-value">{{ totalStudents }}</span>
<div class="text-center text-white stats-item min-w-[4rem]">
<span class="block text-[28px] md:text-[32px] font-700 leading-tight stats-value">{{ totalStudents }}</span>
<span class="text-[13px] opacity-85 stats-label">名学生</span>
</div>
</div>
@ -265,7 +265,31 @@ const viewHistory = (cls: ClassInfo) => {
}
/* 标题卡:移动端堆叠,统计区留足间距,整体左对齐 */
@media (max-width: 768px) {
.class-list-header {
flex-direction: column;
align-items: stretch;
text-align: left;
gap: 20px;
padding-left: 20px;
padding-right: 20px;
}
.class-list-header .header-text {
text-align: left;
}
.class-list-header .header-left {
justify-content: flex-start;
}
.class-list-header-stats {
justify-content: flex-start;
padding-top: 8px;
border-top: 1px solid rgba(255, 255, 255, 0.25);
}
.page-header-wrapper {
flex-direction: column;
text-align: center;

View File

@ -39,7 +39,7 @@
<a-input-search
v-model:value="filters.keyword"
placeholder="搜索课程名称"
style="width: 200px;"
class="feedback-search-input"
@search="handleFilter"
allow-clear
/>
@ -350,6 +350,8 @@ onMounted(() => {
.feedback-view {
min-height: 100%;
padding: 0;
overflow-x: hidden;
min-width: 0;
}
/* 页面头部 */
@ -364,12 +366,16 @@ onMounted(() => {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
min-width: 0;
}
.header-title {
display: flex;
align-items: center;
gap: 16px;
min-width: 0;
}
.title-icon-wrapper {
@ -382,6 +388,11 @@ onMounted(() => {
justify-content: center;
font-size: 32px;
color: white;
flex-shrink: 0;
}
.title-text {
min-width: 0;
}
.title-text h2 {
@ -395,15 +406,19 @@ onMounted(() => {
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
margin: 4px 0 0 0;
word-break: break-word;
}
.header-stats {
display: flex;
gap: 32px;
flex-wrap: wrap;
min-width: 0;
}
.stat-item {
text-align: center;
white-space: nowrap;
}
.stat-value {
@ -445,6 +460,74 @@ onMounted(() => {
.filters {
display: flex;
gap: 12px;
flex: 1;
min-width: 0;
}
.feedback-search-input {
width: 200px;
min-width: 0;
max-width: 100%;
}
@media (max-width: 768px) {
.page-header {
padding: 20px 16px;
}
.header-content {
flex-direction: column;
align-items: stretch;
gap: 20px;
}
.header-title {
gap: 12px;
}
.title-icon-wrapper {
width: 52px;
height: 52px;
font-size: 26px;
}
.title-text h2 {
font-size: 20px;
}
.title-text p {
font-size: 13px;
}
.header-stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px 16px;
}
.stat-item {
min-width: 0;
}
.stat-value {
font-size: 22px;
}
.stat-label {
font-size: 11px;
}
.action-bar {
padding: 12px 16px;
}
.filters {
width: 100%;
}
.feedback-search-input {
width: 100%;
}
}
/* 反馈卡片网格 */

View File

@ -70,6 +70,8 @@
<!-- 课表 -->
<div class="timetable-container">
<a-spin :spinning="loading">
<!-- 横向滚动容器表头与内容同步滚动 -->
<div class="timetable-scroll">
<div class="timetable-header">
<div
v-for="day in weekDays"
@ -120,6 +122,7 @@
</div>
</div>
</div>
</div>
</a-spin>
</div>
@ -502,6 +505,11 @@ onMounted(() => {
<style scoped lang="scss">
.teacher-schedule-view {
overflow-x: hidden;
min-width: 0;
--day-col-width: 140px;
.page-header {
display: flex;
justify-content: space-between;
@ -561,19 +569,37 @@ onMounted(() => {
overflow: hidden;
}
.timetable-scroll {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
/* 细一点的横向滚动条(仅 WebKit */
.timetable-scroll::-webkit-scrollbar {
height: 6px;
}
.timetable-scroll::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.18);
border-radius: 6px;
}
.timetable-scroll::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.28);
}
.timetable-header {
display: table;
width: 100%;
table-layout: fixed;
display: flex;
width: max-content;
min-width: calc(var(--day-col-width) * 7);
background: linear-gradient(135deg, #FF8C42 0%, #E67635 100%);
color: white;
.day-header {
display: table-cell;
flex: 0 0 var(--day-col-width);
padding: 12px 8px;
text-align: center;
border-right: 1px solid rgba(255, 255, 255, 0.2);
vertical-align: middle;
box-sizing: border-box;
&:last-child {
border-right: none;
@ -599,17 +625,17 @@ onMounted(() => {
}
.timetable-grid {
display: table;
width: 100%;
table-layout: fixed;
display: flex;
width: max-content;
min-width: calc(var(--day-col-width) * 7);
.day-column {
display: table-cell;
flex: 0 0 var(--day-col-width);
min-height: 300px;
padding: 8px;
border-right: 1px solid #e8e8e8;
background: #fafafa;
vertical-align: top;
box-sizing: border-box;
&:last-child {
border-right: none;
@ -680,5 +706,28 @@ onMounted(() => {
padding: 20px;
font-size: 12px;
}
@media (max-width: 768px) {
--day-col-width: 120px;
.week-navigation :deep(.ant-space) {
width: 100%;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.week-navigation .week-range {
margin-left: 0;
width: 100%;
text-align: right;
}
/* 今日课程:移动端 2 列 */
.today-section :deep(.ant-col) {
flex: 0 0 50%;
max-width: 50%;
}
}
}
</style>

View File

@ -43,11 +43,11 @@
<!-- 筛选区域 -->
<div class="filter-section">
<a-space :size="16">
<div class="filter-row">
<a-select
v-model:value="filters.status"
placeholder="任务状态"
style="width: 120px;"
class="filter-select"
allowClear
@change="loadTasks"
>
@ -58,7 +58,7 @@
<a-select
v-model:value="filters.taskType"
placeholder="任务类型"
style="width: 120px;"
class="filter-select"
allowClear
@change="loadTasks"
>
@ -69,11 +69,11 @@
<a-input-search
v-model:value="filters.keyword"
placeholder="搜索任务标题"
style="width: 200px;"
class="filter-search"
@search="loadTasks"
allow-clear
/>
</a-space>
</div>
</div>
<a-spin :spinning="loading">
@ -758,6 +758,9 @@ onMounted(() => {
<style scoped lang="scss">
.task-list-view {
overflow-x: hidden;
min-width: 0;
.page-header {
display: flex;
justify-content: space-between;
@ -783,12 +786,12 @@ onMounted(() => {
}
.stats-row {
display: flex;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-bottom: 24px;
.stat-card {
flex: 1;
background: white;
border-radius: 12px;
padding: 20px;
@ -796,6 +799,7 @@ onMounted(() => {
align-items: center;
gap: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
min-width: 0;
.stat-icon {
width: 48px;
@ -831,6 +835,73 @@ onMounted(() => {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.filter-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
min-width: 0;
}
.filter-select {
width: 120px;
min-width: 0;
}
.filter-search {
width: 200px;
min-width: 0;
max-width: 100%;
}
@media (max-width: 768px) {
.page-header {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.page-header > .ant-btn {
width: 100%;
}
.stats-row {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
/* 第三张卡片占满一行,避免被裁切 */
.stats-row .stat-card:nth-child(3) {
grid-column: 1 / -1;
}
.stats-row .stat-card {
padding: 14px;
gap: 12px;
}
.stats-row .stat-card .stat-icon {
width: 42px;
height: 42px;
border-radius: 10px;
font-size: 22px;
}
.stats-row .stat-card .stat-info .stat-value {
font-size: 22px;
}
.filter-row {
flex-direction: column;
align-items: stretch;
}
.filter-select,
.filter-search {
width: 100% !important;
}
}
.task-list {
display: flex;
flex-direction: column;