feat: 修改活动小按钮改为动态
This commit is contained in:
parent
e81ef0a375
commit
8b03809c7a
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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"`
|
||||||
|
|
||||||
|
|||||||
@ -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" +
|
||||||
|
|||||||
@ -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; // 活动图标
|
||||||
}
|
}
|
||||||
|
|
||||||
// 活动道具
|
// 活动道具
|
||||||
|
|||||||
2
backend/scripts/migrate_add_icon_to_activities.sql
Normal file
2
backend/scripts/migrate_add_icon_to_activities.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- 添加 icon 字段到 activities 表
|
||||||
|
ALTER TABLE activities ADD COLUMN icon VARCHAR(500) DEFAULT '' COMMENT '活动图标';
|
||||||
@ -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_type为bus的活动
|
|
||||||
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;
|
||||||
/* 必须是相对定位,作为子元素的定位基准 */
|
/* 必须是相对定位,作为子元素的定位基准 */
|
||||||
|
|||||||
@ -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,12 +742,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 初始化 ==========
|
// ========== 初始化 ==========
|
||||||
@ -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)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user