PosterPage.vue
4.24 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
<!--
* @Date: 2025-12-23 15:50:59
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-23 17:07:47
* @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
:bg-url="posterBg"
:title="title"
:logo-url="logoUrl"
:qr-url="qrCodeUrl"
/>
</div>
<!-- Buttons (Fixed at Bottom) -->
<div class="fixed bottom-0 left-0 right-0 px-8 py-3 flex gap-4 z-50 max-w-md mx-auto w-full">
<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>
</template>
<script setup>
import { ref } 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'
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'
const qrCodeUrl = 'https://cdn.ipadbiz.cn/mlaj/recall/poster/%E4%BA%8C%E7%BB%B4%E7%A0%81@2x.png'
// State
const posterBg = ref(defaultBg)
const title = ref('2017.7.6-7.11 【自然的恩典】“爱我中华”优秀传统文化夏令营-天津场开启~')
/**
* 获取文件哈希(与七牛云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;
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;
showToast('图片上传成功');
}
}
}
} catch (error) {
console.error('图片上传失败:', error)
showToast('图片上传失败,请重试')
} finally {
toast.close();
}
}
</script>
<style lang="less" scoped>
:deep(.van-uploader__input-wrapper) {
width: 100%;
}
</style>