Skip to content

Commit 7cf50f2

Browse files
Merge pull request #213 from Muxi-X/feature/classroom
feat(pages): add classroom page
2 parents f4678c4 + 48a0750 commit 7cf50f2

32 files changed

Lines changed: 1359 additions & 229 deletions

File tree

src/app/(mainPage)/_layout.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ const TITLE_MAP: Record<string, string> = {
1111
electricityBillinBalance: '电费查询',
1212
webview: '常用网站',
1313
scoreCalculation: '计算学分绩',
14+
classroom: '空闲教室',
15+
classroomStar: '我的收藏',
1416
};
1517

16-
// 这些页面有自己的内部 header,不需要布局层的 CustomStackHeader
17-
const PAGES_WITH_OWN_HEADER = new Set<string>([]);
18-
1918
function useCurrentTitle() {
2019
const segments = useSegments();
2120
const lastName = segments[segments.length - 1];
@@ -28,21 +27,15 @@ function useCurrentTitle() {
2827

2928
export default function Layout() {
3029
const currentStyle = useVisualScheme(state => state.currentStyle);
31-
const segments = useSegments();
3230
const title = useCurrentTitle();
3331
const headerRight = useHeaderRightStore(state => state.content);
3432

35-
const lastName = segments[segments.length - 1];
36-
const hideHeader = PAGES_WITH_OWN_HEADER.has(lastName);
37-
3833
return (
3934
<SafeAreaView
4035
edges={['bottom']}
4136
style={[styles.container, currentStyle?.background_style]}
4237
>
43-
{!hideHeader && (
44-
<CustomStackHeader title={title} headerRight={headerRight} />
45-
)}
38+
<CustomStackHeader title={title} headerRight={headerRight} />
4639
<Stack
4740
screenOptions={{
4841
headerShown: false,
@@ -59,6 +52,7 @@ export default function Layout() {
5952
<Stack.Screen name="scoreCalculation" />
6053
<Stack.Screen name="electricityBillinBalance" />
6154
<Stack.Screen name="webview" />
55+
<Stack.Screen name="classroomStar" />
6256
</Stack>
6357
</SafeAreaView>
6458
);

src/app/(mainPage)/classroom.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { router, useFocusEffect } from 'expo-router';
2+
import * as React from 'react';
3+
import { StyleSheet, TouchableOpacity, View } from 'react-native';
4+
5+
import { useClassroomData } from '@/hooks';
6+
7+
import Modal from '@/components/modal';
8+
import Text from '@/components/text';
9+
10+
import { useClassroomWarningStore } from '@/store/classroom';
11+
import { useHeaderRightStore } from '@/store/headerRight';
12+
import useVisualScheme from '@/store/visualScheme';
13+
14+
import StarIcon from '@/assets/icons/star.svg';
15+
import { ClassroomContent } from '@/modules/mainPage/components/classroom';
16+
17+
export default function Classroom() {
18+
const currentStyle = useVisualScheme(state => state.currentStyle);
19+
const setHeaderRight = useHeaderRightStore(state => state.setContent);
20+
21+
const classroomProps = useClassroomData();
22+
23+
const warningHydrated = useClassroomWarningStore(state => state.hydrated);
24+
const warningShown = useClassroomWarningStore(state => state.warningShown);
25+
const setWarningShown = useClassroomWarningStore(
26+
state => state.setWarningShown
27+
);
28+
29+
React.useEffect(() => {
30+
if (!warningHydrated || warningShown) return;
31+
Modal.show({
32+
title: '温馨提示',
33+
children:
34+
'空闲教室数据来自学校官方平台,但仍可能更新不及时或出现错误,请以实际教室使用情况为准。',
35+
confirmText: '我知道了',
36+
mode: 'middle',
37+
onConfirm: () => setWarningShown(true),
38+
onClose: () => setWarningShown(true),
39+
});
40+
}, [warningHydrated, warningShown, setWarningShown]);
41+
42+
const starButton = React.useMemo(
43+
() => (
44+
<TouchableOpacity
45+
onPress={() => router.push({ pathname: '/(mainPage)/classroomStar' })}
46+
style={styles.starButton}
47+
>
48+
<StarIcon width={24} height={24} color="#FFD700" />
49+
<Text style={[styles.starLabel, currentStyle?.header_text_style]}>
50+
我的收藏
51+
</Text>
52+
</TouchableOpacity>
53+
),
54+
[currentStyle?.header_text_style]
55+
);
56+
57+
useFocusEffect(
58+
React.useCallback(() => {
59+
setHeaderRight(starButton);
60+
return () => setHeaderRight(null);
61+
}, [starButton, setHeaderRight])
62+
);
63+
64+
return (
65+
<View style={styles.container}>
66+
<ClassroomContent {...classroomProps} />
67+
</View>
68+
);
69+
}
70+
71+
const styles = StyleSheet.create({
72+
container: {
73+
flex: 1,
74+
},
75+
starButton: {
76+
alignItems: 'center',
77+
justifyContent: 'center',
78+
},
79+
starLabel: {
80+
fontSize: 10,
81+
},
82+
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as React from 'react';
2+
import { StyleSheet, View } from 'react-native';
3+
4+
import { useClassroomData } from '@/hooks';
5+
6+
import { useHeaderRightStore } from '@/store/headerRight';
7+
import useVisualScheme from '@/store/visualScheme';
8+
9+
import { ClassroomContent } from '@/modules/mainPage/components/classroom';
10+
11+
export default function ClassroomStar() {
12+
const currentStyle = useVisualScheme(state => state.currentStyle);
13+
const setHeaderRight = useHeaderRightStore(state => state.setContent);
14+
15+
// 使用共享的教室数据管理Hook,设置为过滤收藏的教室
16+
const classroomProps = useClassroomData(true);
17+
18+
React.useEffect(() => {
19+
setHeaderRight(null);
20+
}, [setHeaderRight]);
21+
22+
// 空状态配置
23+
const emptyStateConfig = {
24+
noStarredTitle: '还没有收藏任何教室',
25+
noStarredSubtitle: '去空闲教室页面收藏一些教室吧~',
26+
noDataTitle: '当前条件下没有收藏的教室',
27+
noDataSubtitle: '请尝试更换地点或楼层查看',
28+
};
29+
30+
return (
31+
<View style={[styles.container, currentStyle?.header_background_style]}>
32+
<ClassroomContent
33+
{...classroomProps}
34+
emptyStateConfig={emptyStateConfig}
35+
/>
36+
</View>
37+
);
38+
}
39+
40+
const styles = StyleSheet.create({
41+
container: {
42+
flex: 1,
43+
},
44+
});

src/app/(setting)/feedback/detail.tsx

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ import ThemeBasedView from '@/components/view';
1717

1818
import useVisualScheme from '@/store/visualScheme';
1919

20-
import { FEEDBACK_TABLE_IDENTIFY, STATUS_LABELS } from '@/constants/FEEDBACKS';
20+
import {
21+
FEEDBACK_TABLE_IDENTIFY,
22+
STATUS_LABELS,
23+
STATUS_STYLE_KEY,
24+
} from '@/constants/FEEDBACKS';
2125
import {
2226
getFeedbackImg,
2327
getSingleFeedbackRecord,
@@ -202,12 +206,12 @@ export default function FeedbackDetail() {
202206
style={[
203207
styles.circle,
204208
statusStep === step
205-
? currentStyle?.feedback_detail_statusCircle_style?.getStyle(
206-
STATUS_LABELS[step - 1]
207-
)
208-
: currentStyle?.feedback_detail_statusCircle_style?.getStyle(
209-
'默认'
210-
),
209+
? currentStyle?.feedback_detail_statusCircle_style?.[
210+
STATUS_STYLE_KEY[STATUS_LABELS[step - 1]]
211+
]
212+
: currentStyle?.feedback_detail_statusCircle_style?.[
213+
'default'
214+
],
211215
]}
212216
>
213217
<Text
@@ -225,9 +229,9 @@ export default function FeedbackDetail() {
225229
style={[
226230
styles.stepLabel,
227231
statusStep === step &&
228-
currentStyle?.feedback_statusText_style?.getStyle(
229-
STATUS_LABELS[step - 1]
230-
),
232+
currentStyle?.feedback_statusText_style?.[
233+
STATUS_STYLE_KEY[STATUS_LABELS[step - 1]]
234+
],
231235
]}
232236
>
233237
{STATUS_LABELS[index]}
@@ -241,9 +245,9 @@ export default function FeedbackDetail() {
241245
key={i}
242246
style={[
243247
styles.connectorBar,
244-
currentStyle?.feedback_detail_statusCircle_style?.getStyle(
245-
'默认'
246-
),
248+
currentStyle?.feedback_detail_statusCircle_style?.[
249+
'default'
250+
],
247251
]}
248252
/>
249253
))}
@@ -297,17 +301,17 @@ export default function FeedbackDetail() {
297301
<View
298302
style={[
299303
styles.itemStatuscontainer,
300-
currentStyle?.feedback_status_style?.getStyle(
301-
feedbackItem.fields.status
302-
),
304+
currentStyle?.feedback_status_style?.[
305+
STATUS_STYLE_KEY[feedbackItem.fields.status] ?? 'pending'
306+
],
303307
]}
304308
>
305309
<Text
306310
style={[
307311
styles.itemStatustext,
308-
currentStyle?.feedback_statusText_style?.getStyle(
309-
feedbackItem.fields.status
310-
),
312+
currentStyle?.feedback_statusText_style?.[
313+
STATUS_STYLE_KEY[feedbackItem.fields.status] ?? 'pending'
314+
],
311315
]}
312316
>
313317
{feedbackItem.fields.status}

src/app/(setting)/feedback/history.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import useVisualScheme from '@/store/visualScheme';
2323
import {
2424
FEEDBACK_RECORD_NAMES,
2525
FEEDBACK_TABLE_IDENTIFY,
26+
STATUS_STYLE_KEY,
2627
} from '@/constants/FEEDBACKS';
2728
import { queryUserFeedbackSheet } from '@/request/api/feedback';
2829

@@ -189,15 +190,17 @@ const FeedbackListItem: React.FC<{ item: FeedbackItem }> = React.memo(
189190
<View
190191
style={[
191192
styles.itemFooterContainer,
192-
currentStyle?.feedback_status_style?.getStyle(item.fields.status),
193+
currentStyle?.feedback_status_style?.[
194+
STATUS_STYLE_KEY[item.fields.status] ?? 'pending'
195+
],
193196
]}
194197
>
195198
<Text
196199
style={[
197200
styles.itemFootertext,
198-
currentStyle?.feedback_statusText_style?.getStyle(
199-
item.fields.status
200-
),
201+
currentStyle?.feedback_statusText_style?.[
202+
STATUS_STYLE_KEY[item.fields.status] ?? 'pending'
203+
],
201204
]}
202205
>
203206
{item.fields.status}

src/assets/icons/choose.svg

Lines changed: 3 additions & 0 deletions
Loading

src/assets/icons/star-gray.svg

Lines changed: 3 additions & 0 deletions
Loading

src/assets/icons/star.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)