| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- import { Image } from "expo-image";
- import { useLocalSearchParams, useRouter } from "expo-router";
- import React, { useCallback, useEffect, useState } from "react";
- import {
- ActivityIndicator,
- Alert,
- FlatList,
- ImageBackground,
- RefreshControl,
- StatusBar,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
- } from "react-native";
- import { useSafeAreaInsets } from "react-native-safe-area-context";
- import { Images } from "@/constants/images";
- import {
- roomAuditPass,
- roomAuditRecord,
- roomAuditUnpass,
- } from "@/services/dimension";
- interface AuditItem {
- id: string;
- avatar: string;
- nickname: string;
- auditStatus: number; // 0-待审核 1-拒绝 2-通过
- }
- const TABS = [
- { title: "待审核", value: 0 },
- { title: "审核通过", value: 2 },
- { title: "审核不通过", value: 1 },
- ];
- export default function AuditListScreen() {
- const { id: roomId } = useLocalSearchParams<{ id: string }>();
- const router = useRouter();
- const insets = useSafeAreaInsets();
- const [activeTab, setActiveTab] = useState(0);
- const [list, setList] = useState<AuditItem[]>([]);
- const [loading, setLoading] = useState(false);
- const [refreshing, setRefreshing] = useState(false);
- const [page, setPage] = useState(1);
- const [hasMore, setHasMore] = useState(true);
- const loadData = useCallback(
- async (pageNum: number, isRefresh = false) => {
- if (loading && !isRefresh) return;
- try {
- if (pageNum === 1) setLoading(true);
- const data = await roomAuditRecord(
- pageNum,
- 20,
- roomId as string,
- TABS[activeTab].value,
- );
- const records = Array.isArray(data)
- ? data
- : data?.records || [];
- if (records.length < 20) setHasMore(false);
- if (pageNum === 1 || isRefresh) {
- setList(records);
- } else {
- setList((prev) => [...prev, ...records]);
- }
- } catch (e) {
- console.error("加载审核记录失败:", e);
- } finally {
- setLoading(false);
- setRefreshing(false);
- }
- },
- [roomId, activeTab, loading],
- );
- useEffect(() => {
- setPage(1);
- setList([]);
- setHasMore(true);
- loadData(1, true);
- }, [activeTab]);
- const handleRefresh = () => {
- setRefreshing(true);
- setPage(1);
- setHasMore(true);
- loadData(1, true);
- };
- const handleLoadMore = () => {
- if (!loading && hasMore) {
- const np = page + 1;
- setPage(np);
- loadData(np);
- }
- };
- const handlePass = async (item: AuditItem, index: number) => {
- try {
- const res = await roomAuditPass(item.id);
- if (res) {
- const newList = [...list];
- newList[index] = { ...item, auditStatus: 2 };
- setList(newList);
- }
- } catch (e) {
- Alert.alert("提示", "操作失败");
- }
- };
- const handleReject = async (item: AuditItem, index: number) => {
- try {
- const res = await roomAuditUnpass(item.id);
- if (res) {
- const newList = [...list];
- newList[index] = { ...item, auditStatus: 1 };
- setList(newList);
- }
- } catch (e) {
- Alert.alert("提示", "操作失败");
- }
- };
- const renderItem = ({
- item,
- index,
- }: {
- item: AuditItem;
- index: number;
- }) => (
- <View style={styles.cell}>
- <Image
- source={{ uri: item.avatar }}
- style={styles.avatar}
- contentFit="cover"
- />
- <Text style={styles.nickname} numberOfLines={1}>
- {item.nickname}
- </Text>
- <View style={styles.actionArea}>
- {item.auditStatus === 0 ? (
- <>
- <TouchableOpacity
- style={[styles.btn, styles.rejectBtn]}
- onPress={() => handleReject(item, index)}
- >
- <Text style={styles.btnText}>拒绝</Text>
- </TouchableOpacity>
- <TouchableOpacity
- style={[styles.btn, styles.passBtn]}
- onPress={() => handlePass(item, index)}
- >
- <Text style={styles.btnText}>通过</Text>
- </TouchableOpacity>
- </>
- ) : (
- <Text style={styles.statusText}>
- {item.auditStatus === 2 ? "通过" : "拒绝"}
- </Text>
- )}
- </View>
- </View>
- );
- 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 }]}>
- <TouchableOpacity
- style={styles.backBtn}
- onPress={() => router.back()}
- >
- <Text style={styles.backText}>←</Text>
- </TouchableOpacity>
- <Text style={styles.title}>审核</Text>
- <View style={styles.placeholder} />
- </View>
- {/* Tab 切换 */}
- <View style={styles.tabs}>
- {TABS.map((tab, index) => {
- const isActive = activeTab === index;
- return (
- <TouchableOpacity
- key={index}
- style={[styles.tabItem, isActive && styles.tabItemActive]}
- onPress={() => setActiveTab(index)}
- >
- <Text
- style={[
- styles.tabText,
- isActive && styles.tabTextActive,
- ]}
- >
- {tab.title}
- </Text>
- {isActive && <View style={styles.tabLine} />}
- </TouchableOpacity>
- );
- })}
- </View>
- {/* 列表 */}
- <FlatList
- data={list}
- renderItem={renderItem}
- keyExtractor={(item, index) => item.id || index.toString()}
- contentContainerStyle={styles.listContent}
- refreshControl={
- <RefreshControl
- refreshing={refreshing}
- onRefresh={handleRefresh}
- tintColor="#fff"
- />
- }
- onEndReached={handleLoadMore}
- onEndReachedThreshold={0.3}
- ListFooterComponent={
- loading && list.length > 0 ? (
- <ActivityIndicator
- color="#fff"
- style={{ marginVertical: 10 }}
- />
- ) : null
- }
- ListEmptyComponent={
- !loading ? (
- <View style={styles.emptyBox}>
- <Text style={styles.emptyText}>暂无记录</Text>
- </View>
- ) : null
- }
- />
- </ImageBackground>
- </View>
- );
- }
- const styles = StyleSheet.create({
- container: { flex: 1, backgroundColor: "#1a1a2e" },
- background: { flex: 1 },
- header: {
- flexDirection: "row",
- alignItems: "center",
- justifyContent: "space-between",
- paddingHorizontal: 15,
- paddingBottom: 10,
- },
- backBtn: {
- width: 40,
- height: 40,
- justifyContent: "center",
- alignItems: "center",
- },
- backText: { color: "#fff", fontSize: 20 },
- title: { color: "#fff", fontSize: 16, fontWeight: "bold" },
- placeholder: { width: 40 },
- // Tabs
- tabs: {
- flexDirection: "row",
- paddingHorizontal: 10,
- borderBottomWidth: 1,
- borderBottomColor: "rgba(255,255,255,0.15)",
- },
- tabItem: {
- flex: 1,
- height: 44,
- justifyContent: "center",
- alignItems: "center",
- position: "relative",
- },
- tabItemActive: {},
- tabText: { color: "#999", fontSize: 14 },
- tabTextActive: { color: "#fff", fontWeight: "bold" },
- tabLine: {
- position: "absolute",
- bottom: 0,
- width: "60%",
- height: 2,
- backgroundColor: "#e79018",
- },
- // List
- listContent: { padding: 15, paddingBottom: 100 },
- cell: {
- flexDirection: "row",
- alignItems: "center",
- backgroundColor: "rgba(255,255,255,0.9)",
- borderRadius: 8,
- paddingHorizontal: 15,
- paddingVertical: 12,
- marginBottom: 10,
- },
- avatar: {
- width: 40,
- height: 40,
- borderRadius: 4,
- borderWidth: 2,
- borderColor: "#000",
- marginRight: 12,
- },
- nickname: {
- flex: 1,
- fontSize: 14,
- color: "#333",
- fontWeight: "500",
- },
- actionArea: {
- flexDirection: "row",
- alignItems: "center",
- },
- btn: {
- width: 68,
- height: 32,
- borderRadius: 4,
- justifyContent: "center",
- alignItems: "center",
- marginLeft: 8,
- },
- rejectBtn: { backgroundColor: "#ff4d4f" },
- passBtn: { backgroundColor: "#52c41a" },
- btnText: { color: "#fff", fontSize: 13, fontWeight: "bold" },
- statusText: {
- fontSize: 13,
- color: "#666",
- fontWeight: "500",
- },
- emptyBox: { alignItems: "center", paddingTop: 80 },
- emptyText: { color: "#999", fontSize: 14 },
- });
|