import { useEffect, useMemo, useState } from 'react'; import { View, Text, Image } from '@tarojs/components'; import Taro, { usePageScroll, useRouter, useShareAppMessage, useShareTimeline } from '@tarojs/taro'; import PageShell from '../../components/PageShell'; import PageNavBar from '../../components/PageNavBar'; import ProductCarousel from '../../components/ProductCarousel'; import ShareNavButton from '../../components/ShareNavButton'; import WechatShareReady from '../../components/WechatShareReady'; import { request, toast } from '../../lib/api'; import { DEFAULT_SHARE_DESC, DEFAULT_SHARE_TITLE, toWeappShareMessage, } from '../../lib/wechat-share'; type StoreMedia = { url?: string | null; bizType?: string | null; mediaType?: string | null; }; type Store = { id: string; name: string; address?: string; province?: string; cityName?: string; city?: string; district?: string; phone?: string; intro?: string | null; benefitUsageRule?: string | null; coverUrl?: string | null; carouselUrls?: string[] | null; media?: StoreMedia[] | null; openTime?: string | null; closeTime?: string | null; openTime2?: string | null; closeTime2?: string | null; avgPrice?: number | null; latitude?: number | string | null; longitude?: number | string | null; category?: { name: string } | null; }; function uniqueUrls(urls: Array) { const seen = new Set(); const out: string[] = []; for (const raw of urls) { const url = String(raw || '').trim(); if (!url || seen.has(url)) continue; seen.add(url); out.push(url); } return out; } function envPhotoUrls(store: Store) { return uniqueUrls( (store.media || []) .filter((m) => !m.bizType || m.bizType === 'ENV') .map((m) => m.url), ); } function fullAddress(store: Store) { const city = store.cityName || store.city || ''; return `${store.province || ''}${city}${store.district || ''}${store.address || ''}`.trim(); } export default function StoreDetailPage() { const router = useRouter(); const storeId = router.params.id ?? ''; const [store, setStore] = useState(null); const [headerSolid, setHeaderSolid] = useState(false); usePageScroll(({ scrollTop }) => { setHeaderSolid(scrollTop > 100); }); useEffect(() => { if (!storeId) return; request(`/stores/${storeId}`) .then(setStore) .catch(() => { request('/stores') .then((list) => { const found = (Array.isArray(list) ? list : []).find((s) => s.id === storeId); if (found) setStore(found); else toast('门店不存在'); }) .catch((e) => toast(e instanceof Error ? e.message : '加载失败')); }); }, [storeId]); const sharePayload = useMemo( () => { const envFirst = store ? envPhotoUrls(store)[0] : undefined; return { title: store?.name || DEFAULT_SHARE_TITLE, desc: store?.intro?.trim() || store?.address || DEFAULT_SHARE_DESC, path: `/pages/store-detail/index?id=${storeId}`, imgUrl: store?.coverUrl || envFirst || store?.carouselUrls?.[0] || undefined, }; }, [store, storeId], ); useShareAppMessage(() => toWeappShareMessage(sharePayload)); useShareTimeline(() => ({ title: sharePayload.title || DEFAULT_SHARE_TITLE, query: storeId ? `id=${storeId}` : '', imageUrl: sharePayload.imgUrl, })); function goBack() { const pages = Taro.getCurrentPages(); if (pages.length > 1) Taro.navigateBack(); else Taro.switchTab({ url: '/pages/stores/index' }); } function callStore() { if (!store?.phone) { toast('暂无门店电话'); return; } Taro.makePhoneCall({ phoneNumber: store.phone }).catch(() => toast('无法拨打电话')); } function openMap() { if (!store) return; const lat = store.latitude != null ? Number(store.latitude) : NaN; const lng = store.longitude != null ? Number(store.longitude) : NaN; const address = fullAddress(store) || store.address || store.name; if (Number.isFinite(lat) && Number.isFinite(lng)) { Taro.openLocation({ latitude: lat, longitude: lng, name: store.name, address, scale: 16, }).catch(() => { if (process.env.TARO_ENV === 'h5' && typeof window !== 'undefined') { window.location.href = `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(store.name)}&address=${encodeURIComponent(address)}`; return; } toast('无法打开地图导航'); }); return; } if (process.env.TARO_ENV === 'h5' && typeof window !== 'undefined' && address) { window.location.href = `https://uri.amap.com/search?keyword=${encodeURIComponent(address)}&src=dukang`; return; } toast('门店位置待完善,暂无法导航'); } if (!store) { return ( 加载中… ); } const envPhotos = envPhotoUrls(store); const images = uniqueUrls([ store.coverUrl, ...(store.carouselUrls || []), ...envPhotos, ]); const intro = store.intro?.trim() || ''; const benefitRule = store.benefitUsageRule?.trim() || ''; function previewEnv(index: number) { if (!envPhotos.length) return; Taro.previewImage({ current: envPhotos[index], urls: envPhotos, }).catch(() => toast('无法预览图片')); } return ( } /> {store.name} {store.district ? `${store.district} · ` : ''} {store.address || '地址待完善'} 导航 营业时间:{' '} {(() => { const parts: string[] = []; if (store.openTime && store.closeTime) parts.push(`${store.openTime}-${store.closeTime}`); if (store.openTime2 && store.closeTime2) parts.push(`${store.openTime2}-${store.closeTime2}`); return parts.length ? parts.join(',') : '10:00-22:00'; })()} {store.avgPrice != null && Number(store.avgPrice) > 0 ? ( 人均约 ¥{Number(store.avgPrice).toFixed(0)} ) : null} {store.phone ? ( 电话: {store.phone} 拨打 ) : null} {store.category?.name ? ( {store.category.name} ) : null} 可核销 好客门店 {intro ? ( 门店详情 {intro} ) : null} {benefitRule ? ( 好客权益券使用规则 {benefitRule} ) : null} {envPhotos.length > 0 ? ( 店内环境 {envPhotos.map((url, index) => ( previewEnv(index)} > ))} ) : null} Taro.navigateTo({ url: '/pages/redeem/index' })} > 到店核销 ); }