feat(admin,partner): Tencent map location picker and expose LBS key
Store create/edit on HQ and partner can pick coords via Tencent locpicker; client-config exposes TENCENT_LBS_KEY; seed empty system settings from env. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
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';
|
||||
@@ -13,6 +13,12 @@ import {
|
||||
toWeappShareMessage,
|
||||
} from '../../lib/wechat-share';
|
||||
|
||||
type StoreMedia = {
|
||||
url?: string | null;
|
||||
bizType?: string | null;
|
||||
mediaType?: string | null;
|
||||
};
|
||||
|
||||
type Store = {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -25,6 +31,7 @@ type Store = {
|
||||
intro?: string | null;
|
||||
coverUrl?: string | null;
|
||||
carouselUrls?: string[] | null;
|
||||
media?: StoreMedia[] | null;
|
||||
openTime?: string | null;
|
||||
closeTime?: string | null;
|
||||
openTime2?: string | null;
|
||||
@@ -35,6 +42,26 @@ type Store = {
|
||||
category?: { name: string } | null;
|
||||
};
|
||||
|
||||
function uniqueUrls(urls: Array<string | null | undefined>) {
|
||||
const seen = new Set<string>();
|
||||
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();
|
||||
@@ -66,12 +93,15 @@ export default function StoreDetailPage() {
|
||||
}, [storeId]);
|
||||
|
||||
const sharePayload = useMemo(
|
||||
() => ({
|
||||
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 || store?.carouselUrls?.[0] || undefined,
|
||||
}),
|
||||
() => {
|
||||
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],
|
||||
);
|
||||
|
||||
@@ -135,15 +165,23 @@ export default function StoreDetailPage() {
|
||||
);
|
||||
}
|
||||
|
||||
const images =
|
||||
(store.carouselUrls && store.carouselUrls.length > 0
|
||||
? store.carouselUrls
|
||||
: store.coverUrl
|
||||
? [store.coverUrl]
|
||||
: []) as string[];
|
||||
const envPhotos = envPhotoUrls(store);
|
||||
const images = uniqueUrls([
|
||||
store.coverUrl,
|
||||
...(store.carouselUrls || []),
|
||||
...envPhotos,
|
||||
]);
|
||||
|
||||
const intro = store.intro?.trim() || '';
|
||||
|
||||
function previewEnv(index: number) {
|
||||
if (!envPhotos.length) return;
|
||||
Taro.previewImage({
|
||||
current: envPhotos[index],
|
||||
urls: envPhotos,
|
||||
}).catch(() => toast('无法预览图片'));
|
||||
}
|
||||
|
||||
return (
|
||||
<PageShell variant="scroll" className="store-detail-page" hasFixedFooter>
|
||||
<WechatShareReady payload={sharePayload} />
|
||||
@@ -210,6 +248,23 @@ export default function StoreDetailPage() {
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{envPhotos.length > 0 ? (
|
||||
<View className="store-detail-section">
|
||||
<Text className="store-detail-section-title">店内环境</Text>
|
||||
<View className="store-detail-env-grid">
|
||||
{envPhotos.map((url, index) => (
|
||||
<View
|
||||
key={`${url}-${index}`}
|
||||
className="store-detail-env-item"
|
||||
onClick={() => previewEnv(index)}
|
||||
>
|
||||
<Image className="store-detail-env-img" src={url} mode="aspectFill" />
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
<View className="store-detail-bar">
|
||||
<View
|
||||
className="u-btn u-btn--block"
|
||||
|
||||
@@ -144,6 +144,27 @@
|
||||
color: var(--color-on-surface);
|
||||
}
|
||||
|
||||
.store-detail-env-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.store-detail-env-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
border-radius: var(--radius-md, 8px);
|
||||
overflow: hidden;
|
||||
background: var(--color-surface-container);
|
||||
}
|
||||
|
||||
.store-detail-env-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.store-detail-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
||||
Reference in New Issue
Block a user