ActivityHistoryPage.vue
8.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<template>
<div class="activity-history-page w-full min-h-screen bg-[#F7F8FA] relative pb-[140px]">
<!-- Header Banner -->
<div class="w-full relative h-[180px] overflow-hidden">
<img :src="historyBg" class="w-full h-full object-cover" alt="History Banner" />
<div class="absolute inset-0 flex flex-col justify-center items-center text-center px-4">
<h1 class="text-[#FFDD01] text-3xl font-bold mb-2 tracking-wider drop-shadow-md mt-3">{{ recordDate }}</h1>
<h2 class="text-white text-2xl font-bold mb-4 tracking-wider drop-shadow-md">您的活动历史</h2>
<div class="w-full max-w-md rounded-lg px-4 py-2"
style="background: linear-gradient(96deg, rgba(82,88,254,0) 0%, #5258FE 47%, rgba(92,106,241,0) 100%);">
<p class="text-white text-xs leading-tight opacity-90">
查看并确认您参与的星球活动记录,<br>
如果有缺失,点击没找到我的星球活动,进行补充
</p>
</div>
</div>
</div>
<!-- Filter Bar -->
<div class="bg-white px-4 py-3 flex justify-between items-center sticky top-0 z-20 shadow-sm">
<span class="text-[#333] font-medium text-sm">活动记录</span>
<div class="flex items-center text-[#666] text-sm">
<span>{{ activities.length }}条</span>
</div>
</div>
<!-- List -->
<div class="px-4 py-4 space-y-4">
<div v-for="item in activities" :key="item.id"
class="bg-white rounded-xl py-4 pr-4 pl-0 shadow-sm relative overflow-hidden flex">
<!-- Blue Marker (Absolute or Flex) -->
<!-- Based on image, it is sticking to the left edge but inside the card padding area potentially, or flush left -->
<!-- Looking at image, it is flush left to the card container -->
<div class="w-1 h-4 bg-[#0052D9] rounded-r-sm mt-1 shrink-0 self-start"></div>
<div class="pl-3 flex-1">
<h3 class="text-[#333] font-bold text-base leading-snug">
{{ item.title }}
</h3>
<div class="border-t border-dashed border-gray-200 my-3"></div>
<div class="flex justify-between items-center text-xs text-[#666] mb-2">
<span>单价: ¥{{ item.price.toFixed(2) }}/人</span>
<!-- <span>人数: {{ item.count }}</span> -->
<span class="text-[#FF3B30] font-bold">实付金额: ¥{{ item.price.toFixed(2) }}</span>
</div>
<div class="flex justify-between items-center text-xs text-[#666] mb-4">
<!-- <span>下单时间: {{ item.date }}</span> -->
<!-- <span class="text-[#FF3B30] font-bold">实付金额: ¥{{ item.total.toFixed(0) }}</span> -->
</div>
<div class="flex justify-end">
<van-button size="small" plain color="#0052D9" class="!rounded-full !px-4 !h-[28px] !text-xs"
@click="handleGeneratePoster(item)">
生成活动海报
</van-button>
</div>
</div>
</div>
</div>
<!-- Fixed Bottom Buttons -->
<div
class="fixed bottom-0 left-0 right-0 bg-white/60 backdrop-blur-md p-4 pb-8 z-30 shadow-[0_-2px_10px_rgba(0,0,0,0.05)]">
<van-button v-if="!userInfo.has_activity_registration" block color="#0052D9" class="!rounded-lg !mb-3 !h-[44px] !text-base !font-bold"
@click="handleCollectCoins">
收集星球币
</van-button>
<van-button v-else block color="#0052D9" class="!rounded-lg !mb-3 !h-[44px] !text-base !font-bold"
@click="handleViewCoins">
查看星球币
</van-button>
<van-button block plain color="#0052D9" class="!rounded-lg !h-[44px] !text-base !font-medium"
@click="showApplyHistoryPopup = true">
<template #icon>
<van-icon name="question-o" class="mr-1" />
</template>
没找到我的星球活动
</van-button>
</div>
<ActivityApplyHistoryPopup v-model:show="showApplyHistoryPopup" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useTitle } from '@vueuse/core'
import { showToast } from 'vant'
import ActivityApplyHistoryPopup from '@/components/activity/ActivityApplyHistoryPopup.vue'
import { userInfoAPI, searchOldActivityAPI } from '@/api/recall_users'
import { oldActivityBatchActivityRegistrationAPI } from '@/api/points'
const historyBg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/history_bg@2x.png'
const router = useRouter()
useTitle('活动历史')
const activities = ref([])
// State
const showApplyHistoryPopup = ref(false)
// 处理生成海报
const handleGeneratePoster = (item) => {
router.push({
path: '/recall/poster',
query: {
title: item.title, stu_uid: item.stu_uid, campaign_id: item.id
}
})
}
const handleCollectCoins = async () => {
if (activities.value.length === 0) {
showToast({
message: '暂无活动可收集',
})
return
}
// 从缓存获取用户信息
const cachedUserInfo = localStorage.getItem('cached_user_info')
if (cachedUserInfo) {
const userInfo = JSON.parse(cachedUserInfo)
// 调用积分接口
const res = await oldActivityBatchActivityRegistrationAPI({
name: userInfo.name || '',
mobile: userInfo.phone || '',
idcard: userInfo.idCard || '',
old_activity_data: activityInfo.value
})
if (res.code === 1) {
showToast({
message: '收集星球币成功',
icon: 'success'
})
router.push({ path: '/recall/points' })
} else {
showToast({
message: '收集星球币失败',
icon: 'error'
})
}
}
}
/**
* 查看星球币
*/
const handleViewCoins = () => {
router.push({ path: '/recall/points' })
}
const userInfo = ref({});
const campaign_info = ref([]);
const activityInfo = ref({})
// 记录日期
const recordDate = ref('')
/**
* 映射活动数据
* @param campaign_list 活动列表
* @returns 映射后的活动列表
*/
const mapCampaignToActivities = (campaign_list) => {
return (campaign_list || []).map(item => ({
id: item.campaign_id || 0,
stu_uid: item.stu_uid || '',
title: item.campaign_name || '',
price: item.fee_stu || 0,
count: item.stu_cnt || 0,
date: item.campaign_year || '',
total: item.fee_stu * item.stu_cnt || 0
}))
}
/**
* 设置记录日期
* @param activity_list 活动列表
*/
const setRecordDateByActivities = (activity_list) => {
const sorted_dates = (activity_list || []).map(item => item.date).sort((a, b) => new Date(a) - new Date(b))
recordDate.value = sorted_dates.length ? `${sorted_dates[0]}-2025` : ''
}
/**
* 处理活动响应
* @param activity_res 活动响应
* @param should_set_activity_info 是否设置活动信息
*/
const applyActivityResponse = (activity_res, should_set_activity_info) => {
if (!activity_res || !activity_res.code) return
if (should_set_activity_info) {
activityInfo.value = activity_res.data || {}
}
campaign_info.value = activity_res.data?.campaign_info || []
if (!campaign_info.value.length) return
activities.value = mapCampaignToActivities(campaign_info.value)
setRecordDateByActivities(activities.value)
}
/**
* 获取缓存用户参数
* @returns 缓存用户参数
*/
const getCachedUserParams = () => {
const cached_user_info = localStorage.getItem('cached_user_info')
if (!cached_user_info) return { has_cache: false, params: null }
try {
const user_info = JSON.parse(cached_user_info)
if (user_info?.name && user_info?.phone && user_info?.idCard) {
return {
has_cache: true,
params: {
name: user_info.name,
mobile: user_info.phone,
idcard: user_info.idCard
}
}
}
} catch (e) {
return { has_cache: true, params: null }
}
return { has_cache: true, params: null }
}
onMounted(async () => {
// 从缓存获取用户信息
const { has_cache, params } = getCachedUserParams()
if (has_cache) {
if (params) {
const activity_res = await searchOldActivityAPI(params)
applyActivityResponse(activity_res, true)
}
} else {
const activity_res = await searchOldActivityAPI()
applyActivityResponse(activity_res, false)
}
// 获取用户信息
const userInfoRes = await userInfoAPI()
if (userInfoRes.code === 1) {
userInfo.value = userInfoRes.data.user || {};
}
})
</script>
<style lang="less" scoped>
// Custom Scrollbar hide for cleaner look if needed
::-webkit-scrollbar {
width: 0px;
background: transparent;
}
</style>