taro3.x: 查询条件
tsx:
import React, { useEffect, useState } from 'react'
import { View, Text, ScrollView, Image } from '@tarojs/components'
import classnames from 'classnames'
import { find, remove } from 'lodash'
import api from '@services/api'
import app from '@services/request'
import NavBar from '@components/navbar/index'
import useNavData from '@hooks/useNavData'
import { PRICE_TYPE, SALE_STATUS } from '@constants/house'
import '@styles/common/house-list.scss'
import '@styles/common/search-tab.scss'
import './index.scss'
interface IFilter {
id: string
name: string
value?: string
}
interface IConditionState {
region?: IFilter
unit_price?: IFilter
total_price?: IFilter
house_type?: IFilter
house_property?: IFilter
sale_status?: IFilter
renovation?: IFilter
feature?: IFilter
}
const initial_value = { id: '', name: '', value: '' }
const INIT_CONDITION = {
region: { id: 'all000', name: '不限', value: '' },
unit_price: { id: 'all000', name: '不限', value: '' },
total_price: initial_value,
house_type: { id: 'all000', name: '不限', value: '' },
house_property: initial_value,
sale_status: initial_value,
renovation: initial_value,
feature: initial_value
}
const NewHouse = () => {
const { appHeaderHeight, contentHeight } = useNavData()
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>('unit_price')
const [selected, setSelected] = useState<IConditionState>(INIT_CONDITION)
const [condition, setCondition] = useState<any>()
const [houseList, setHouseList] = useState<any>([])
const tabs = [
{
type: 'region',
name: '区域',
keys: ['region']
},
{
type: 'price',
name: '价格',
keys: ['unit_price', 'total_price']
},
{
type: 'house_type',
name: '户型',
keys: ['house_type']
},
{
type: 'more',
name: '更多',
keys: ['house_property', 'sale_status', 'renovation', 'feature']
}]
const priceTabs = [
{
id: 'id_01',
name: '按单价',
value: "unit_price"
},
{
id: 'id_02',
name: '按总价',
value: "total_price"
}
]
useEffect(() => {
fetchCondition()
fetchHouseList()
}, [])
const fetchCondition = () => {
app.request({
url: api.getHouseCondition,
data: { type: 'newHouse' }
}, {
isMock: true,
loading: false
}).then((result: any) => {
setCondition(result || {})
})
}
const fetchHouseList = () => {
app.request({
url: api.getHouseNew,
data: {}
}, {
isMock: true,
loading: false
}).then((result: any) => {
setHouseList(result || [])
})
}
const switchCondition = (item) => {
if (tab === item.type) {
setTab('')
return
}
setTab(item.type)
}
const handleSingleClick = (key: string, item: any) => {
setTab('')
if (key === 'unit_price') {
setSelected({
...selected,
total_price: initial_value,
[key]: item
})
} else if (key === 'total_price') {
setSelected({
...selected,
unit_price: initial_value,
[key]: item
})
} else {
setSelected({
...selected,
[key]: item
})
}
}
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,
house_property: initial_value,
renovation: initial_value,
sale_status: initial_value,
feature: initial_value
})
}
const handleConfirm = () => {
setTab('')
}
const renderSplitItem = (key: string) => {
return (
<ScrollView className="split-list flex-item" scrollY style={{ height: scrollHeight }}>
{
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-top" style={{ top: appHeaderHeight }}>
<View className="newhouse-header view-content">
<View className="newhouse-search">
<Text className="iconfont iconsearch"></Text>
<Text className="newhouse-search-text placeholder">请输入楼盘名称或地址</Text>
</View>
<View className="newhouse-nav-right">
<Text className="iconfont iconmap"></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 === 'region' && 'actived')}>
<View className="search-content">
<View className="search-split">
<View className="split-type flex-item">
<View className="split-item actived">区域</View>
</View>
{renderSplitItem('region')}
</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 === 'house_type' && 'actived')}>
<View className="search-content">
<View className="search-split">
{renderSplitItem('house_type')}
</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('house_property', '类型')}
{renderMultiItem('renovation', '装修')}
{renderMultiItem('sale_status', '状态')}
{renderMultiItem('feature', '特色')}
</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 view-content" scrollY style={{ height: contentHeight - 85 }}>
<View className="house-list-ul">
{
houseList.length > 0 && houseList.map((item: any) => (
<View className="house-list-li" key={item.id}>
<View className="li-image">
<Image src={item.image_path}></Image>
</View>
<View className="li-text">
<View className="title mb10">
<Text>{item.house_name}</Text>
</View>
<View className="small-desc mb10">
<Text>{item.area && item.area.name}</Text>
<Text className="line-split"></Text>
<Text>建面{item.building_area}平米</Text>
</View>
<View className="mb10">
<Text className="price">{item.price}</Text>
<Text className="price-unit">{PRICE_TYPE[item.price_type]}</Text>
</View>
<View className="tags">
<Text className={classnames('tags-item', `sale-status-${item.sale_status}`)}>{SALE_STATUS[item.sale_status]}</Text>
</View>
</View>
</View>
))
}
</View>
</ScrollView>
</View>
</View>
)
}
export default NewHouse
图例:

scss:
.search-tab { display: flex; justify-content: center; align-items: center; height: 80px; line-height: 80px; font-size: $font-basic; border-bottom: $border; background-color: $white; z-index: 99; &-item { flex: 1; text-align: center; &.actived { color: $primary-color; .iconfont { color: $primary-color; } } .text { display: inline-block; max-width: 70%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; } .iconfont { color: $desc-color; margin-left: 10px; vertical-align: middle; } } } .search-container { position: absolute; width: 100%; max-height: 50vh; z-index: -10; background-color: $white; font-size: $font-basic; transform: translateY(-100%); transition: 0.2s; &.actived { transform: translateY(0); } .search-content-scroll { margin-bottom: 120px; } .search-content { .search-split { display: flex; .flex-item { flex: 1; border-right: $border; } .flex-item:last-child { border-right: 0; } .split-item { height: 80px; line-height: 80px; padding-left: 30px; border-bottom: $border; &.actived { color: $primary-color; background-color: $bg-color; } } } .search-multi-item { padding: 16px 24px; .title { font-size: 30px; color: $title-color; padding: 10px; } .options { display: flex; flex-wrap: wrap; &-item { width: 19.5%; margin: 8px; text-align: center; font-size: 24px; padding: 14px 10px; border: 0.5px solid $bg2-color; border-radius: 6px; background-color: $bg2-color; color: $text-color; &.actived { color: $primary-color; border-color: $primary-color; background-color: $white; } } } } } .search-footer { position: absolute; bottom: 0; display: flex; width: 100%; justify-content: space-around; align-items: center; padding: 20px 0; background-color: #fff; .btn { width: 40%; line-height: 80px; text-align: center; border-radius: 6px; &.reset-btn { color: $text-color; background-color: $bg-color; } &.confirm-btn { color: $white; background-color: $primary-color; } &.single-btn { width: 25%; } } .search-input { width: 25%; height: 80px; line-height: 80px; text-align: center; background-color: $bg-color; } } } .search-multi-container { max-height: 60vh; }

浙公网安备 33010602011771号