登录页面

This commit is contained in:
2026-07-12 15:17:54 +08:00
parent becf91da52
commit bfac6c6663
63 changed files with 4662 additions and 431 deletions
+95 -18
View File
@@ -1,7 +1,9 @@
import { useEffect, useState } from 'react';
import { View, Text } from '@tarojs/components';
import { useDidShow } from '@tarojs/taro';
import { View, Text, Image, Input } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
import RegionPicker from '../../components/RegionPicker';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import { request, toast } from '../../lib/api';
@@ -9,12 +11,23 @@ type Store = {
id: string;
name: string;
address?: string;
district?: string;
coverUrl?: string | null;
openTime?: string | null;
closeTime?: string | null;
status?: string;
};
const CATEGORY_TABS = ['全部', '火锅', '地方菜', '高端餐饮', '烧烤烤肉', '西餐'] as const;
const MOCK_DISTANCES = ['800m', '1.2km', '3.5km', '1.5km', '2.0km'];
export default function StoresPage() {
const [stores, setStores] = useState<Store[]>([]);
const [loading, setLoading] = useState(true);
const [categoryTab, setCategoryTab] = useState<string>('全部');
const [keyword, setKeyword] = useState('');
const [regionLabel, setRegionLabel] = useState('郑州市 · 全部区域');
const [regionOpen, setRegionOpen] = useState(false);
useDidShow(() => {
syncTabBarSelected(1);
@@ -27,29 +40,93 @@ export default function StoresPage() {
.finally(() => setLoading(false));
}, []);
const filtered = stores.filter((s) => {
if (!keyword.trim()) return true;
const q = keyword.trim();
return s.name.includes(q) || (s.address ?? '').includes(q) || (s.district ?? '').includes(q);
});
function formatHours(store: Store) {
if (store.openTime && store.closeTime) {
return `营业时间: ${store.openTime}-${store.closeTime}`;
}
return '营业时间: 10:00-22:00';
}
return (
<View className="u-page u-page--tab">
<PageShell variant="tab" className="store-page">
<TabMainHeader title="门店" />
<View className="u-card">
{loading ? (
<View className="u-empty"></View>
) : stores.length === 0 ? (
<View className="u-empty"></View>
) : (
stores.map((s) => (
<View key={s.id} className="u-store-row">
<View className="u-store-avatar" />
<View style={{ flex: 1, minWidth: 0 }}>
<Text className="u-store-name">{s.name}</Text>
<Text className="u-muted" style={{ display: 'block', marginTop: '4px' }}>
<View className="store-toolbar">
<View className="store-location" onClick={() => setRegionOpen(true)}>
<View className="store-location-pin" />
<Text>{regionLabel} </Text>
</View>
<Input
className="store-search"
placeholder="搜索门店名称或地址"
value={keyword}
onInput={(e) => setKeyword(e.detail.value)}
/>
</View>
<View className="store-category-tabs">
{CATEGORY_TABS.map((tab) => (
<Text
key={tab}
className={`store-category-tab${categoryTab === tab ? ' store-category-tab--active' : ''}`}
onClick={() => setCategoryTab(tab)}
>
{tab}
</Text>
))}
</View>
<View className="store-list">
{loading ? <View className="u-empty"></View> : null}
{!loading && filtered.length === 0 ? <View className="u-empty"></View> : null}
{!loading &&
filtered.map((s, index) => (
<View
key={s.id}
className="store-card"
onClick={() => Taro.navigateTo({ url: `/pages/store-detail/index?id=${s.id}` })}
>
{s.coverUrl ? (
<Image className="store-card-cover" src={s.coverUrl} mode="aspectFill" />
) : (
<View className="store-card-cover--empty" />
)}
<View className="store-card-body">
<Text className="store-card-name">{s.name}</Text>
<Text className="store-card-meta">
{s.district ? `${s.district} · ` : ''}
{s.address || '地址待完善'}
</Text>
<Text className="store-card-meta">{formatHours(s)}</Text>
<View className="store-card-footer">
<Text className="store-card-distance">{MOCK_DISTANCES[index % MOCK_DISTANCES.length]}</Text>
<Text
className="store-card-cta"
onClick={(e) => {
e.stopPropagation();
Taro.navigateTo({ url: '/pages/redeem/index' });
}}
>
</Text>
</View>
</View>
</View>
))
)}
))}
</View>
{shouldRenderPageTabBar() ? <UserTabBar selected={1} /> : null}
</View>
<RegionPicker
open={regionOpen}
valueLabel="郑州市"
onClose={() => setRegionOpen(false)}
onConfirm={(label) => setRegionLabel(`${label} · 全部区域`)}
/>
</PageShell>
);
}