| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- import { Image } from 'expo-image';
- import { useRouter } from 'expo-router';
- import React, { useEffect, useState } from 'react';
- import {
- ActivityIndicator,
- Alert,
- ScrollView,
- StatusBar,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
- } from 'react-native';
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
- import { get, post } from '@/services/http';
- interface BoxItem {
- id: string;
- boxName: string;
- boxCover: string;
- }
- const getMyBoxes = async () => {
- const res = await get('/api/nestedBox/myBoxes');
- return res.data;
- };
- const openBoxes = async (boxIds: string) => {
- const res = await post('/api/nestedBox/openBox', { boxIds });
- return res;
- };
- export default function BoxListScreen() {
- const router = useRouter();
- const insets = useSafeAreaInsets();
- const [loading, setLoading] = useState(true);
- const [list, setList] = useState<BoxItem[]>([]);
- const [selectedIds, setSelectedIds] = useState<string[]>([]);
- const loadData = async () => {
- setLoading(true);
- try {
- const res = await getMyBoxes();
- setList(res || []);
- } catch (error) {
- console.error('加载宝箱列表失败:', error);
- }
- setLoading(false);
- };
- useEffect(() => {
- loadData();
- }, []);
- const toggleSelect = (id: string) => {
- setSelectedIds(prev =>
- prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id]
- );
- };
- const selectAll = () => {
- if (selectedIds.length === list.length) {
- setSelectedIds([]);
- } else {
- setSelectedIds(list.map(item => item.id));
- }
- };
- const handleOpen = async () => {
- if (selectedIds.length === 0) {
- Alert.alert('提示', '请先选择宝箱');
- return;
- }
- try {
- const res = await openBoxes(selectedIds.join(','));
- if (res.code === 0) {
- Alert.alert('成功', '开启成功');
- setSelectedIds([]);
- loadData();
- }
- } catch (error) {
- console.error('开启失败:', error);
- }
- };
- return (
- <View style={styles.container}>
- <StatusBar barStyle="light-content" />
- <View style={[styles.header, { paddingTop: insets.top }]}>
- <TouchableOpacity onPress={() => router.back()}>
- <Text style={styles.backText}>←</Text>
- </TouchableOpacity>
- <Text style={styles.title}>宝箱</Text>
- <View style={{ width: 40 }} />
- </View>
- {loading ? (
- <ActivityIndicator size="large" color="#fff" style={{ marginTop: 50 }} />
- ) : (
- <ScrollView style={styles.content}>
- <View style={styles.grid}>
- {list.map(item => (
- <TouchableOpacity
- key={item.id}
- style={[styles.item, selectedIds.includes(item.id) && styles.itemSelected]}
- onPress={() => toggleSelect(item.id)}
- >
- <Image source={{ uri: item.boxCover }} style={styles.itemImage} contentFit="cover" />
- <Text style={styles.itemName} numberOfLines={1}>{item.boxName}</Text>
- {selectedIds.includes(item.id) && (
- <View style={styles.checkMark}><Text style={styles.checkText}>✓</Text></View>
- )}
- </TouchableOpacity>
- ))}
- </View>
- </ScrollView>
- )}
- <View style={[styles.footer, { paddingBottom: insets.bottom + 10 }]}>
- <TouchableOpacity style={styles.selectAllBtn} onPress={selectAll}>
- <Text style={styles.btnText}>{selectedIds.length === list.length ? '取消全选' : '全选'}</Text>
- </TouchableOpacity>
- <TouchableOpacity style={styles.openBtn} onPress={handleOpen}>
- <Text style={styles.btnText}>开启宝箱 {selectedIds.length > 0 ? `(${selectedIds.length})` : ''}</Text>
- </TouchableOpacity>
- </View>
- </View>
- );
- }
- const styles = StyleSheet.create({
- container: { flex: 1, backgroundColor: '#1a1a2e' },
- header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 15, paddingBottom: 10 },
- backText: { color: '#fff', fontSize: 24 },
- title: { color: '#fff', fontSize: 18, fontWeight: 'bold' },
- content: { flex: 1, padding: 10 },
- grid: { flexDirection: 'row', flexWrap: 'wrap' },
- item: { width: '33%', padding: 5, position: 'relative' },
- itemSelected: { opacity: 0.7 },
- itemImage: { width: '100%', aspectRatio: 1, borderRadius: 8 },
- itemName: { color: '#fff', fontSize: 12, textAlign: 'center', marginTop: 5 },
- checkMark: { position: 'absolute', top: 10, right: 10, backgroundColor: '#ff6600', width: 24, height: 24, borderRadius: 12, justifyContent: 'center', alignItems: 'center' },
- checkText: { color: '#fff', fontSize: 14 },
- footer: { flexDirection: 'row', paddingHorizontal: 15, paddingTop: 10, backgroundColor: 'rgba(0,0,0,0.8)' },
- selectAllBtn: { flex: 1, backgroundColor: '#666', paddingVertical: 12, borderRadius: 8, marginRight: 10, alignItems: 'center' },
- openBtn: { flex: 2, backgroundColor: '#ff6600', paddingVertical: 12, borderRadius: 8, alignItems: 'center' },
- btnText: { color: '#fff', fontSize: 16, fontWeight: 'bold' },
- });
|