海报update

This commit is contained in:
lanzhihui 2026-04-15 16:13:19 +08:00
parent ac431927b7
commit 7c1fdb0647
3 changed files with 212 additions and 154 deletions

View File

@ -118,7 +118,7 @@ router.beforeEach((to, from, next) => {
if (!IS_PROD) { if (!IS_PROD) {
localStorage.setItem( localStorage.setItem(
'saas_token', 'saas_token',
'eyJpdiI6ImNoV0hTOFJCSjlSMklkYis4OHUrblE9PSIsInZhbHVlIjoicGZCZjFjS3d1UUl0ek1sUW52aVdqcGo2V0VwZGE4SCtpZTUrS1lGQ0czcDJLcDB2YlpENlNZd28xNkl1ZGJCTiIsIm1hYyI6IjhkYzlkMzAzZGQ2YTljMTVlY2YwOWIxMmQ2Y2I0ODE2M2Y5MDExNDdjMWMxZWU0ZDYyNWNmNmFkYTlhMmMzNTEifQ==' 'eyJpdiI6IlAzSFM4cHFJT01RN3R3OUMxV0ptM3c9PSIsInZhbHVlIjoiNFl6QUhcL3daME9QOTZjTVMzTFpJeUtJZ01NZ3hBb0ZtYmlRSlk5ZkVmK2l3Q1NSUGhRNm5GYXE2ZHo4TUtTVDQiLCJtYWMiOiJjODdkY2ZjYjc2NjI4MjkwMDUyNmQ3OGNmNjc1YTc0MGY5ZjNiZjYyZjBmMGYxZWNkMzEwNzhhMjZlMWJlY2FhIn0='
) )
localStorage.setItem('authorize_at', '2022-01-17 10:39:24') localStorage.setItem('authorize_at', '2022-01-17 10:39:24')
} }

View File

@ -6,7 +6,7 @@ import { baseApi, baseApiV2 } from '@/config'
import store from '@/store' import store from '@/store'
import router from '@/router' import router from '@/router'
const service = axios.create({ const service = axios.create({
baseURL: location.href.includes('https') ? '/api' : baseApiV2, // url = base api url + request url baseURL: location.href.includes('https') ? '/api' : 'https://love.ufutx.cn/api', // url = base api url + request url
withCredentials: false, // send cookies when cross-domain requests withCredentials: false, // send cookies when cross-domain requests
timeout: 12000, // request timeout timeout: 12000, // request timeout
headers: { headers: {

View File

@ -25,10 +25,17 @@
<span class="confirm-btn" @click="showActivityPicker = false">确定</span> <span class="confirm-btn" @click="showActivityPicker = false">确定</span>
</div> </div>
<div class="scroll-wrapper"> <div class="scroll-wrapper">
<van-list v-model:loading="listLoading" :finished="listFinished" finished-text="没有更多活动了" <van-list
v-model:loading="listLoading"
:finished="listFinished"
finished-text="没有更多活动了"
@load="onLoadMore"> @load="onLoadMore">
<div v-for="item in activityList" :key="item.id" class="activity-item" <div
:class="{ active: selectedActivity?.id === item.id }" @click="onSelectActivity(item)"> v-for="item in activityList"
:key="item.id"
class="activity-item"
:class="{ active: selectedActivity?.id === item.id }"
@click="onSelectActivity(item)">
<div class="activity-title">{{ item.title }}</div> <div class="activity-title">{{ item.title }}</div>
<div class="activity-time">{{ item.Subtitle }} | {{ formatDateToShow(item.end_time) }}</div> <div class="activity-time">{{ item.Subtitle }} | {{ formatDateToShow(item.end_time) }}</div>
</div> </div>
@ -91,177 +98,221 @@
</div> </div>
</template> </template>
<script setup> <script>
import { nextTick, onMounted, ref, watch } from 'vue' import { nextTick } from 'vue' // Vue 2 vue nextTick使 this.$nextTick
import html2canvas from 'html2canvas' import html2canvas from 'html2canvas'
import { showDialog, showImagePreview, showLoadingToast, showToast } from 'vant' import { ImagePreview, Icon, Loading } from 'vant'
import requestApp from '@/utils/requestApp' import { $toastText, $toastSuccess, $toastLoading, $toastClear } from '@/config/toast'
import requestApp from '@/utils/request'
import QRCode from 'qrcode' import QRCode from 'qrcode'
import { weXinShare } from '@/plugins/wxShare' import Vue from 'vue'
// 🔥 Vue.use(Icon)
const sponsorName = ref('') Vue.use(Loading)
const posterRef = ref(null) export default {
const posterImg = ref('') name: 'ActivityPoster',
const isGenerating = ref(false) data() {
const isWeChatEnv = ref(false) return {
const qrcodeCanvas = ref(null) // ( ref reactive)
sponsorName: '',
posterImg: '',
isGenerating: false,
isWeChatEnv: false,
activityList: [],
selectedActivity: null,
selectedActivityTitle: '',
showActivityPicker: false,
listLoading: false,
listFinished: true,
openId: ''
// qrcodeCanvas DOM mounted this.$refs 访
}
},
mounted() {
// onMounted
this.detectWeChatEnv()
this.getData()
console.log('33')
},
methods: {
// script setup
async getData() {
console.log('33455')
const vm = this
const activityList = ref([]) this.listLoading = true
const selectedActivity = ref(null) // weXinShare Vue 2
const selectedActivityTitle = ref('') vm.$nextTick(() => {
const showActivityPicker = ref(false) setTimeout(() => {
const listLoading = ref(false) // if (vm.$store.state.app.configData) {
const listFinished = ref(true) const urls = `${vm.$shareCallback}/api/official/live/wechat/FamilyAuth?from_openid=${localStorage.getItem('openid')}&merchant_id=${vm.$store.state.app.merchant_id}&spread_merchant_id=${vm.$store.state.app.spread_merchant_id}&url=` + encodeURIComponent(`${vm.$shareCallback}/pu/#/VIPDetail/${vm.id}`)
const openId = ref('') vm.$shareList(
'https://image.fulllinkai.com/202310/28/88e931a50ec0a8094fb46191b389457e.png?x-oss-process=image/resize,w_200,h_200',
urls,
'查看详情',
'活动海报生成「saas」'
)
// }
}, 300)
})
// vm.$shareList('https://image.fulllinkai.com/202310/28/88e931a50ec0a8094fb46191b389457e.png',
// `https://health.ufutx.cn/go_html/role_apply#/activityPoster`,
// '', 'saas')
// + try {
watch(selectedActivity, async (newVal) => { const res = await requestApp({
if (newVal && newVal.id && qrcodeCanvas.value) { url: '/s/h5/uftx/community/activity/list',
// method: 'get'
sponsorName.value = newVal.sponsor || '' })
openId.value = localStorage.getItem('openid') console.log(res, 'res---')
const link = `https://love.ufutx.cn/api/official/live/wechat/FamilyAuth?merchant_id=44&serve_tab=&from_openid=${openId.value}&url=https%3A%2F%2Flove.ufutx.cn%2Fpu%2F%23%2FactivityDetails%2F${newVal.id}`
await QRCode.toCanvas(qrcodeCanvas.value, link, {
width: 76,
margin: 1,
color: { dark: '#000000', light: '#ffffff' }
})
}
})
const getData = () => { if (Array.isArray(res)) {
listLoading.value = true this.activityList = res
weXinShare('https://image.fulllinkai.com/202310/28/88e931a50ec0a8094fb46191b389457e.png', `https://health.ufutx.cn/go_html/role_apply#/activityPoster`, '活动海报生成「saas」', '查看详情') } else {
requestApp({ url: '/sh5/uftx/community/activity/list', method: 'get' }) $toastText('活动列表获取失败')
.then((res) => { }
if (res.code === 0 && Array.isArray(res.data)) { console.log(this.activityList, ' this.activityList')
activityList.value = res.data } catch (err) {
// console.error('获取活动列表失败:', err)
// if (res.data.length > 0) { $toastText('活动列表获取失败,请重试')
// onSelectActivity(res.data[0]); } finally {
// } this.listLoading = false
} else { this.listFinished = true
showToast('活动列表获取失败') $toastClear()
} }
}) },
.catch((err) => {
console.error('获取活动列表失败:', err)
showToast('活动列表获取失败,请重试')
})
.finally(() => {
listLoading.value = false
listFinished.value = true
})
}
const detectWeChatEnv = () => { detectWeChatEnv() {
const userAgent = navigator.userAgent.toLowerCase() const userAgent = navigator.userAgent.toLowerCase()
isWeChatEnv.value = /micromessenger/.test(userAgent) this.isWeChatEnv = /micromessenger/.test(userAgent)
} },
// onSelectActivity(item) {
const onSelectActivity = (item) => { this.selectedActivity = item
selectedActivity.value = item this.selectedActivityTitle = item.title
selectedActivityTitle.value = item.title this.showActivityPicker = false
showActivityPicker.value = false this.generatePoster()
generatePoster() },
}
const onLoadMore = () => { onLoadMore() {
listLoading.value = false this.listLoading = false
listFinished.value = true this.listFinished = true
} },
const formatDateToShow = (timeStr) => { formatDateToShow(timeStr) {
if (!timeStr) return '' if (!timeStr) return ''
const date = new Date(timeStr) const date = new Date(timeStr)
const year = date.getFullYear() const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0') const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0')
return `${year}${month}${day}` return `${year}${month}${day}`
} },
const formatDateToChinese = (timeStr) => { formatDateToChinese(timeStr) {
if (!timeStr) { if (!timeStr) {
const now = new Date() const now = new Date()
const year = now.getFullYear() const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0') const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0') const day = String(now.getDate()).padStart(2, '0')
return `${year}/${month}/${day}` return `${year}/${month}/${day}`
} }
const [datePart] = timeStr.split(' ') const [datePart] = timeStr.split(' ')
const [year, month, day] = datePart.split('-') const [year, month, day] = datePart.split('-')
return `${year}/${month}/${day}` return `${year}/${month}/${day}`
} },
const formatTime = (timeStr) => { formatTime(timeStr) {
if (!timeStr) return '14:00' if (!timeStr) return '14:00'
const [, timePart] = timeStr.split(' ') const [, timePart] = timeStr.split(' ')
return timePart.slice(0, 5) return timePart.slice(0, 5)
} },
const showImagePreviewFn = (img) => { showImagePreviewFn(img) {
return showImagePreview([img]) return ImagePreview({
} images: [img],
showIndex: true
})
},
const generatePoster = async () => { async generatePoster() {
try { try {
if (!selectedActivity.value) { if (!this.selectedActivity) {
showDialog({ message: '请先选择活动!' }) $toastText('请先选择活动!')
return return
}
this.isGenerating = true
$toastLoading('海报生成中...')
// Vue 2 使 $nextTick
await this.$nextTick()
// 使 ref="posterRef" this.$refs 访
const posterElement = this.$refs.posterRef
if (!posterElement) {
this.isGenerating = false
$toastClear()
return
}
const canvas = await html2canvas(posterElement, {
useCORS: true,
scale: 3,
backgroundColor: null,
logging: false,
imageTimeout: 10000
})
this.posterImg = canvas.toDataURL('image/png', 1.0)
$toastClear()
$toastSuccess('海报生成成功')
} catch (err) {
console.error('生成海报失败:', err)
$toastText('生成海报失败,请重试!')
} finally {
this.isGenerating = false
$toastClear()
}
},
downloadPoster() {
if (!this.posterImg) return
const link = document.createElement('a')
link.href = this.posterImg
const fileName = `[${this.selectedActivity?.title || '活动'}]海报.png`
link.download = fileName.replace(/[\\/:*?"<>|]/g, '')
link.click()
URL.revokeObjectURL(link.href)
} }
},
watch: {
// ( watch(selectedActivity, ...))
selectedActivity: {
handler(newVal) {
if (newVal && newVal.id) {
//
this.sponsorName = newVal.sponsor || ''
this.openId = localStorage.getItem('openid')
isGenerating.value = true // Vue 2 this.$refs 访 DOM
const toast = showLoadingToast({ const canvas = this.$refs.qrcodeCanvas
message: '海报生成中...', if (canvas) {
forbidClick: true, const link = `https://love.ufutx.cn/api/official/live/wechat/FamilyAuth?merchant_id=44&serve_tab=&from_openid=${this.openId}&url=https%3A%2F%2Flove.ufutx.cn%2Fpu%2F%23%2FactivityDetails%2F${newVal.id}`
duration: 0
})
await nextTick() QRCode.toCanvas(canvas, link, {
const posterElement = posterRef.value width: 76,
if (!posterElement) { margin: 1,
isGenerating.value = false color: { dark: '#000000', light: '#ffffff' }
toast.close() }).catch(err => {
return console.error('生成二维码失败:', err)
})
}
}
},
immediate: true // immediate
} }
const canvas = await html2canvas(posterElement, {
useCORS: true,
scale: 3,
backgroundColor: null,
logging: false,
imageTimeout: 10000
})
posterImg.value = canvas.toDataURL('image/png', 1.0)
toast.close()
showToast({ message: '海报生成成功!', icon: 'success' })
} catch (err) {
console.error('生成海报失败:', err)
showToast({ message: '生成海报失败,请重试!', icon: 'fail' })
} finally {
isGenerating.value = false
} }
} }
function downloadPoster() {
if (!posterImg.value) return
const link = document.createElement('a')
link.href = posterImg.value
// /
const fileName = `[${selectedActivity.value?.title || '活动'}]海报.png`
link.download = fileName.replace(/[\\/:*?"<>|]/g, '')
link.click()
URL.revokeObjectURL(link.href)
}
onMounted(() => {
detectWeChatEnv()
getData()
})
</script> </script>
<style scoped> <style scoped>
@ -538,6 +589,12 @@ img {
color: #9ca3af; color: #9ca3af;
font-size: 14px; font-size: 14px;
flex-shrink: 0; flex-shrink: 0;
width: 16px;
height: 16px;
.vant-select-icon{
width: 16px;
height: 16px;
}
} }
/* 弹窗样式 */ /* 弹窗样式 */
@ -581,6 +638,7 @@ img {
.scroll-wrapper { .scroll-wrapper {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
margin-bottom: 100px;
} }
.activity-item { .activity-item {