Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/(guest)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import dayjs from 'dayjs';
import { Stack, useFocusEffect } from 'expo-router';
import * as ExpoSplashScreen from 'expo-splash-screen';
import { useCallback, useEffect, useState } from 'react';
Expand Down Expand Up @@ -105,7 +106,7 @@ export default function SplashScreen() {
const lastDate = await AsyncStorage.getItem(SPLASH_DATE);
let displayCount = 0;
// 如果上次展示不是今天,重置计数
if (lastDate !== new Date().toDateString()) {
if (lastDate !== dayjs().format('YYYY-MM-DD')) {
await AsyncStorage.setItem(SPLASH_DISPLAY_COUNT, '0');
} else {
displayCount = Number(await AsyncStorage.getItem(SPLASH_DISPLAY_COUNT));
Expand All @@ -124,7 +125,7 @@ export default function SplashScreen() {
setShowSplashImage(true);
await AsyncStorage.multiSet([
[SPLASH_DISPLAY_COUNT, (displayCount + 1).toString()],
[SPLASH_DATE, new Date().toDateString()],
[SPLASH_DATE, dayjs().format('YYYY-MM-DD')],
]);
} catch {
// 不使用 handleError,静默处理
Expand Down
3 changes: 2 additions & 1 deletion app/common/about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { Icon } from '@/components/Icon';
import PageContainer from '@/components/page-container';
import { Text } from '@/components/ui/text';
import dayjs from 'dayjs';
import Constants from 'expo-constants';
import { Href, Link, Stack, router } from 'expo-router';
import { useCallback, useEffect, useState } from 'react';
Expand Down Expand Up @@ -152,7 +153,7 @@ export default function AboutPage() {
已通过福州大学网络安全和信息化办公室安全质量检测
</Text>
<Text className="mb-6 text-center text-sm text-text-tertiary">
Copyright &copy; 2017-{new Date().getFullYear()} west2-online. All Rights Reserved.
Copyright &copy; 2017-{dayjs().year()} west2-online. All Rights Reserved.
</Text>
</SafeAreaView>
</View>
Expand Down
3 changes: 2 additions & 1 deletion app/common/academic-calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { Stack } from 'expo-router';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { FlatList, RefreshControl, useWindowDimensions } from 'react-native';
Expand Down Expand Up @@ -33,7 +34,7 @@ const AcademicContent = React.memo<CourseContentProps>(({ term }) => {
});

const termData = useMemo(() => data?.events || [], [data]);
const lastUpdated = useMemo(() => new Date(dataUpdatedAt), [dataUpdatedAt]);
const lastUpdated = useMemo(() => dayjs(dataUpdatedAt).toDate(), [dataUpdatedAt]);
const { bottom } = useSafeAreaInsets();

const keyExtractor = useCallback((item: any, index: number) => `${item.name}-${index}`, []);
Expand Down
12 changes: 2 additions & 10 deletions app/devtools/learning-center-api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,15 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Text } from '@/components/ui/text';
import { LearningCenterContext } from '@/context/learning-center';
import dayjs from 'dayjs';
import { router, Stack } from 'expo-router';
import { useCallback, useContext, useState } from 'react';
import { ScrollView } from 'react-native-gesture-handler';
import { SafeAreaView } from 'react-native-safe-area-context';
import { toast } from 'sonner-native';

// 用于生成符合后端要求的日期格式
const formatDate = (timestamp: number) => {
const date = new Date(timestamp);
const year = date.getFullYear();
const month = ('0' + (date.getMonth() + 1)).slice(-2);
const day = ('0' + date.getDate()).slice(-2);
return `${year}-${month}-${day}`;
};

export default function LearningCenterApi() {
const [date, setDate] = useState(formatDate(Date.now() + 24 * 60 * 60 * 3000)); // 初始化为三天后的日期
const [date, setDate] = useState(dayjs().add(3, 'day').format('YYYY-MM-DD')); // 初始化为三天后的日期
const [beginTime, setStartTime] = useState(''); // 开始时间
const [endTime, setEndTime] = useState(''); // 结束时间
const [spaceName, setSpaceName] = useState('');
Expand Down
3 changes: 2 additions & 1 deletion app/toolbox/academic/credits.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { Stack } from 'expo-router';
import React, { useCallback, useMemo, useState } from 'react';
import { FlatList, RefreshControl, useWindowDimensions } from 'react-native';
Expand Down Expand Up @@ -36,7 +37,7 @@ const TabContent = React.memo<TabContentProps>(({ group, dataUpdatedAt, onRefres
refreshControl={<RefreshControl refreshing={false} onRefresh={onRefresh} />}
ListEmptyComponent={<EmptyView className="-h-screen-safe-offset-12" />}
ListFooterComponent={
group.data && group.data.length > 0 ? <LastUpdateTime lastUpdated={new Date(dataUpdatedAt)} /> : null
group.data && group.data.length > 0 ? <LastUpdateTime lastUpdated={dayjs(dataUpdatedAt).toDate()} /> : null
}
style={{ width: screenWidth }}
/>
Expand Down
3 changes: 2 additions & 1 deletion app/toolbox/academic/grades.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { Tabs } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { FlatList, RefreshControl, useWindowDimensions } from 'react-native';
Expand Down Expand Up @@ -31,7 +32,7 @@ interface TermContentProps {
// 单个学期的内容
const TermContent = React.memo<TermContentProps>(({ termData, dataUpdatedAt, onRefresh }) => {
const { width: screenWidth } = useWindowDimensions(); // 获取屏幕宽度
const lastUpdated = useMemo(() => new Date(dataUpdatedAt), [dataUpdatedAt]);
const lastUpdated = useMemo(() => dayjs(dataUpdatedAt).toDate(), [dataUpdatedAt]);
const summary = useMemo(() => calSingleTermSummary(termData), [termData]);
const sortedTermData = useMemo(() => {
return termData.sort((a, b) => parseScore(b.score) - parseScore(a.score));
Expand Down
3 changes: 2 additions & 1 deletion app/toolbox/academic/unified-exam.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { Stack } from 'expo-router';
import { RefreshControl, ScrollView } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
Expand All @@ -15,7 +16,7 @@ export default function UnifiedExamScorePage() {
// 获取统考成绩数据
const apiResult = useApiRequest(getApiV1JwchAcademicUnifiedExam);
const { data: unifiedExamData, dataUpdatedAt, isFetching, refetch } = apiResult;
const lastUpdated = new Date(dataUpdatedAt);
const lastUpdated = dayjs(dataUpdatedAt).toDate();

const { state } = useMultiStateRequest(apiResult, {
emptyCondition: data => !data || data.length === 0,
Expand Down
13 changes: 7 additions & 6 deletions app/toolbox/exam-room.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { Stack } from 'expo-router';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { FlatList, RefreshControl, useWindowDimensions } from 'react-native';
Expand Down Expand Up @@ -37,7 +38,7 @@ const TermContent = React.memo<TermContentProps>(({ term }) => {
const termData = useMemo(
() =>
formatExamData(data || []).sort((a, b) => {
const now = new Date(); // 当前日期
const now = dayjs(); // 当前日期
// 排序优先级 最近的考试 > 稍近的考试 > 过期的考试 > 没有日期的考试

// 如果只有一个有 date,优先排序有 date 的
Expand All @@ -48,23 +49,23 @@ const TermContent = React.memo<TermContentProps>(({ term }) => {
if (!a.date && !b.date) return 0;

// 两者都有 date,确保 date 是有效的
const dateA = new Date(a.date!); // 使用非空断言(!)告诉 TypeScript 这里一定有值
const dateB = new Date(b.date!);
const dateA = dayjs(a.date); // 使用 dayjs 解析日期
const dateB = dayjs(b.date);

// 如果一个未完成一个已完成,未完成优先
if (a.isFinished && !b.isFinished) return 1; // a 已完成,b 未完成,b 优先
if (!a.isFinished && b.isFinished) return -1; // a 未完成,b 已完成,a 优先

// 计算与当前日期的时间差
const diffA = Math.abs(dateA.getTime() - now.getTime());
const diffB = Math.abs(dateB.getTime() - now.getTime());
const diffA = Math.abs(dateA.diff(now, 'millisecond'));
const diffB = Math.abs(dateB.diff(now, 'millisecond'));

// 时间差小的优先
return diffA - diffB;
}),
[data],
);
const lastUpdated = useMemo(() => new Date(dataUpdatedAt), [dataUpdatedAt]);
const lastUpdated = useMemo(() => dayjs(dataUpdatedAt).toDate(), [dataUpdatedAt]);
const { bottom } = useSafeAreaInsets();
const contentContainerStyle = useMemo(() => ({ paddingBottom: bottom }), [bottom]);
const flatListStyle = useMemo(() => ({ width: screenWidth }), [screenWidth]);
Expand Down
18 changes: 12 additions & 6 deletions app/toolbox/learning-center/qr-scanner.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import dayjs from 'dayjs';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import { CameraView, useCameraPermissions } from 'expo-camera';
import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
import { useEffect, useState } from 'react';
Expand All @@ -11,6 +14,9 @@ import { Text } from '@/components/ui/text';
import { useLearningCenterApi } from '@/context/learning-center';
import { SafeAreaView } from 'react-native-safe-area-context';

dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);

export default function QrScannerPage() {
const router = useRouter();
const { appointmentId } = useLocalSearchParams<{ appointmentId: string }>();
Expand Down Expand Up @@ -40,22 +46,22 @@ export default function QrScannerPage() {
return false;
}

const startTime = new Date(parts[1]);
const endTime = new Date(parts[2]);
const currentTime = new Date();
const startTime = dayjs(parts[1]);
const endTime = dayjs(parts[2]);
const currentTime = dayjs();

if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) {
if (!startTime.isValid() || !endTime.isValid()) {
return false;
}

// 验证时间间隔为1分钟
const timeDiffInMinutes = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
const timeDiffInMinutes = endTime.diff(startTime, 'minute', true);
if (Math.abs(timeDiffInMinutes - 1) > 0.1) {
return false;
}

// 检查当前时间是否在有效期内
return currentTime >= startTime && currentTime <= endTime;
return currentTime.isSameOrAfter(startTime) && currentTime.isSameOrBefore(endTime);
} catch (error) {
console.error('QR码验证失败:', error);
return false;
Expand Down
9 changes: 5 additions & 4 deletions app/toolbox/learning-center/time-select.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { router, Stack } from 'expo-router';
import { useCallback, useMemo, useState } from 'react';
import { FlatList, View } from 'react-native';
Expand All @@ -13,14 +14,14 @@ import { SafeAreaView } from 'react-native-safe-area-context';

export default function SeatsPage() {
// 修改默认日期,如果当前时间晚于或等于22:00则为次日
const now = new Date();
const defaultDate = now.getHours() >= 22 ? new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1) : now;
const now = dayjs();
const defaultDate = now.hour() >= 22 ? now.add(1, 'day').toDate() : now.toDate();
const [selectedDate, setSelectedDate] = useState(defaultDate);
const [beginTime, setBeginTime] = useState<string | null>(null);
const [endTime, setEndTime] = useState<string | null>(null);

// 生成未来7天的日期
const dates = useMemo(() => Array.from({ length: 7 }, (_, index) => addHours(new Date(), 24 * index)), []);
const dates = useMemo(() => Array.from({ length: 7 }, (_, index) => addHours(dayjs().toDate(), 24 * index)), []);

// 生成时间段 8:00 - 22:30 每隔30分钟
const timeSlots = useMemo(() => {
Expand Down Expand Up @@ -130,7 +131,7 @@ export default function SeatsPage() {
scrollEnabled={false}
renderItem={({ item }) => (
<DateCard
date={item.getDate().toString()}
date={dayjs(item).date().toString()}
day={formatDate(item, 'EEE')}
onPress={() => {
setSelectedDate(item);
Expand Down
4 changes: 1 addition & 3 deletions components/course/course-week.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const DAYS = ['一', '二', '三', '四', '五', '六', '日'];

// 一周课表
const CourseWeek: React.FC<CourseWeekProps> = ({ week, startDate, schedulesByDays, flatListLayout }) => {
const month = useMemo(() => new Date(startDate).getMonth() + 1, [startDate]);
const month = useMemo(() => dayjs(startDate).month() + 1, [startDate]);
const [currentDate, setCurrentDate] = useState(dayjs().format(DATE_FORMAT_FULL)); // 当前日期

useEffect(() => {
Expand All @@ -39,8 +39,6 @@ const CourseWeek: React.FC<CourseWeekProps> = ({ week, startDate, schedulesByDay

// 头部日期
const headerDays = useMemo(() => {
const today = new Date();
today.setHours(today.getHours() + 8);
return Array.from({ length: 7 }, (_, i) => {
const newDate = dayjs(startDate).add(i, 'day');
const isToday = newDate.isSame(currentDate, 'day');
Expand Down
7 changes: 2 additions & 5 deletions components/course/time-col.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import { memo, useEffect, useMemo, useState } from 'react';
import { Text, View } from 'react-native';

Expand All @@ -20,11 +21,7 @@ const isTimeInRange = (currentTime: string, startTime: string, endTime: string):

// 获取当前时间的字符串格式(HH:mm)
const getCurrentTime = () => {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');

return `${hours}:${minutes}`;
return dayjs().format('HH:mm');
};

interface TimeColProps {
Expand Down
8 changes: 4 additions & 4 deletions lib/course.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ export class CourseCache {
*/
public static mergeExamCourses(exam: MergedExamData[], semesterStart: string, semesterEnd: string) {
// 更新时间戳
this.lastExamUpdateTime = new Date().toLocaleString();
this.lastExamUpdateTime = dayjs().format('YYYY/M/D HH:mm:ss');
// 生成当前 tempData 的 digest
const currentDigest = this.calculateDigest(exam);
// 如果当前 digest 和上一次的 digest 一致,则不再进行后续处理
Expand Down Expand Up @@ -563,7 +563,7 @@ export class CourseCache {
/* 缓存校对处理,如果缓存和传入的数据一致,不做任何改动 */

// 更新时间戳
this.lastCourseUpdateTime = new Date().toLocaleString();
this.lastCourseUpdateTime = dayjs().format('YYYY/M/D HH:mm:ss');
// 生成当前 tempData 的 digest
const currentDigest = this.calculateDigest(tempData);

Expand Down Expand Up @@ -633,7 +633,7 @@ export class CourseCache {
...course,
id: this.allocateID(),
storageKey: randomUUID(),
lastUpdateTime: new Date().toISOString(),
lastUpdateTime: dayjs().toISOString(),
};

this.cachedCustomData[newIndex].push(newCourse);
Expand Down Expand Up @@ -676,7 +676,7 @@ export class CourseCache {

const updatedCourse: CustomCourse = {
...course,
lastUpdateTime: new Date().toISOString(),
lastUpdateTime: dayjs().toISOString(),
};

// 先删除再添加
Expand Down
27 changes: 10 additions & 17 deletions lib/locate-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,37 +76,30 @@ export default async function locateDate(noCache = false): Promise<LocateDateRes

// 根据学期开始日期和当前周数获取当前周的第一天日期
export function getFirstDateByWeek(semesterStart: string, currentWeek: number): string {
const startDate = new Date(semesterStart);
const startDayOfWeek = (startDate.getDay() + 6) % 7; // 将星期日(0)转换为 6,其他天数减 1 对应星期一到星期六
const adjustedStartDate = new Date(startDate);
const startDate = dayjs(semesterStart);
const startDayOfWeek = (startDate.day() + 6) % 7; // 将星期日(0)转换为 6,其他天数减 1 对应星期一到星期六
const adjustedStartDate = startDate.subtract(startDayOfWeek, 'day');

// 如果学期开始日期不是星期一,则调整到最近的星期一
adjustedStartDate.setDate(startDate.getDate() - startDayOfWeek);
const firstDayOfWeek = adjustedStartDate.add((currentWeek - 1) * 7, 'day');

const firstDayOfWeek = new Date(adjustedStartDate);
firstDayOfWeek.setDate(firstDayOfWeek.getDate() + (currentWeek - 1) * 7);

return firstDayOfWeek.toISOString().split('T')[0]; // 返回日期字符串格式 YYYY-MM-DD
return firstDayOfWeek.format('YYYY-MM-DD'); // 返回日期字符串格式 YYYY-MM-DD
}

// 根据学期开始日期和当前周数获取当前周的日期(会返回一个完整的一周)
export function getDatesByWeek(semesterStart: string, currentWeek: number): string[] {
const firstDayOfWeek = new Date(getFirstDateByWeek(semesterStart, currentWeek));
firstDayOfWeek.setDate(firstDayOfWeek.getDate() + (currentWeek - 1) * 7);
const firstDayOfWeek = dayjs(getFirstDateByWeek(semesterStart, currentWeek));

return Array.from({ length: 7 }, (_, i) => {
const date = new Date(firstDayOfWeek);
date.setDate(firstDayOfWeek.getDate() + i);
return date.toISOString().split('T')[0]; // 返回日期字符串格式 YYYY-MM-DD
return firstDayOfWeek.add(i, 'day').format('YYYY-MM-DD'); // 返回日期字符串格式 YYYY-MM-DD
});
}

// 根据学期开始日期和结束日期计算一学期一共有多少周
export function getWeeksBySemester(semesterStart: string, semesterEnd: string): number {
const startDate = new Date(semesterStart);
const endDate = new Date(semesterEnd);
const diffTime = Math.abs(endDate.getTime() - startDate.getTime());
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
const startDate = dayjs(semesterStart);
const endDate = dayjs(semesterEnd);
const diffDays = endDate.diff(startDate, 'day');

return Math.ceil(diffDays / 7);
}
Expand Down
15 changes: 5 additions & 10 deletions utils/learning-center/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@ import dayjs from 'dayjs';

// 判断时间是否已过
export const isTimePast = (date: Date, timeStr: string): boolean => {
const isToday = formatDate(date, 'YYYY-MM-DD') === formatDate(new Date(), 'YYYY-MM-DD');
const isToday = formatDate(date, 'YYYY-MM-DD') === dayjs().format('YYYY-MM-DD');

if (!isToday) return false;

const now = new Date();
const currentHour = now.getHours();
const currentMinute = now.getMinutes();

const now = dayjs();
const [hour, minute] = timeStr.split(':').map(Number);
const targetTime = dayjs().hour(hour).minute(minute);

if (currentHour > hour) return true;
if (currentHour === hour && currentMinute >= minute) return true;

return false;
return now.isAfter(targetTime) || now.isSame(targetTime);
};

// 格式化日期
Expand Down Expand Up @@ -47,5 +42,5 @@ export const calculateHoursDifference = (startTime: string, endTime: string): nu

// 添加指定小时到当前日期
export const addHours = (date: Date, hours: number): Date => {
return new Date(date.getTime() + hours * 60 * 60 * 1000);
return dayjs(date).add(hours, 'hour').toDate();
};
Loading