| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- import { Image } from 'expo-image';
- import { useRouter } from 'expo-router';
- import React, { useCallback, useEffect, useRef, useState } from 'react';
- import {
- ActivityIndicator,
- Dimensions,
- ImageBackground,
- RefreshControl,
- ScrollView,
- StatusBar,
- StyleSheet,
- Text,
- TextInput,
- TouchableOpacity,
- View,
- } from 'react-native';
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
- import { Images } from '@/constants/images';
- import { getRoomTypePermission, getWealList } from '@/services/weal';
- import { RuleModal, RuleModalRef } from './components/RuleModal';
- interface RoomItem {
- id: string;
- name: string;
- type: string;
- goodsQuantity: number;
- officialFlag: number;
- user: { avatar: string; username: string };
- luckRoomGoodsList: { spu: { cover: string } }[];
- participatingList: any[];
- mode?: string;
- }
- export default function RoomScreen() {
- const router = useRouter();
- const insets = useSafeAreaInsets();
- const [loading, setLoading] = useState(true);
- const [refreshing, setRefreshing] = useState(false);
- const [list, setList] = useState<RoomItem[]>([]);
- const [searchVal, setSearchVal] = useState('');
- const [type, setType] = useState('');
- const [typeIndex, setTypeIndex] = useState(0);
- const [scrollTop, setScrollTop] = useState(0);
- const [roomTab, setRoomTab] = useState([
- { name: '全部', value: '' }
- ]);
- const ruleRef = useRef<RuleModalRef>(null);
- const loadPermission = async () => {
- try {
- const permission = await getRoomTypePermission();
- let tabs = [{ name: '全部', value: '' }];
- if (permission && permission.roomConfig !== 0) {
- tabs.push({ name: '福利房', value: 'COMMON' });
- tabs.push({ name: '口令房', value: 'PASSWORD' });
- }
- if (permission && permission.roomGAS !== 0) {
- tabs.push({ name: '欧气房', value: 'EUROPEAN_GAS' });
- }
- if (permission && permission.roomCjf !== 0) {
- tabs.push({ name: '成就房', value: 'ACHIEVEMENT' });
- }
- setRoomTab(tabs);
- } catch (error) {
- console.error('获取房间类型权限失败:', error);
- }
- };
- const loadData = useCallback(async (isRefresh = false) => {
- if (isRefresh) setRefreshing(true);
- else setLoading(true);
- try {
- const data = await getWealList(1, 20, searchVal, type);
- setList(data || []);
- } catch (error) {
- console.error('加载房间列表失败:', error);
- }
- setLoading(false);
- setRefreshing(false);
- }, [type, searchVal]);
- useEffect(() => {
- loadPermission();
- }, []);
- useEffect(() => {
- loadData();
- }, [type]);
- const handleSearch = () => {
- loadData();
- };
- const handleTypeChange = (item: any, index: number) => {
- setTypeIndex(index);
- setType(item.value);
- };
- const handleRoomPress = (item: RoomItem) => {
- if (item.mode === 'YFS_PRO') {
- router.push({ pathname: '/award-detail-yfs', params: { id: item.id } } as any);
- } else {
- router.push({ pathname: '/weal/detail', params: { id: item.id } } as any);
- }
- };
- const isItemType = (type: string) => {
- const map: Record<string, string> = {
- COMMON: '福利房',
- PASSWORD: '口令房',
- EUROPEAN_GAS: '欧气房',
- ACHIEVEMENT: '成就房',
- };
- return map[type] || type;
- };
- const headerBg = scrollTop > 0 ? '#333' : 'transparent';
- return (
- <View style={styles.container}>
- <StatusBar barStyle="light-content" />
- <ImageBackground source={{ uri: Images.mine.kaixinMineBg }} style={styles.background} resizeMode="cover">
- {/* 顶部导航 */}
- <View style={[styles.header, { paddingTop: insets.top, backgroundColor: headerBg }]}>
- <TouchableOpacity style={styles.backBtn} onPress={() => router.back()}>
- <Text style={styles.backText}>←</Text>
- </TouchableOpacity>
- <Text style={styles.title}>房间</Text>
- <View style={styles.placeholder} />
- </View>
- {/* 头部背景 */}
- <ImageBackground source={{ uri: Images.mine.kaixinMineHeadBg }} style={styles.headBg} resizeMode="cover" />
- <ScrollView
- style={styles.scrollView}
- showsVerticalScrollIndicator={false}
- onScroll={(e) => setScrollTop(e.nativeEvent.contentOffset.y)}
- scrollEventThrottle={16}
- refreshControl={<RefreshControl refreshing={refreshing} onRefresh={() => loadData(true)} tintColor="#fff" />}
- >
- <View style={{ height: 90 + insets.top }} />
- {/* 搜索栏和功能按钮 */}
- <View style={styles.topSection}>
- <ImageBackground source={{ uri: Images.welfare.roomInputBg }} style={styles.searchBox} resizeMode="stretch">
- <Image source={{ uri: Images.home.search2 }} style={styles.searchIcon} contentFit="contain" />
- <TextInput
- style={styles.searchInput}
- placeholder="搜索"
- placeholderTextColor="#6C6C6C"
- value={searchVal}
- onChangeText={setSearchVal}
- onSubmitEditing={handleSearch}
- returnKeyType="search"
- />
- </ImageBackground>
- <View style={styles.funcBtns}>
- <TouchableOpacity style={styles.funcItem} onPress={() => router.push('/weal/create' as any)}>
- <Image source={{ uri: Images.welfare.roomIcon0 }} style={styles.funcIcon} contentFit="contain" />
- <Text style={styles.funcText}>创建</Text>
- </TouchableOpacity>
- <TouchableOpacity style={styles.funcItem} onPress={() => router.push('/weal/record' as any)}>
- <Image source={{ uri: Images.welfare.roomIcon1 }} style={styles.funcIcon} contentFit="contain" />
- <Text style={styles.funcText}>我的</Text>
- </TouchableOpacity>
- <TouchableOpacity style={styles.funcItem} onPress={() => ruleRef.current?.show()}>
- <Image source={{ uri: Images.welfare.roomIcon2 }} style={styles.funcIcon} contentFit="contain" />
- <Text style={styles.funcText}>玩法</Text>
- </TouchableOpacity>
- </View>
- </View>
- {/* 类型切换 */}
- <View style={styles.typeContainer}>
- <ScrollView horizontal showsHorizontalScrollIndicator={false} style={styles.typeSection}>
- {roomTab.map((item, index) => (
- <TouchableOpacity
- key={index}
- style={styles.typeItem}
- onPress={() => handleTypeChange(item, index)}
- >
- <Text style={[styles.typeText, typeIndex === index && styles.typeTextActive]}>{item.name}</Text>
- </TouchableOpacity>
- ))}
- </ScrollView>
- </View>
- {/* 房间列表 */}
- {loading ? (
- <ActivityIndicator size="large" color="#fff" style={{ marginTop: 50 }} />
- ) : list.length === 0 ? (
- <View style={styles.emptyBox}>
- <Text style={styles.emptyText}>暂无房间</Text>
- </View>
- ) : (
- <View style={styles.roomList}>
- {list.map((item) => (
- <TouchableOpacity key={item.id} onPress={() => handleRoomPress(item)} activeOpacity={0.8}>
- <ImageBackground source={{ uri: Images.welfare.roomItemBg }} style={styles.roomItem} resizeMode="stretch">
- {/* 官方标签 */}
- {item.officialFlag === 1 && (
- <View style={styles.officialBadge}>
- <Image source={{ uri: Images.welfare.official }} style={styles.officialImg} contentFit="contain" />
- </View>
- )}
- {/* 成就房标签 */}
- {item.type === 'ACHIEVEMENT' && (
- <View style={styles.mustBeBadge}>
- <Image source={{ uri: Images.welfare.mustBe }} style={styles.mustBeImg} contentFit="contain" />
- </View>
- )}
- {/* 商品图片 */}
- <ImageBackground source={{ uri: Images.welfare.roomItemImgBg }} style={styles.roomCover} resizeMode="contain">
- {item.luckRoomGoodsList?.[0]?.spu?.cover && (
- <Image source={{ uri: item.luckRoomGoodsList[0].spu.cover }} style={styles.roomCoverImg} contentFit="cover" />
- )}
- </ImageBackground>
- {/* 房间信息 */}
- <View style={styles.roomInfo}>
- <View style={styles.roomTop}>
- <Text style={styles.roomName} numberOfLines={1}>{item.name}</Text>
- <Text style={styles.roomTypeLabel}>{isItemType(item.type)}</Text>
- </View>
- <View style={styles.roomBottom}>
- <View style={styles.userInfo}>
- {item.user?.avatar && (
- <Image source={{ uri: item.user.avatar }} style={styles.userAvatar} contentFit="cover" />
- )}
- <Text style={styles.userName} numberOfLines={1}>{item.user?.username || '匿名'}</Text>
- </View>
- <Text style={styles.goodsNum}>共{item.goodsQuantity}件赠品</Text>
- <View style={styles.participantBox}>
- <Image source={{ uri: Images.welfare.participationIcon }} style={styles.participantIcon} contentFit="contain" />
- <Text style={styles.participantNum}>{item.participatingList?.length || 0}</Text>
- </View>
- </View>
- </View>
- </ImageBackground>
- </TouchableOpacity>
- ))}
- </View>
- )}
- <View style={{ height: 100 }} />
- </ScrollView>
- <RuleModal ref={ruleRef} />
- </ImageBackground>
- </View>
- );
- }
- const { width: SCREEN_WIDTH } = Dimensions.get('window');
- const styles = StyleSheet.create({
- container: { flex: 1, backgroundColor: '#1a1a2e' },
- background: { flex: 1 },
- header: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between',
- paddingHorizontal: 15,
- paddingBottom: 10,
- position: 'absolute',
- top: 0,
- left: 0,
- right: 0,
- zIndex: 100,
- height: 90,
- },
- backBtn: { width: 40, height: 40, justifyContent: 'center', alignItems: 'center' },
- backText: { color: '#fff', fontSize: 20 },
- title: { color: '#fff', fontSize: 16, fontWeight: 'bold' },
- placeholder: { width: 40 },
- headBg: { position: 'absolute', top: 0, left: 0, right: 0, height: 215 },
- scrollView: { flex: 1 },
- // 顶部搜索和功能区
- topSection: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15, marginTop: 10, marginBottom: 15 },
- searchBox: { flex: 1, height: 37, flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15 },
- searchIcon: { width: 19, height: 19, marginRight: 8 },
- searchInput: { flex: 1, fontSize: 12, color: '#000', padding: 0 },
- funcBtns: { flexDirection: 'row', marginLeft: 10 },
- funcItem: { alignItems: 'center', marginLeft: 12 },
- funcIcon: { width: 16, height: 16 },
- funcText: { fontSize: 10, color: '#DFDFDF', marginTop: 2 },
- // 类型切换
- typeContainer: { paddingHorizontal: 15, marginBottom: 40 },
- typeSection: {},
- typeItem: { marginRight: 20, paddingVertical: 8 },
- typeText: { fontSize: 12, color: '#DFDFDF' },
- typeTextActive: {
- color: '#e79018',
- fontWeight: 'bold',
- fontSize: 15,
- textShadowColor: '#000',
- textShadowOffset: { width: 1, height: 1 },
- textShadowRadius: 1
- },
- // 房间列表
- roomList: { paddingHorizontal: 0, alignItems: 'center' },
- roomItem: { width: SCREEN_WIDTH - 12, height: 84, flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, marginBottom: 6, position: 'relative' },
- officialBadge: { position: 'absolute', right: 0, top: 0, width: 48, height: 22 },
- officialImg: { width: '100%', height: '100%' },
- mustBeBadge: { position: 'absolute', left: 0, top: 0, width: 51, height: 51 },
- mustBeImg: { width: '100%', height: '100%' },
- roomCover: { width: 58, height: 58, justifyContent: 'center', alignItems: 'center', marginRight: 14 },
- roomCoverImg: { width: 44, height: 44 },
- roomInfo: { flex: 1 },
- roomTop: { flexDirection: 'row', alignItems: 'center', marginBottom: 10 },
- roomName: {
- flex: 1,
- color: '#fff',
- fontSize: 14,
- fontWeight: '400',
- marginRight: 10,
- textShadowColor: '#000',
- textShadowOffset: { width: 1, height: 1 },
- textShadowRadius: 1
- },
- roomTypeLabel: { color: '#2E0000', fontSize: 12 },
- roomBottom: { flexDirection: 'row', alignItems: 'center' },
- userInfo: { flexDirection: 'row', alignItems: 'center', width: '45%' },
- userAvatar: { width: 24, height: 24, borderRadius: 2, backgroundColor: '#FFDD00', borderWidth: 1.5, borderColor: '#000', marginRight: 5 },
- userName: { color: '#2E0000', fontSize: 12, fontWeight: 'bold', maxWidth: 60 },
- goodsNum: { color: '#2E0000', fontSize: 10, width: '35%' },
- participantBox: { flexDirection: 'row', alignItems: 'center', width: '20%' },
- participantIcon: { width: 14, height: 14 },
- participantNum: { color: '#2E0000', fontSize: 12, marginLeft: 3 },
- emptyBox: { alignItems: 'center', paddingTop: 50 },
- emptyText: { color: '#999', fontSize: 14 },
- });
|