海报update
This commit is contained in:
parent
ac431927b7
commit
7c1fdb0647
@ -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')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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: {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user