微信支付

This commit is contained in:
2026-07-02 17:23:13 +08:00
parent 4b2589156c
commit a0f4d8c18f
12 changed files with 320 additions and 98 deletions
+52 -13
View File
@@ -11,6 +11,12 @@ import {
type RegionSelection,
} from '../lib/region-data';
type OpenCity = {
code: string;
name: string;
province: string;
};
type StoreItem = {
id: string;
name: string;
@@ -25,6 +31,11 @@ type StoreItem = {
category?: { name: string } | null;
};
function resolveCityCode(region: RegionSelection, cities: OpenCity[]): string | undefined {
if (region.province === REGION_ALL || region.city === REGION_ALL) return undefined;
return cities.find((c) => c.province === region.province && c.name === region.city)?.code;
}
const CATEGORY_TABS = ['全部', '火锅', '地方菜', '高端餐饮', '烧烤烤肉', '西餐'] as const;
const MOCK_DISTANCES = ['800m', '1.2km', '3.5km', '1.5km', '2.0km'];
@@ -43,29 +54,56 @@ function formatHours(store: StoreItem) {
export default function StoreListPage() {
const navigate = useNavigate();
const [cities, setCities] = useState<OpenCity[]>([]);
const [stores, setStores] = useState<StoreItem[]>([]);
const [loading, setLoading] = useState(false);
const [categoryTab, setCategoryTab] = useState<string>('全部');
const [keyword, setKeyword] = useState('');
const [region, setRegion] = useState<RegionSelection>(DEFAULT_REGION);
const [regionPickerOpen, setRegionPickerOpen] = useState(false);
const cityCode = useMemo(() => resolveCityCode(region, cities), [region, cities]);
useEffect(() => {
request<StoreItem[]>('USER_H5', '/stores?cityCode=410100').then(setStores);
request<OpenCity[]>('USER_H5', '/catalog/cities').then(setCities);
}, []);
useEffect(() => {
let cancelled = false;
setLoading(true);
const qs = cityCode ? `?cityCode=${encodeURIComponent(cityCode)}` : '';
request<StoreItem[]>('USER_H5', `/stores${qs}`)
.then((data) => {
if (!cancelled) setStores(data);
})
.catch(() => {
if (!cancelled) setStores([]);
})
.finally(() => {
if (!cancelled) setLoading(false);
});
return () => {
cancelled = true;
};
}, [cityCode]);
const filtered = useMemo(() => {
let list = stores;
if (categoryTab !== '全部') {
list = list.filter((s) => s.category?.name === categoryTab);
}
list = list.filter((s) => {
const province = s.province ?? '河南省';
const city = s.cityName ?? '郑州市';
if (region.province !== REGION_ALL && province !== region.province) return false;
if (region.city !== REGION_ALL && city !== region.city) return false;
if (region.district !== REGION_ALL && s.district !== region.district) return false;
return true;
});
if (!cityCode) {
list = list.filter((s) => {
const province = s.province ?? '河南省';
const city = s.cityName ?? '郑州市';
if (region.province !== REGION_ALL && province !== region.province) return false;
if (region.city !== REGION_ALL && city !== region.city) return false;
if (region.district !== REGION_ALL && s.district !== region.district) return false;
return true;
});
} else if (region.district !== REGION_ALL) {
list = list.filter((s) => s.district === region.district);
}
const q = keyword.trim().toLowerCase();
if (q) {
list = list.filter(
@@ -76,7 +114,7 @@ export default function StoreListPage() {
);
}
return list;
}, [stores, categoryTab, keyword, region]);
}, [stores, categoryTab, keyword, region, cityCode]);
const regionLabel = formatRegion(region.province, region.city, region.district);
@@ -123,7 +161,8 @@ export default function StoreListPage() {
</header>
<main className="store-list">
{filtered.map((s, index) => (
{loading && <div className="store-empty">...</div>}
{!loading && filtered.map((s, index) => (
<article
key={s.id}
className="store-card"
@@ -170,11 +209,11 @@ export default function StoreListPage() {
</article>
))}
{filtered.length === 0 && (
{!loading && filtered.length === 0 && (
<div className="store-empty">{stores.length === 0 ? '暂无门店' : '未找到匹配门店'}</div>
)}
{filtered.length > 0 && (
{!loading && filtered.length > 0 && (
<p className="store-list-end"></p>
)}
</main>