|
|
|
@ -9,6 +9,7 @@ import { Popup, Toast, Tabs } from '@taroify/core' |
|
|
|
import { useCascader } from '@taroify/hooks' |
|
|
|
import { useCascader } from '@taroify/hooks' |
|
|
|
import { Arrow, Cross, Search } from '@taroify/icons' |
|
|
|
import { Arrow, Cross, Search } from '@taroify/icons' |
|
|
|
import { appStore } from '../../store' |
|
|
|
import { appStore } from '../../store' |
|
|
|
|
|
|
|
import { getStoreList, StoreInfoDto } from '../../api/basicInfo' |
|
|
|
import storeIcon from '../../assets/icon/storeIcon.png' |
|
|
|
import storeIcon from '../../assets/icon/storeIcon.png' |
|
|
|
import locationIcon from '../../assets/icon/locationIcon.png' |
|
|
|
import locationIcon from '../../assets/icon/locationIcon.png' |
|
|
|
import './index.scss' |
|
|
|
import './index.scss' |
|
|
|
@ -60,53 +61,14 @@ const cityOptions = [ |
|
|
|
}, |
|
|
|
}, |
|
|
|
] |
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
// 模拟门店数据
|
|
|
|
|
|
|
|
const mockStoreList = [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: '1', |
|
|
|
|
|
|
|
name: '北京黑八大师联盟球厅店', |
|
|
|
|
|
|
|
price: 16.00, |
|
|
|
|
|
|
|
billiardCount: 6, |
|
|
|
|
|
|
|
billiardEmpty: 6, |
|
|
|
|
|
|
|
chessCount: 2, |
|
|
|
|
|
|
|
chessEmpty: 2, |
|
|
|
|
|
|
|
type: '直营店', |
|
|
|
|
|
|
|
address: '北京市XXX区XXX街道XXX路19号606', |
|
|
|
|
|
|
|
distance: '0.05km', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: '2', |
|
|
|
|
|
|
|
name: '北京晶彩桌球世界店', |
|
|
|
|
|
|
|
price: 24.00, |
|
|
|
|
|
|
|
billiardCount: 8, |
|
|
|
|
|
|
|
billiardEmpty: 8, |
|
|
|
|
|
|
|
chessCount: 1, |
|
|
|
|
|
|
|
chessEmpty: 1, |
|
|
|
|
|
|
|
type: '加盟店', |
|
|
|
|
|
|
|
address: '北京市XXX区XXX街道XXX路XXXXXX大厦101', |
|
|
|
|
|
|
|
distance: '0.1km', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: '3', |
|
|
|
|
|
|
|
name: '北京飓风台球店', |
|
|
|
|
|
|
|
price: 106.00, |
|
|
|
|
|
|
|
billiardCount: 0, |
|
|
|
|
|
|
|
billiardEmpty: 0, |
|
|
|
|
|
|
|
chessCount: 0, |
|
|
|
|
|
|
|
chessEmpty: 0, |
|
|
|
|
|
|
|
type: '加盟店', |
|
|
|
|
|
|
|
address: '北京市XXX区XXX街道106号A01', |
|
|
|
|
|
|
|
distance: '100.00km', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const StoreIndex = observer(() => { |
|
|
|
const StoreIndex = observer(() => { |
|
|
|
const [selectedCity, setSelectedCity] = useState('选城市') |
|
|
|
const [selectedCity, setSelectedCity] = useState('选城市') |
|
|
|
const [searchValue, setSearchValue] = useState('') |
|
|
|
const [searchValue, setSearchValue] = useState('') |
|
|
|
const [cityPopupOpen, setCityPopupOpen] = useState(false) |
|
|
|
const [cityPopupOpen, setCityPopupOpen] = useState(false) |
|
|
|
const [storeList, setStoreList] = useState(mockStoreList) |
|
|
|
const [allStores, setAllStores] = useState<StoreInfoDto[]>([]) |
|
|
|
|
|
|
|
const [storeList, setStoreList] = useState<StoreInfoDto[]>([]) |
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
const [isSearched, setIsSearched] = useState(false) // 是否已执行搜索
|
|
|
|
const [isSearched, setIsSearched] = useState(false) |
|
|
|
const [cityValue, setCityValue] = useState<string[]>([]) |
|
|
|
const [cityValue, setCityValue] = useState<string[]>([]) |
|
|
|
const [tabIndex, setTabIndex] = useState(0) |
|
|
|
const [tabIndex, setTabIndex] = useState(0) |
|
|
|
|
|
|
|
|
|
|
|
@ -119,8 +81,22 @@ const StoreIndex = observer(() => { |
|
|
|
|
|
|
|
|
|
|
|
useLoad(() => { |
|
|
|
useLoad(() => { |
|
|
|
console.log('门店页面加载') |
|
|
|
console.log('门店页面加载') |
|
|
|
|
|
|
|
loadStores() |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const loadStores = async () => { |
|
|
|
|
|
|
|
setLoading(true) |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
const res = await getStoreList() |
|
|
|
|
|
|
|
setAllStores(res.data) |
|
|
|
|
|
|
|
setStoreList(res.data) |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
console.error('获取门店列表失败:', e) |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
setLoading(false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 监听弹窗状态,控制TabBar显示/隐藏
|
|
|
|
// 监听弹窗状态,控制TabBar显示/隐藏
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
if (cityPopupOpen) { |
|
|
|
if (cityPopupOpen) { |
|
|
|
@ -166,30 +142,14 @@ const StoreIndex = observer(() => { |
|
|
|
|
|
|
|
|
|
|
|
// 搜索门店
|
|
|
|
// 搜索门店
|
|
|
|
const handleSearch = () => { |
|
|
|
const handleSearch = () => { |
|
|
|
// 无内容时提示输入
|
|
|
|
|
|
|
|
if (!searchValue.trim()) { |
|
|
|
if (!searchValue.trim()) { |
|
|
|
Toast.open('请输入门店名称或地址') |
|
|
|
Toast.open('请输入门店名称或地址') |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
setIsSearched(true) |
|
|
|
setLoading(true) |
|
|
|
setStoreList(allStores.filter(store => |
|
|
|
Toast.loading({ |
|
|
|
store.name.includes(searchValue) || (store.address || '').includes(searchValue) |
|
|
|
message: '搜索中...', |
|
|
|
|
|
|
|
duration: 0, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟接口请求
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
setLoading(false) |
|
|
|
|
|
|
|
Toast.close() |
|
|
|
|
|
|
|
Toast.success('搜索完成') |
|
|
|
|
|
|
|
setIsSearched(true) // 标记已搜索,切换为取消图标
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根据输入内容过滤数据
|
|
|
|
|
|
|
|
setStoreList(mockStoreList.filter(store => |
|
|
|
|
|
|
|
store.name.includes(searchValue) || store.address.includes(searchValue) |
|
|
|
|
|
|
|
)) |
|
|
|
)) |
|
|
|
}, 1500) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 输入框变化
|
|
|
|
// 输入框变化
|
|
|
|
@ -200,28 +160,15 @@ const StoreIndex = observer(() => { |
|
|
|
// 清除搜索并恢复默认数据
|
|
|
|
// 清除搜索并恢复默认数据
|
|
|
|
const handleClearSearch = () => { |
|
|
|
const handleClearSearch = () => { |
|
|
|
setSearchValue('') |
|
|
|
setSearchValue('') |
|
|
|
setIsSearched(false) // 切换回搜索图标
|
|
|
|
setIsSearched(false) |
|
|
|
|
|
|
|
setStoreList(allStores) |
|
|
|
// 恢复默认数据
|
|
|
|
|
|
|
|
setLoading(true) |
|
|
|
|
|
|
|
Toast.loading({ |
|
|
|
|
|
|
|
message: '加载中...', |
|
|
|
|
|
|
|
duration: 0, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
setLoading(false) |
|
|
|
|
|
|
|
Toast.close() |
|
|
|
|
|
|
|
setStoreList(mockStoreList) |
|
|
|
|
|
|
|
}, 500) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 跳转到店铺详情
|
|
|
|
// 跳转到店铺详情
|
|
|
|
const clickStoreItem = (store: any) => { |
|
|
|
const clickStoreItem = (store: StoreInfoDto) => { |
|
|
|
Taro.navigateTo({ |
|
|
|
Taro.navigateTo({ |
|
|
|
url: '/pageStore/storeDetail/index?id=' + store.id |
|
|
|
url: '/pageStore/storeDetail/index?id=' + store.id |
|
|
|
}) |
|
|
|
}) |
|
|
|
console.log('跳转到店铺详情', store) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 跳转到地图找店页面(分包页面)
|
|
|
|
// 跳转到地图找店页面(分包页面)
|
|
|
|
@ -273,46 +220,50 @@ const StoreIndex = observer(() => { |
|
|
|
|
|
|
|
|
|
|
|
{/* 门店列表 */} |
|
|
|
{/* 门店列表 */} |
|
|
|
<View className="store-list"> |
|
|
|
<View className="store-list"> |
|
|
|
{storeList.map((store) => ( |
|
|
|
{loading ? ( |
|
|
|
|
|
|
|
<View className="list-footer"><Text className="footer-text">加载中...</Text></View> |
|
|
|
|
|
|
|
) : storeList.length === 0 ? ( |
|
|
|
|
|
|
|
<View className="list-footer"><Text className="footer-text">暂无门店数据</Text></View> |
|
|
|
|
|
|
|
) : ( |
|
|
|
|
|
|
|
storeList.map((store) => ( |
|
|
|
<View className="store-item" key={store.id} onClick={() => clickStoreItem(store)}> |
|
|
|
<View className="store-item" key={store.id} onClick={() => clickStoreItem(store)}> |
|
|
|
{/* 标题和价格 */} |
|
|
|
{/* 标题和类型 */} |
|
|
|
<View className="store-header"> |
|
|
|
<View className="store-header"> |
|
|
|
<Text className="store-name">{store.name}</Text> |
|
|
|
<Text className="store-name">{store.name}</Text> |
|
|
|
<View className="store-price"> |
|
|
|
<View className="store-price"> |
|
|
|
<Text className="price-symbol">¥</Text> |
|
|
|
<Text className="price-value">{store.typeName || (store.isUnion === 1 ? '加盟店' : '直营店')}</Text> |
|
|
|
<Text className="price-value">{store.price.toFixed(2)}</Text> |
|
|
|
|
|
|
|
<Text className="price-unit">起/小时</Text> |
|
|
|
|
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
|
|
{/* 标签 */} |
|
|
|
{/* 标签 */} |
|
|
|
<View className="store-tags"> |
|
|
|
<View className="store-tags"> |
|
|
|
<View className="tag tag-billiard"> |
|
|
|
{store.instName && ( |
|
|
|
台球 {store.billiardCount} 桌空闲 |
|
|
|
<View className="tag tag-billiard">{store.instName}</View> |
|
|
|
</View> |
|
|
|
)} |
|
|
|
<View className="tag tag-chess"> |
|
|
|
{store.regionName && ( |
|
|
|
棋牌 {store.chessCount} 桌空闲 |
|
|
|
<View className="tag tag-chess">{store.regionName}</View> |
|
|
|
</View> |
|
|
|
)} |
|
|
|
<View className="tag tag-type"> |
|
|
|
|
|
|
|
{store.type} |
|
|
|
|
|
|
|
</View> |
|
|
|
|
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
|
|
{/* 地址和距离 */} |
|
|
|
{/* 地址和电话 */} |
|
|
|
<View className="store-location"> |
|
|
|
<View className="store-location"> |
|
|
|
<View className="location-left"> |
|
|
|
<View className="location-left"> |
|
|
|
<Image className="location-icon" src={locationIcon} mode="aspectFit" /> |
|
|
|
<Image className="location-icon" src={locationIcon} mode="aspectFit" /> |
|
|
|
<Text className="address-text">{store.address}</Text> |
|
|
|
<Text className="address-text">{store.address || '地址未填写'}</Text> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
<Text className="distance-text">距离{store.distance} {'>'}</Text> |
|
|
|
{store.phone && ( |
|
|
|
|
|
|
|
<Text className="distance-text">{store.phone}</Text> |
|
|
|
|
|
|
|
)} |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
))} |
|
|
|
)) |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{/* 列表底部提示 */} |
|
|
|
{!loading && storeList.length > 0 && ( |
|
|
|
<View className="list-footer"> |
|
|
|
<View className="list-footer"> |
|
|
|
<Text className="footer-text">到底了~</Text> |
|
|
|
<Text className="footer-text">到底了~</Text> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
)} |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
|
|
|