Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

课表页面 #14

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
8 changes: 7 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"[html]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
Expand All @@ -19,15 +20,20 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[yaml]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
},
"tailwindCSS.rootFontSize": 14
}
19 changes: 17 additions & 2 deletions app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import { Tabs } from 'expo-router';

import { TabBarIcon } from '@/components/navigation/TabBarIcon';
import { HeaderIcon } from '@/components/HeaderIcon';
import { TabBarIcon } from '@/components/TabBarIcon';
import { Text, View } from 'react-native';

export default function TabLayout() {
return (
<Tabs>
<Tabs.Screen
name="index"
options={{
title: '主页',
title: '课程',
headerTitleAlign: 'center',
// eslint-disable-next-line react/no-unstable-nested-components
headerLeft: props => (
<View className="px-4">
<Text>第 X 周</Text>
</View>
),
// eslint-disable-next-line react/no-unstable-nested-components
headerRight: props => (
<View className="px-4">
<HeaderIcon name="settings-outline" />
</View>
),
// eslint-disable-next-line react/no-unstable-nested-components
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'calendar' : 'calendar-outline'} color={color} />
Expand Down
193 changes: 163 additions & 30 deletions app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,174 @@
import { Alert, Button, Text, TextInput } from 'react-native';
import { useState } from 'react';
import { Pressable, ScrollView, Text, View } from 'react-native';

import { getApiV1JwchCourseList, getApiV1JwchUserInfo } from '@/api/generate';
import { ThemedView } from '@/components/ThemedView';
import { getApiV1JwchCourseList } from '@/api/generate';
import usePersistedQuery from '@/hooks/usePersistedQuery';
import { useState } from 'react';
import { parseCourses, type ParsedCourse } from '@/utils/parseCourses';

const classes = [
['08:20', '09:05'],
['09:15', '10:00'],
['10:20', '11:05'],
['11:15', '12:00'],
['14:00', '14:45'],
['14:55', '15:40'],
['15:50', '16:35'],
['16:45', '17:30'],
['19:00', '19:45'],
['19:55', '20:40'],
['20:50', '21:35'],
];

function Header() {
return (
<View className="flex flex-none flex-row items-center bg-white shadow ring-1 ring-black ring-opacity-5">
<View className="w-[32px] flex-shrink-0 flex-grow-0">
<View className="flex flex-shrink-0 flex-col items-center justify-center px-2 py-3">
<Text>10</Text>
<Text>月</Text>
</View>
</View>
<View className="flex flex-shrink flex-grow flex-row">
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周一</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center rounded-full bg-indigo-600 text-center align-middle font-semibold text-white">
10
</Text>
</Pressable>
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周二</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center text-center align-middle font-semibold text-gray-900">
11
</Text>
</Pressable>
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周三</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center text-center align-middle font-semibold text-gray-900">
12
</Text>
</Pressable>
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周四</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center text-center align-middle font-semibold text-gray-900">
13
</Text>
</Pressable>
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周五</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center text-center align-middle font-semibold text-gray-900">
14
</Text>
</Pressable>
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周六</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center text-center align-middle font-semibold text-gray-900">
15
</Text>
</Pressable>
<Pressable className="flex flex-grow flex-col items-center pb-3 pt-2">
<Text className="text-sm text-gray-500">周日</Text>
<Text className="mt-1 flex h-8 w-8 items-center justify-center text-center align-middle font-semibold text-gray-900">
16
</Text>
</Pressable>
</View>
</View>
);
}

interface CalendarColProps {
week: number;
weekday: number;
schedules: ParsedCourse[];
}

function CalendarCol({ week, weekday, schedules }: CalendarColProps) {
const [height, setHeight] = useState<number>(49 * 11);

const schedulesOnDay = schedules.filter(schedule => schedule.weekday === weekday);

console.log(schedulesOnDay, weekday);
const res: React.ReactNode[] = [];

for (let i = 1; i <= 11; i++) {
const schedule = schedulesOnDay.find(s => s.startClass === i && s.startWeek <= week && s.endWeek >= week);

if (schedule) {
const span = schedule.endClass - schedule.startClass + 1;

res.push(
<Pressable
key={i}
className="flex min-h-14 flex-shrink-0 flex-grow-0 basis-0 flex-col items-center justify-center border border-gray-200"
style={{
flexGrow: span,
height: (span / 11) * height,
}}
>
<Text className="truncate text-wrap break-all text-center text-[10px] text-gray-500">{schedule.name}</Text>
<Text className="text-wrap break-all text-[8px] text-gray-500">{schedule.location}</Text>
</Pressable>,
);

i += span - 1;
} else {
res.push(
<View
key={i}
className="flex-grow-1 flex min-h-14 flex-shrink-0 basis-0 flex-col items-center justify-center"
/>,
);
}
}

return (
<View
className="flex w-[14.285714%] flex-shrink-0 flex-grow flex-col"
onLayout={({ nativeEvent }) => {
setHeight(nativeEvent.layout.height);
}}
>
{res}
</View>
);
}

export default function HomePage() {
const [term, setTerm] = useState('202401');
const term = '202401';
const week = 10;
const { data, isLoading } = usePersistedQuery({
queryKey: ['getApiV1JwchCourseList', term],
queryFn: () =>
getApiV1JwchCourseList({
term,
}),
queryFn: () => getApiV1JwchCourseList({ term }),
});
async function test2() {
const data = {
term: '202401',
};
const res = await getApiV1JwchUserInfo(data);
Alert.alert(JSON.stringify(res));
}

if (!data) return null;

const schedules = parseCourses(data.data.data);

return (
<>
<ThemedView>
<Text>{isLoading}</Text>
<TextInput value={term} onChangeText={text => setTerm(text)} />
<Text>{JSON.stringify(data, null, 2)}</Text>

<Button
title="ss2"
onPress={() => {
test2();
}}
/>
</ThemedView>
</>
<ScrollView
className="flex h-full flex-auto flex-col overflow-auto bg-white"
stickyHeaderIndices={[0]}
overScrollMode="never"
bounces={false}
>
<Header />
<View className="flex flex-none flex-grow flex-row py-1">
<View className="flex w-[32px] flex-shrink-0 flex-grow-0 basis-[32px] flex-col">
{classes.map((time, index) => (
<View key={index} className="flex min-h-14 w-[32px] flex-grow flex-col items-center py-1">
<Text className="text-[12px] font-bold text-gray-500">{index + 1}</Text>
<Text className="text-[8px] text-gray-500">{time[0]}</Text>
<Text className="text-[8px] text-gray-500">{time[1]}</Text>
</View>
))}
</View>
<View className="flex flex-shrink flex-grow flex-row">
{Array.from({ length: 7 }).map((_, index) => (
<CalendarCol key={index} week={week} weekday={index + 1} schedules={schedules} />
))}
</View>
</View>
</ScrollView>
);
}
73 changes: 73 additions & 0 deletions backend.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
export interface GetCourseListResponse {
code: string;
data: Course[];
message: string;
}

export interface Course {
/**
* 授课计划地址
*/
lessonplan: string;
/**
* 课程名
*/
name: string;
rawAdjust: string;
rawScheduleRules: string;
/**
* 备注
*/
remark: string;
/**
* 课程安排
*/
scheduleRules: CourseScheduleRule[];
/**
* 教学大纲地址
*/
syllabus: string;
/**
* 老师
*/
teacher: string;
}

export interface CourseScheduleRule {
/**
* 调课
*/
adjust: boolean;
/**
* 双周
*/
double: boolean;
/**
* 结束节次
*/
endClass: number;
/**
* 结束周数
*/
endWeek: number;
/**
* 上课地点
*/
location: string;
/**
* 单周
*/
single: boolean;
/**
* 开始节次
*/
startClass: number;
/**
* 起始周数
*/
startWeek: number;
/**
* 周几
*/
weekday: number;
}
9 changes: 9 additions & 0 deletions components/HeaderIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Ionicons from '@expo/vector-icons/Ionicons';
import { type IconProps } from '@expo/vector-icons/build/createIconSet';
import { type ComponentProps } from 'react';

export function HeaderIcon({
...rest
}: IconProps<ComponentProps<typeof Ionicons>['name']>) {
return <Ionicons size={20} {...rest} />;
}
File renamed without changes.
11 changes: 11 additions & 0 deletions metro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
const { withNativeWind } = require('nativewind/metro');

/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);

module.exports = withNativeWind(config, {
input: './global.css',
inlineRem: false,
});
10 changes: 0 additions & 10 deletions metro.config.ts

This file was deleted.

3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
"@expo/vector-icons": "^14.0.2",
"@react-native-async-storage/async-storage": "1.23.1",
"@react-navigation/native": "^6.0.2",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/react-query": "^5.59.16",
"axios": "^1.7.9",
"expo": "~51.0.28",
Expand Down
2 changes: 1 addition & 1 deletion tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const config: Config = {
theme: {
extend: {},
},
plugins: [require('@tailwindcss/aspect-ratio'), require('@tailwindcss/typography'), require('@tailwindcss/forms')],
plugins: [],
};

export default config;
Loading
Loading