| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- import { useRouter } from 'expo-router';
- import React, { useCallback, useEffect, useState } from 'react';
- import {
- ActivityIndicator,
- FlatList,
- RefreshControl,
- StatusBar,
- StyleSheet,
- Text,
- TouchableOpacity,
- View
- } from 'react-native';
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
- import { getMessageList } from '@/services/base';
- interface MessageItem {
- id: string;
- title: string;
- content: string;
- createTime: string;
- type?: string;
- }
- export default function MessageScreen() {
- const router = useRouter();
- const insets = useSafeAreaInsets();
-
- const [messages, setMessages] = useState<MessageItem[]>([]);
- const [loading, setLoading] = useState(false);
- const [refreshing, setRefreshing] = useState(false);
- const [pageNum, setPageNum] = useState(1);
- const [hasMore, setHasMore] = useState(true);
- const pageSize = 10;
- const loadData = useCallback(async (page: number, isRefresh = false) => {
- if (loading && !isRefresh) return;
-
- try {
- if (isRefresh) {
- setRefreshing(true);
- } else {
- setLoading(true);
- }
- const res = await getMessageList(page, pageSize);
- const records = res?.records || [];
-
- if (isRefresh) {
- setMessages(records);
- } else {
- setMessages(prev => [...prev, ...records]);
- }
-
- setHasMore(records.length >= pageSize);
- setPageNum(page);
- } catch (error) {
- console.error('获取消息失败:', error);
- } finally {
- setLoading(false);
- setRefreshing(false);
- }
- }, [loading]);
- useEffect(() => {
- loadData(1, true);
- }, []);
- const handleRefresh = () => {
- loadData(1, true);
- };
- const handleLoadMore = () => {
- if (hasMore && !loading) {
- loadData(pageNum + 1);
- }
- };
- const handleBack = () => {
- router.back();
- };
- const renderItem = ({ item }: { item: MessageItem }) => (
- <View style={styles.cell}>
- <View style={styles.cellHeader}>
- <View style={styles.icon}>
- <Text style={styles.iconText}>🔔</Text>
- </View>
- <Text style={styles.title} numberOfLines={1}>{item.title}</Text>
- <Text style={styles.time}>{item.createTime}</Text>
- </View>
- <Text style={styles.content}>{item.content}</Text>
- </View>
- );
- const renderEmpty = () => (
- <View style={styles.emptyBox}>
- <Text style={styles.emptyText}>暂无消息</Text>
- </View>
- );
- const renderFooter = () => {
- if (!hasMore && messages.length > 0) {
- return (
- <View style={styles.footer}>
- <Text style={styles.footerText}>没有更多了</Text>
- </View>
- );
- }
- if (loading && messages.length > 0) {
- return (
- <View style={styles.footer}>
- <ActivityIndicator size="small" color="#999" />
- </View>
- );
- }
- return null;
- };
- return (
- <View style={styles.container}>
- <StatusBar barStyle="light-content" />
-
- {/* 顶部导航 */}
- <View style={[styles.header, { paddingTop: insets.top }]}>
- <TouchableOpacity style={styles.backBtn} onPress={handleBack}>
- <Text style={styles.backIcon}>‹</Text>
- </TouchableOpacity>
- <Text style={styles.headerTitle}>消息</Text>
- <View style={styles.placeholder} />
- </View>
- <FlatList
- data={messages}
- renderItem={renderItem}
- keyExtractor={(item, index) => item.id || String(index)}
- contentContainerStyle={[
- styles.listContent,
- messages.length === 0 && styles.emptyList
- ]}
- refreshControl={
- <RefreshControl
- refreshing={refreshing}
- onRefresh={handleRefresh}
- colors={['#FC7D2E']}
- tintColor="#FC7D2E"
- />
- }
- onEndReached={handleLoadMore}
- onEndReachedThreshold={0.2}
- ListEmptyComponent={!loading ? renderEmpty : null}
- ListFooterComponent={renderFooter}
- />
- </View>
- );
- }
- const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: '#1a1a2e',
- },
- header: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between',
- paddingHorizontal: 10,
- height: 80,
- backgroundColor: 'transparent',
- },
- backBtn: {
- width: 40,
- height: 40,
- justifyContent: 'center',
- alignItems: 'center',
- },
- backIcon: {
- fontSize: 32,
- color: '#fff',
- fontWeight: 'bold',
- },
- headerTitle: {
- fontSize: 16,
- fontWeight: 'bold',
- color: '#fff',
- },
- placeholder: {
- width: 40,
- },
- listContent: {
- paddingHorizontal: 14,
- paddingBottom: 30,
- },
- emptyList: {
- flex: 1,
- },
- cell: {
- backgroundColor: '#fff',
- borderRadius: 10,
- padding: 15,
- marginTop: 10,
- },
- cellHeader: {
- flexDirection: 'row',
- alignItems: 'center',
- },
- icon: {
- width: 20,
- height: 20,
- borderRadius: 10,
- backgroundColor: '#333',
- justifyContent: 'center',
- alignItems: 'center',
- },
- iconText: {
- fontSize: 10,
- },
- title: {
- flex: 1,
- fontSize: 14,
- fontWeight: 'bold',
- color: '#333',
- marginLeft: 10,
- },
- time: {
- fontSize: 12,
- color: '#999',
- },
- content: {
- fontSize: 14,
- color: '#666',
- marginTop: 8,
- lineHeight: 20,
- },
- emptyBox: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- paddingTop: 200,
- },
- emptyText: {
- fontSize: 14,
- color: '#999',
- },
- footer: {
- paddingVertical: 20,
- alignItems: 'center',
- },
- footerText: {
- fontSize: 12,
- color: '#999',
- },
- });
|