|
|
@@ -5,7 +5,7 @@ import { ActivityIndicator, Toast } from '@ant-design/react-native';
|
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
|
import { useFocusEffect } from 'expo-router';
|
|
|
import React, { useCallback, useRef, useState } from 'react';
|
|
|
-import { Pressable, ScrollView, Text, TextInput, View } from 'react-native';
|
|
|
+import { FlatList, Pressable, Text, TextInput, View } from 'react-native';
|
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
|
|
|
type CustomerLoanStatus = 'matched' | 'unmatch' | 'pending' | 'completed' | undefined;
|
|
|
@@ -13,392 +13,222 @@ const CustomerLoanStatusText: Record<NonNullable<CustomerLoanStatus>, string> =
|
|
|
matched: '已匹配',
|
|
|
unmatch: '未匹配',
|
|
|
pending: '匹配中',
|
|
|
- completed: '已完成'
|
|
|
-}
|
|
|
+ completed: '已完成',
|
|
|
+};
|
|
|
|
|
|
type Customer = {
|
|
|
id: string;
|
|
|
name: string;
|
|
|
mobile: string;
|
|
|
loan_status: CustomerLoanStatus;
|
|
|
- note: string,
|
|
|
+ note: string;
|
|
|
score?: string;
|
|
|
updatetime: string;
|
|
|
};
|
|
|
|
|
|
+const PAGE_SIZE = 15;
|
|
|
+const CACHE_KEY = 'customer_first';
|
|
|
|
|
|
+function CustomerCard({ item }: { item: Customer }) {
|
|
|
+ return (
|
|
|
+ <Pressable
|
|
|
+ className="rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-4"
|
|
|
+ style={({ pressed }) => ({
|
|
|
+ opacity: pressed ? 0.93 : 1,
|
|
|
+ transform: [{ scale: pressed ? 0.995 : 1 }],
|
|
|
+ })}
|
|
|
+ >
|
|
|
+ <View className="mb-3 flex-row items-start justify-between gap-3">
|
|
|
+ <View className="flex-1 flex-row items-center gap-3">
|
|
|
+ <View className="h-11 w-11 items-center justify-center rounded-full bg-primary-fixed">
|
|
|
+ <Text className="text-base font-bold text-primary">{item.name[0]}</Text>
|
|
|
+ </View>
|
|
|
+ <View className="flex-1">
|
|
|
+ <Text className="text-lg font-bold text-on-surface">{item.name}</Text>
|
|
|
+ <Text className="mt-1 text-sm text-on-surface-variant">{item.mobile}</Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ <StatusBadge text={item.loan_status || ''} variant="secondary" />
|
|
|
+ </View>
|
|
|
|
|
|
-export default function CustomerScreens() {
|
|
|
+ <Text className="mb-2.5 text-sm leading-6 text-on-surface-variant">{item.note}</Text>
|
|
|
|
|
|
+ <View className="mb-3 flex-row flex-wrap items-center gap-3">
|
|
|
+ <View className="flex-row items-center gap-1">
|
|
|
+ <Ionicons name="document-text-outline" size={14} color="#737686" />
|
|
|
+ <Text className="text-xs text-on-surface-variant">{item.loan_status}</Text>
|
|
|
+ </View>
|
|
|
+ {item.score ? (
|
|
|
+ <View className="flex-row items-center gap-1">
|
|
|
+ <Ionicons name="analytics-outline" size={14} color="#737686" />
|
|
|
+ <Text className="text-xs text-on-surface-variant">评分 {item.score}</Text>
|
|
|
+ </View>
|
|
|
+ ) : null}
|
|
|
+ <Text className="ml-auto text-xs text-outline">{item.updatetime}</Text>
|
|
|
+ </View>
|
|
|
|
|
|
+ <View className="flex-row gap-3">
|
|
|
+ <Pressable
|
|
|
+ className="flex-1 items-center rounded-xl bg-primary-container py-2.5"
|
|
|
+ style={({ pressed }) => ({ opacity: pressed ? 0.88 : 1 })}
|
|
|
+ >
|
|
|
+ <Text className="text-sm font-bold text-on-primary">{item.loan_status}</Text>
|
|
|
+ </Pressable>
|
|
|
+ <Pressable
|
|
|
+ className="flex-1 items-center rounded-xl bg-surface-container-high py-2.5"
|
|
|
+ style={({ pressed }) => ({ opacity: pressed ? 0.88 : 1 })}
|
|
|
+ >
|
|
|
+ <Text className="text-sm font-semibold text-on-surface">编辑资料</Text>
|
|
|
+ </Pressable>
|
|
|
+ </View>
|
|
|
+ </Pressable>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+const renderCustomer = ({ item }: { item: Customer }) => <CustomerCard item={item} />;
|
|
|
+const keyExtractor = (item: Customer) => item.id;
|
|
|
+
|
|
|
+export default function CustomerScreens() {
|
|
|
const [searchKey, setSearchKey] = useState('');
|
|
|
const [list, setList] = useState<Customer[]>([]);
|
|
|
- const listRef = useRef<Customer[]>([]);
|
|
|
- const startRef = useRef<number>(0);
|
|
|
+ const startRef = useRef(0);
|
|
|
const loanStatusRef = useRef<CustomerLoanStatus>(undefined);
|
|
|
const hasMoreRef = useRef(true);
|
|
|
+ const loadingRef = useRef(false);
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
+
|
|
|
const load = useCallback(async (start: number, loanStatus?: CustomerLoanStatus) => {
|
|
|
+ if (loadingRef.current) return;
|
|
|
+ loadingRef.current = true;
|
|
|
loanStatusRef.current = loanStatus;
|
|
|
startRef.current = start;
|
|
|
setLoading(true);
|
|
|
+
|
|
|
if (start === 0 && !loanStatus) {
|
|
|
- const cache = getApiCache().getObject<ListResponse<Customer>>("customer_first");
|
|
|
+ const cache = getApiCache().getObject<ListResponse<Customer>>(CACHE_KEY);
|
|
|
if (cache) {
|
|
|
- setLoading(false);
|
|
|
- listRef.current = cache.list;
|
|
|
- startRef.current += cache.list.length;
|
|
|
setList(cache.list);
|
|
|
- hasMoreRef.current = list.length > 14;
|
|
|
+ startRef.current = cache.list.length;
|
|
|
+ hasMoreRef.current = cache.list.length >= PAGE_SIZE;
|
|
|
+ setLoading(false);
|
|
|
+ loadingRef.current = false;
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
try {
|
|
|
- // @ts-ignore
|
|
|
const res = await api.post<ListResponse<Customer>>('customer/list', {
|
|
|
start,
|
|
|
- size: 15,
|
|
|
- loanStatus
|
|
|
+ size: PAGE_SIZE,
|
|
|
+ loanStatus,
|
|
|
});
|
|
|
- if (!res) {
|
|
|
- throw "err";
|
|
|
- }
|
|
|
- const { list } = res;
|
|
|
- if (list.length == 0) {
|
|
|
- Toast.offline("没有更多数据可加载");
|
|
|
- return;
|
|
|
+ if (loanStatusRef.current !== loanStatus) return;
|
|
|
+ const next = res?.list ?? [];
|
|
|
+ if (start === 0 && !loanStatus && next.length) {
|
|
|
+ getApiCache().setObject(CACHE_KEY, res, 60);
|
|
|
}
|
|
|
- if (start === 0 && !loanStatus) {
|
|
|
- getApiCache().setObject('customer_first', res, 60);
|
|
|
+ hasMoreRef.current = next.length >= PAGE_SIZE;
|
|
|
+ setList((prev) => (start === 0 ? next : prev.concat(next)));
|
|
|
+ startRef.current = start + next.length;
|
|
|
+ if (!next.length && start > 0) {
|
|
|
+ Toast.offline('没有更多数据可加载');
|
|
|
}
|
|
|
- if (loanStatusRef.current != loanStatus) {
|
|
|
- return;
|
|
|
- }
|
|
|
- listRef.current = start == 0 ? list : listRef.current.concat(...list);
|
|
|
- hasMoreRef.current = list.length > 14;
|
|
|
- startRef.current += list.length;
|
|
|
- setList(() => [...listRef.current]);
|
|
|
- } catch (e) {
|
|
|
- Toast.fail("加载列表失败!");
|
|
|
- }
|
|
|
- finally {
|
|
|
+ } catch {
|
|
|
+ Toast.fail('加载列表失败!');
|
|
|
+ } finally {
|
|
|
setLoading(false);
|
|
|
+ loadingRef.current = false;
|
|
|
}
|
|
|
}, []);
|
|
|
|
|
|
useFocusEffect(
|
|
|
useCallback(() => {
|
|
|
load(0);
|
|
|
- }, []));
|
|
|
+ }, [load])
|
|
|
+ );
|
|
|
|
|
|
const loadMore = useCallback(() => {
|
|
|
- if (!hasMoreRef.current) {
|
|
|
- return;
|
|
|
- }
|
|
|
- load(startRef.current);
|
|
|
- }, []);
|
|
|
+ if (!hasMoreRef.current || loadingRef.current) return;
|
|
|
+ load(startRef.current, loanStatusRef.current);
|
|
|
+ }, [load]);
|
|
|
+
|
|
|
+ const ListHeader = (
|
|
|
+ <>
|
|
|
+ <Text className="mb-2 text-3xl font-extrabold tracking-tight text-on-surface">客户</Text>
|
|
|
+ <Text className="mb-5 text-base leading-7 text-on-surface-variant">
|
|
|
+ 统一跟进客户资料、征信进度和产品匹配状态
|
|
|
+ </Text>
|
|
|
+
|
|
|
+ <View className="mb-3 flex-row items-center rounded-2xl bg-surface-container-low px-4 py-3">
|
|
|
+ <Ionicons name="search-outline" size={20} color="#737686" />
|
|
|
+ <TextInput
|
|
|
+ value={searchKey}
|
|
|
+ onChangeText={setSearchKey}
|
|
|
+ placeholder="搜索客户姓名 / 手机号"
|
|
|
+ placeholderTextColor="#9ca3af"
|
|
|
+ className="ml-3 flex-1 p-0 text-base text-on-surface"
|
|
|
+ />
|
|
|
+ {searchKey.length > 0 ? (
|
|
|
+ <Pressable hitSlop={8} onPress={() => setSearchKey('')}>
|
|
|
+ <Ionicons name="close-circle" size={20} color="#c3c6d7" />
|
|
|
+ </Pressable>
|
|
|
+ ) : null}
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View className="mb-5 flex-row gap-2">
|
|
|
+ {Object.entries(CustomerLoanStatusText).map(([key, item]) => (
|
|
|
+ <Pressable
|
|
|
+ key={key}
|
|
|
+ onPress={() => {}}
|
|
|
+ className="rounded-full bg-surface-container-lowest px-4 py-2"
|
|
|
+ style={({ pressed }) => ({ opacity: pressed ? 0.84 : 1 })}
|
|
|
+ >
|
|
|
+ <Text className="text-sm font-bold text-on-surface-variant">{item}</Text>
|
|
|
+ </Pressable>
|
|
|
+ ))}
|
|
|
+ </View>
|
|
|
+ </>
|
|
|
+ );
|
|
|
+
|
|
|
+ const ListEmpty = !loading ? (
|
|
|
+ <View className="items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-6 py-14">
|
|
|
+ <Ionicons name="people-outline" size={44} color="#c3c6d7" />
|
|
|
+ <Text className="mt-4 text-base text-on-surface-variant">暂无匹配客户</Text>
|
|
|
+ </View>
|
|
|
+ ) : null;
|
|
|
+
|
|
|
+ const ListFooter =
|
|
|
+ loading && list.length > 0 ? (
|
|
|
+ <View className="flex-row justify-center items-center mt-2">
|
|
|
+ <ActivityIndicator />
|
|
|
+ <Text className="ml-2 pb-4">加载中</Text>
|
|
|
+ </View>
|
|
|
+ ) : null;
|
|
|
+
|
|
|
+ const ListInitialLoading =
|
|
|
+ loading && list.length === 0 ? (
|
|
|
+ <View className="flex-row justify-center items-center mt-2">
|
|
|
+ <ActivityIndicator />
|
|
|
+ <Text className="ml-2 pb-4">加载中</Text>
|
|
|
+ </View>
|
|
|
+ ) : null;
|
|
|
+
|
|
|
return (
|
|
|
<SafeAreaView className="flex-1 bg-surface" edges={['top']}>
|
|
|
- <ScrollView
|
|
|
+ <FlatList
|
|
|
className="flex-1"
|
|
|
- contentContainerClassName="px-5 pt-3 pb-24"
|
|
|
+ contentContainerClassName="px-5 pt-3 pb-24 gap-3"
|
|
|
+ data={list}
|
|
|
+ keyExtractor={keyExtractor}
|
|
|
+ renderItem={renderCustomer}
|
|
|
keyboardShouldPersistTaps="handled"
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
- >
|
|
|
- <Text className="mb-2 text-3xl font-extrabold tracking-tight text-on-surface">
|
|
|
- 客户
|
|
|
- </Text>
|
|
|
- <Text className="mb-5 text-base leading-7 text-on-surface-variant">
|
|
|
- 统一跟进客户资料、征信进度和产品匹配状态
|
|
|
- </Text>
|
|
|
-
|
|
|
- <View className="mb-3 flex-row items-center rounded-2xl bg-surface-container-low px-4 py-3">
|
|
|
- <Ionicons name="search-outline" size={20} color="#737686" />
|
|
|
- <TextInput
|
|
|
- value={searchKey}
|
|
|
- onChangeText={setSearchKey}
|
|
|
- placeholder="搜索客户姓名 / 手机号"
|
|
|
- placeholderTextColor="#9ca3af"
|
|
|
- className="ml-3 flex-1 p-0 text-base text-on-surface"
|
|
|
- />
|
|
|
- {!loading && searchKey.length > 0 ? (
|
|
|
- <Pressable hitSlop={8} onPress={() => setSearchKey('')}>
|
|
|
- <Ionicons name="close-circle" size={20} color="#c3c6d7" />
|
|
|
- </Pressable>
|
|
|
- ) : null}
|
|
|
-
|
|
|
- </View>
|
|
|
-
|
|
|
- <ScrollView
|
|
|
- horizontal
|
|
|
- showsHorizontalScrollIndicator={false}
|
|
|
- contentContainerClassName="gap-2 pb-1"
|
|
|
- className="mb-5"
|
|
|
- >
|
|
|
- {Object.entries(CustomerLoanStatusText).map(([key, item]) => {
|
|
|
- const active = false;
|
|
|
- return (
|
|
|
- <Pressable
|
|
|
- key={key}
|
|
|
- onPress={() => { }}
|
|
|
- className={`rounded-full px-4 py-2 ${active ? 'bg-primary-container' : 'bg-surface-container-lowest'
|
|
|
- }`}
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.84 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text
|
|
|
- className={`text-sm font-bold ${active ? 'text-on-primary' : 'text-on-surface-variant'
|
|
|
- }`}
|
|
|
- >
|
|
|
- {item}
|
|
|
- </Text>
|
|
|
- </Pressable>
|
|
|
- );
|
|
|
- })}
|
|
|
- </ScrollView>
|
|
|
-
|
|
|
- <View className="gap-3">
|
|
|
- {true && startRef.current == 0 && <View className='flex-row justify-center items-center mt-2'>
|
|
|
- <ActivityIndicator /><Text className='ml-2 pb-4'>加载中</Text>
|
|
|
- </View>}
|
|
|
- {list.length === 0 ? (
|
|
|
- <View className="items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-6 py-14">
|
|
|
- <Ionicons name="people-outline" size={44} color="#c3c6d7" />
|
|
|
- <Text className="mt-4 text-base text-on-surface-variant">暂无匹配客户</Text>
|
|
|
- </View>
|
|
|
- ) : (
|
|
|
- list.map((item) => (
|
|
|
- <Pressable
|
|
|
- key={item.id}
|
|
|
- className="rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-4"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.93 : 1,
|
|
|
- transform: [{ scale: pressed ? 0.995 : 1 }],
|
|
|
- })}
|
|
|
- >
|
|
|
- <View className="mb-3 flex-row items-start justify-between gap-3">
|
|
|
- <View className="flex-1 flex-row items-center gap-3">
|
|
|
- <View className="h-11 w-11 items-center justify-center rounded-full bg-primary-fixed">
|
|
|
- <Text className="text-base font-bold text-primary">{item.name[0]}</Text>
|
|
|
- </View>
|
|
|
- <View className="flex-1">
|
|
|
- <Text className="text-lg font-bold text-on-surface">{item.name}</Text>
|
|
|
- <Text className="mt-1 text-sm text-on-surface-variant">
|
|
|
- {item.mobile}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- <StatusBadge
|
|
|
- text={item.loan_status || ''}
|
|
|
- variant={'secondary'}
|
|
|
- />
|
|
|
- </View>
|
|
|
-
|
|
|
- <Text className="mb-2.5 text-sm leading-6 text-on-surface-variant">
|
|
|
- {item.note}
|
|
|
- </Text>
|
|
|
-
|
|
|
- <View className="mb-3 flex-row flex-wrap items-center gap-3">
|
|
|
- <View className="flex-row items-center gap-1">
|
|
|
- <Ionicons name="document-text-outline" size={14} color="#737686" />
|
|
|
- <Text className="text-xs text-on-surface-variant">{item.loan_status}</Text>
|
|
|
- </View>
|
|
|
- {item.score ? (
|
|
|
- <View className="flex-row items-center gap-1">
|
|
|
- <Ionicons name="analytics-outline" size={14} color="#737686" />
|
|
|
- <Text className="text-xs text-on-surface-variant">
|
|
|
- 评分 {item.score}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- ) : null}
|
|
|
- <Text className="ml-auto text-xs text-outline">{item.updatetime}</Text>
|
|
|
- </View>
|
|
|
-
|
|
|
- <View className="flex-row gap-3">
|
|
|
- <Pressable
|
|
|
- className="flex-1 items-center rounded-xl bg-primary-container py-2.5"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.88 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text className="text-sm font-bold text-on-primary">
|
|
|
- {item.loan_status}
|
|
|
- </Text>
|
|
|
- </Pressable>
|
|
|
- <Pressable
|
|
|
- className="flex-1 items-center rounded-xl bg-surface-container-high py-2.5"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.88 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text className="text-sm font-semibold text-on-surface">编辑资料</Text>
|
|
|
- </Pressable>
|
|
|
- </View>
|
|
|
- </Pressable>
|
|
|
- ))
|
|
|
- )}
|
|
|
- </View>
|
|
|
- <View className="gap-3">
|
|
|
- {list.length === 0 ? (
|
|
|
- <View className="items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-6 py-14">
|
|
|
- <Ionicons name="people-outline" size={44} color="#c3c6d7" />
|
|
|
- <Text className="mt-4 text-base text-on-surface-variant">暂无匹配客户</Text>
|
|
|
- </View>
|
|
|
- ) : (
|
|
|
- list.map((item) => (
|
|
|
- <Pressable
|
|
|
- key={item.id}
|
|
|
- className="rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-4"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.93 : 1,
|
|
|
- transform: [{ scale: pressed ? 0.995 : 1 }],
|
|
|
- })}
|
|
|
- >
|
|
|
- <View className="mb-3 flex-row items-start justify-between gap-3">
|
|
|
- <View className="flex-1 flex-row items-center gap-3">
|
|
|
- <View className="h-11 w-11 items-center justify-center rounded-full bg-primary-fixed">
|
|
|
- <Text className="text-base font-bold text-primary">{item.name[0]}</Text>
|
|
|
- </View>
|
|
|
- <View className="flex-1">
|
|
|
- <Text className="text-lg font-bold text-on-surface">{item.name}</Text>
|
|
|
- <Text className="mt-1 text-sm text-on-surface-variant">
|
|
|
- {item.mobile}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- <StatusBadge
|
|
|
- text={item.loan_status || ''}
|
|
|
- variant={'secondary'}
|
|
|
- />
|
|
|
- </View>
|
|
|
-
|
|
|
- <Text className="mb-2.5 text-sm leading-6 text-on-surface-variant">
|
|
|
- {item.note}
|
|
|
- </Text>
|
|
|
-
|
|
|
- <View className="mb-3 flex-row flex-wrap items-center gap-3">
|
|
|
- <View className="flex-row items-center gap-1">
|
|
|
- <Ionicons name="document-text-outline" size={14} color="#737686" />
|
|
|
- <Text className="text-xs text-on-surface-variant">{item.loan_status}</Text>
|
|
|
- </View>
|
|
|
- {item.score ? (
|
|
|
- <View className="flex-row items-center gap-1">
|
|
|
- <Ionicons name="analytics-outline" size={14} color="#737686" />
|
|
|
- <Text className="text-xs text-on-surface-variant">
|
|
|
- 评分 {item.score}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- ) : null}
|
|
|
- <Text className="ml-auto text-xs text-outline">{item.updatetime}</Text>
|
|
|
- </View>
|
|
|
-
|
|
|
- <View className="flex-row gap-3">
|
|
|
- <Pressable
|
|
|
- className="flex-1 items-center rounded-xl bg-primary-container py-2.5"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.88 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text className="text-sm font-bold text-on-primary">
|
|
|
- {item.loan_status}
|
|
|
- </Text>
|
|
|
- </Pressable>
|
|
|
- <Pressable
|
|
|
- className="flex-1 items-center rounded-xl bg-surface-container-high py-2.5"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.88 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text className="text-sm font-semibold text-on-surface">编辑资料</Text>
|
|
|
- </Pressable>
|
|
|
- </View>
|
|
|
- </Pressable>
|
|
|
- ))
|
|
|
- )}
|
|
|
- </View>
|
|
|
- <View className="gap-3">
|
|
|
- {list.length === 0 ? (
|
|
|
- <View className="items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-6 py-14">
|
|
|
- <Ionicons name="people-outline" size={44} color="#c3c6d7" />
|
|
|
- <Text className="mt-4 text-base text-on-surface-variant">暂无匹配客户</Text>
|
|
|
- </View>
|
|
|
- ) : (
|
|
|
- list.map((item) => (
|
|
|
- <Pressable
|
|
|
- key={item.id}
|
|
|
- className="rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-4"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.93 : 1,
|
|
|
- transform: [{ scale: pressed ? 0.995 : 1 }],
|
|
|
- })}
|
|
|
- >
|
|
|
- <View className="mb-3 flex-row items-start justify-between gap-3">
|
|
|
- <View className="flex-1 flex-row items-center gap-3">
|
|
|
- <View className="h-11 w-11 items-center justify-center rounded-full bg-primary-fixed">
|
|
|
- <Text className="text-base font-bold text-primary">{item.name[0]}</Text>
|
|
|
- </View>
|
|
|
- <View className="flex-1">
|
|
|
- <Text className="text-lg font-bold text-on-surface">{item.name}</Text>
|
|
|
- <Text className="mt-1 text-sm text-on-surface-variant">
|
|
|
- {item.mobile}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- <StatusBadge
|
|
|
- text={item.loan_status || ''}
|
|
|
- variant={'secondary'}
|
|
|
- />
|
|
|
- </View>
|
|
|
-
|
|
|
- <Text className="mb-2.5 text-sm leading-6 text-on-surface-variant">
|
|
|
- {item.note}
|
|
|
- </Text>
|
|
|
-
|
|
|
- <View className="mb-3 flex-row flex-wrap items-center gap-3">
|
|
|
- <View className="flex-row items-center gap-1">
|
|
|
- <Ionicons name="document-text-outline" size={14} color="#737686" />
|
|
|
- <Text className="text-xs text-on-surface-variant">{item.loan_status}</Text>
|
|
|
- </View>
|
|
|
- {item.score ? (
|
|
|
- <View className="flex-row items-center gap-1">
|
|
|
- <Ionicons name="analytics-outline" size={14} color="#737686" />
|
|
|
- <Text className="text-xs text-on-surface-variant">
|
|
|
- 评分 {item.score}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- ) : null}
|
|
|
- <Text className="ml-auto text-xs text-outline">{item.updatetime}</Text>
|
|
|
- </View>
|
|
|
-
|
|
|
- <View className="flex-row gap-3">
|
|
|
- <Pressable
|
|
|
- className="flex-1 items-center rounded-xl bg-primary-container py-2.5"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.88 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text className="text-sm font-bold text-on-primary">
|
|
|
- {item.loan_status}
|
|
|
- </Text>
|
|
|
- </Pressable>
|
|
|
- <Pressable
|
|
|
- className="flex-1 items-center rounded-xl bg-surface-container-high py-2.5"
|
|
|
- style={({ pressed }) => ({
|
|
|
- opacity: pressed ? 0.88 : 1,
|
|
|
- })}
|
|
|
- >
|
|
|
- <Text className="text-sm font-semibold text-on-surface">编辑资料</Text>
|
|
|
- </Pressable>
|
|
|
- </View>
|
|
|
- </Pressable>
|
|
|
- ))
|
|
|
- )}
|
|
|
- </View>
|
|
|
- {loading && startRef.current > 0 && <View className='flex-row justify-center items-center mt-2'>
|
|
|
- <ActivityIndicator /><Text className='ml-2 pb-4'>加载中</Text>
|
|
|
- </View>}
|
|
|
- </ScrollView>
|
|
|
+ ListHeaderComponent={ListHeader}
|
|
|
+ ListEmptyComponent={ListInitialLoading ?? ListEmpty}
|
|
|
+ ListFooterComponent={ListFooter}
|
|
|
+ onEndReached={loadMore}
|
|
|
+ onEndReachedThreshold={0.5}
|
|
|
+ />
|
|
|
|
|
|
<View className="absolute bottom-7 right-5">
|
|
|
<Pressable
|