import React, { useEffect, useState } from 'react' import Taro from '@tarojs/taro' import { View, Text, ScrollView, Image } from '@tarojs/components' import classnames from 'classnames' import find from 'lodash/find' import remove from 'lodash/remove' import api from '@services/api' import app from '@services/request' import NavBar from '@components/navbar/index' import useNavData from '@hooks/useNavData' import { IPage, INIT_PAGE, getTotalPage } from '@utils/page' import { PRICE_TYPE, SALE_STATUS, SALE_STATUS_ATTR } from '@constants/house' import '@styles/common/house.scss' import '@styles/common/search-tab.scss' import './index.scss' interface IFilter { id: string name: string value?: string } interface IConditionState { currentPage: number areaList?: IFilter unitPrice?: IFilter totalPrice?: IFilter priceType?: string room?: IFilter propertyType?: IFilter fangBuildingType?: IFilter saleStatus?: IFilter renovationStatus?: IFilter projectFeature?: IFilter } const initial_value = { id: '', name: '' } const default_value = { id: 'all', name: '不限' } const INIT_CONDITION = { currentPage: 1, priceType: '', areaList: default_value, unitPrice: default_value, totalPrice: initial_value, room: default_value, propertyType: initial_value, fangBuildingType: initial_value, saleStatus: initial_value, renovationStatus: initial_value, projectFeature: initial_value } const NewHouse = () => { const { appHeaderHeight, contentHeight } = useNavData() const PAGE_LIMIT = 10 const footerBtnHeight = 60 const scrollHeight = contentHeight * 0.5 - footerBtnHeight const scrollMoreHeight = contentHeight * 0.6 - footerBtnHeight const [tab, setTab] = useState<string>('') const [priceType, setPriceType] = useState<string>('unitPrice') const [selected, setSelected] = useState<IConditionState>(INIT_CONDITION) const [page, setPage] = useState<IPage>(INIT_PAGE) const [showEmpty, setShowEmpty] = useState<boolean>(false) const [condition, setCondition] = useState<any>() const [houseList, setHouseList] = useState<any>([]) const tabs = [ { type: 'areaList', name: '区域', keys: ['areaList'] }, { type: 'price', name: '价格', keys: ['totalPrice', 'unitPrice'] }, { type: 'room', name: '户型', keys: ['room'] }, { type: 'more', name: '更多', keys: ['propertyType', 'fangBuildingType', 'renovationStatus', 'projectFeature'] }] const priceTabs = [ { id: '1', name: '按单价', value: "unitPrice" }, { id: '2', name: '按总价', value: "totalPrice" } ] useEffect(() => { fetchCondition() }, []) useEffect(() => { fetchHouseList(selected.currentPage) }, [selected.currentPage, selected.areaList, selected.unitPrice, selected.totalPrice, selected.room]) const fetchCondition = () => { app.request({ url: app.testApiUrl(api.getHouseAttr) }).then((result: any) => { setCondition({ ...result, saleStatus: SALE_STATUS_ATTR }) }) } const fetchHouseList = (currentPage: number = 1) => { app.request({ url: app.areaApiUrl(api.getHouseList), data: { page: currentPage, limit: PAGE_LIMIT, fang_area_id: filterParam(selected.areaList?.id), price: filterParam(selected.unitPrice?.id || selected.totalPrice?.id), price_type: filterParam(selected.priceType), sale_status: selected.saleStatus?.id, fang_room_type: filterParam(selected.room?.id), fang_project_feature: selected.projectFeature?.id, fang_renovation_status: selected.renovationStatus?.id, fang_property_type: selected.propertyType?.id, fang_building_type: selected.fangBuildingType?.id } }).then((result: any) => { const totalPage = getTotalPage(PAGE_LIMIT, result.pagination.totalCount) if (totalPage <= INIT_CONDITION.currentPage) { setShowEmpty(true) } else { setShowEmpty(false) } setPage({ totalCount: result.pagination.totalCount, totalPage }) if (currentPage === 1) { setHouseList(result.data) } else { setHouseList([...houseList, ...result.data]) } }) } const handleScrollToLower = () => { if (page.totalPage > selected.currentPage) { setSelected({ ...selected, currentPage: selected.currentPage + 1 }) } else { setShowEmpty(true) } } const filterParam = (id: any) => { return id === 'all' ? '' : id } const switchCondition = (item) => { if (tab === item.type) { setTab('') return } setTab(item.type) } const handleSingleClick = (key: string, item: any) => { setTab('') if (key === 'unitPrice') { setSelected({ ...selected, totalPrice: initial_value, priceType: '1', [key]: item, currentPage: INIT_CONDITION.currentPage }) } else if (key === 'totalPrice') { setSelected({ ...selected, unitPrice: initial_value, priceType: '2', [key]: item, currentPage: INIT_CONDITION.currentPage }) } else { setSelected({ ...selected, [key]: item, currentPage: INIT_CONDITION.currentPage }) } } const handleMultiClick = (key: string, item: any) => { let selectedValue = selected[key] if (selectedValue instanceof Object) { if (selectedValue.id === item.id) { setSelected({ ...selected, [key]: initial_value }) } else { setSelected({ ...selected, [key]: item }) } } if (selectedValue instanceof Array) { let target = find(selectedValue, { id: item.id }) if (target) { remove(selectedValue, { id: item.id }) setSelected({ ...selected, [key]: selectedValue }) } else { setSelected({ ...selected, [key]: [...selectedValue, item] }) } } } const handleReset = () => { setSelected({ ...selected, propertyType: initial_value, renovationStatus: initial_value, saleStatus: initial_value, projectFeature: initial_value }) } const handleConfirm = () => { setTab('') fetchHouseList() } const handleHouseItemClick = (item: any) => { Taro.navigateTo({ url: `/house/new/index/index?id=${item.id}&name=${item.title}` }) } const handleSearchClick = () => { Taro.navigateTo({ url: `/house/new/search/index` }) } const renderSplitItem = (key: string) => { return ( <ScrollView className="split-list flex-item" scrollY style={{ height: scrollHeight }}> <View className={classnames("split-item", selected[key].id === default_value.id && 'actived')} onClick={() => handleSingleClick(key, default_value)} >{default_value.name} </View> { condition && condition[key].map((item: any, index: number) => ( <View key={index} className={classnames("split-item", selected[key].id === item.id && 'actived')} onClick={() => handleSingleClick(key, item)} >{item.name} </View> )) } </ScrollView> ) } const renderMultiItem = (key: string, title: string = '') => { return ( <View className="search-multi-item"> {title && <View className="title">{title}</View>} <View className="options"> { condition && condition[key].map((item: any, index: number) => ( <View key={index} className={classnames("options-item", selected[key].id === item.id && 'actived')} onClick={() => handleMultiClick(key, item)} > {item.name} </View> )) } </View> </View> ) } const renderShowName = (item: any) => { let showList: string[] = [] for (const key of item.keys) { if (selected[key] instanceof Object) { let showName: string = selected[key].name if (!showName || ['不限', '全部'].includes(showName)) { continue } showList.push(showName) } } if (showList.length > 1) { showList = ['多选'] } return showList.join(',') } return ( <View className="newhouse"> <NavBar title="新房" back={true} /> <View className="fixed" style={{ top: appHeaderHeight }}> <View className="newhouse-header view-content"> <View className="newhouse-search" onClick={handleSearchClick}> <Text className="iconfont iconsearch"></Text> <Text className="newhouse-search-text placeholder">请输入楼盘名称或地址</Text> </View> <View className="newhouse-nav-right"> <Text className="iconfont iconaddress"></Text> <Text className="text">地图找房</Text> </View> </View> <View className="search-tab"> { tabs.map((item: any, index: number) => { let showName = renderShowName(item) return ( <View key={index} className={classnames('search-tab-item', showName && 'actived')} onClick={() => switchCondition(item)} > <Text className="text">{showName ? showName : item.name}</Text> <Text className="iconfont iconarrow-down-bold"></Text> </View> ) }) } </View> <View className={classnames('search-container', tab === 'areaList' && 'actived')}> <View className="search-content"> <View className="search-split"> <View className="split-type flex-item"> <View className="split-item actived">区域</View> </View> {renderSplitItem('areaList')} </View> </View> </View> <View className={classnames('search-container', tab === 'price' && 'actived')}> <View className="search-content"> <View className="search-split"> <View className="split-type flex-item"> { priceTabs.map((item: any) => ( <View key={item.id} className={classnames("split-item", item.value === priceType && 'actived')} onClick={() => setPriceType(item.value)}> {item.name} </View> )) } </View> {renderSplitItem(priceType)} </View> </View> {/* <View className="search-footer"> <Input className="search-input" placeholder="最低价" />- <Input className="search-input" placeholder="最高价" /> <View className="btn confirm-btn single-btn">确定</View> </View> */} </View> <View className={classnames('search-container', tab === 'room' && 'actived')}> <View className="search-content"> <View className="search-split"> {renderSplitItem('room')} </View> </View> </View> <View className={classnames('search-container', 'search-multi-container', tab === 'more' && 'actived')}> <ScrollView className="search-content search-content-scroll" scrollY style={{ maxHeight: scrollMoreHeight }}> {renderMultiItem('propertyType', '建筑类型')} {renderMultiItem('renovationStatus', '装修状况')} {renderMultiItem('saleStatus', '销售状态')} {renderMultiItem('projectFeature', '项目特色')} </ScrollView> <View className="search-footer"> <View className="btn reset-btn" onClick={handleReset}>重置</View> <View className="btn confirm-btn" onClick={handleConfirm}>确定</View> </View> </View> </View> <View className={classnames('mask', tab && 'show')} onClick={() => setTab('')}></View> <View className="newhouse-content"> <ScrollView className="house-list" scrollY style={{ maxHeight: contentHeight - 90 }} lowerThreshold={30} onScrollToLower={handleScrollToLower} > <View className="house-list-ul"> { houseList.length > 0 && houseList.map((item: any) => ( <View className="house-list-li" key={item.id} onClick={() => handleHouseItemClick(item)}> <View className="li-image"> <Image src={item.image_path}></Image> </View> <View className="li-text"> <View className="text-item title mb10"> <Text>{item.title}</Text> </View> <View className="text-item small-desc mb10"> <Text>{item.area && item.area.name}</Text> <Text className="line-split"></Text> <Text>{item.address}</Text> </View> <View className="mb10"> <Text className="price">{item.price}</Text> <Text className="price-unit">{PRICE_TYPE[item.price_type]}</Text> </View> <View className="text-item tags"> <Text className={classnames('tags-item', `sale-status-${item.sale_status}`)}>{SALE_STATUS[item.sale_status]}</Text> </View> </View> </View> )) } </View> { showEmpty && <View className="empty-container"> <Text>没有更多数据了</Text> </View> } </ScrollView> </View> </View> ) } export default NewHouse