PosterPage.vue
5.82 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
<!--
* @Date: 2025-12-23 15:50:59
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-31 17:04:10
* @FilePath: /mlaj/src/views/recall/PosterPage.vue
* @Description: 分享海报页面
-->
<template>
<div class="min-h-screen bg-[#1E40C8] relative flex flex-col">
<!-- Poster Container (Scrollable Area) -->
<div class="flex-1 overflow-y-auto px-6 pt-6 pb-32 flex flex-col items-center">
<RecallPoster
v-if="isReady"
:bg-url="posterBg"
:title="title"
:logo-url="logoUrl"
:qr-url="qrCodeUrl"
/>
<div v-else class="w-full h-[62vh] min-h-[400px] flex items-center justify-center">
<van-loading color="#ffffff" vertical>加载中...</van-loading>
</div>
</div>
<!-- Buttons (Fixed at Bottom) -->
<div class="fixed bottom-0 left-0 right-0 px-8 py-3 z-50 max-w-md mx-auto w-full">
<div class="flex gap-4">
<van-uploader :after-read="afterRead" accept="image/*" class="flex-1 w-full" :show-upload="false">
<template #default>
<van-button block color="#0052D9" plain
class="!rounded-lg !h-[44px] !text-[15px] !font-bold w-full !border-[#0052D9] !bg-white">
更换图片
</van-button>
</template>
</van-uploader>
</div>
<div class="mt-2 text-[12px] leading-[16px] text-white/80 text-center">
上传您参加活动时的照片,制作独有海报
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTitle } from '@vueuse/core'
import RecallPoster from '@/components/ui/RecallPoster.vue'
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common'
import { showToast, showLoadingToast } from 'vant'
import { qiniuFileHash } from '@/utils/qiniuFileHash'
import { useAuth } from '@/contexts/auth'
import { getPosterAPI, editPosterAPI, trackingAPI } from '@/api/recall_users'
const $route = useRoute();
const $router = useRouter();
const { currentUser } = useAuth();
useTitle('分享海报');
// Assets
const defaultBg = 'https://cdn.ipadbiz.cn/mlaj/images/test-bgg03.jpg?imageMogr2/thumbnail/800x/strip/quality/80'
const logoUrl = 'https://cdn.ipadbiz.cn/mlaj/recall/poster/kai@2x.png'
// State
const posterBg = ref(defaultBg)
const qrCodeUrl = ref('')
const isReady = ref(false)
/**
* 获取文件哈希(与七牛云ETag一致)
*/
const getFileMD5 = async (file) => {
return await qiniuFileHash(file)
}
// 上传到七牛云
const uploadToQiniu = async (file, token, fileName) => {
const formData = new FormData()
formData.append('file', file)
formData.append('token', token)
formData.append('key', fileName)
const config = {
headers: { 'Content-Type': 'multipart/form-data' }
}
// 根据协议选择上传地址
const qiniuUploadUrl = window.location.protocol === 'https:'
? 'https://up.qbox.me'
: 'http://upload.qiniu.com'
return await qiniuUploadAPI(qiniuUploadUrl, formData, config)
}
// Actions
const afterRead = async (file) => {
const toast = showLoadingToast({
message: '上传中...',
forbidClick: true,
duration: 0 // 持续展示
});
try {
// 获取MD5值
const md5 = await getFileMD5(file.file)
// 获取七牛token
const tokenResult = await qiniuTokenAPI({
name: file.file.name,
hash: md5
})
// 文件已存在,直接使用
if (tokenResult.data) {
posterBg.value = tokenResult.data.src + '?imageMogr2/thumbnail/800x/strip/quality/80';
// 编辑海报配置
await editPosterAPI({
stu_uid: stu_uid.value,
campaign_id: campaign_id.value,
background_image: tokenResult.data.src
})
showToast('图片上传成功');
return;
}
// 新文件上传
if (tokenResult.token) {
const suffix = /.[^.]+$/.exec(file.file.name) || ''
// 使用 recall/poster 路径
const mobile = currentUser.value?.mobile || 'guest'
const fileName = `mlaj/upload/recall/poster/${mobile}/${md5}${suffix}`
const { filekey, image_info } = await uploadToQiniu(
file.file,
tokenResult.token,
fileName
)
if (filekey) {
// 保存文件信息
const { data } = await saveFileAPI({
name: file.file.name,
filekey,
hash: md5,
height: image_info?.height,
width: image_info?.width
})
if (data) {
posterBg.value = data.src + '?imageMogr2/thumbnail/800x/strip/quality/80';
// 编辑海报配置
await editPosterAPI({
stu_uid: stu_uid.value,
campaign_id: campaign_id.value,
background_image: data.src
})
showToast('图片上传成功');
}
}
}
} catch (error) {
console.error('图片上传失败:', error)
showToast('图片上传失败,请重试')
} finally {
toast.close();
}
}
const stu_uid = ref($route.query.stu_uid || '')
const campaign_id = ref($route.query.campaign_id || '')
const title = ref($route.query.title || '活动海报')
onMounted(async () => {
// 埋点
trackingAPI({
event_type: 'share_poster',
campaign_id: campaign_id.value,
stu_uid: stu_uid.value
})
if (stu_uid.value && campaign_id.value) {
const { code, data } = await getPosterAPI({
stu_uid: stu_uid.value,
campaign_id: campaign_id.value
})
if (code) {
posterBg.value = data.background_image ? data.background_image + '?imageMogr2/thumbnail/800x/strip/quality/80' : defaultBg
qrCodeUrl.value = data?.qrcode || ''
isReady.value = true
}
} else {
// 如果没有参数,也设置为 ready,显示默认背景
isReady.value = true
}
})
</script>
<style lang="less" scoped>
:deep(.van-uploader__input-wrapper) {
width: 100%;
}
</style>