| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- import { Image } from 'expo-image';
- import React, { forwardRef, useImperativeHandle, useState } from 'react';
- import {
- ActivityIndicator,
- FlatList,
- Modal,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
- } from 'react-native';
- import { getBuyRecord } from '@/services/award';
- interface RecordItem {
- id: string;
- nickname: string;
- avatar: string;
- goodsName: string;
- cover: string; // API 返回的是 cover 字段
- level: string;
- createTime: string;
- }
- interface RecordModalProps {
- poolId: string;
- }
- export interface RecordModalRef {
- show: () => void;
- close: () => void;
- }
- const LEVEL_MAP: Record<string, string> = {
- A: '超神款',
- B: '欧皇款',
- C: '隐藏款',
- D: '普通款',
- };
- export const RecordModal = forwardRef<RecordModalRef, RecordModalProps>(
- ({ poolId }, ref) => {
- const [visible, setVisible] = useState(false);
- const [loading, setLoading] = useState(false);
- const [records, setRecords] = useState<RecordItem[]>([]);
- const [levelFilter, setLevelFilter] = useState<number | undefined>();
- useImperativeHandle(ref, () => ({
- show: () => {
- setVisible(true);
- loadRecords();
- },
- close: () => setVisible(false),
- }));
- const loadRecords = async (level?: number) => {
- setLoading(true);
- try {
- const res = await getBuyRecord(poolId, undefined, level);
- setRecords(res || []);
- } catch (error) {
- console.error('加载记录失败:', error);
- }
- setLoading(false);
- };
- const handleLevelFilter = (level?: number) => {
- setLevelFilter(level);
- loadRecords(level);
- };
- const renderItem = ({ item }: { item: RecordItem }) => (
- <View style={styles.recordItem}>
- <Image
- source={{ uri: item.avatar }}
- style={styles.avatar}
- contentFit="cover"
- />
- <View style={styles.recordInfo}>
- <Text style={styles.nickname} numberOfLines={1}>{item.nickname}</Text>
- <Text style={styles.time}>{item.createTime}</Text>
- </View>
- <View style={styles.goodsInfo}>
- <Image
- source={{ uri: item.cover }}
- style={styles.goodsImage}
- contentFit="cover"
- />
- <View style={styles.goodsDetail}>
- <Text style={styles.goodsName} numberOfLines={1}>{item.goodsName}</Text>
- <Text style={styles.levelText}>{LEVEL_MAP[item.level] || item.level}</Text>
- </View>
- </View>
- </View>
- );
- const levels = [
- { label: '全部', value: undefined },
- { label: '超神款', value: 1 },
- { label: '欧皇款', value: 2 },
- { label: '隐藏款', value: 3 },
- { label: '普通款', value: 4 },
- ];
- return (
- <Modal visible={visible} transparent animationType="slide" onRequestClose={() => setVisible(false)}>
- <View style={styles.overlay}>
- <View style={styles.container}>
- <View style={styles.header}>
- <Text style={styles.title}>购买记录</Text>
- <TouchableOpacity onPress={() => setVisible(false)} style={styles.closeBtn}>
- <Text style={styles.closeText}>×</Text>
- </TouchableOpacity>
- </View>
- <View style={styles.filterRow}>
- {levels.map((item) => (
- <TouchableOpacity
- key={item.label}
- style={[styles.filterBtn, levelFilter === item.value && styles.filterBtnActive]}
- onPress={() => handleLevelFilter(item.value)}
- >
- <Text style={[styles.filterText, levelFilter === item.value && styles.filterTextActive]}>
- {item.label}
- </Text>
- </TouchableOpacity>
- ))}
- </View>
- {loading ? (
- <View style={styles.loadingBox}>
- <ActivityIndicator size="large" color="#ff6600" />
- </View>
- ) : (
- <FlatList
- data={records}
- renderItem={renderItem}
- keyExtractor={(item, index) => item.id || index.toString()}
- contentContainerStyle={styles.listContent}
- ListEmptyComponent={
- <View style={styles.emptyBox}>
- <Text style={styles.emptyText}>暂无记录</Text>
- </View>
- }
- />
- )}
- </View>
- </View>
- </Modal>
- );
- }
- );
- const styles = StyleSheet.create({
- overlay: {
- flex: 1,
- backgroundColor: 'rgba(0,0,0,0.5)',
- justifyContent: 'flex-end',
- },
- container: {
- backgroundColor: '#fff',
- borderTopLeftRadius: 20,
- borderTopRightRadius: 20,
- height: '70%',
- },
- header: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- padding: 15,
- borderBottomWidth: 1,
- borderBottomColor: '#eee',
- },
- title: { fontSize: 16, fontWeight: '600', color: '#333' },
- closeBtn: { position: 'absolute', right: 15, top: 10 },
- closeText: { fontSize: 24, color: '#999' },
- filterRow: {
- flexDirection: 'row',
- paddingHorizontal: 10,
- paddingVertical: 10,
- borderBottomWidth: 1,
- borderBottomColor: '#eee',
- },
- filterBtn: {
- paddingHorizontal: 12,
- paddingVertical: 6,
- borderRadius: 15,
- marginRight: 8,
- backgroundColor: '#f5f5f5',
- },
- filterBtnActive: { backgroundColor: '#ff6600' },
- filterText: { fontSize: 12, color: '#666' },
- filterTextActive: { color: '#fff' },
- listContent: { padding: 15 },
- recordItem: {
- flexDirection: 'row',
- alignItems: 'center',
- paddingVertical: 12,
- borderBottomWidth: 1,
- borderBottomColor: '#f5f5f5',
- },
- avatar: { width: 40, height: 40, borderRadius: 20 },
- recordInfo: { flex: 1, marginLeft: 10 },
- nickname: { fontSize: 14, color: '#333' },
- time: { fontSize: 11, color: '#999', marginTop: 2 },
- goodsInfo: { flexDirection: 'row', alignItems: 'center' },
- goodsImage: { width: 50, height: 50, borderRadius: 5 },
- goodsDetail: { marginLeft: 8, alignItems: 'flex-end' },
- goodsName: { fontSize: 12, color: '#333', maxWidth: 80 },
- levelText: { fontSize: 11, color: '#ff6600', marginTop: 2 },
- loadingBox: { flex: 1, justifyContent: 'center', alignItems: 'center' },
- emptyBox: { alignItems: 'center', paddingVertical: 50 },
- emptyText: { color: '#999', fontSize: 14 },
- });
|