456 lines
13 KiB
JavaScript
456 lines
13 KiB
JavaScript
// pages/theme-travel/theme-travel.js - 高端定制页面
|
|
const api = require('../../utils/api')
|
|
const app = getApp()
|
|
|
|
Page({
|
|
data: {
|
|
statusBarHeight: 44,
|
|
navBarHeight: 44,
|
|
totalNavHeight: 88,
|
|
loading: false,
|
|
loadingMore: false,
|
|
activeTab: 'featured',
|
|
|
|
// 活动列表
|
|
activityList: [],
|
|
|
|
// 分页相关
|
|
page: 1,
|
|
limit: 20,
|
|
hasMore: true,
|
|
total: 0,
|
|
|
|
// 二维码引导弹窗
|
|
showQrcodeModal: false,
|
|
qrcodeImageUrl: 'https://ai-c.maimanji.com/api/common/qrcode?type=theme-travel'
|
|
},
|
|
|
|
onLoad(options) {
|
|
// 计算导航栏高度
|
|
const systemInfo = wx.getSystemInfoSync()
|
|
const statusBarHeight = systemInfo.statusBarHeight || 44
|
|
const menuButton = wx.getMenuButtonBoundingClientRect()
|
|
const navBarHeight = menuButton.height + (menuButton.top - statusBarHeight) * 2
|
|
const totalNavHeight = statusBarHeight + navBarHeight
|
|
|
|
this.setData({
|
|
statusBarHeight,
|
|
navBarHeight,
|
|
totalNavHeight
|
|
})
|
|
|
|
this.loadActivityList()
|
|
},
|
|
|
|
/**
|
|
* 返回上一页
|
|
*/
|
|
onBack() {
|
|
wx.navigateBack()
|
|
},
|
|
|
|
/**
|
|
* 加载活动列表(支持分页)
|
|
*/
|
|
async loadActivityList(isLoadMore = false) {
|
|
if (isLoadMore) {
|
|
this.setData({ loadingMore: true })
|
|
} else {
|
|
this.setData({ loading: true, page: 1, hasMore: true, activityList: [] })
|
|
}
|
|
|
|
try {
|
|
const { activeTab, page, limit } = this.data
|
|
const params = {
|
|
category: 'travel',
|
|
limit: limit,
|
|
page: page
|
|
}
|
|
|
|
if (activeTab === 'featured') {
|
|
params.tab = 'featured'
|
|
} else if (activeTab === 'free') {
|
|
params.priceType = 'free'
|
|
} else if (activeTab === 'vip') {
|
|
params.is_vip = true
|
|
} else if (activeTab === 'svip') {
|
|
params.is_svip = true
|
|
}
|
|
|
|
const res = await api.activity.getList(params)
|
|
|
|
if (res.success && res.data && res.data.list) {
|
|
const total = res.data.total || 0
|
|
const allActivities = res.data.list
|
|
const travelActivities = allActivities.filter(item => item.categoryName === '高端定制')
|
|
|
|
let clubQrcode = ''
|
|
const firstWithQrcode = travelActivities.find(item => item.activityGuideQrcode || item.activity_guide_qrcode)
|
|
if (firstWithQrcode && !isLoadMore) {
|
|
clubQrcode = firstWithQrcode.activityGuideQrcode || firstWithQrcode.activity_guide_qrcode
|
|
}
|
|
|
|
const newActivityList = travelActivities.map(item => {
|
|
const heat = item.heat || (item.likes * 2 + (item.views || 0) + (item.current_participants || 0) * 3)
|
|
|
|
return {
|
|
id: item.id,
|
|
title: item.title,
|
|
date: this.formatDate(item.start_date || item.activityDate, item.end_date || item.endDate),
|
|
location: item.location || '',
|
|
venue: item.venue || '',
|
|
image: item.coverImage || item.cover_image || '',
|
|
heat: Math.floor(heat),
|
|
price: item.price_text || item.priceText || '免费',
|
|
priceType: item.is_free || item.priceType === 'free' ? 'free' : 'paid',
|
|
likes: item.likes || item.likesCount || 0,
|
|
participants: item.current_participants || item.currentParticipants || 0,
|
|
isLiked: item.is_liked || item.isLiked || false,
|
|
isSignedUp: item.is_registered || item.isSignedUp || false,
|
|
status: item.status || (item.currentParticipants >= item.maxParticipants && item.maxParticipants > 0 ? 'full' : 'upcoming'),
|
|
activityGuideQrcode: item.activityGuideQrcode || item.activity_guide_qrcode || ''
|
|
}
|
|
})
|
|
|
|
const hasMore = newActivityList.length >= limit && (this.data.activityList.length + newActivityList.length) < total
|
|
|
|
if (isLoadMore) {
|
|
this.setData({
|
|
activityList: [...this.data.activityList, ...newActivityList],
|
|
loadingMore: false,
|
|
hasMore,
|
|
page: this.data.page + 1,
|
|
total
|
|
})
|
|
} else {
|
|
this.setData({
|
|
activityList: newActivityList,
|
|
hasMore,
|
|
total,
|
|
qrcodeImageUrl: clubQrcode || this.data.qrcodeImageUrl
|
|
})
|
|
}
|
|
|
|
console.log('[theme-travel] 加载成功,总数:', total, '当前:', this.data.activityList.length, 'hasMore:', hasMore)
|
|
} else {
|
|
if (isLoadMore) {
|
|
this.setData({ loadingMore: false, hasMore: false })
|
|
} else {
|
|
this.setData({ activityList: [], hasMore: false })
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('加载活动列表失败', err)
|
|
if (isLoadMore) {
|
|
this.setData({ loadingMore: false })
|
|
} else {
|
|
this.setData({ activityList: [], loading: false })
|
|
}
|
|
} finally {
|
|
if (!isLoadMore) {
|
|
this.setData({ loading: false })
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 标签切换
|
|
*/
|
|
onTabChange(e) {
|
|
const tab = e.currentTarget.dataset.tab
|
|
if (tab === this.data.activeTab) return
|
|
|
|
this.setData({
|
|
activeTab: tab,
|
|
activityList: [],
|
|
page: 1,
|
|
hasMore: true
|
|
})
|
|
this.loadActivityList()
|
|
},
|
|
|
|
/**
|
|
* 下拉刷新
|
|
*/
|
|
onPullDownRefresh() {
|
|
this.loadActivityList(false).finally(() => {
|
|
wx.stopPullDownRefresh()
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 上拉加载更多
|
|
*/
|
|
onReachBottom() {
|
|
if (this.data.hasMore && !this.data.loadingMore && !this.data.loading) {
|
|
this.loadActivityList(true)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 加载模拟数据(降级方案)
|
|
*/
|
|
loadMockActivities() {
|
|
// 使用空数据,等待后端API返回真实数据
|
|
const mockActivities = []
|
|
|
|
this.setData({ activityList: mockActivities })
|
|
},
|
|
|
|
/**
|
|
* 格式化日期
|
|
*/
|
|
formatDate(startDate, endDate) {
|
|
if (!startDate) return ''
|
|
|
|
const formatSingle = (dateStr) => {
|
|
const date = new Date(dateStr)
|
|
const year = date.getFullYear()
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
return `${year}年${month}月${day}日`
|
|
}
|
|
|
|
// 如果有结束日期且不同于开始日期,显示日期范围
|
|
if (endDate && endDate !== startDate) {
|
|
const startFormatted = formatSingle(startDate)
|
|
const endFormatted = formatSingle(endDate)
|
|
// 如果是同一年,省略结束日期的年份
|
|
if (startFormatted.split('年')[0] === endFormatted.split('年')[0]) {
|
|
return `${startFormatted}-${endFormatted.split('年')[1]}`
|
|
}
|
|
return `${startFormatted}-${endFormatted}`
|
|
}
|
|
|
|
return formatSingle(startDate)
|
|
},
|
|
|
|
/**
|
|
* 立即报名
|
|
*/
|
|
async onSignUp(e) {
|
|
const id = e.currentTarget.dataset.id
|
|
const index = e.currentTarget.dataset.index
|
|
|
|
if (!app.globalData.isLoggedIn) {
|
|
wx.navigateTo({ url: '/pages/login/login' })
|
|
return
|
|
}
|
|
|
|
const activity = this.data.activityList[index]
|
|
|
|
// 检查活动状态
|
|
if (activity.status === 'full' || activity.status === 'ended') {
|
|
const qrCode = activity.activityGuideQrcode || activity.activity_guide_qrcode || this.data.qrcodeImageUrl
|
|
this.setData({
|
|
qrcodeImageUrl: qrCode,
|
|
showQrcodeModal: true
|
|
})
|
|
return
|
|
}
|
|
|
|
try {
|
|
if (activity.isSignedUp) {
|
|
// 取消报名
|
|
const res = await api.activity.cancelSignup(id)
|
|
if (res.success) {
|
|
wx.showToast({ title: '已取消报名', icon: 'success' })
|
|
this.loadActivityList()
|
|
}
|
|
} else {
|
|
// 报名
|
|
const res = await api.activity.signup(id)
|
|
if (res.success) {
|
|
wx.showToast({ title: '报名成功', icon: 'success' })
|
|
this.loadActivityList()
|
|
} else {
|
|
// 检查是否需要显示二维码(后端开关关闭或活动已结束)
|
|
if (res.code === 'QR_CODE_REQUIRED' || res.error === 'QR_CODE_REQUIRED' || res.code === 'ACTIVITY_ENDED' || res.error === '活动已结束') {
|
|
if (activity.activityGuideQrcode || activity.activity_guide_qrcode) {
|
|
this.setData({ qrcodeImageUrl: activity.activityGuideQrcode || activity.activity_guide_qrcode })
|
|
}
|
|
this.setData({ showQrcodeModal: true })
|
|
if (res.code === 'ACTIVITY_ENDED' || res.error === '活动已结束') {
|
|
wx.showToast({ title: '活动已结束,进群查看更多', icon: 'none' })
|
|
}
|
|
} else {
|
|
wx.showToast({
|
|
title: res.error || '报名失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('报名操作失败', err)
|
|
// 捕获特定错误码以显示二维码
|
|
const isQrRequired = err && (err.code === 'QR_CODE_REQUIRED' || (err.data && err.data.code === 'QR_CODE_REQUIRED'))
|
|
const isActivityEnded = err && (err.code === 'ACTIVITY_ENDED' || (err.data && err.data.code === 'ACTIVITY_ENDED') || err.error === '活动已结束')
|
|
|
|
if (isQrRequired || isActivityEnded) {
|
|
if (activity.activityGuideQrcode || activity.activity_guide_qrcode) {
|
|
this.setData({ qrcodeImageUrl: activity.activityGuideQrcode || activity.activity_guide_qrcode })
|
|
}
|
|
this.setData({ showQrcodeModal: true })
|
|
if (isActivityEnded) {
|
|
wx.showToast({ title: '活动已结束,进群查看更多', icon: 'none' })
|
|
}
|
|
} else {
|
|
wx.showToast({
|
|
title: err.error || err.message || '操作失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 点赞/取消点赞
|
|
*/
|
|
async onLike(e) {
|
|
const id = e.currentTarget.dataset.id
|
|
const index = e.currentTarget.dataset.index
|
|
|
|
if (!app.globalData.isLoggedIn) {
|
|
wx.navigateTo({ url: '/pages/login/login' })
|
|
return
|
|
}
|
|
|
|
try {
|
|
const res = await api.activity.toggleLike(id)
|
|
if (res.success) {
|
|
this.setData({
|
|
[`activityList[${index}].isLiked`]: res.data.isLiked,
|
|
[`activityList[${index}].likes`]: res.data.likesCount
|
|
})
|
|
}
|
|
} catch (err) {
|
|
console.error('点赞失败', err)
|
|
wx.showToast({ title: '操作失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 点击活动卡片
|
|
*/
|
|
onActivityTap(e) {
|
|
const id = e.currentTarget.dataset.id
|
|
wx.navigateTo({
|
|
url: `/pages/activity-detail/activity-detail?id=${id}`
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 加入高端定制群
|
|
*/
|
|
onJoinGroup() {
|
|
let qrcodeUrl = this.data.qrcodeImageUrl
|
|
|
|
if (!qrcodeUrl && this.data.activityList && this.data.activityList.length > 0) {
|
|
const firstWithQrcode = this.data.activityList.find(item => item.activityGuideQrcode || item.activity_guide_qrcode)
|
|
if (firstWithQrcode) {
|
|
qrcodeUrl = firstWithQrcode.activityGuideQrcode || firstWithQrcode.activity_guide_qrcode
|
|
}
|
|
}
|
|
|
|
if (!qrcodeUrl) {
|
|
wx.showToast({ title: '暂无二维码', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
this.setData({
|
|
showQrcodeModal: true,
|
|
qrcodeImageUrl: qrcodeUrl
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 关闭二维码弹窗
|
|
*/
|
|
onCloseQrcodeModal() {
|
|
this.setData({
|
|
showQrcodeModal: false
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 保存二维码
|
|
*/
|
|
async onSaveQrcode() {
|
|
try {
|
|
const { qrcodeImageUrl } = this.data
|
|
if (!qrcodeImageUrl) {
|
|
wx.showToast({ title: '二维码链接不存在', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
wx.showLoading({ title: '保存中...' })
|
|
|
|
let filePath = ''
|
|
|
|
// 判断是否是 Base64 格式
|
|
if (qrcodeImageUrl.startsWith('data:image')) {
|
|
const fs = wx.getFileSystemManager()
|
|
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(qrcodeImageUrl) || []
|
|
if (!format || !bodyData) {
|
|
throw new Error('Base64 格式错误')
|
|
}
|
|
filePath = `${wx.env.USER_DATA_PATH}/qrcode_${Date.now()}.${format}`
|
|
fs.writeFileSync(filePath, bodyData, 'base64')
|
|
} else {
|
|
// 远程 URL 格式
|
|
const downloadRes = await new Promise((resolve, reject) => {
|
|
wx.downloadFile({
|
|
url: qrcodeImageUrl,
|
|
success: resolve,
|
|
fail: reject
|
|
})
|
|
})
|
|
|
|
if (downloadRes.statusCode !== 200) {
|
|
throw new Error('下载图片失败')
|
|
}
|
|
filePath = downloadRes.tempFilePath
|
|
}
|
|
|
|
// 保存到相册
|
|
await new Promise((resolve, reject) => {
|
|
wx.saveImageToPhotosAlbum({
|
|
filePath: filePath,
|
|
success: resolve,
|
|
fail: reject
|
|
})
|
|
})
|
|
|
|
wx.hideLoading()
|
|
wx.showToast({ title: '保存成功', icon: 'success' })
|
|
this.onCloseQrcodeModal()
|
|
} catch (err) {
|
|
wx.hideLoading()
|
|
console.error('保存二维码失败', err)
|
|
|
|
if (err.errMsg && (err.errMsg.includes('auth deny') || err.errMsg.includes('auth denied'))) {
|
|
wx.showModal({
|
|
title: '需要授权',
|
|
content: '请允许访问相册以保存二维码',
|
|
confirmText: '去设置',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
wx.openSetting()
|
|
}
|
|
}
|
|
})
|
|
} else {
|
|
wx.showToast({ title: err.message || '保存失败', icon: 'none' })
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 阻止冒泡
|
|
*/
|
|
preventBubble() {
|
|
return
|
|
}
|
|
})
|