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, "banner_image": activity.BannerImage,
"current_stage_background": activity.CurrentStageBackground, "current_stage_background": activity.CurrentStageBackground,
"current_stage_title": activity.CurrentStageTitle, "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"` CurrentProgress int64 `json:"current_progress" gorm:"default:0"`
Status string `json:"status" gorm:"size:20;default:pending"` // pending/active/completed/expired Status string `json:"status" gorm:"size:20;default:pending"` // pending/active/completed/expired
StageConfigs json.RawMessage `json:"stage_configs" gorm:"type:jsonb"` // 阶段配置 StageConfigs json.RawMessage `json:"stage_configs" gorm:"type:jsonb"` // 阶段配置
Icon string `json:"icon" gorm:"size:500"` // 活动图标
CreatedAt int64 `json:"created_at" gorm:"not null"` CreatedAt int64 `json:"created_at" gorm:"not null"`
UpdatedAt int64 `json:"updated_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"` // 当前阶段背景图 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"` // 当前阶段标题 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"` // 整体活动结束时间 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 unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -204,6 +205,13 @@ func (x *Activity) GetOverallEndTime() int64 {
return 0 return 0
} }
func (x *Activity) GetIcon() string {
if x != nil {
return x.Icon
}
return ""
}
// 活动道具 // 活动道具
type ActivityItem struct { type ActivityItem struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@ -1355,7 +1363,7 @@ var File_activity_proto protoreflect.FileDescriptor
const file_activity_proto_rawDesc = "" + const file_activity_proto_rawDesc = "" +
"\n" + "\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" + "\bActivity\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x03R\x02id\x12#\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12#\n" +
"\ractivity_type\x18\x02 \x01(\tR\factivityType\x12\x14\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" + "\fbanner_image\x18\x0e \x01(\tR\vbannerImage\x128\n" +
"\x18current_stage_background\x18\x0f \x01(\tR\x16currentStageBackground\x12.\n" + "\x18current_stage_background\x18\x0f \x01(\tR\x16currentStageBackground\x12.\n" +
"\x13current_stage_title\x18\x10 \x01(\tR\x11currentStageTitle\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" + "\fActivityItem\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x1b\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x1b\n" +
"\titem_type\x18\x02 \x01(\tR\bitemType\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_background = 15; //
string current_stage_title = 16; // string current_stage_title = 16; //
int64 overall_end_time = 18; // 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> --> </view> -->
<!-- 星援活动 --> <!-- 星援活动列表 -->
<view v-if="showStarActivityIcon" class="daily-task-group" @click="handleStarActivityClick"> <view v-if="showStarActivityIcon" class="star-activity-list">
<!-- 1. 上层星援活动悬浮在上面 --> <view
v-for="activity in starActivities"
:key="activity.id"
class="daily-task-group"
@click="handleActivityClick(activity)"
>
<!-- 上层活动图标 -->
<view class="task-icon-box"> <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> <image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
</view> </view>
<!-- 2. 下层文字背景块 --> <!-- 下层文字背景块 -->
<view class="task-text-box"> <view class="task-text-box">
<text class="task-text-label">星援活动</text> <text class="task-text-label">{{ activity.theme || '星援活动' }}</text>
</view>
</view> </view>
</view> </view>
@ -94,9 +101,12 @@ import { useStore } from 'vuex';
import Avatar from './Avatar.vue'; import Avatar from './Avatar.vue';
import DailyTasks from '@/pages/tasks/daily-tasks.vue'; import DailyTasks from '@/pages/tasks/daily-tasks.vue';
import GuideModal from '@/pages/tasks/GuideModal.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'; import { reportEvent } from '@/utils/task-api.js';
// square useBanner
const { bannerActivities, loadBannerActivities } = useBanner();
// props // props
const props = defineProps({ const props = defineProps({
showBack: { showBack: {
@ -226,9 +236,16 @@ function checkAndReportDailyLogin() {
} }
} }
// // - bannerActivities expired
const starActivities = computed(() => {
// return bannerActivities.value
return bannerActivities.value.filter(activity => activity.status !== 'expired');
});
//
onMounted(() => { onMounted(() => {
loadUserInfo(); loadUserInfo();
loadBannerActivities();
uni.$on('avatarUpdated', handleAvatarUpdate); uni.$on('avatarUpdated', handleAvatarUpdate);
uni.$on('userInfoUpdated', handleUserInfoUpdate); uni.$on('userInfoUpdated', handleUserInfoUpdate);
uni.$on('balanceUpdated', handleBalanceUpdate); uni.$on('balanceUpdated', handleBalanceUpdate);
@ -270,58 +287,10 @@ const handleTaskClick = () => {
}; };
// //
const handleStarActivityClick = async () => { const handleActivityClick = (activity) => {
try { if (activity) {
// 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) {
//
uni.navigateTo({ uni.navigateTo({
url: `/pages/support-activity/index?id=${busActivity.id}` url: `/pages/support-activity/index?id=${activity.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'
}); });
} }
}; };
@ -443,6 +412,12 @@ defineExpose({
margin-left: auto; margin-left: auto;
} }
.star-activity-list {
display: flex;
align-items: center;
gap: 8rpx;
}
.daily-task-group { .daily-task-group {
position: relative; position: relative;
/* 必须是相对定位,作为子元素的定位基准 */ /* 必须是相对定位,作为子元素的定位基准 */

View File

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

View File

@ -11,8 +11,9 @@ export function useBanner() {
if (res.code === 200 && res.data?.activities) { if (res.code === 200 && res.data?.activities) {
const activities = 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) { } catch (e) {
console.error('[useBanner] 加载 banner 活动失败', e?.message ?? e) console.error('[useBanner] 加载 banner 活动失败', e?.message ?? e)