修复了课程表和发帖按钮
This commit is contained in:
@@ -24,13 +24,13 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { useFocusEffect, useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { colors, fontSizes, spacing, borderRadius, shadows } from '../../theme';
|
||||
import { useResponsive } from '../../hooks/useResponsive';
|
||||
import {
|
||||
Course,
|
||||
COURSE_COLORS,
|
||||
TimeSlot,
|
||||
getCourseColor,
|
||||
hasCourseInWeek,
|
||||
getCurrentWeek,
|
||||
} from '../../types/schedule';
|
||||
import type { ScheduleStackParamList } from '../../navigation/types';
|
||||
import { scheduleService } from '../../services/scheduleService';
|
||||
@@ -44,8 +44,8 @@ const VISIBLE_WEEKDAY_NAMES = ['周一', '周二', '周三', '周四', '周五',
|
||||
// 星期列宽度(根据屏幕宽度自动计算)
|
||||
const getDayColumnWidth = () => Math.max(46, (SCREEN_WIDTH - TIME_COLUMN_WIDTH - 2) / VISIBLE_DAY_VALUES.length);
|
||||
|
||||
// 每个大节(两小节)高度
|
||||
const SECTION_HEIGHT = 105;
|
||||
// 每个大节(两小节)高度 - 默认值,会在组件中动态调整
|
||||
const DEFAULT_SECTION_HEIGHT = 105;
|
||||
// 顶部周选择器高度
|
||||
const WEEK_SELECTOR_HEIGHT = 44;
|
||||
// 星期标题行高度
|
||||
@@ -106,6 +106,18 @@ const getTodayColumnIndex = () => {
|
||||
// 第1周固定从2026年3月9日(周一)开始
|
||||
const FIRST_WEEK_START = new Date(2026, 2, 9); // 2026年3月9日
|
||||
|
||||
// 计算当前日期对应的周数(返回1-20)
|
||||
const getCurrentWeekNumber = (): number => {
|
||||
const now = new Date();
|
||||
// 计算当前日期与第一周周一的差距天数
|
||||
const diffTime = now.getTime() - FIRST_WEEK_START.getTime();
|
||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
||||
// 计算周数(从1开始)
|
||||
const weekNumber = Math.floor(diffDays / 7) + 1;
|
||||
// 确保周数在有效范围内
|
||||
return Math.max(1, Math.min(TOTAL_WEEKS, weekNumber));
|
||||
};
|
||||
|
||||
// 获取指定周的起始日期、每天的日期和月份
|
||||
// weekIndex: 0表示第1周,1表示第2周,以此类推
|
||||
const getWeekInfo = (weekIndex: number = 0) => {
|
||||
@@ -131,18 +143,41 @@ const getWeekDates = (weekOffset: number = 0) => {
|
||||
return getWeekInfo(weekOffset).dates;
|
||||
};
|
||||
|
||||
// 学期起始日期字符串(用于 getCurrentWeek 函数)
|
||||
const SEMESTER_START_DATE = '2026-03-09';
|
||||
|
||||
// 计算当前实际周数
|
||||
const getInitialWeek = (): number => {
|
||||
return getCurrentWeek(SEMESTER_START_DATE, TOTAL_WEEKS);
|
||||
};
|
||||
// 获取初始周数(仅在组件初始化时计算一次)
|
||||
const INITIAL_WEEK = getCurrentWeekNumber();
|
||||
|
||||
export const ScheduleScreen: React.FC = () => {
|
||||
const navigation = useNavigation<NativeStackNavigationProp<ScheduleStackParamList>>();
|
||||
const [currentWeek, setCurrentWeek] = useState(getInitialWeek);
|
||||
// 使用响应式 hook 检测屏幕尺寸
|
||||
const { width: screenWidth, height: screenHeight, isMobile, platform } = useResponsive();
|
||||
const isWeb = platform.isWeb;
|
||||
const [currentWeek, setCurrentWeek] = useState(INITIAL_WEEK);
|
||||
const [courses, setCourses] = useState<Course[]>([]);
|
||||
|
||||
// 动态计算日列宽度:移动端填满屏幕宽度,电脑端也填满
|
||||
// Web端需要特殊处理,确保周一到周日刚好横向填满
|
||||
const dayColumnWidth = useMemo(() => {
|
||||
if (isWeb) {
|
||||
// Web端:使用更大的宽度确保填满
|
||||
return Math.max(80, (screenWidth - TIME_COLUMN_WIDTH) / VISIBLE_DAY_VALUES.length);
|
||||
}
|
||||
// 移动端和原生桌面端
|
||||
return Math.max(46, (screenWidth - TIME_COLUMN_WIDTH - 2) / VISIBLE_DAY_VALUES.length);
|
||||
}, [screenWidth, isWeb]);
|
||||
|
||||
// 动态计算每节课的高度
|
||||
// 手机端:第六节课底部刚好跟底部导航栏持平(可用高度 = 屏幕高度 - 周选择器 - 星期标题 - 底部Tab栏)
|
||||
// 电脑端:第六节课刚好填到底部(可用高度 = 屏幕高度 - 周选择器 - 星期标题)
|
||||
const sectionHeight = useMemo((): number => {
|
||||
const totalHeaderHeight = WEEK_SELECTOR_HEIGHT + HEADER_HEIGHT;
|
||||
const bottomOffset = isMobile ? TAB_BAR_HEIGHT : 0;
|
||||
// 可用高度 = 屏幕高度 - 顶部区域 - 底部偏移
|
||||
const availableHeight = screenHeight - totalHeaderHeight - bottomOffset;
|
||||
// 6节课,每节课高度 = 可用高度 / 6
|
||||
const calculatedHeight = Math.floor(availableHeight / 6);
|
||||
// 确保高度不低于默认值
|
||||
return Math.max(DEFAULT_SECTION_HEIGHT, calculatedHeight);
|
||||
}, [screenHeight, isMobile]);
|
||||
const [isAddModalVisible, setIsAddModalVisible] = useState(false);
|
||||
const [pendingDay, setPendingDay] = useState<number>(0);
|
||||
const [pendingMergedSection, setPendingMergedSection] = useState<number>(1);
|
||||
@@ -172,13 +207,10 @@ export const ScheduleScreen: React.FC = () => {
|
||||
};
|
||||
}, []);
|
||||
const todayColumnIndex = getTodayColumnIndex();
|
||||
// 获取当前实际周数,用于判断是否在查看当前周
|
||||
const actualCurrentWeek = getInitialWeek();
|
||||
// 只有在查看当前实际周时才高亮今日列
|
||||
const isViewingCurrentWeek = currentWeek === actualCurrentWeek;
|
||||
// 当前正在查看的周是否为真实的当前周
|
||||
const isViewingCurrentWeek = currentWeek === INITIAL_WEEK;
|
||||
const activeTodayColumn = isViewingCurrentWeek ? todayColumnIndex : -1;
|
||||
|
||||
const dayColumnWidth = getDayColumnWidth();
|
||||
const usedCourseColors = useMemo(
|
||||
() => new Set(courses.map(item => normalizeHexColor(item.color || '')).filter(Boolean)),
|
||||
[courses]
|
||||
@@ -396,7 +428,7 @@ export const ScheduleScreen: React.FC = () => {
|
||||
style={[
|
||||
styles.dayHeader,
|
||||
{
|
||||
width: dayColumnWidth,
|
||||
flex: 1,
|
||||
backgroundColor: index === activeTodayColumn ? `${colors.primary.main}10` : 'transparent',
|
||||
},
|
||||
]}
|
||||
@@ -433,7 +465,7 @@ export const ScheduleScreen: React.FC = () => {
|
||||
key={slot.section}
|
||||
style={[
|
||||
styles.timeCell,
|
||||
{ height: SECTION_HEIGHT },
|
||||
{ height: sectionHeight },
|
||||
]}
|
||||
>
|
||||
<View style={styles.timeSectionBadge}>
|
||||
@@ -558,8 +590,8 @@ export const ScheduleScreen: React.FC = () => {
|
||||
const startMergedSection = getMergedSectionIndex(course.startSection);
|
||||
const endMergedSection = getMergedSectionIndex(course.endSection);
|
||||
const duration = endMergedSection - startMergedSection + 1;
|
||||
const top = (startMergedSection - 1) * SECTION_HEIGHT;
|
||||
const height = duration * SECTION_HEIGHT - 4;
|
||||
const top = (startMergedSection - 1) * sectionHeight;
|
||||
const height = duration * sectionHeight - 4;
|
||||
const laneGap = 2;
|
||||
const baseLeft = 2;
|
||||
const availableWidth = dayColumnWidth - baseLeft * 2;
|
||||
@@ -618,9 +650,8 @@ export const ScheduleScreen: React.FC = () => {
|
||||
style={[
|
||||
styles.dayColumn,
|
||||
{
|
||||
width: dayColumnWidth,
|
||||
borderRightWidth: isLastColumn ? 0 : 1,
|
||||
backgroundColor: columnIndex === activeTodayColumn ? `${colors.primary.main}08` : 'transparent',
|
||||
backgroundColor: columnIndex === activeTodayColumn ? `${colors.primary.main}08` : colors.background.default,
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -633,7 +664,7 @@ export const ScheduleScreen: React.FC = () => {
|
||||
key={slot.section}
|
||||
style={[
|
||||
styles.gridCell,
|
||||
{ height: SECTION_HEIGHT },
|
||||
{ height: sectionHeight },
|
||||
]}
|
||||
activeOpacity={1}
|
||||
delayLongPress={280}
|
||||
@@ -652,7 +683,11 @@ export const ScheduleScreen: React.FC = () => {
|
||||
};
|
||||
|
||||
// 渲染课程表主体
|
||||
const renderScheduleBody = () => (
|
||||
const renderScheduleBody = () => {
|
||||
// 移动端和电脑端都不添加额外底部间距,让内容填满整个区域
|
||||
// 动态计算的高度已经确保第六节课显示在正确位置
|
||||
|
||||
return (
|
||||
<PanGestureHandler
|
||||
activeOffsetX={[-8, 8]}
|
||||
failOffsetY={[-80, 80]}
|
||||
@@ -661,13 +696,14 @@ export const ScheduleScreen: React.FC = () => {
|
||||
<View style={styles.scheduleBodyGestureLayer}>
|
||||
<ScrollView
|
||||
style={styles.scheduleBody}
|
||||
showsVerticalScrollIndicator={true}
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.scheduleBodyContent}
|
||||
>
|
||||
{renderTimeColumn()}
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
>
|
||||
<View style={styles.daysContainer}>
|
||||
{VISIBLE_DAY_VALUES.map((dayOfWeek, index) =>
|
||||
@@ -678,7 +714,8 @@ export const ScheduleScreen: React.FC = () => {
|
||||
</ScrollView>
|
||||
</View>
|
||||
</PanGestureHandler>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} edges={['top']}>
|
||||
@@ -1063,11 +1100,11 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
height: HEADER_HEIGHT,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
},
|
||||
timeHeader: {
|
||||
borderRightWidth: StyleSheet.hairlineWidth,
|
||||
borderRightWidth: 1,
|
||||
borderRightColor: colors.divider,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
@@ -1079,6 +1116,7 @@ const styles = StyleSheet.create({
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
dayHeader: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 3,
|
||||
@@ -1118,7 +1156,6 @@ const styles = StyleSheet.create({
|
||||
scheduleBody: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default,
|
||||
marginBottom: TAB_BAR_HEIGHT,
|
||||
},
|
||||
scheduleBodyGestureLayer: {
|
||||
flex: 1,
|
||||
@@ -1164,11 +1201,16 @@ const styles = StyleSheet.create({
|
||||
// ── 日期列容器 ────────────────────────────────────────
|
||||
daysContainer: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default,
|
||||
minWidth: TIME_COLUMN_WIDTH, // 确保最小宽度
|
||||
},
|
||||
|
||||
// ── 单日列 ────────────────────────────────────────────
|
||||
dayColumn: {
|
||||
borderRightWidth: StyleSheet.hairlineWidth,
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default, // 使用主题默认背景色
|
||||
borderRightWidth: 1,
|
||||
borderRightColor: '#EBEBEB',
|
||||
},
|
||||
gridCell: {
|
||||
|
||||
Reference in New Issue
Block a user