From 1c540db3218fec4c645a551f780c361e70a6a313 Mon Sep 17 00:00:00 2001 From: DU Date: Thu, 15 Jan 2026 21:51:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=97=E9=93=BA=EF=BC=8C=E6=89=BE=E5=BA=97?= =?UTF-8?q?=EF=BC=8C=E5=AF=BC=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- babel.config.js | 5 +- package-lock.json | 1 + package.json | 1 + src/app.config.ts | 17 + src/app.scss | 9 + src/app.ts | 2 - src/assets/icon/locationIcon.png | Bin 0 -> 3304 bytes src/assets/icon/storeIcon.png | Bin 0 -> 14307 bytes src/custom-tab-bar/index.scss | 2 +- src/pageStore/mapStore/index.config.ts | 5 + src/pageStore/mapStore/index.scss | 221 ++++++++++++ src/pageStore/mapStore/index.tsx | 478 +++++++++++++++++++++++++ src/pages/store/index.scss | 304 +++++++++++++++- src/pages/store/index.tsx | 332 ++++++++++++++++- 14 files changed, 1351 insertions(+), 26 deletions(-) create mode 100644 src/assets/icon/locationIcon.png create mode 100644 src/assets/icon/storeIcon.png create mode 100644 src/pageStore/mapStore/index.config.ts create mode 100644 src/pageStore/mapStore/index.scss create mode 100644 src/pageStore/mapStore/index.tsx diff --git a/babel.config.js b/babel.config.js index 8dd05d2..72e84e1 100644 --- a/babel.config.js +++ b/babel.config.js @@ -10,13 +10,12 @@ module.exports = { }] ], plugins: [ - // Taroify 组件按需导入配置 [ "import", { libraryName: "@taroify/core", libraryDirectory: "", - style: false, // 样式已在 app.ts 中全局导入 + style: true, }, "@taroify/core", ], @@ -26,7 +25,7 @@ module.exports = { libraryName: "@taroify/icons", libraryDirectory: "", camel2DashComponentName: false, - style: false, + style: () => "@taroify/icons/style", customName: (name) => name === "Icon" ? "@taroify/icons/van/VanIcon" : `@taroify/icons/${name}`, }, "@taroify/icons", diff --git a/package-lock.json b/package-lock.json index 0f15391..775cbf1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@babel/runtime": "^7.24.4", "@taroify/core": "^0.9.0", + "@taroify/hooks": "^0.9.0", "@taroify/icons": "^0.9.0", "@tarojs/components": "4.0.9", "@tarojs/helper": "4.0.9", diff --git a/package.json b/package.json index d9f02cc..12ba100 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "dependencies": { "@babel/runtime": "^7.24.4", "@taroify/core": "^0.9.0", + "@taroify/hooks": "^0.9.0", "@taroify/icons": "^0.9.0", "@tarojs/components": "4.0.9", "@tarojs/helper": "4.0.9", diff --git a/src/app.config.ts b/src/app.config.ts index 772474e..58d5929 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -7,6 +7,23 @@ export default defineAppConfig({ 'pages/user/index', 'pages/scanCode/index', // 独立扫码页面(无tabbar) ], + // 分包配置 + subpackages: [ + { + root: 'pageStore', + name: 'store-package', + pages: [ + 'mapStore/index', // 地图找店页面 + ] + } + ], + // 分包预下载规则 + preloadRule: { + 'pages/store/index': { + network: 'all', + packages: ['store-package'] + } + }, window: { backgroundTextStyle: 'light', navigationBarBackgroundColor: '#fff', diff --git a/src/app.scss b/src/app.scss index b7efbb9..3bafdae 100644 --- a/src/app.scss +++ b/src/app.scss @@ -64,3 +64,12 @@ page { color: #999; font-size: 28px; } + +/* 覆盖 taroify Popup 的 z-index,使其高于自定义 tabbar (z-index: 9999) */ +.taroify-popup { + z-index: 10001 !important; +} + +.taroify-backdrop { + z-index: 10000 !important; +} \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index b1735f9..3e1cf5e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -3,8 +3,6 @@ import { useLaunch } from '@tarojs/taro' import Taro from '@tarojs/taro' import { userStore } from './store' import './app.scss' -// 导入 taroify 全局样式 -import '@taroify/core/index.scss' function App({ children }: PropsWithChildren) { useLaunch(() => { diff --git a/src/assets/icon/locationIcon.png b/src/assets/icon/locationIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..f1956791f49097d3c686a4eac0403416991443f7 GIT binary patch literal 3304 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 m{}#SY@Bjb+21!IgR09B8X~qz3e{;?N0000& literal 0 HcmV?d00001 diff --git a/src/assets/icon/storeIcon.png b/src/assets/icon/storeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..6624e56236ca0efbe98c94589c64846060cf910c GIT binary patch literal 14307 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 R+ARP8002ovPDHLkV1j*dlhptK literal 0 HcmV?d00001 diff --git a/src/custom-tab-bar/index.scss b/src/custom-tab-bar/index.scss index 59e8a54..3e72670 100644 --- a/src/custom-tab-bar/index.scss +++ b/src/custom-tab-bar/index.scss @@ -12,7 +12,7 @@ right: 0; width: 100%; height: 100Px; /* 继续减小高度,给凸起留足空间 */ - z-index: 9999; + z-index: 99; pointer-events: none; // 背景白色层 #0E0D0D diff --git a/src/pageStore/mapStore/index.config.ts b/src/pageStore/mapStore/index.config.ts new file mode 100644 index 0000000..4c1648d --- /dev/null +++ b/src/pageStore/mapStore/index.config.ts @@ -0,0 +1,5 @@ +export default { + navigationBarTitleText: '地图找店', + navigationBarBackgroundColor: '#FFFFFF', + navigationBarTextStyle: 'black' +} diff --git a/src/pageStore/mapStore/index.scss b/src/pageStore/mapStore/index.scss new file mode 100644 index 0000000..b2fb8d0 --- /dev/null +++ b/src/pageStore/mapStore/index.scss @@ -0,0 +1,221 @@ +.map-store-page { + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + background: #F5F5F5; + position: relative; + + // 地图容器 + .map-container { + width: 100%; + height: 650px; + position: relative; + } + + // 重新定位按钮 + .relocate-btn { + position: absolute; + top: 550px; + right: 30px; + width: 80px; + height: 80px; + background: #FFFFFF; + border-radius: 50%; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + } + + // 底部内容区域 + .content-area { + flex: 1; + display: flex; + flex-direction: column; + background: #F2F3F5; + border-radius: 30px 30px 0 0; + margin-top: -30px; + padding: 30px 30px 0; + position: relative; + z-index: 5; + box-shadow: 0 -3px 14px 0 rgba(202, 203, 204, 0.5); + + // 筛选区域 + .filter-area { + // margin-bottom: 30px; + + .filter-left { + display: flex; + align-items: center; + gap: 20px; + + // 城市选择 + .city-select { + flex-shrink: 0; + display: flex; + align-items: center; + gap: 8px; + padding: 16px 24px; + background: #FFFFFF; + border-radius: 8px; + + .city-text { + font-weight: 400; + font-size: 29px; + color: #333333; + } + } + + // 搜索输入框 + .search-input-wrapper { + flex: 1; + display: flex; + align-items: center; + background: #FFFFFF; + border-radius: 8px; + padding: 16px 24px; + gap: 16px; + + .search-input { + flex: 1; + font-size: 29px; + color: #333333; + } + + .search-placeholder { + font-size: 29px; + color: #999999; + } + + .search-icon-btn { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + } + } + } + } + + // 列表头部 + .list-header { + display: flex; + justify-content: space-between; + align-items: center; + margin: 30px 0; + + .list-title { + font-size: 29px; + font-weight: 400; + color: #333333; + } + + .list-count { + font-size: 26px; + color: #999999; + } + } + + // 门店列表 + .store-list { + flex: 1; + margin: 0 -30px; + padding: 0 30px; + + .store-item { + padding: 30px; + background: #FFFFFF; + border-radius: 13px; + margin-bottom: 28px; + transition: all 0.3s; + + &.active { + background: #FFF7E6; + border: 2px solid #FF9900; + box-shadow: 0 4px 12px rgba(255, 153, 0, 0.2); + } + + // 头部:名称和距离 + .store-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 22px; + + .store-name { + flex: 1; + font-weight: 500; + font-size: 33px; + color: #000000; + margin-right: 20px; + } + + .store-distance { + flex-shrink: 0; + font-size: 25px; + color: #333333; + } + } + + // 地址 + .store-address { + margin-bottom: 22px; + + .address-text { + font-size: 25px; + color: #595959; + line-height: 1.5; + word-break: break-all; + } + } + + // 价格信息 + .store-price { + display: flex; + align-items: baseline; + gap: 30px; + + .price-item { + display: flex; + align-items: baseline; + + .price-label { + font-size: 25px; + color: #8B8B8B; + margin-right: 8px; + } + + .price-symbol { + font-size: 25px; + color: #333333; + } + + .price-value { + font-size: 25px; + font-weight: 500; + color: #333333; + } + + .price-unit { + font-size: 25px; + color: #333333; + } + } + } + } + + // 空状态 + .empty-state { + padding: 100px 0; + text-align: center; + + .empty-text { + font-size: 28px; + color: #999999; + } + } + } + } +} diff --git a/src/pageStore/mapStore/index.tsx b/src/pageStore/mapStore/index.tsx new file mode 100644 index 0000000..92ae062 --- /dev/null +++ b/src/pageStore/mapStore/index.tsx @@ -0,0 +1,478 @@ +/** + * 地图找店页面 + */ +import { View, Text, Map, ScrollView, Image, Input } from '@tarojs/components' +import Taro, { useLoad } from '@tarojs/taro' +import { observer } from 'mobx-react' +import { useState, useRef, useEffect } from 'react' +import { Search, Arrow, Location } from '@taroify/icons' +import './index.scss' + +// 模拟门店数据(带经纬度) +const mockStoreData = [ + { + id: '1', + name: '北京黑八大师联盟球厅店', + address: '北京市XXX区XXX街道XXX路19号606', + latitude: 39.910823, + longitude: 116.400470, + price: 16.00, + billiardCount: 6, + billiardEmpty: 6, + chessCount: 2, + chessEmpty: 2, + type: '直营店', + phone: '010-12345678', + distance: 0, + distanceText: '0.05km' + }, + { + id: '2', + name: '北京晶彩桌球世界店', + address: '北京市XXX区XXX街道XXX路XXXXXX大厦101', + latitude: 39.905823, + longitude: 116.395470, + price: 24.00, + billiardCount: 8, + billiardEmpty: 8, + chessCount: 1, + chessEmpty: 1, + type: '加盟店', + phone: '010-87654321', + distance: 0, + distanceText: '0.1km' + }, + { + id: '3', + name: '北京飓风台球店', + address: '北京市XXX区XXX街道106号A01', + latitude: 39.915823, + longitude: 116.405470, + price: 106.00, + billiardCount: 10, + billiardEmpty: 10, + chessCount: 0, + chessEmpty: 0, + type: '加盟店', + phone: '010-11223344', + distance: 0, + distanceText: '1.3km' + }, + { + id: '4', + name: '北京星耀台球俱乐部', + address: '北京市XXX区XXX街道XXX路99号', + latitude: 39.900823, + longitude: 116.390470, + price: 30.00, + billiardCount: 12, + billiardEmpty: 10, + chessCount: 3, + chessEmpty: 2, + type: '直营店', + phone: '010-99887766', + distance: 0, + distanceText: '2.3km' + } +] + +interface Store { + id: string + name: string + address: string + latitude: number + longitude: number + price: number + billiardCount: number + billiardEmpty: number + chessCount: number + chessEmpty: number + type: string + phone: string + distance: number + distanceText: string +} + +interface Marker { + id: number + latitude: number + longitude: number + iconPath: string + width: number + height: number + callout?: any + label?: any +} + +const MapStorePage = observer(() => { + // 用户位置(默认北京天安门) + const [userLocation, setUserLocation] = useState({ + latitude: 39.908823, + longitude: 116.397470 + }) + + // 地图中心点(默认跟随用户位置) + const [mapCenter, setMapCenter] = useState({ + latitude: 39.908823, + longitude: 116.397470 + }) + + const [storeList, setStoreList] = useState([]) + const [markers, setMarkers] = useState([]) + const [activeStoreId, setActiveStoreId] = useState(null) + const [searchValue, setSearchValue] = useState('') + const [selectedCity, setSelectedCity] = useState('选城市') + + const mapContext = useRef(null) + + useLoad(() => { + // 页面加载时获取用户位置 + requestLocationPermission() + }) + + useEffect(() => { + // 初始化地图上下文 + mapContext.current = Taro.createMapContext('storeMap') + }, []) + + // 请求位置权限并获取位置 + const requestLocationPermission = async () => { + try { + // 检查权限 + const setting = await Taro.getSetting() + + if (!setting.authSetting['scope.userLocation']) { + // 请求授权 + await Taro.authorize({ scope: 'scope.userLocation' }) + } + + // 获取位置 + Taro.showLoading({ title: '定位中...' }) + + const location = await Taro.getLocation({ + type: 'gcj02', // 返回国测局坐标,适用于微信小程序地图 + isHighAccuracy: true, + altitude: false + }) + + Taro.hideLoading() + + const userPos = { + latitude: location.latitude, + longitude: location.longitude + } + + setUserLocation(userPos) + setMapCenter(userPos) + + // 获取附近门店(使用模拟数据) + fetchNearbyStores(userPos.latitude, userPos.longitude) + + } catch (error) { + Taro.hideLoading() + console.error('获取位置失败:', error) + + // 使用默认位置并加载门店 + fetchNearbyStores(userLocation.latitude, userLocation.longitude) + + Taro.showModal({ + title: '定位提示', + content: '未能获取您的位置,将使用默认位置展示门店', + showCancel: false + }) + } + } + + // 获取附近门店(模拟接口) + const fetchNearbyStores = async (lat: number, lng: number) => { + try { + Taro.showLoading({ title: '加载中...' }) + + // TODO: 替换为真实接口 + // const res = await Taro.request({ + // url: 'https://your-api.com/api/stores/nearby', + // method: 'GET', + // data: { + // latitude: lat, + // longitude: lng, + // radius: 10000, + // limit: 50 + // } + // }) + + // 模拟网络延迟 + await new Promise(resolve => setTimeout(resolve, 500)) + + // 使用模拟数据并计算距离 + const storesWithDistance = mockStoreData.map(store => ({ + ...store, + distance: calculateDistance(lat, lng, store.latitude, store.longitude), + distanceText: formatDistance( + calculateDistance(lat, lng, store.latitude, store.longitude) + ) + })) + + // 按距离排序 + storesWithDistance.sort((a, b) => a.distance - b.distance) + + setStoreList(storesWithDistance) + + // 生成地图标记 + generateMarkers(storesWithDistance) + + Taro.hideLoading() + + } catch (error) { + Taro.hideLoading() + console.error('获取门店失败:', error) + Taro.showToast({ + title: '获取门店失败', + icon: 'none' + }) + } + } + + // 计算两点之间的距离(米)- Haversine 公式 + const calculateDistance = ( + lat1: number, + lng1: number, + lat2: number, + lng2: number + ): number => { + const R = 6371e3 // 地球半径(米) + const φ1 = (lat1 * Math.PI) / 180 + const φ2 = (lat2 * Math.PI) / 180 + const Δφ = ((lat2 - lat1) * Math.PI) / 180 + const Δλ = ((lng2 - lng1) * Math.PI) / 180 + + const a = + Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2) + + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) + + return R * c // 返回米 + } + + // 格式化距离显示 + const formatDistance = (distance: number): string => { + if (distance < 1000) { + return `${distance.toFixed(0)}m` + } else { + return `${(distance / 1000).toFixed(2)}km` + } + } + + // 生成地图标记 + const generateMarkers = (stores: Store[]) => { + // 使用默认标记图标(微信小程序会提供默认图标) + // 如果需要自定义图标,准备好图片后替换 iconPath + const newMarkers: Marker[] = stores.map((store, index) => ({ + id: index, + latitude: store.latitude, + longitude: store.longitude, + iconPath: '', // 空字符串使用默认图标,或指定自定义图标路径 + width: 30, + height: 30, + callout: { + content: store.name, + color: '#333333', + fontSize: 12, + borderRadius: 8, + bgColor: '#FFFFFF', + padding: 8, + display: 'BYCLICK' // 点击标记时显示 + } + })) + + setMarkers(newMarkers) + } + + // 点击地图标记 + const handleMarkerTap = (e: any) => { + const markerIndex = e.detail.markerId + const store = storeList[markerIndex] + + if (store) { + setActiveStoreId(store.id) + setMapCenter({ + latitude: store.latitude, + longitude: store.longitude + }) + } + } + + // 点击列表项 + const handleStoreItemClick = (store: Store) => { + setActiveStoreId(store.id) + + // 移动地图到对应位置 + setMapCenter({ + latitude: store.latitude, + longitude: store.longitude + }) + + // 使用 moveToLocation 移动地图(需要 mapContext) + if (mapContext.current) { + mapContext.current.moveToLocation({ + latitude: store.latitude, + longitude: store.longitude + }) + } + } + + // 重新定位 + const handleRelocate = () => { + requestLocationPermission() + } + + // 导航到门店 + const handleNavigate = (store: Store, e: any) => { + e.stopPropagation() + + Taro.openLocation({ + latitude: store.latitude, + longitude: store.longitude, + name: store.name, + address: store.address, + scale: 18 + }) + } + + // 搜索门店 + const handleSearch = () => { + if (!searchValue.trim()) { + Taro.showToast({ + title: '请输入门店名称或地址', + icon: 'none' + }) + return + } + + // TODO: 调用搜索接口 + const filtered = mockStoreData.filter( + store => + store.name.includes(searchValue) || store.address.includes(searchValue) + ) + + if (filtered.length > 0) { + setStoreList(filtered) + generateMarkers(filtered) + + // 移动到第一个搜索结果 + setMapCenter({ + latitude: filtered[0].latitude, + longitude: filtered[0].longitude + }) + } else { + Taro.showToast({ + title: '未找到相关门店', + icon: 'none' + }) + } + } + + return ( + + {/* 地图区域 */} + {}} + /> + + {/* 重新定位按钮 */} + + + + + {/* 底部内容区域 */} + + {/* 筛选区域 */} + + + {/* 城市选择 */} + + {selectedCity} + + + + {/* 搜索输入框 */} + + setSearchValue(e.detail.value)} + /> + + + + + + + + {/* 门店列表 */} + + 附近门店 + 共 {storeList.length} 家 + + + + {storeList.map((store) => ( + handleStoreItemClick(store)} + > + {/* 头部:名称和距离 */} + + {store.name} + 距离{store.distanceText} + + + {/* 地址 */} + + {store.address} + + + {/* 价格信息 */} + + + 台球 + ¥ + {store.price.toFixed(2)} + + + + 棋牌 + ¥ + {(store.price + 4).toFixed(2)} + + + + + ))} + + {storeList.length === 0 && ( + + 暂无门店数据 + + )} + + + + ) +}) + +export default MapStorePage diff --git a/src/pages/store/index.scss b/src/pages/store/index.scss index 952373c..915e1a5 100644 --- a/src/pages/store/index.scss +++ b/src/pages/store/index.scss @@ -1,19 +1,299 @@ +/** + * 门店列表页样式 + * 设计稿宽度: 750px + */ + .store-page { - min-height: 100vh; + // 高度为 100vh 减去 tabbar 高度 + height: calc(100vh - 40Px); + height: calc(100vh - 40Px - constant(safe-area-inset-bottom)); + height: calc(100vh - 40Px - env(safe-area-inset-bottom)); background-color: #121212; + position: relative; + overflow-x: hidden; + overflow-y: auto; + box-sizing: border-box; +} - .header { - padding: 32px; - background: #fff; - - .title { - font-size: 36px; - font-weight: bold; - color: #333; - } +/* 内容区域 */ +.content-area { + padding-top: 175px; + padding-left: 30px; + padding-right: 30px; +} + +/* 筛选区域 */ +.filter-area { + height: 84px; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + +.filter-left { + flex: 1; + display: flex; + align-items: center; + background-color: #21212A; + border-radius: 10px; + height: 100%; + padding: 0 20px; +} + +/* 城市选择 */ +.city-select { + display: flex; + align-items: center; + flex-shrink: 0; + padding-right: 20px; + border-right: 1px solid #333; + margin-right: 20px; + + .city-text { + font-weight: 400; + font-size: 29px; + color: #FFFFFF; + margin-right: 8px; + } +} + +/* 搜索输入框包装器 */ +.search-input-wrapper { + flex: 1; + display: flex; + align-items: center; + height: 100%; + position: relative; +} + +/* 搜索输入框 */ +.search-input { + flex: 1; + height: 100%; + font-size: 29px; + color: #FFFFFF; + background: transparent; +} + +.search-placeholder { + font-size: 29px; + color: #999999; +} + +/* 输入框右侧图标按钮(搜索/清除) */ +.input-icon-btn { + display: flex; + align-items: center; + justify-content: center; + width: 50px; + height: 50px; + flex-shrink: 0; +} + +/* 找店按钮 */ +.find-store-btn { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-left: 30px; + flex-shrink: 0; + + .store-icon { + width: 50px; + height: 50px; + margin-bottom: 6px; + } + + .find-text { + font-weight: 400; + font-size: 21px; + color: #E5E5E5; + } +} + +/* 门店列表 */ +.store-list { + margin-top: 30px; +} + +/* 门店项 */ +.store-item { + background-color: #21212A; + border-radius: 13px; + padding: 28px; + margin-bottom: 28px; +} + +/* 门店头部 - 名称和价格 */ +.store-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 24px; +} + +.store-name { + font-weight: 500; + font-size: 33px; + color: #FFFFFF; + flex: 1; + margin-right: 20px; +} + +.store-price { + display: flex; + align-items: baseline; + flex-shrink: 0; + + .price-symbol { + font-size: 25px; + color: #01CA68; + } + + .price-value { + font-size: 33px; + color: #01CA68; + font-weight: 500; + } + + .price-unit { + font-size: 25px; + color: #01CA68; + } +} + +/* 标签区域 */ +.store-tags { + display: flex; + flex-wrap: wrap; + gap: 16px; + margin-bottom: 24px; +} + +.tag { + padding: 8px 16px; + border-radius: 6px; + font-size: 23px; + border-width: 1px; + border-style: solid; +} + +.tag-billiard { + color: #01CA68; + border-color: #01CA68; + background: transparent; +} + +.tag-chess { + color: #FF9900; + border-color: #FF9900; + background: transparent; +} + +.tag-type { + color: #E5E5E5; + border-color: #E5E5E5; + background: transparent; +} + +/* 地址和距离 */ +.store-location { + display: flex; + justify-content: space-between; + align-items: flex-start; +} + +.location-left { + display: flex; + align-items: flex-start; + max-width: 389px; +} + +.location-icon { + width: 28px; + height: 28px; + flex-shrink: 0; + margin-right: 8px; + margin-top: 4px; +} + +.address-text { + font-size: 25px; + color: #E5E5E5; + line-height: 1.4; + word-break: break-all; +} + +.distance-text { + font-size: 25px; + color: #E5E5E5; + flex-shrink: 0; + margin-left: 20px; +} + +/* 列表底部 */ +.list-footer { + text-align: center; + padding: 40px 0; + + .footer-text { + font-size: 26px; + color: #666; } +} + +/* 城市选择弹窗 */ +.city-picker { + background: #fff; + border-radius: 20px 20px 0 0; +} + +.picker-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 30px; + border-bottom: 1px solid #eee; +} + +.picker-cancel { + font-size: 30px; + color: #666; +} + +.picker-title { + font-size: 32px; + font-weight: 500; + color: #333; +} + +.picker-confirm { + font-size: 30px; + color: #01CA68; +} + +/* Cascader 选项列表 */ +.cascader-options { + height: 600px; + background: #fff; +} - .content { - padding: 32px; +.cascader-option { + padding: 30px; + border-bottom: 1px solid #f5f5f5; + + &.active { + .option-text { + color: #01CA68; + font-weight: 500; + } } } + +.option-text { + font-size: 28px; + color: #333; +} + diff --git a/src/pages/store/index.tsx b/src/pages/store/index.tsx index 74fc17a..39706fc 100644 --- a/src/pages/store/index.tsx +++ b/src/pages/store/index.tsx @@ -1,26 +1,342 @@ /** * 门店列表页 */ -import { View, Text } from '@tarojs/components' -import { useLoad } from '@tarojs/taro' +import { View, Text, Image, Input, ScrollView } from '@tarojs/components' +import Taro, { useLoad } from '@tarojs/taro' import { observer } from 'mobx-react' +import { useState } from 'react' +import { Popup, Toast, Tabs } from '@taroify/core' +import { useCascader } from '@taroify/hooks' +import { Arrow, Cross, Search } from '@taroify/icons' +import storeIcon from '../../assets/icon/storeIcon.png' +import locationIcon from '../../assets/icon/locationIcon.png' import './index.scss' +// 城市数据 - useCascader 格式(嵌套 children) +const cityOptions = [ + { + label: '天津市', + value: 'tianjin', + children: [{ label: '天津市', value: 'tianjin_city' }], + }, + { + label: '河北省', + value: 'hebei', + children: [ + { label: '赤峰市', value: 'chifeng' }, + { label: '通辽市', value: 'tongliao' }, + ], + }, + { + label: '山西省', + value: 'shanxi', + children: [{ label: '鄂尔多斯市', value: 'eerduosi' }], + }, + { + label: '内蒙古自治区', + value: 'neimenggu', + children: [ + { label: '呼伦贝尔市', value: 'hulunbeier' }, + { label: '巴彦淖尔市', value: 'bayannaoer' }, + { label: '乌兰察布市', value: 'wulanchabu' }, + { label: '锡林郭勒盟', value: 'xilingol' }, + ], + }, + { + label: '辽宁省', + value: 'liaoning', + children: [{ label: '沈阳市', value: 'shenyang' }], + }, + { + label: '吉林省', + value: 'jilin', + children: [{ label: '长春市', value: 'changchun' }], + }, + { + label: '黑龙江省', + value: 'heilongjiang', + children: [{ label: '哈尔滨市', value: 'haerbin' }], + }, +] + +// 模拟门店数据 +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 [selectedCity, setSelectedCity] = useState('选城市') + const [searchValue, setSearchValue] = useState('') + const [cityPopupOpen, setCityPopupOpen] = useState(false) + const [storeList, setStoreList] = useState(mockStoreList) + const [loading, setLoading] = useState(false) + const [isSearched, setIsSearched] = useState(false) // 是否已执行搜索 + const [cityValue, setCityValue] = useState([]) + const [tabIndex, setTabIndex] = useState(0) + + // 使用 useCascader hook + const { columns } = useCascader({ + value: cityValue, + depth: 2, + options: cityOptions, + }) + useLoad(() => { console.log('门店页面加载') }) + // 打开城市选择 + const handleOpenCityPicker = () => { + setCityPopupOpen(true) + } + + // 关闭城市选择 + const handleCloseCityPicker = () => { + setCityPopupOpen(false) + } + + // 选择选项 + const handleSelectOption = (option: any, columnIndex: number) => { + const newValue = [...cityValue] + newValue[columnIndex] = option.value + // 清除后面的选中值 + newValue.splice(columnIndex + 1) + setCityValue(newValue) + + // 如果选择了最后一级(城市),关闭弹窗 + if (columnIndex === 1 || !option.children || option.children.length === 0) { + setSelectedCity(option.label) + setCityPopupOpen(false) + setTabIndex(0) + } else { + // 切换到下一个 tab + setTabIndex(columnIndex + 1) + } + } + + // 搜索门店 + const handleSearch = () => { + // 无内容时提示输入 + if (!searchValue.trim()) { + Toast.open('请输入门店名称或地址') + return + } + + setLoading(true) + Toast.loading({ + 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) + } + + // 输入框变化 + const handleInputChange = (e: { detail: { value: string } }) => { + setSearchValue(e.detail.value) + } + + // 清除搜索并恢复默认数据 + const handleClearSearch = () => { + setSearchValue('') + setIsSearched(false) // 切换回搜索图标 + + // 恢复默认数据 + setLoading(true) + Toast.loading({ + message: '加载中...', + duration: 0, + }) + + setTimeout(() => { + setLoading(false) + Toast.close() + setStoreList(mockStoreList) + }, 500) + } + + // 跳转到地图找店页面(分包页面) + const handleGoToMap = () => { + Taro.navigateTo({ + url: '/pageStore/mapStore/index' + }) + } + return ( - - 附近门店 - - - - 门店列表功能开发中... + {/* 内容区域 */} + + {/* 筛选区域 */} + + + {/* 城市选择 */} + + {selectedCity} + + + {/* 搜索输入框 */} + + + {/* 已搜索时显示取消图标,未搜索时显示搜索图标 */} + {isSearched ? ( + + + + ) : ( + + + + )} + + + {/* 找店按钮 */} + + + 找店 + + + + {/* 门店列表 */} + + {storeList.map((store) => ( + + {/* 标题和价格 */} + + {store.name} + + ¥ + {store.price.toFixed(2)} + 起/小时 + + + + {/* 标签 */} + + + 台球 {store.billiardCount} 桌空闲 + + + 棋牌 {store.chessCount} 桌空闲 + + + {store.type} + + + + {/* 地址和距离 */} + + + + {store.address} + + 距离{store.distance} {'>'} + + + ))} + + {/* 列表底部提示 */} + + 到底了~ + + + {/* 城市选择弹窗 - 使用 useCascader */} + + + {/* 头部 */} + + 取消 + 城市选择 + 确定 + + + {/* Tabs 切换 */} + + {columns.map((column, columnIndex) => ( + opt.value === cityValue[columnIndex])?.label || '请选择' + : '请选择' + } + > + + {column.map((option) => ( + handleSelectOption(option, columnIndex)} + > + {option.label} + + ))} + + + ))} + + + + + {/* Toast 组件 */} + ) })