From 18147e157fa263c17182186187ca977125a77293 Mon Sep 17 00:00:00 2001 From: jacy <18049821889@163.com> Date: Mon, 17 Aug 2026 21:48:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(mini-user):=20=E9=97=A8=E5=BA=97=E5=A5=97?= =?UTF-8?q?=E9=A4=90=E5=9B=BE=E7=89=87=E8=87=AA=E9=80=82=E5=BA=94=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E6=98=BE=E7=A4=BA=EF=BC=8C=E4=B8=8D=E5=86=8D=E8=A3=81?= =?UTF-8?q?=E5=89=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ProductCarousel 新增 imageFit="adaptive"(widthFix + 动态高度) - 门店套餐详情按图片真实比例自适应高度,完整显示不裁剪 - 补充 v3.4.18 文档 F 项 Co-Authored-By: WorkBuddy --- .../src/components/ProductCarousel.tsx | 61 +++++++++++++++++-- .../src/pages/store-package-detail/index.tsx | 1 + apps/mini-user/src/styles/product-detail.css | 15 +++++ 杜康好客-v3.4.18-门店体验与登录态优化.md | 14 +++++ 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/apps/mini-user/src/components/ProductCarousel.tsx b/apps/mini-user/src/components/ProductCarousel.tsx index 4b53f86..47f8a8c 100644 --- a/apps/mini-user/src/components/ProductCarousel.tsx +++ b/apps/mini-user/src/components/ProductCarousel.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { View, Image, Swiper, SwiperItem } from '@tarojs/components'; import Taro from '@tarojs/taro'; @@ -7,8 +7,12 @@ type ProductCarouselProps = { alt: string; variant?: 'home' | 'detail' | 'store'; previewable?: boolean; - /** cover=aspectFill 裁剪铺满;contain=aspectFit 缩放完整显示(门店门头固定区) */ - imageFit?: 'cover' | 'contain'; + /** + * cover=aspectFill 裁剪铺满(固定高度,可能裁切) + * contain=aspectFit 完整显示(固定高度,可能留白) + * adaptive=widthFix 按图片真实比例自适应高度,完整显示不裁剪(门店套餐详情用) + */ + imageFit?: 'cover' | 'contain' | 'adaptive'; }; /** 商品/门店轮播(对齐 h5 ProductCarousel 三变体) */ @@ -21,10 +25,55 @@ export default function ProductCarousel({ }: ProductCarouselProps) { const slides = images.length > 0 ? images : ['']; const [activeIndex, setActiveIndex] = useState(0); + // adaptive 模式:实测容器宽度与各图渲染高度 + const [wrapWidth, setWrapWidth] = useState(0); + const [imgHeights, setImgHeights] = useState([]); const prefix = variant === 'store' ? 'store-detail-carousel' : variant === 'home' ? 'home-carousel' : 'detail-carousel'; const isContain = imageFit === 'contain'; - const wrapClass = `${prefix}-wrap${isContain ? ` ${prefix}-wrap--contain` : ''}`; + const isAdaptive = imageFit === 'adaptive'; + const wrapClass = `${prefix}-wrap${isContain ? ` ${prefix}-wrap--contain` : ''}${isAdaptive ? ` ${prefix}-wrap--adaptive` : ''}`; + + function getWindowWidth(): number { + try { + const info = (Taro as any).getWindowInfo?.() ?? Taro.getSystemInfoSync(); + return info?.windowWidth || 375; + } catch { + return 375; + } + } + + useEffect(() => { + if (!isAdaptive) return; + const query = Taro.createSelectorQuery(); + query + .select(`.${prefix}-wrap--adaptive`) + .boundingClientRect((rect: { width?: number }) => { + if (rect && rect.width) setWrapWidth(rect.width); + else setWrapWidth(getWindowWidth()); + }) + .exec(); + // 仅挂载时测量一次容器宽度(页面宽度稳定) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isAdaptive, prefix]); + + function handleImageLoad(index: number, e: any) { + const detail = e?.detail; + const naturalW = detail?.width; + const naturalH = detail?.height; + if (!naturalW || !naturalH) return; + const w = wrapWidth || getWindowWidth(); + const h = Math.round((naturalH / naturalW) * w); + setImgHeights((prev) => { + const next = [...prev]; + next[index] = h; + return next; + }); + } + + // adaptive:随当前幻灯片高度变化;未加载时给一个 3:4 兜底高度 + const adaptiveHeight = imgHeights[activeIndex] || Math.round((wrapWidth || getWindowWidth()) * 0.75); + const swiperStyle = isAdaptive ? { height: `${adaptiveHeight}px` } : undefined; function previewAt(index: number) { const urls = slides.filter(Boolean); @@ -37,6 +86,7 @@ export default function ProductCarousel({ 1} {...(variant === 'detail' && slides.length > 1 ? { autoplay: true, interval: 3500 } : {})} onChange={(e) => setActiveIndex(e.detail.current)} @@ -47,8 +97,9 @@ export default function ProductCarousel({ {alt} handleImageLoad(index, e) : undefined} onClick={previewable ? () => previewAt(index) : undefined} /> ) : ( diff --git a/apps/mini-user/src/pages/store-package-detail/index.tsx b/apps/mini-user/src/pages/store-package-detail/index.tsx index e4639e9..10d0dfc 100644 --- a/apps/mini-user/src/pages/store-package-detail/index.tsx +++ b/apps/mini-user/src/pages/store-package-detail/index.tsx @@ -143,6 +143,7 @@ export default function StorePackageDetailPage() { alt={pkg.name} variant="detail" previewable + imageFit="adaptive" /> ) : null} diff --git a/apps/mini-user/src/styles/product-detail.css b/apps/mini-user/src/styles/product-detail.css index a40747f..cb2d3fa 100644 --- a/apps/mini-user/src/styles/product-detail.css +++ b/apps/mini-user/src/styles/product-detail.css @@ -18,6 +18,21 @@ overflow: hidden; } +/* adaptive 模式:去掉固定 1:1 比例,按图片真实比例自适应高度,完整显示不裁剪 */ +.detail-carousel-wrap--adaptive { + aspect-ratio: auto; + overflow: visible; +} + +.detail-carousel-wrap--adaptive .detail-carousel { + height: auto; + transition: height 0.2s ease; +} + +.detail-carousel-wrap--adaptive .detail-carousel-image { + height: auto; +} + .detail-carousel { width: 100%; height: 100%; diff --git a/杜康好客-v3.4.18-门店体验与登录态优化.md b/杜康好客-v3.4.18-门店体验与登录态优化.md index d667369..a9b9dc4 100644 --- a/杜康好客-v3.4.18-门店体验与登录态优化.md +++ b/杜康好客-v3.4.18-门店体验与登录态优化.md @@ -12,6 +12,7 @@ | C. 合伙人账号暂停禁止登录 | 非 `ACTIVE` → 登录/发码均拒,提示「该账号已暂停使用,请联系客服人员」 | | D. 门店端 申请提现 / 筛选栏留白对齐 | `WithdrawPage` 左右内边距统一 `--space-page` | | E. 门店端 休息中核销 → 是否开启营业 | 核销页拦截时弹「是否开启营业?」,确认即开张后继续核销 | +| F. mini-user 门店套餐图片自适应完整显示 | `ProductCarousel` 新增 `imageFit="adaptive"`(widthFix + 动态高度),门店套餐详情不再裁剪 | ## A. mini-user 门店座机电话脱敏(中间四位隐藏) @@ -84,6 +85,18 @@ | `apps/h5-shop/src/pages/StatusPage.tsx` `requestToggle` / `confirmToggle` | 复用开张调用 | | `PUT /shop/store/status` `GET /shop/store` | 切换营业 / 读取门店(已存在) | +## F. mini-user 门店套餐图片自适应完整显示(不裁剪) + +门店套餐详情(`apps/mini-user/src/pages/store-package-detail/index.tsx`)的 `ProductCarousel` 此前用 `variant="detail"` 默认 `imageFit="cover"`(= `aspectFill`),配合 `.detail-carousel-wrap` 的固定 `aspect-ratio: 1` 与 `overflow:hidden`,非正方形图片被裁切 → 用户反馈「图片没显示全」。 + +- 新增 `imageFit="adaptive"` 模式(仅作用于门店套餐详情): + - `Image` 改用 `mode="widthFix"`,按图片真实比例缩放、完整显示、不裁剪。 + - 组件挂载时实测容器宽度(`Taro.createSelectorQuery().select('.detail-carousel-wrap--adaptive').boundingClientRect`),图片 `onLoad` 拿到自然宽高后按 `容器宽 × (自然高/自然宽)` 计算每张幻灯片渲染高度,赋给 `` 内联 `height`,实现轮播高度自适应(多图比例不一也能逐张适配,带 0.2s 过渡)。 + - 未加载前兜底高度为 `容器宽 × 0.75`(约 3:4)。 +- 样式:`product-detail.css` 增加 `.detail-carousel-wrap--adaptive`,覆盖基类固定 `aspect-ratio:1` 与 `overflow:hidden`(`aspect-ratio:auto; overflow:visible`),并令 `.detail-carousel-image` 高度为 `auto`。 +- `autoplay`(3.5s)/ `1/5` 计数(feature B)在 adaptive 下保持不变。 +- 仅门店套餐详情传 `imageFit="adaptive"`;门店头图(`variant="store"` 仍 `contain`)、商品详情(`cover`)不受影响。 + ## 验收 - [ ] 门店详情座机显示形如 `0379-12****78`(中间四位隐藏),手机号仍 `138****8000`;拨打为明文。 @@ -91,6 +104,7 @@ - [ ] 合伙人账号处于非 ACTIVE(暂停 / 停用)时:短信登录与微信登录均被拦截,提示「该账号已暂停使用,请联系客服人员」,无法进入。 - [ ] 门店管理(结算提现)页:申请提现按钮与筛选栏左右留白与其他区块一致(统一 `--space-page`),不再贴边。 - [ ] 门店休息中时进入核销:弹「是否开启营业?」;确认开张后可继续核销;取消则维持拦截;未过审门店开张被拒时给出对应提示。 +- [ ] 门店套餐详情图片按真实比例完整显示、不再被裁切(轮播高度随图自适应);自动轮播与 `1/5` 计数仍正常。 - [ ] A 仅 `maskPhone` 规则、C/D/E 仅前端样式 / 交互;均无需 Prisma 迁移(C 复用 `DISABLED`)。 ## HQ 开发计划