import { View, Text, Image as NativeImage, ScrollView, TouchableOpacity, Dimensions, } from "react-native"; import React, { useState, useEffect, useRef } from "react"; import { useTailwind } from "tailwind-rn"; import { useSafeAreaInsets, SafeAreaProvider, } from "react-native-safe-area-context"; import { SearchBar, ListItem, Icon, CheckBox, BottomSheet, } from "@rneui/themed"; import { Image } from "expo-image"; import Empty from "../../components/Empty"; import Toast from "react-native-toast-message"; import baseRequest from "../../utils/baseRequest"; import { generateSignature } from "../../utils/crypto"; import MyDivider from "../../components/MyDivider/index"; import MySlider from "../../components/MySlider"; import Picker from "../../components/Picker"; import { get } from "../../utils/storeInfo"; export default function Search({ navigation, route }) { const tailwind = useTailwind(); const insets = useSafeAreaInsets(); const searchRef = useRef(null); const screenDimensions = Dimensions.get("screen"); const [search, setSearch] = useState(""); const [isMember, setIsMember] = useState(0); const [streamers, setStreamers] = useState([]); const [recommList, setRecommList] = useState([]); const [zones, setZones] = useState([]); const [isloading, setIsloading] = useState(false); const [isFilterVisible, setIsFilterVisible] = useState({ comprehensive: false, zone_admission_price: false, }); const filters = [ { name: "年龄", upper_bound: 60, lower_bound: 18, default: 19, step: 1, type: "slider", unit: "岁", key: "age", stepValues: Array(61) .fill(null) .map((_, index) => index), }, { name: "全网粉丝", upper_bound: 200, lower_bound: 1, default: 24, step: 200 / 10, type: "slider", unit: "万", key: "fans", stepValues: [1, 3, 5, 10, 20, 50, 75, 100, 150, 200, 1000], }, { name: "身高", upper_bound: 200, lower_bound: 140, default: 160, step: 1, type: "slider", unit: "CM", key: "height", stepValues: Array(201) .fill(null) .map((_, index) => index), }, { name: "体重", upper_bound: 100, lower_bound: 35, default: 50, step: 1, type: "slider", unit: "KG", key: "weight", stepValues: Array(101) .fill(null) .map((_, index) => index), }, { name: "所在地", upper_bound: 1000, lower_bound: 10, default: 24, step: 1, type: "select", items: [ "北京市", "天津市", "河北省", "山西省", "内蒙古自治区", "辽宁省", "吉林省", "黑龙江省", "上海市", "江苏省", "浙江省", "安徽省", "福建省", "江西省", "山东省", "河南省", "湖北省", "湖南省", "广东省", "广西壮族自治区", "海南省", "重庆市", "四川省", "贵州省", "云南省", "西藏自治区", "陕西省", "甘肃省", "青海省", "宁夏回族自治区", "新疆维吾尔自治区", "台湾省", "香港特别行政区", "澳门特别行政区", ], key: "city", }, { name: "星座", upper_bound: 1000, lower_bound: 10, default: 24, step: 1, type: "select", key: "constellation", items: [ "白羊座", "‌金牛座", "‌双子座", "‌巨蟹座", "‌狮子座", "‌处女座", "‌天秤座", "‌天蝎座", "‌射手座", "‌摩羯座", "‌水瓶座", "‌双鱼座", ], }, { name: "最近7日内空间有更新", upper_bound: 1000, lower_bound: 10, default: 24, step: 1, type: "checkbox", key: "is_active_within_a_week", }, ]; const priceFilters = [ { name: "空间价格", upper_bound: 200, lower_bound: 0, default: 24, step: 200 / 7, type: "slider", unit: "¥", key: "zone", stepValues: [0, 1, 10, 50, 100, 150, 200, 4000], }, { name: "微信价格", upper_bound: 200, lower_bound: 0, default: 24, step: 200 / 8, type: "slider", unit: "金币", key: "wechat", stepValues: [0, 10, 100, 200, 500, 1000, 5000, 10000, 100000], }, ]; const [filtersValue, setFiltersValue] = useState({ age: { lower_bound: 18, upper_bound: 60 }, fans: { lower_bound: 1, upper_bound: 1000 }, height: { lower_bound: 140, upper_bound: 200 }, weight: { lower_bound: 35, upper_bound: 100 }, city: "", constellation: "", is_active_within_a_week: 0, zone_admission_price: { lower_bound: 0, upper_bound: 4000 }, wechat_coin_price: { lower_bound: 0, upper_bound: 100000 }, priceUsed: { show: false, used: false }, comprehensiveUsed: { show: false, used: false }, }); const updateSearch = (search) => { setSearch(search); if (!search) return; setIsloading(true); }; //进入页面默认focus useEffect(() => { searchRef.current.focus(); getIsMember(); }, []); //搜索框文本变化时进行搜索 useEffect(() => { if (!search) { setStreamers([]); setZones([]); return; } const isNumeric = (str) => { return /^\d+$/.test(str); }; const getResult = async () => { const apiUrl = process.env.EXPO_PUBLIC_API_URL; const isSearchInt = isNumeric(search); let api; let querryParams; if (isSearchInt) { api = "/api/streamer/list_ext_fuzzily_by_user_id"; querryParams = { user_id: parseInt(search, 10) }; } else { api = "/api/streamer/list_ext_fuzzily_by_name"; querryParams = { name: search }; } try { const base = await baseRequest(); const signature = await generateSignature({ ...base, ...querryParams, offset: 0, limit: 20, }); const response = await fetch(`${apiUrl}${api}?signature=${signature}`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ ...base, ...querryParams, offset: 0, limit: 20, }), }); const data = await response.json(); if (data.ret === -1) { Toast.show({ type: "error", text1: data.msg, topOffset: 60, }); return; } if (!ignore) { const zonesData = data.data.list.filter( (item) => item.zones.length > 0 ); setStreamers(data.data.list); setZones(zonesData); } setIsloading(false); } catch (error) { console.error(error); } }; let ignore = false; getResult(); return () => { ignore = true; }; }, [search]); const getFiltersResult = async () => { const apiUrl = process.env.EXPO_PUBLIC_API_URL; let api; let querryParams; api = "/api/streamer/filter"; let currentFilterValue = { ...filtersValue }; delete currentFilterValue.comprehensiveUsed; delete currentFilterValue.priceUsed; querryParams = currentFilterValue; try { const base = await baseRequest(); const signature = await generateSignature({ ...base, ...querryParams, offset: 0, limit: 20, }); const response = await fetch(`${apiUrl}${api}?signature=${signature}`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ ...base, ...querryParams, offset: 0, limit: 20, }), }); const data = await response.json(); if (data.ret === -1) { Toast.show({ type: "error", text1: data.msg, topOffset: 60, }); return; } const zonesData = data.data.streamer_list.filter( (item) => item.zones.length > 0 ); setStreamers(data.data.streamer_list); setZones(zonesData); setRecommList(data.data.recomm_list); setIsloading(false); } catch (error) { console.error(error); } }; const getIsMember = async () => { const apiUrl = process.env.EXPO_PUBLIC_API_URL; let api; api = "/api/account/list_by_mid"; const account = await get("account"); try { const base = await baseRequest(); const signature = await generateSignature({ ...base, mid: account.mid, }); const response = await fetch(`${apiUrl}${api}?signature=${signature}`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ ...base, mid: account.mid, }), }); const data = await response.json(); setIsMember(data.data.account.is_a_member); } catch (error) { console.error(error); } }; //重置筛选值 const handleResetFiltersValue = (type) => { let obj = {}; if (type == "comprehensive") { obj = { ...filtersValue, age: { lower_bound: 18, upper_bound: 60 }, fans: { lower_bound: 1, upper_bound: 1000 }, weight: { lower_bound: 35, upper_bound: 100 }, height: { lower_bound: 140, upper_bound: 200 }, city: "", constellation: "", is_active_within_a_week: 0, comprehensiveUsed: { show: false, used: false }, }; } else { obj = { ...filtersValue, zone_admission_price: { lower_bound: 0, upper_bound: 4000 }, wechat_coin_price: { lower_bound: 0, upper_bound: 100000 }, priceUsed: { show: false, used: false }, }; } setFiltersValue((old) => ({ ...old, ...obj, })); if (!obj.comprehensiveUsed.used && !obj.priceUsed.used) { setRecommList([]); setStreamers([]); setZones([]); } }; //空间组件 const ZoneItem = ({ item }) => { return ( navigation.navigate("SpaceIntroduce", { mid: item?.mid }) } containerStyle={tailwind("p-0 bg-[#07050A]")} > {item?.name} {item?.user_id} {item.zones[0].profile} {zones.length === 1 && ( Ta的动态· {item.zones[0].zone_moment_count > 99 ? "99+" : item.zones[0].zone_moment_count} {item.zones[0].image_count > 0 && ` | 图片·${ item.zones[0].image_count > 99 ? "99+" : item.zones[0].image_count }`} {item.zones[0].video_count > 0 && ` | 视频·${ item.zones[0].video_count > 99 ? "99+" : item.zones[0].video_count }`} {item.album.images.map((_item, index) => { if (index > 1) return; return ( ); })} )} ); }; //主播组件 const StreamerItem = ({ item }) => { return ( navigation.navigate("StreamerProfile", { mid: item.mid, }) } containerStyle={tailwind("p-0 bg-[#07050A]")} > {item?.name} {item?.user_id} {item.bio} ); }; return ( navigation.goBack()} /> <>} searchIcon={() => <>} showLoading={isloading} onChangeText={updateSearch} value={search} disabled={ filtersValue.comprehensiveUsed.used || filtersValue.priceUsed.used } /> { setIsFilterVisible({ ...isFilterVisible, comprehensive: !isFilterVisible.comprehensive, }); }} style={{ ...tailwind("px-2 rounded-xl flex-row items-center"), borderColor: "#ff75c8", borderWidth: filtersValue.comprehensiveUsed.used ? 1 : 0, boxSizing: "border-box", width: 110, }} > 综合筛选 {filtersValue.comprehensiveUsed.used && ( handleResetFiltersValue("comprehensive")} style={{ width: 24 }} > )} { setIsFilterVisible({ ...isFilterVisible, zone_admission_price: !isFilterVisible.zone_admission_price, }); }} style={{ ...tailwind("px-2 rounded-xl flex-row items-center"), borderColor: "#ff75c8", borderWidth: filtersValue.priceUsed.used ? 1 : 0, boxSizing: "border-box", width: 110, }} > 价格筛选 {filtersValue.priceUsed.used && ( handleResetFiltersValue("zone_admission_price")} style={{ width: 24 }} > )} { const { y } = event.nativeEvent.contentOffset; if (y < -50) { setIsFilterVisible({ zone_admission_price: false, comprehensive: false, }); } }, }} isVisible={isFilterVisible.comprehensive} style={{ paddingTop: 110, }} > {filters.map((item, index) => ( {item.name} {item.type == "slider" ? ( { if (item.key == "age") { setFiltersValue((old) => ({ ...old, age: value })); } else if (item.key == "fans") { setFiltersValue((old) => ({ ...old, fans: value })); } else if (item.key == "height") { setFiltersValue((old) => ({ ...old, height: value })); } else if (item.key == "weight") { setFiltersValue((old) => ({ ...old, weight: value })); } }} maximumTrackTintColor="#ff75c81a" minimumTrackTintColor="#ff75c8" processHeight={5} unit={item.unit} thumbImage={require("../../assets/icon/32DP/edit.png")} /> ) : item.type == "checkbox" ? ( setFiltersValue((old) => ({ ...old, is_active_within_a_week: old.is_active_within_a_week ? 0 : 1, })) } iconType="material-community" checkedIcon="checkbox-marked" uncheckedIcon="checkbox-blank-outline" checkedColor="#FF669E" containerStyle={tailwind("p-0 m-0 bg-transparent")} size={24} /> ) : ( ({ label: it, value: it, }))} value={ item.key == "constellation" ? filtersValue.constellation : filtersValue.city } onChange={(value) => setFiltersValue((old) => { let newValue = { ...old }; if (item.key == "constellation") { newValue.constellation = value; } else { newValue.city = value; } return newValue; }) } /> )} ))} {isMember == 1 && ( handleResetFiltersValue("comprehensive")} > 重置 )} { setIsFilterVisible({ zone_admission_price: false, comprehensive: false, }); if (!isMember) { navigation.navigate("WebWithoutHeader", { uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip", }); return; } setFiltersValue((old) => ({ ...old, comprehensiveUsed: { show: false, used: true }, })); getFiltersResult(); }} style={{ ...tailwind("text-white px-4 py-2 rounded-xl"), marginVertical: 6, backgroundColor: "#ff75c8", minWidth: 120, }} > {!isMember ? "开通VIP后即可筛选" : "确定"} { const { y } = event.nativeEvent.contentOffset; if (y < -50) { setIsFilterVisible({ zone_admission_price: false, comprehensive: false, }); } }, }} isVisible={isFilterVisible.zone_admission_price} style={{ paddingTop: 110, }} > {priceFilters.map((item) => ( {item.name} { if (item.key == "zone") { setFiltersValue((old) => ({ ...old, zone_admission_price: value, })); } else if (item.key == "wechat") { setFiltersValue((old) => ({ ...old, wechat_coin_price: value, })); } }} maximumTrackTintColor="#ff75c81a" minimumTrackTintColor="#ff75c8" processHeight={5} unit={item.unit} thumbImage={require("../../assets/icon/32DP/edit.png")} /> ))} {isMember == 1 && ( handleResetFiltersValue("zone_admission_price") } > 重置 )} { setIsFilterVisible({ zone_admission_price: false, comprehensive: false, }); if (!isMember) { navigation.navigate("WebWithoutHeader", { uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip", }); return; } setFiltersValue((old) => ({ ...old, priceUsed: { show: false, used: true }, })); getFiltersResult(); }} style={{ ...tailwind("text-white px-4 py-2 rounded-xl"), marginVertical: 6, backgroundColor: "#ff75c8", minWidth: 120, }} > {!isMember ? "开通VIP后即可筛选" : "确定"} {zones.length > 0 && ( 空间 )} {zones?.map((item, index) => ( ))} {zones.length > 0 && } {streamers.length > 0 && ( 用户 )} {streamers?.map((item, index) => ( ))} {recommList.length > 0 && } {recommList.length > 0 && ( 猜你喜欢 )} {recommList?.map((item, index) => ( ))} {streamers.length === 0 && recommList.length === 0 && ( )} ); }