From 8e25e23e81c756556027682f63a0512724e6ffda Mon Sep 17 00:00:00 2001 From: jacy <18049821889@163.com> Date: Sun, 2 Aug 2026 21:39:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=95=86=E5=93=81=E5=8F=AA=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=8E=B0=E5=9C=BA=E6=8F=90=E8=B4=A7=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mini-user/src/lib/product-fulfillment.ts | 30 +++++++++++++++++++ apps/mini-user/src/pages/home/index.tsx | 22 +++++++++----- .../src/pages/product-detail/index.tsx | 12 +++++--- 3 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 apps/mini-user/src/lib/product-fulfillment.ts diff --git a/apps/mini-user/src/lib/product-fulfillment.ts b/apps/mini-user/src/lib/product-fulfillment.ts new file mode 100644 index 0000000..7ecde3c --- /dev/null +++ b/apps/mini-user/src/lib/product-fulfillment.ts @@ -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(p: T): T { + return { + ...p, + allowOnlinePurchase: canBuyOnline(p), + allowOnSitePickup: canPickupOnSite(p), + allowCrossCityDelivery: canCrossCity(p), + }; +} diff --git a/apps/mini-user/src/pages/home/index.tsx b/apps/mini-user/src/pages/home/index.tsx index d41b2fb..dd9c7e5 100644 --- a/apps/mini-user/src/pages/home/index.tsx +++ b/apps/mini-user/src/pages/home/index.tsx @@ -17,6 +17,12 @@ import { isLoggedIn, request, toast } from '../../lib/api'; import { ensurePayReady } from '../../lib/pay-ready'; import { capturePromoSceneAndTouchScan } from '../../lib/promo'; import { getProductMainImage } from '../../lib/product-images'; +import { + canBuyOnline, + canCrossCity, + canPickupOnSite, + normalizeFulfillmentFlags, +} from '../../lib/product-fulfillment'; import { getCityCodeForCatalog, resolveUserCity } from '../../lib/user-location'; import { DEFAULT_SHARE_DESC, @@ -50,9 +56,9 @@ const FULFILLMENT_FILTERS: Array<{ key: FulfillmentFilter; label: string }> = [ function matchFulfillmentFilter(p: Product, filter: FulfillmentFilter): boolean { if (filter === 'ALL') return true; - if (filter === 'ONLINE') return p.allowOnlinePurchase !== false; - if (filter === 'CROSS_CITY') return p.allowCrossCityDelivery !== false; - return !!p.allowOnSitePickup; + if (filter === 'ONLINE') return canBuyOnline(p); + if (filter === 'CROSS_CITY') return canCrossCity(p); + return canPickupOnSite(p); } type MiniHomeConfig = { @@ -117,7 +123,9 @@ export default function HomePage() { const loadProducts = useCallback(() => { setLoading(true); return request(`/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 : '加载失败')) .finally(() => setLoading(false)); }, [cityCode]); @@ -138,7 +146,7 @@ export default function HomePage() { request(`/catalog/products?cityCode=${encodeURIComponent(nextCode)}`), loadMiniHome(), ]); - setProducts(Array.isArray(list) ? list : []); + setProducts(Array.isArray(list) ? list.map((p) => normalizeFulfillmentFlags(p)) : []); } catch (e) { toast(e instanceof Error ? e.message : '加载失败'); } finally { @@ -268,7 +276,7 @@ export default function HomePage() { - {p.allowOnSitePickup ? ( + {canPickupOnSite(p) ? ( { @@ -279,7 +287,7 @@ export default function HomePage() { 现场取货 ) : null} - {p.allowOnlinePurchase !== false ? ( + {canBuyOnline(p) ? ( { diff --git a/apps/mini-user/src/pages/product-detail/index.tsx b/apps/mini-user/src/pages/product-detail/index.tsx index c3248d2..0d58126 100644 --- a/apps/mini-user/src/pages/product-detail/index.tsx +++ b/apps/mini-user/src/pages/product-detail/index.tsx @@ -16,6 +16,11 @@ import { getProductMainImage, type ProductImageSource, } from '../../lib/product-images'; +import { + canBuyOnline, + canPickupOnSite, + normalizeFulfillmentFlags, +} from '../../lib/product-fulfillment'; import { DEFAULT_SHARE_DESC, DEFAULT_SHARE_TITLE, @@ -49,7 +54,7 @@ export default function ProductDetailPage() { useEffect(() => { if (!productId) return; request(`/catalog/products/${productId}`) - .then(setProduct) + .then((p) => setProduct(normalizeFulfillmentFlags(p))) .catch((e) => toast(e instanceof Error ? e.message : '加载失败')); }, [productId]); @@ -107,9 +112,6 @@ export default function ProductDetailPage() { Taro.navigateTo({ url: returnPath }); } - const allowOnline = product?.allowOnlinePurchase !== false; - const allowOnSite = !!product?.allowOnSitePickup; - if (!product) { return ( @@ -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 carouselImages = getProductCarouselImages(product); const detailImages = getProductDetailImages(product);