diff --git a/.workbuddy/memory/2026-07-15.md b/.workbuddy/memory/2026-07-15.md index 02edfa9..ff0abf2 100644 --- a/.workbuddy/memory/2026-07-15.md +++ b/.workbuddy/memory/2026-07-15.md @@ -243,3 +243,25 @@ - 编译验证:`npx taro build --type weapp` 14.89s 成功 - 设计稿预览:`.workbuddy/sms-login-preview.html`(按 375×812 真机尺寸渲染的 mockup,可直接浏览器打开看) - 业务规则:login/register/sms-login 三个页面已统一视觉风格(同一套渐变 + 圆形 logo + 大字标题 + 白色卡片),后续新增 passport 类页面照搬这一套即可 + +## 修复首页轮播图只显示一张的问题 +- 文件:`src/pages/index/index.tsx` +- 现象:后台一个广告位下配置了 3 张图片,但小程序首页轮播只显示第一张 +- 根因:原代码把每个 `CmsAd` 作为一个 `SwiperItem`,图片只取 `item.imageList?.[0]?.url`,所以无论后台配几张都只渲染首图 +- 修复: + - 新增 `bannerSlides`:用 `flatMap` 把每个广告位下的 `imageList` 全部展开成独立轮播项,key 用 `adId-uid`(无 uid 则 fallback 到索引) + - 保留 `item.image` 单图兜底逻辑,兼容只配单张图片的老数据 + - 渲染 `SwiperItem` 改为遍历 `bannerSlides`,点击跳转仍使用对应广告位的 `path` +- 验证:代码逻辑走查通过;项目原有 `npx tsc --noEmit` 的 `@tarojs/taro` 类型定义错误与本次修改无关 + +## 首页轮播图高度改为按后台 width/height 自适应 +- 文件:`src/pages/index/index.tsx` +- 原状:`Swiper` 的 `height` 固定写死 `160px`,与后台广告位配置脱节 +- 修复: + - 新增 `bannerWrapWidth` 状态,页面渲染后用 `Taro.createSelectorQuery().select('.index-banner-wrap').boundingClientRect()` 获取容器实际宽度 + - 新增 `bannerHeight`(useMemo):取第一个带有效 `width/height` 的广告位,按 `容器宽度 * (height / width)` 计算高度;无值或解析失败则 fallback `160px` + - 轮播容器增加 `index-banner-wrap` 类名用于选择器查询 + - `Swiper` 和「暂无轮播图」占位区的高度都改用 `bannerHeight` +- 注意:宽度仍由容器 `w-full` + `mx-3` 边距控制,不直接套用后台 `width` 像素值;高度按比例缩放适配不同屏幕 + + diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index cf20cfb..9f91764 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback, useRef } from 'react' +import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react' import { View, Text, ScrollView, Swiper, SwiperItem, Image } from '@tarojs/components' import Taro, { useDidShow } from '@tarojs/taro' import { useUser } from '@/hooks/useUser' @@ -26,6 +26,7 @@ definePageConfig({ const IndexPage: React.FC = () => { const { user, isLoggedIn } = useUser() const [banners, setBanners] = useState([]) + const [bannerWrapWidth, setBannerWrapWidth] = useState(0) const [announcements, setAnnouncements] = useState([]) const [hotProducts, setHotProducts] = useState([]) const [loading, setLoading] = useState(true) @@ -190,6 +191,31 @@ const IndexPage: React.FC = () => { } } + // 获取轮播容器实际宽度,用于根据后台 width/height 计算比例高度 + useEffect(() => { + if (bannerWrapWidth > 0) return + const timer = setTimeout(() => { + const query = Taro.createSelectorQuery() + query.select('.index-banner-wrap').boundingClientRect((rect) => { + if (rect && rect.width > 0) { + setBannerWrapWidth(rect.width) + } + }).exec() + }, 0) + return () => clearTimeout(timer) + }, [bannerWrapWidth]) + + // 根据广告位后台返回的 width/height 计算轮播区域高度(无值则 fallback 160px) + const bannerHeight = useMemo(() => { + if (bannerWrapWidth <= 0) return 160 + const firstAd = banners.find(b => b.width && b.height) + if (!firstAd) return 160 + const w = parseInt(firstAd.width || '0', 10) + const h = parseInt(firstAd.height || '0', 10) + if (!w || !h || w <= 0 || h <= 0) return 160 + return Math.round(bannerWrapWidth * (h / w)) + }, [bannerWrapWidth, banners]) + // 轮播图数据:每个广告位下的所有图片都作为独立轮播项 const bannerSlides = banners.flatMap(item => (item.imageList && item.imageList.length > 0) @@ -233,13 +259,13 @@ const IndexPage: React.FC = () => { {/* 轮播图 */} - + {bannerSlides.length > 0 ? ( {bannerSlides.map(slide => ( @@ -255,7 +281,7 @@ const IndexPage: React.FC = () => { ))} ) : ( - + 暂无轮播图 )}