From 5ce0d76154bf4c1d70543476cdfad9a30195b0f8 Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期六, 10 十月 2026 16:44:38 +0800
Subject: [PATCH] fix(miniapp): 调整首页圆角布局并隐藏滚动条

---
 rencaika/pages/shopping-benefits/shopping-benefits.uvue |   28 ++++++++++++++++++++--------
 1 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/rencaika/pages/shopping-benefits/shopping-benefits.uvue b/rencaika/pages/shopping-benefits/shopping-benefits.uvue
index 289ad94..0921fef 100644
--- a/rencaika/pages/shopping-benefits/shopping-benefits.uvue
+++ b/rencaika/pages/shopping-benefits/shopping-benefits.uvue
@@ -1,8 +1,8 @@
 <template>
 	<view class="page">
 		<view class="custom-nav" :class="isSolidNav ? 'is-solid' : ''"><view class="nav-bg"></view><view class="safe-space" :style="'height:' + navTop + 'px'"></view><view class="nav-row" :style="'height:' + navHeight + 'px;padding-right:' + navRight + 'px'"><view class="back-button" @tap="goBack"><image src="/static/food-assets/arrow-left-white.svg" mode="aspectFit"></image></view><text class="nav-title">购—{{topicTitle}}</text><view class="capsule-space" :style="'width:' + navWidth + 'px'"></view></view></view>
-		<scroll-view class="page-scroll" scroll-y lower-threshold="80" @scroll="handleScroll" @scrolltolower="loadMore">
-			<view class="hero"><image class="hero-image" :src="activeScene.image" mode="aspectFill" @error="replaceImage(activeScene)"></image><view class="hero-top-shade"></view><view class="hero-bottom-shade"></view><text class="scene-name">{{activeScene.name}}</text><scroll-view class="scene-scroll" scroll-x :show-scrollbar="false" scroll-with-animation :scroll-left="sceneScrollLeft" @scrollend="handleSceneScrollEnd"><view class="scene-row" :style="'width:' + sceneTrackWidth + 'rpx'"><view class="scene-pad"></view><view v-for="(item, index) in scenes" :key="item.id" class="scene-item" :class="index == activeIndex ? 'active' : ''" @tap="selectScene(index)"><image :src="item.image" mode="aspectFill" @error="replaceImage(item)"></image></view><view class="scene-pad"></view></view></scroll-view></view>
+		<scroll-view :show-scrollbar="false" class="page-scroll" scroll-y lower-threshold="80" @scroll="handleScroll" @scrolltolower="loadMore">
+			<view class="hero"><swiper v-if="scenes.length > 0" class="hero-swiper" :current="activeIndex < 0 ? 0 : activeIndex" :circular="scenes.length > 1" :duration="240" @change="handleHeroChange"><swiper-item v-for="(item, index) in scenes" :key="item.id"><image class="hero-image" :src="item.image" mode="aspectFill" @error="replaceImage(item)"></image></swiper-item></swiper><image v-else class="hero-image" :src="activeScene.image" mode="aspectFill" @error="replaceImage(activeScene)"></image><view class="hero-top-shade"></view><view class="hero-bottom-shade"></view><text class="scene-name">{{activeScene.name}}</text><scroll-view class="scene-scroll" scroll-x :show-scrollbar="false" scroll-with-animation :scroll-left="sceneScrollLeft" @scrollend="handleSceneScrollEnd"><view class="scene-row" :style="'width:' + sceneTrackWidth + 'rpx'"><view class="scene-pad"></view><view v-for="(item, index) in scenes" :key="item.id" class="scene-item" :class="index == activeIndex ? 'active' : ''" @tap="selectScene(index)"><image :src="item.image" mode="aspectFill" @error="replaceImage(item)"></image></view><view class="scene-pad"></view></view></scroll-view></view>
 			<view v-if="topicError" class="topic-error"><text>专题配置加载失败</text><text @tap="loadShoppingTopic">重新加载</text></view>
 			<view v-if="topicDescription != ''" class="topic-summary"><view class="intro-card"><text>{{topicDescription}}</text></view></view>
 			<view class="service-section">
@@ -21,7 +21,7 @@
 	import { isApiConfigured } from '../../config/api.uts'
 	import { getShoppingTopic, getShoppingTopicMerchants } from '../../services/portal.uts'
 	import { resolveApiUrl } from '../../services/http.uts'
-	import { getSession } from '../../services/session.uts'
+	import { resolveTalentId } from '../../utils/talent-id.uts'
 	import { safeBack } from '../../utils/navigation.uts'
 
 	const navTop = ref(28); const navHeight = ref(32); const navWidth = ref(88); const navRight = ref(10); const windowWidth = ref(375)
@@ -37,7 +37,7 @@
 		// #ifdef MP-WEIXIN
 		const capsule = uni.getMenuButtonBoundingClientRect(); const info = uni.getSystemInfoSync(); windowWidth.value = info.windowWidth; navTop.value = capsule.top; navHeight.value = capsule.height; navWidth.value = capsule.width; navRight.value = info.windowWidth - capsule.right
 		// #endif
-		const session = getSession(); if (session != null && session.talentId != null) talentId.value = session.talentId as string
+		talentId.value = resolveTalentId()
 		if (options != null && options['previewState'] != null) { const state = options['previewState'] as string; failInitialOnce.value = state == 'initialError'; failLoadMoreOnce.value = state == 'loadMoreError' }
 		selectScene(0); loadShoppingTopic()
 	})
@@ -45,6 +45,8 @@
 	const centerActiveScene = (index: number) => { sceneScrollLeft.value = index * 137 * windowWidth.value / 750 }
 	const selectScene = (index: number) => { if (index < 0 || index >= scenes.value.length) return; activeIndex.value = index; activeScene.value = scenes.value[index]; centerActiveScene(index) }
 	const handleSceneScrollEnd = (event: any) => { let index = Math.round(event.detail.scrollLeft * 750 / windowWidth.value / 137); if (index < 0) index = 0; if (index >= scenes.value.length) index = scenes.value.length - 1; selectScene(index) }
+	/** 主图左右滑动:滑动落点同步到缩略图、名称与描述。 */
+	const handleHeroChange = (event: any) => { const current = event != null && event.detail != null && event.detail.current != null ? Number(event.detail.current) : -1; if (current < 0) return; selectScene(current) }
 	const handleScroll = (event: any) => { isSolidNav.value = event.detail.scrollTop > 64 }
 	const loadShoppingTopic = () => {
 		if (!isApiConfigured()) { topicError.value = true; initialLoading.value = false; initialError.value = true; return }
@@ -75,11 +77,19 @@
 			for (let index = 0; index < records.length; index++) {
 				const item = records[index]
 				const merchantType = item.merchantType != null ? item.merchantType as string : ''
-				const tags: string[] = []
-				if (item.couponAvailable === true || Number(item.couponAvailable) == 1) tags.push('券')
 				const configuredTag = item.discountText != null ? String(item.discountText).trim() : ''
-				if (merchantType == 'culture' && (item.storeConsumeAvailable === true || Number(item.storeConsumeAvailable) == 1)) tags.push('到店消费')
-				if (merchantType != 'culture' && configuredTag != '' && tags.indexOf(configuredTag) < 0) tags.push(configuredTag)
+				const tags: string[] = []
+				if (item.benefitTags instanceof Array) {
+					const tagRecords: any[] = item.benefitTags as any[]
+					for (let tagIndex = 0; tagIndex < tagRecords.length; tagIndex++) {
+						const tag = String(tagRecords[tagIndex]).trim()
+						if (tag != '' && tag != '人才专享' && tags.indexOf(tag) < 0) tags.push(tag)
+					}
+				} else {
+					if (item.couponAvailable === true || Number(item.couponAvailable) == 1) tags.push('券')
+					if (merchantType == 'culture' && (item.storeConsumeAvailable === true || Number(item.storeConsumeAvailable) == 1)) tags.push('到店消费')
+					if (merchantType != 'culture' && configuredTag != '' && tags.indexOf(configuredTag) < 0) tags.push(configuredTag)
+				}
 				next.push({ id: '' + item.id, merchantType: merchantType, name: item.merchantName != null && item.merchantName != '' ? item.merchantName as string : '商家名称未配置', discount: configuredTag, tags: tags, address: item.address != null ? item.address as string : '', image: item.coverUrl != null && item.coverUrl != '' ? resolveApiUrl(item.coverUrl as string) : fallbackImage, available: item.available !== false, unavailableReason: item.unavailableReason != null && item.unavailableReason != '' ? item.unavailableReason as string : '该服务当前不可用' })
 			}
 			visibleServices.value = next; currentPage.value++; hasMore.value = data != null && data.total != null ? next.length < data.total : false; initialLoading.value = false; loadingMore.value = false; hasLoaded.value = true
@@ -106,5 +116,7 @@
 	.page,.page-scroll { width:100%; height:100vh; background-color:#FFFFFF; }.custom-nav { position:fixed; z-index:20; left:0; right:0; top:0; padding-bottom:20rpx; }.nav-bg { position:absolute; left:0; right:0; top:0; bottom:0; opacity:0; background-image:linear-gradient(180deg,#F26A38,#EE542B); transition:opacity 280ms ease-out; }.custom-nav.is-solid .nav-bg { opacity:1; }.safe-space,.nav-row { position:relative; z-index:1; }.safe-space { height:28px; }.nav-row { display:flex; box-sizing:border-box; padding-left:24rpx; flex-direction:row; align-items:center; justify-content:space-between; }.back-button { display:flex; width:54rpx; height:54rpx; position:relative; z-index:2; border-radius:50%; background-color:rgba(45,45,45,.52); justify-content:center; align-items:center; }.custom-nav.is-solid .back-button { background-color:transparent; }.back-button image { width:38rpx; height:38rpx; }.nav-title { position:absolute; z-index:1; left:0; right:0; color:#FFFFFF; font-size:31rpx; font-weight:500; text-align:center; text-shadow:0 2rpx 8rpx rgba(0,0,0,.35); }.capsule-space { height:100%; flex-shrink:0; }
 	.hero { height:730rpx; position:relative; overflow:visible; background-color:#1C315E; }.hero-image { position:absolute; left:0; top:0; width:100%; height:730rpx; }.hero-top-shade { position:absolute; left:0; right:0; top:0; height:245rpx; background-image:linear-gradient(180deg,rgba(0,0,0,.62),rgba(0,0,0,0)); }.hero-bottom-shade { position:absolute; left:0; right:0; bottom:0; height:230rpx; background-image:linear-gradient(180deg,rgba(0,0,0,0),rgba(0,0,0,.42)); }.scene-name { position:absolute; z-index:3; left:38rpx; top:318rpx; color:#FFFFFF; font-family:'FoodCalligraphy'; font-size:48rpx; line-height:66rpx; text-shadow:0 3rpx 10rpx rgba(0,0,0,.55); }.scene-scroll { position:absolute; z-index:4; left:0; right:0; top:469rpx; width:100%; height:150rpx; white-space:nowrap; }.scene-row { display:flex; height:150rpx; flex-direction:row; align-items:center; }.scene-pad { width:322rpx; height:1rpx; flex-shrink:0; }.scene-item { display:flex; width:106rpx; height:106rpx; margin-right:31rpx; box-sizing:border-box; overflow:hidden; position:relative; z-index:1; border:3rpx solid rgba(255,255,255,.9); border-radius:8rpx; flex-shrink:0; transition:transform 180ms ease-out; }.scene-item image { width:100%; height:100%; }.scene-item.active { z-index:3; border-width:4rpx; border-color:#FFD329; transform:scale(1.28); box-shadow:0 8rpx 18rpx rgba(0,0,0,.28); }
 	.topic-error { display:flex; height:76rpx; padding:0 31rpx; background-color:#FFF8F4; flex-direction:row; justify-content:center; align-items:center; }.topic-error text { color:#A48A7A; font-size:22rpx; }.topic-error text + text { margin-left:22rpx; color:#F26A38; }.topic-summary { position:relative; z-index:4; margin-top:-66rpx; }.intro-card { margin:0 31rpx; box-sizing:border-box; padding:25rpx 31rpx; border-radius:26rpx; background-image:linear-gradient(90deg,#FF5320,#FF8A22); box-shadow:0 10rpx 22rpx rgba(255,104,28,.24); }.intro-card text { color:#FFFFFF; font-size:23rpx; line-height:34rpx; }.service-section { padding:32rpx 31rpx 0; }.tab-scroll { width:100%; height:78rpx; white-space:nowrap; }.service-tabs { display:flex; height:72rpx; flex-direction:row; align-items:flex-start; }.service-tab { display:flex; width:180rpx; margin-right:30rpx; flex-direction:column; align-items:center; flex-shrink:0; }.service-tab text { color:#8A8D92; font-size:29rpx; line-height:40rpx; font-weight:600; white-space:nowrap; }.service-tab.active text { color:#363636; font-weight:700; }.tab-line { width:0; height:7rpx; margin-top:12rpx; border-radius:4rpx; background-image:linear-gradient(90deg,#FF4D36,#FFBF3A); transition:width 180ms ease-out; }.service-tab.active .tab-line { width:61rpx; }
+	/* 主图轮播:与下方缩略图带同高同位,盖在原来的静态主图上。 */
+	.hero-swiper { position:absolute; left:0; top:0; width:100%; height:730rpx; }
 	.service-list { padding-top:10rpx; }.service-item { display:flex; min-height:215rpx; margin-bottom:22rpx; flex-direction:row; align-items:flex-start; }.service-item.is-unavailable { opacity:.55; }.service-image { width:184rpx; height:184rpx; border-radius:17rpx; flex-shrink:0; background-color:#EEEEEE; }.service-info { display:flex; min-width:0; min-height:184rpx; flex:1; box-sizing:border-box; padding:4rpx 0 4rpx 24rpx; flex-direction:column; justify-content:space-between; }.service-name { color:#292929; font-size:29rpx; line-height:40rpx; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }.service-discount { align-self:flex-start; max-width:400rpx; padding:6rpx 9rpx; border-radius:6rpx; background-color:#FFF5E7; color:#FF7C2B; font-size:21rpx; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }.service-tags { display:flex; min-height:38rpx; flex-direction:row; align-items:center; }.service-tags text { margin-right:9rpx; padding:5rpx 9rpx; border-radius:5rpx; font-size:21rpx; line-height:28rpx; white-space:nowrap; }.coupon-tag { background-color:#FFF0EC; color:#FF5D37; }.service-tag { background-color:#FFF5E7; color:#FF7C2B; }.address-row { display:flex; min-width:0; box-sizing:border-box; padding:7rpx 10rpx; border-radius:7rpx; background-image:linear-gradient(90deg,rgba(239,240,242,.98),rgba(242,243,245,.76) 58%,rgba(255,255,255,0)); flex-direction:row; align-items:flex-start; }.address-row image { width:27rpx; height:27rpx; margin-right:8rpx; flex-shrink:0; }.address-row text { min-width:0; flex:1; color:#7E8490; font-size:21rpx; line-height:31rpx; max-height:62rpx; overflow:hidden; }.service-empty { display:flex; height:310rpx; justify-content:center; align-items:center; }.service-empty text { color:#A5A8AD; font-size:25rpx; }.error-state { flex-direction:column; }.error-state .retry-text { margin-top:22rpx; color:#F26A38; }.loading-row,.no-more { display:flex; height:90rpx; flex-direction:row; justify-content:center; align-items:center; }.loading-spinner { width:28rpx; height:28rpx; margin-right:13rpx; box-sizing:border-box; border:3rpx solid #FFD6C4; border-top-color:#FF6C2B; border-radius:50%; animation:shopping-loading 720ms linear infinite; }.loading-row text { color:#989DA5; font-size:22rpx; }.load-error text { color:#F26A38; }.no-more view { width:70rpx; height:1rpx; background-color:#E7E7E7; }.no-more text { margin:0 18rpx; color:#B1B3B7; font-size:21rpx; }.bottom-space { height:calc(30rpx + env(safe-area-inset-bottom)); }@keyframes shopping-loading { from { transform:rotate(0deg); } to { transform:rotate(360deg); } }
 </style>

--
Gitblit v1.7.1