hookehuyr

feat(recall): 新增分享海报功能组件和页面

添加 RecallPoster 组件用于生成分享海报
创建 PosterPage 页面路由和视图
实现海报背景更换、竖排文字绘制和二维码展示功能
...@@ -32,6 +32,7 @@ declare module 'vue' { ...@@ -32,6 +32,7 @@ declare module 'vue' {
32 PdfPreview: typeof import('./components/ui/PdfPreview.vue')['default'] 32 PdfPreview: typeof import('./components/ui/PdfPreview.vue')['default']
33 PdfViewer: typeof import('./components/ui/PdfViewer.vue')['default'] 33 PdfViewer: typeof import('./components/ui/PdfViewer.vue')['default']
34 PostCountModel: typeof import('./components/count/postCountModel.vue')['default'] 34 PostCountModel: typeof import('./components/count/postCountModel.vue')['default']
35 + RecallPoster: typeof import('./components/ui/RecallPoster.vue')['default']
35 ReviewPopup: typeof import('./components/courses/ReviewPopup.vue')['default'] 36 ReviewPopup: typeof import('./components/courses/ReviewPopup.vue')['default']
36 RouterLink: typeof import('vue-router')['RouterLink'] 37 RouterLink: typeof import('vue-router')['RouterLink']
37 RouterView: typeof import('vue-router')['RouterView'] 38 RouterView: typeof import('vue-router')['RouterView']
......
This diff is collapsed. Click to expand it.
1 /* 1 /*
2 * @Date: 2025-03-20 20:36:36 2 * @Date: 2025-03-20 20:36:36
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-12-23 15:31:50 4 + * @LastEditTime: 2025-12-23 15:51:28
5 * @FilePath: /mlaj/src/router/routes.js 5 * @FilePath: /mlaj/src/router/routes.js
6 * @Description: 路由地址映射配置 6 * @Description: 路由地址映射配置
7 */ 7 */
...@@ -139,6 +139,12 @@ export const routes = [ ...@@ -139,6 +139,12 @@ export const routes = [
139 meta: { title: '活动历史' }, 139 meta: { title: '活动历史' },
140 }, 140 },
141 { 141 {
142 + path: '/recall/poster',
143 + name: 'Poster',
144 + component: () => import('../views/recall/PosterPage.vue'),
145 + meta: { title: '分享海报' },
146 + },
147 + {
142 path: '/checkout', 148 path: '/checkout',
143 name: 'CheckoutPage', 149 name: 'CheckoutPage',
144 component: () => import('../views/checkout/CheckoutPage.vue'), 150 component: () => import('../views/checkout/CheckoutPage.vue'),
......
1 +<!--
2 + * @Date: 2025-12-23 15:50:59
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-12-23 16:40:19
5 + * @FilePath: /mlaj/src/views/recall/PosterPage.vue
6 + * @Description: 分享海报页面
7 +-->
8 +<template>
9 + <div class="min-h-screen bg-[#1E40C8] relative flex flex-col">
10 +
11 + <!-- Poster Container (Scrollable Area) -->
12 + <div class="flex-1 overflow-y-auto px-6 pt-6 pb-32 flex flex-col items-center">
13 + <RecallPoster
14 + :bg-url="posterBg"
15 + :title="title"
16 + :logo-url="logoUrl"
17 + :qr-url="qrCodeUrl"
18 + />
19 + </div>
20 +
21 + <!-- Buttons (Fixed at Bottom) -->
22 + <div class="fixed bottom-0 left-0 right-0 bg-[#1E40C8] px-8 py-6 pb-10 flex gap-4 z-50 max-w-md mx-auto w-full">
23 + <van-uploader :after-read="afterRead" accept="image/*" class="flex-1 w-full" :show-upload="false">
24 + <template #default>
25 + <van-button block color="#0052D9" plain
26 + class="!rounded-lg !h-[44px] !text-[15px] !font-bold w-full !border-[#0052D9] !bg-white">
27 + 更换图片
28 + </van-button>
29 + </template>
30 + </van-uploader>
31 + </div>
32 + </div>
33 +</template>
34 +
35 +<script setup>
36 +import { ref } from 'vue'
37 +import { useRoute, useRouter } from 'vue-router'
38 +import { useTitle } from '@vueuse/core'
39 +import RecallPoster from '@/components/ui/RecallPoster.vue'
40 +
41 +const $route = useRoute();
42 +const $router = useRouter();
43 +useTitle('分享海报');
44 +
45 +// Assets
46 +const defaultBg = 'https://cdn.ipadbiz.cn/mlaj/images/test-bgg03.jpg?imageMogr2/thumbnail/800x/strip/quality/80'
47 +const logoUrl = 'https://cdn.ipadbiz.cn/mlaj/recall/poster/kai@2x.png'
48 +const qrCodeUrl = 'https://cdn.ipadbiz.cn/mlaj/recall/poster/%E4%BA%8C%E7%BB%B4%E7%A0%81@2x.png'
49 +
50 +// State
51 +const posterBg = ref(defaultBg)
52 +const title = ref('2017.7.6-7.11 【自然的恩典】“爱我中华”优秀传统文化夏令营-天津场开启~')
53 +
54 +// Actions
55 +const afterRead = (file) => {
56 + // Use Object URL for local preview to avoid uploading
57 + posterBg.value = URL.createObjectURL(file.file)
58 +}
59 +</script>
60 +
61 +<style lang="less" scoped>
62 +:deep(.van-uploader__input-wrapper) {
63 + width: 100%;
64 +}
65 +</style>