商品只支持现场提货的功能修改

This commit is contained in:
2026-08-02 21:39:22 +08:00
parent a017a27b60
commit 8e25e23e81
3 changed files with 53 additions and 11 deletions
@@ -0,0 +1,30 @@
/** 商品履约能力(与 HQ / 交易硬闸一致) */
export type FulfillmentFlags = {
allowOnlinePurchase?: boolean | null;
allowOnSitePickup?: boolean | null;
allowCrossCityDelivery?: boolean | null;
};
/** 未返回时默认允许线上(存量商品) */
export function canBuyOnline(p: FulfillmentFlags): boolean {
return p.allowOnlinePurchase !== false;
}
/** 仅显式开启才展示现场取货 */
export function canPickupOnSite(p: FulfillmentFlags): boolean {
return p.allowOnSitePickup === true;
}
export function canCrossCity(p: FulfillmentFlags): boolean {
return p.allowCrossCityDelivery !== false;
}
export function normalizeFulfillmentFlags<T extends FulfillmentFlags>(p: T): T {
return {
...p,
allowOnlinePurchase: canBuyOnline(p),
allowOnSitePickup: canPickupOnSite(p),
allowCrossCityDelivery: canCrossCity(p),
};
}
+15 -7
View File
@@ -17,6 +17,12 @@ import { isLoggedIn, request, toast } from '../../lib/api';
import { ensurePayReady } from '../../lib/pay-ready'; import { ensurePayReady } from '../../lib/pay-ready';
import { capturePromoSceneAndTouchScan } from '../../lib/promo'; import { capturePromoSceneAndTouchScan } from '../../lib/promo';
import { getProductMainImage } from '../../lib/product-images'; import { getProductMainImage } from '../../lib/product-images';
import {
canBuyOnline,
canCrossCity,
canPickupOnSite,
normalizeFulfillmentFlags,
} from '../../lib/product-fulfillment';
import { getCityCodeForCatalog, resolveUserCity } from '../../lib/user-location'; import { getCityCodeForCatalog, resolveUserCity } from '../../lib/user-location';
import { import {
DEFAULT_SHARE_DESC, DEFAULT_SHARE_DESC,
@@ -50,9 +56,9 @@ const FULFILLMENT_FILTERS: Array<{ key: FulfillmentFilter; label: string }> = [
function matchFulfillmentFilter(p: Product, filter: FulfillmentFilter): boolean { function matchFulfillmentFilter(p: Product, filter: FulfillmentFilter): boolean {
if (filter === 'ALL') return true; if (filter === 'ALL') return true;
if (filter === 'ONLINE') return p.allowOnlinePurchase !== false; if (filter === 'ONLINE') return canBuyOnline(p);
if (filter === 'CROSS_CITY') return p.allowCrossCityDelivery !== false; if (filter === 'CROSS_CITY') return canCrossCity(p);
return !!p.allowOnSitePickup; return canPickupOnSite(p);
} }
type MiniHomeConfig = { type MiniHomeConfig = {
@@ -117,7 +123,9 @@ export default function HomePage() {
const loadProducts = useCallback(() => { const loadProducts = useCallback(() => {
setLoading(true); setLoading(true);
return request<Product[]>(`/catalog/products?cityCode=${encodeURIComponent(cityCode)}`) return request<Product[]>(`/catalog/products?cityCode=${encodeURIComponent(cityCode)}`)
.then((list) => setProducts(Array.isArray(list) ? list : [])) .then((list) =>
setProducts(Array.isArray(list) ? list.map((p) => normalizeFulfillmentFlags(p)) : []),
)
.catch((e) => toast(e instanceof Error ? e.message : '加载失败')) .catch((e) => toast(e instanceof Error ? e.message : '加载失败'))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}, [cityCode]); }, [cityCode]);
@@ -138,7 +146,7 @@ export default function HomePage() {
request<Product[]>(`/catalog/products?cityCode=${encodeURIComponent(nextCode)}`), request<Product[]>(`/catalog/products?cityCode=${encodeURIComponent(nextCode)}`),
loadMiniHome(), loadMiniHome(),
]); ]);
setProducts(Array.isArray(list) ? list : []); setProducts(Array.isArray(list) ? list.map((p) => normalizeFulfillmentFlags(p)) : []);
} catch (e) { } catch (e) {
toast(e instanceof Error ? e.message : '加载失败'); toast(e instanceof Error ? e.message : '加载失败');
} finally { } finally {
@@ -268,7 +276,7 @@ export default function HomePage() {
<CouponBadge amount={p.benefitDisplay ?? p.price} label="好客权益" /> <CouponBadge amount={p.benefitDisplay ?? p.price} label="好客权益" />
</View> </View>
<View className="home-product-actions"> <View className="home-product-actions">
{p.allowOnSitePickup ? ( {canPickupOnSite(p) ? (
<Text <Text
className="home-pickup-btn" className="home-pickup-btn"
onClick={(e) => { onClick={(e) => {
@@ -279,7 +287,7 @@ export default function HomePage() {
</Text> </Text>
) : null} ) : null}
{p.allowOnlinePurchase !== false ? ( {canBuyOnline(p) ? (
<Text <Text
className="home-buy-btn" className="home-buy-btn"
onClick={(e) => { onClick={(e) => {
@@ -16,6 +16,11 @@ import {
getProductMainImage, getProductMainImage,
type ProductImageSource, type ProductImageSource,
} from '../../lib/product-images'; } from '../../lib/product-images';
import {
canBuyOnline,
canPickupOnSite,
normalizeFulfillmentFlags,
} from '../../lib/product-fulfillment';
import { import {
DEFAULT_SHARE_DESC, DEFAULT_SHARE_DESC,
DEFAULT_SHARE_TITLE, DEFAULT_SHARE_TITLE,
@@ -49,7 +54,7 @@ export default function ProductDetailPage() {
useEffect(() => { useEffect(() => {
if (!productId) return; if (!productId) return;
request<Product>(`/catalog/products/${productId}`) request<Product>(`/catalog/products/${productId}`)
.then(setProduct) .then((p) => setProduct(normalizeFulfillmentFlags(p)))
.catch((e) => toast(e instanceof Error ? e.message : '加载失败')); .catch((e) => toast(e instanceof Error ? e.message : '加载失败'));
}, [productId]); }, [productId]);
@@ -107,9 +112,6 @@ export default function ProductDetailPage() {
Taro.navigateTo({ url: returnPath }); Taro.navigateTo({ url: returnPath });
} }
const allowOnline = product?.allowOnlinePurchase !== false;
const allowOnSite = !!product?.allowOnSitePickup;
if (!product) { if (!product) {
return ( return (
<PageShell variant="scroll" className="product-detail-page"> <PageShell variant="scroll" className="product-detail-page">
@@ -119,6 +121,8 @@ export default function ProductDetailPage() {
); );
} }
const allowOnline = canBuyOnline(product);
const allowOnSite = canPickupOnSite(product);
const benefit = Number(product.benefitDisplay ?? product.benefitAmount ?? product.price); const benefit = Number(product.benefitDisplay ?? product.benefitAmount ?? product.price);
const carouselImages = getProductCarouselImages(product); const carouselImages = getProductCarouselImages(product);
const detailImages = getProductDetailImages(product); const detailImages = getProductDetailImages(product);