feat: 修改活动小按钮改为动态

This commit is contained in:
zerosaturation 2026-05-13 14:41:17 +08:00
parent e81ef0a375
commit 8b03809c7a
8 changed files with 66 additions and 75 deletions

View File

@ -559,6 +559,7 @@ func convertActivityListResponse(resp *pbActivity.GetActivityListResponse) map[s
"banner_image": activity.BannerImage,
"current_stage_background": activity.CurrentStageBackground,
"current_stage_title": activity.CurrentStageTitle,
"icon": activity.Icon,
})
}

View File

@ -20,6 +20,7 @@ type Activity struct {
CurrentProgress int64 `json:"current_progress" gorm:"default:0"`
Status string `json:"status" gorm:"size:20;default:pending"` // pending/active/completed/expired
StageConfigs json.RawMessage `json:"stage_configs" gorm:"type:jsonb"` // 阶段配置
Icon string `json:"icon" gorm:"size:500"` // 活动图标
CreatedAt int64 `json:"created_at" gorm:"not null"`
UpdatedAt int64 `json:"updated_at" gorm:"not null"`

View File

@ -44,6 +44,7 @@ type Activity struct {
CurrentStageBackground string `protobuf:"bytes,15,opt,name=current_stage_background,json=currentStageBackground,proto3" json:"current_stage_background,omitempty"` // 当前阶段背景图
CurrentStageTitle string `protobuf:"bytes,16,opt,name=current_stage_title,json=currentStageTitle,proto3" json:"current_stage_title,omitempty"` // 当前阶段标题
OverallEndTime int64 `protobuf:"varint,18,opt,name=overall_end_time,json=overallEndTime,proto3" json:"overall_end_time,omitempty"` // 整体活动结束时间
Icon string `protobuf:"bytes,19,opt,name=icon,proto3" json:"icon,omitempty"` // 活动图标
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -204,6 +205,13 @@ func (x *Activity) GetOverallEndTime() int64 {
return 0
}
func (x *Activity) GetIcon() string {
if x != nil {
return x.Icon
}
return ""
}
// 活动道具
type ActivityItem struct {
state protoimpl.MessageState `protogen:"open.v1"`
@ -1355,7 +1363,7 @@ var File_activity_proto protoreflect.FileDescriptor
const file_activity_proto_rawDesc = "" +
"\n" +
"\x0eactivity.proto\x12\x10topfans.activity\x1a\x12proto/common.proto\x1a\x1cgoogle/api/annotations.proto\"\xff\x04\n" +
"\x0eactivity.proto\x12\x10topfans.activity\x1a\x12proto/common.proto\x1a\x1cgoogle/api/annotations.proto\"\x93\x05\n" +
"\bActivity\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x03R\x02id\x12#\n" +
"\ractivity_type\x18\x02 \x01(\tR\factivityType\x12\x14\n" +
@ -1377,7 +1385,8 @@ const file_activity_proto_rawDesc = "" +
"\fbanner_image\x18\x0e \x01(\tR\vbannerImage\x128\n" +
"\x18current_stage_background\x18\x0f \x01(\tR\x16currentStageBackground\x12.\n" +
"\x13current_stage_title\x18\x10 \x01(\tR\x11currentStageTitle\x12(\n" +
"\x10overall_end_time\x18\x12 \x01(\x03R\x0eoverallEndTime\"\xc7\x01\n" +
"\x10overall_end_time\x18\x12 \x01(\x03R\x0eoverallEndTime\x12\x12\n" +
"\x04icon\x18\x13 \x01(\tR\x04icon\"\xc7\x01\n" +
"\fActivityItem\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x1b\n" +
"\titem_type\x18\x02 \x01(\tR\bitemType\x12\x1b\n" +

View File

@ -29,6 +29,7 @@ message Activity {
string current_stage_background = 15; //
string current_stage_title = 16; //
int64 overall_end_time = 18; //
string icon = 19; //
}
//

View File

@ -0,0 +1,2 @@
-- 添加 icon 字段到 activities 表
ALTER TABLE activities ADD COLUMN icon VARCHAR(500) DEFAULT '' COMMENT '活动图标';

View File

@ -35,17 +35,24 @@
</view>
</view> -->
<!-- 星援活动 -->
<view v-if="showStarActivityIcon" class="daily-task-group" @click="handleStarActivityClick">
<!-- 1. 上层星援活动悬浮在上面 -->
<!-- 星援活动列表 -->
<view v-if="showStarActivityIcon" class="star-activity-list">
<view
v-for="activity in starActivities"
:key="activity.id"
class="daily-task-group"
@click="handleActivityClick(activity)"
>
<!-- 上层活动图标 -->
<view class="task-icon-box">
<image class="task-icon-img" src="/static/icon/bus-icon.png" mode="aspectFit"></image>
<image class="task-icon-img" :src="activity.icon || '/static/icon/bus-icon.png'" mode="aspectFit"></image>
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
</view>
<!-- 2. 下层文字背景块 -->
<!-- 下层文字背景块 -->
<view class="task-text-box">
<text class="task-text-label">星援活动</text>
<text class="task-text-label">{{ activity.theme || '星援活动' }}</text>
</view>
</view>
</view>
@ -94,9 +101,12 @@ import { useStore } from 'vuex';
import Avatar from './Avatar.vue';
import DailyTasks from '@/pages/tasks/daily-tasks.vue';
import GuideModal from '@/pages/tasks/GuideModal.vue';
import { getActivityListApi } from '@/utils/api.js';
import { useBanner } from '@/pages/square/composables/useBanner.js';
import { reportEvent } from '@/utils/task-api.js';
// square useBanner
const { bannerActivities, loadBannerActivities } = useBanner();
// props
const props = defineProps({
showBack: {
@ -226,9 +236,16 @@ function checkAndReportDailyLogin() {
}
}
//
// - bannerActivities expired
const starActivities = computed(() => {
// return bannerActivities.value
return bannerActivities.value.filter(activity => activity.status !== 'expired');
});
//
onMounted(() => {
loadUserInfo();
loadBannerActivities();
uni.$on('avatarUpdated', handleAvatarUpdate);
uni.$on('userInfoUpdated', handleUserInfoUpdate);
uni.$on('balanceUpdated', handleBalanceUpdate);
@ -270,58 +287,10 @@ const handleTaskClick = () => {
};
//
const handleStarActivityClick = async () => {
try {
// star_id
const starId = uni.getStorageSync('star_id');
if (!starId) {
uni.showToast({
title: '无法获取用户信息',
icon: 'none'
});
return;
}
//
uni.showLoading({
title: '加载中...'
});
// API
const response = await getActivityListApi(starId, 1, 10);
uni.hideLoading();
//
if (response && response.data && response.data.activities) {
const activities = response.data.activities;
// activity_typebus
const busActivity = activities.find(activity => activity.activity_type === 'bus');
if (busActivity) {
//
const handleActivityClick = (activity) => {
if (activity) {
uni.navigateTo({
url: `/pages/support-activity/index?id=${busActivity.id}`
});
} else {
uni.showToast({
title: '暂无巴士应援活动',
icon: 'none'
});
}
} else {
uni.showToast({
title: '获取活动列表失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('获取活动列表失败:', error);
uni.showToast({
title: error.message || '获取活动列表失败',
icon: 'none'
url: `/pages/support-activity/index?id=${activity.id}`
});
}
};
@ -443,6 +412,12 @@ defineExpose({
margin-left: auto;
}
.star-activity-list {
display: flex;
align-items: center;
gap: 8rpx;
}
.daily-task-group {
position: relative;
/* 必须是相对定位,作为子元素的定位基准 */

View File

@ -13,7 +13,7 @@
>
<view
ref="waterfallInnerRef"
class="waterfall-inner ios-css-animate"
:class="{'waterfall-inner': true, 'ios-css-animate': !iosScrollPaused}"
:style="innerStyle"
>
<view
@ -742,13 +742,14 @@ const handleCardClick = (card) => {
});
} else {
//
if(card.id){
cardTapTimers[card.id] = setTimeout(() => {
delete cardTapTimers[card.id];
uni.navigateTo({ url: `/pages/asset-detail/asset-detail?asset_id=${card.id}` });
}, 300);
}
}
}
// ========== ==========
onMounted(() => {
@ -966,7 +967,7 @@ const loadUsersAndStartScroll = () => {
}
@keyframes iosAutoScroll {
from { transform: translateX(0); }
/* from { transform: translateX(0); } */
to { transform: translateX(var(--scroll-dist)); }
}

View File

@ -11,8 +11,9 @@ export function useBanner() {
if (res.code === 200 && res.data?.activities) {
const activities = res.data.activities
// 直接使用后端返回的图片URL
bannerActivities.value = activities
// 过滤掉已过期的活动
// bannerActivities.value = activities
bannerActivities.value = activities.filter(item => item.status !== 'expired')
}
} catch (e) {
console.error('[useBanner] 加载 banner 活动失败', e?.message ?? e)