Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
飞
飞鹤小程序
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
FH
飞鹤小程序
Commits
9d3c12ee
Commit
9d3c12ee
authored
Nov 10, 2025
by
spc
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixed
parent
90fb9427
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
119 additions
and
117 deletions
+119
-117
ActivitySelectedPopup.vue
components/ActivitySelectedPopup.vue
+98
-72
index.vue
pages/index/index.vue
+21
-45
No files found.
components/ActivitySelectedPopup.vue
View file @
9d3c12ee
<
template
>
<view
v-
if
=
"visible"
class=
"activity-selected-popup"
@
tap=
"handleMaskClick"
>
<view
v-
show
=
"visible"
class=
"activity-selected-popup"
@
tap=
"handleMaskClick"
>
<!-- 背景遮罩 -->
<view
class=
"popup-mask"
></view>
<!-- 弹窗容器 -->
<view
class=
"popup-wrapper"
:style=
"popupStyle"
>
<!-- 背景底 -->
<view
class=
"popup-background"
></view>
<!-- 弹窗内容 -->
<view
class=
"popup-content"
@
tap
.
stop
>
<!-- 标题 -->
<view
class=
"popup-title"
>
恭喜你入选啦!
</view>
<!-- 活动列表 -->
<scroll-view
v-if=
"activityList.length > 3"
class=
"activity-scroll"
scroll-y
:scroll-top=
"scrollTop"
>
<view
v-for=
"(activity, index) in activityList"
:key=
"index"
class=
"activity-item"
>
<text
class=
"activity-text"
>
已入选
{{
activity
.
name
||
''
}}
</text>
<view
class=
"activity-btn"
:class=
"
{ disabled: activity.disabled }"
@tap="handleViewActivity(activity, index)"
>
查看活动
<view
v-if=
"activityList.length >= 3"
class=
"activity-scroll-wrapper"
>
<scroll-view
class=
"activity-scroll"
scroll-y
:scroll-top=
"scrollTop"
>
<view
v-for=
"(activity, index) in activityList"
:key=
"index"
class=
"activity-item"
>
<text
class=
"activity-text"
>
已入选
{{
activity
.
name
||
''
}}
</text>
<view
class=
"activity-btn"
:class=
"
{ disabled: activity.disabled }"
@tap="handleViewActivity(activity, index)">
查看活动
</view>
</view>
</scroll-view>
<!-- 底部渐变蒙层 -->
<view
class=
"scroll-fade-mask"
>
<image
class=
"mask-image"
:src=
"`$
{$baseUrl}homepage/Q3Res/actSelectMask.png`" mode="aspectFit">
</image>
</view>
</
scroll-
view>
</view>
<view
v-else
class=
"activity-list"
>
<view
v-for=
"(activity, index) in activityList"
:key=
"index"
class=
"activity-item"
>
<view
v-for=
"(activity, index) in activityList"
:key=
"index"
class=
"activity-item"
>
<text
class=
"activity-text"
>
已入选
{{
activity
.
name
||
''
}}
</text>
<view
class=
"activity-btn"
:class=
"
{ disabled: activity.disabled }"
@tap="handleViewActivity(activity, index)"
>
<view
class=
"activity-btn"
:class=
"
{ disabled: activity.disabled }"
@tap="handleViewActivity(activity, index)">
查看活动
</view>
</view>
</view>
</view>
</view>
<!-- 关闭按钮 -->
<view
class=
"close-btn"
@
tap=
"handleClose"
>
<
text
class=
"close-icon"
>
×
</text
>
<
image
class=
"close-icon"
:src=
"`$
{$baseUrl}homepage/Q3Res/commonCloseBtn.png`" mode="aspectFit">
</image
>
</view>
</view>
</
template
>
<
script
setup
>
import
{
computed
,
ref
}
from
'vue'
import
{
computed
,
ref
,
getCurrentInstance
}
from
'vue'
import
{
fetchUserClickActivity
}
from
'../api/home'
const
{
proxy
}
=
getCurrentInstance
()
const
$baseUrl
=
proxy
.
$baseUrl
const
props
=
defineProps
({
visible
:
{
type
:
Boolean
,
...
...
@@ -85,13 +75,13 @@ const scrollTop = ref(0)
const
popupStyle
=
computed
(()
=>
{
const
count
=
props
.
activityList
.
length
let
height
=
320
// 默认高度(1个活动)160px * 2
if
(
count
===
2
)
{
height
=
420
// 210px * 2
}
else
if
(
count
>=
3
)
{
height
=
520
// 260px * 2,超过3个时内容区域可滚动
}
return
{
height
:
height
+
'rpx'
}
...
...
@@ -102,19 +92,18 @@ const handleViewActivity = async (activity, index) => {
if
(
activity
.
disabled
)
{
return
}
// 调用接口,传单个 activityId
if
(
activity
.
id
)
{
try
{
await
fetchUserClickActivity
({
activityIds
:
[
activity
.
id
]
})
console
.
log
(
'点击活动接口调用成功:'
,
activity
.
id
)
}
catch
(
error
)
{
console
.
error
(
'点击活动接口调用失败:'
,
error
)
// 调用接口,传单个 activityId
if
(
activity
.
id
)
{
try
{
await
fetchUserClickActivity
({
activityIds
:
[
activity
.
id
]
})
}
catch
(
error
)
{
console
.
error
(
'点击活动接口调用失败:'
,
error
)
}
}
}
emit
(
'viewActivity'
,
activity
,
index
)
}
...
...
@@ -124,18 +113,17 @@ const handleClose = async () => {
const
activityIds
=
props
.
activityList
.
filter
(
activity
=>
activity
.
id
)
.
map
(
activity
=>
activity
.
id
)
if
(
activityIds
.
length
>
0
)
{
try
{
await
fetchUserClickActivity
({
activityIds
:
activityIds
})
console
.
log
(
'关闭弹窗接口调用成功:'
,
activityIds
)
}
catch
(
error
)
{
console
.
error
(
'关闭弹窗接口调用失败:'
,
error
)
}
}
emit
(
'close'
)
}
...
...
@@ -152,12 +140,18 @@ const handleMaskClick = (e) => {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 99999 !important;
display: flex;
align-items: center;
justify-content: center;
pointer-events: auto;
/* #ifdef MP-WEIXIN */
z-index: 99999;
/* #endif */
}
.popup-mask {
...
...
@@ -201,20 +195,48 @@ const handleMaskClick = (e) => {
.popup-title {
font-size: 36rpx;
font-weight: bold;
color: #
FFA500
;
color: #
D3A458
;
text-align: center;
margin-bottom: 40rpx;
}
.activity-scroll {
.activity-scroll-wrapper {
position: relative;
max-height: 360rpx;
height: 360rpx;
}
.activity-scroll {
max-height: 250rpx;
height: 250rpx;
}
/* 底部渐变蒙层 */
.scroll-fade-mask {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 85rpx;
pointer-events: none;
z-index: 10;
display: flex;
align-items: flex-end;
justify-content: center;
}
.mask-image {
width: 546rpx;
height: 170rpx;
flex-shrink: 0;
object-fit: cover;
}
.activity-list {
display: flex;
flex-direction: column;
gap: 3
0
rpx;
gap: 3
5
rpx;
}
.activity-item {
...
...
@@ -231,13 +253,19 @@ const handleMaskClick = (e) => {
}
.activity-btn {
padding: 12rpx 32rpx;
background: linear-gradient(180deg, #FFA500 0%, #FF8C00 100%);
border-radius: 30rpx;
display: flex;
width: 160rpx;
height: 60rpx;
justify-content: center;
align-items: center;
gap: 20rpx;
flex-shrink: 0;
border-radius: 44rpx;
background: #D3A358;
color: #FFFFFF;
font-size: 24rpx;
text-align: center;
min-width: 140rp
x;
box-sizing: border-bo
x;
}
.activity-btn.disabled {
...
...
@@ -247,12 +275,12 @@ const handleMaskClick = (e) => {
.close-btn {
position: absolute;
bottom: -8
0rpx;
top: 113
0rpx;
left: 50%;
transform: translateX(-50%);
width:
60
rpx;
height:
60
rpx;
background-color:
#FFFFFF
;
width:
56
rpx;
height:
56
rpx;
background-color:
rgba(255, 255, 255, 0.5)
;
border-radius: 50%;
display: flex;
align-items: center;
...
...
@@ -261,9 +289,7 @@ const handleMaskClick = (e) => {
}
.close-icon {
font-size: 40rpx;
color: #666666;
line-height: 1;
width: 56rpx;
height: 56rpx;
}
</
style
>
pages/index/index.vue
View file @
9d3c12ee
...
...
@@ -13,16 +13,19 @@
}">
<!--
<text
class=
"back-text"
>
返回app
</text>
-->
</button>
<!-- 活动入选弹窗 -->
<ActivitySelectedPopup
:visible=
"showActivitySelectedPopup"
:activityList=
"selectedActivityList"
@
close=
"showActivitySelectedPopup = false"
@
viewActivity=
"handleViewActivity"
/>
</view>
<!-- 活动入选弹窗 - 移到容器外部,确保 fixed 定位正确 -->
<ActivitySelectedPopup
v-if=
"showActivitySelectedPopup || selectedActivityList.length > 0"
:visible=
"showActivitySelectedPopup"
:activityList=
"selectedActivityList"
@
close=
"showActivitySelectedPopup = false"
@
viewActivity=
"handleViewActivity"
/>
</
template
>
<
script
setup
>
import
{
ref
,
getCurrentInstance
,
watch
,
onMounted
}
from
"vue"
;
import
{
ref
,
getCurrentInstance
,
watch
,
onMounted
,
nextTick
}
from
"vue"
;
import
{
onLoad
,
onShareAppMessage
,
onShareTimeline
,
onPageScroll
,
onShow
}
from
"@dcloudio/uni-app"
;
import
TabBar
from
"@/components/TabBar.vue"
;
import
Home
from
"@/views/Home.vue"
;
...
...
@@ -46,7 +49,6 @@ const isBackApp = ref(false);
// 活动入选弹窗
const
showActivitySelectedPopup
=
ref
(
false
);
const
selectedActivityList
=
ref
([]);
const
hasShownActivityPopup
=
ref
(
false
);
// 标记是否已经显示过弹窗
const
shareOptions
=
{
0
:
{
title
:
"8000万中国妈妈信赖的育儿品牌"
,
...
...
@@ -88,45 +90,28 @@ function handleTabClick({ index }) {
// 查看活动
const
handleViewActivity
=
(
activity
,
index
)
=>
{
console
.
log
(
'查看活动:'
,
activity
,
index
)
// 接口调用已在组件内部完成,这里只需要处理跳转逻辑
// 根据 activityUri 跳转到对应页面
const
uri
=
activity
.
uri
||
activity
.
activityUri
if
(
!
uri
)
{
console
.
warn
(
'活动没有跳转地址'
)
return
}
console
.
log
(
'跳转到活动页面:'
,
uri
)
// 判断跳转类型
// H5 链接
jump
({
type
:
JumpType
.
H5
,
url
:
uri
})
}
// 显示活动入选弹窗
const
showActivitySelectedPopupFunc
=
(
activityList
)
=>
{
selectedActivityList
.
value
=
activityList
||
[]
showActivitySelectedPopup
.
value
=
true
}
// 检查并显示活动入选弹窗
const
checkAndShowActivityPopup
=
()
=>
{
// 如果已经显示过弹窗,不再重复显示
if
(
hasShownActivityPopup
.
value
)
{
console
.
log
(
'活动入选弹窗已显示过,跳过'
)
return
}
const
memberInfo
=
userStore
.
memberInfo
console
.
log
(
'检查活动入选弹窗 - memberInfo:'
,
memberInfo
)
console
.
log
(
'检查活动入选弹窗 - passedActivityList:'
,
memberInfo
?.
passedActivityList
)
if
(
memberInfo
&&
memberInfo
.
passedActivityList
&&
memberInfo
.
passedActivityList
.
length
>
0
)
{
// 只要后端返回有值就显示弹窗
if
(
memberInfo
?.
passedActivityList
&&
Array
.
isArray
(
memberInfo
.
passedActivityList
)
&&
memberInfo
.
passedActivityList
.
length
>
0
)
{
// 将 passedActivityList 转换为组件需要的格式
const
activityList
=
memberInfo
.
passedActivityList
.
map
(
item
=>
({
id
:
item
.
activityId
,
...
...
@@ -135,35 +120,21 @@ const checkAndShowActivityPopup = () => {
disabled
:
false
}))
console
.
log
(
'转换后的活动列表:'
,
activityList
)
selectedActivityList
.
value
=
activityList
showActivitySelectedPopup
.
value
=
true
hasShownActivityPopup
.
value
=
true
// 标记已显示
console
.
log
(
'显示活动入选弹窗:'
,
activityList
)
}
else
{
console
.
log
(
'没有活动入选数据,不显示弹窗'
)
}
}
// 监听 memberInfo 变化,检查是否有 passedActivityList
watch
(()
=>
userStore
.
memberInfo
,
(
newVal
,
oldVal
)
=>
{
if
(
newVal
&&
newVal
.
passedActivityList
&&
newVal
.
passedActivityList
.
length
>
0
)
{
// 检查是否是新的活动列表(通过比较 activityId 来判断)
const
oldActivityIds
=
oldVal
?.
passedActivityList
?.
map
(
item
=>
item
.
activityId
)
||
[]
const
newActivityIds
=
newVal
.
passedActivityList
.
map
(
item
=>
item
.
activityId
)
// 如果有新的活动,重置标记并显示弹窗
const
hasNewActivity
=
newActivityIds
.
some
(
id
=>
!
oldActivityIds
.
includes
(
id
))
if
(
hasNewActivity
)
{
hasShownActivityPopup
.
value
=
false
}
watch
(()
=>
userStore
.
memberInfo
,
(
newVal
)
=>
{
// 只要后端返回有值就显示弹窗
if
(
newVal
?.
passedActivityList
&&
Array
.
isArray
(
newVal
.
passedActivityList
)
&&
newVal
.
passedActivityList
.
length
>
0
)
{
// 延迟一下,确保页面已经渲染完成
setTimeout
(()
=>
{
checkAndShowActivityPopup
()
},
300
)
}
},
{
deep
:
true
})
},
{
deep
:
true
,
immediate
:
false
})
onLoad
(
async
(
options
)
=>
{
const
optionsSync
=
wx
.
getEnterOptionsSync
()
...
...
@@ -198,14 +169,19 @@ onLoad(async (options) => {
// 加载会员信息,检查是否有活动入选
if
(
userStore
.
isLogin
)
{
await
userStore
.
loadMemberInfo
()
// 使用 nextTick 确保数据已更新
await
nextTick
()
checkAndShowActivityPopup
()
}
});
onShow
(
async
()
=>
{
// 页面显示时,如果已登录,刷新会员信息
(但不强制显示弹窗,由 watch 监听处理)
// 页面显示时,如果已登录,刷新会员信息
if
(
userStore
.
isLogin
)
{
await
userStore
.
loadMemberInfo
()
// 使用 nextTick 确保数据已更新后再检查
await
nextTick
()
checkAndShowActivityPopup
()
}
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment