// pages/happy-school/happy-school.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/images/qrcode-happy-school.jpg' }, onLoad() { 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() }, /** * 切换活动标签 */ 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) } }, /** * 加载活动列表 - 根据categoryName筛选快乐学堂(支持分页) */ 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: 'school', 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 schoolActivities = allActivities.filter(item => item.categoryName === '快乐学堂') let clubQrcode = '' const firstWithQrcode = schoolActivities.find(item => item.activityGuideQrcode || item.activity_guide_qrcode) if (firstWithQrcode && !isLoadMore) { clubQrcode = firstWithQrcode.activityGuideQrcode || firstWithQrcode.activity_guide_qrcode } const newActivityList = schoolActivities.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), 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('[happy-school] 加载成功,总数:', 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 }) } } }, /** * 格式化日期 */ formatDate(dateStr) { if (!dateStr) return '' 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}日` }, /** * 活动卡片点击 */ onActivityTap(e) { const id = e.currentTarget.dataset.id wx.navigateTo({ url: `/pages/activity-detail/activity-detail?id=${id}` }) }, /** * 点赞 */ 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' }) } }, /** * 报名按钮点击 */ 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 || 'https://ai-c.maimanji.com/api/common/qrcode?type=group' 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' }) } } }, /** * 加入群组 */ onJoinGroup() { // 如果没有二维码,尝试获取第一个活动的二维码 if (!this.data.qrcodeImageUrl && this.data.activityList.length > 0) { const firstWithQrcode = this.data.activityList.find(item => item.activityGuideQrcode || item.activity_guide_qrcode) if (firstWithQrcode) { this.setData({ qrcodeImageUrl: firstWithQrcode.activityGuideQrcode || firstWithQrcode.activity_guide_qrcode }) } } this.setData({ showQrcodeModal: true }) }, /** * 阻止冒泡 */ preventBubble() { return }, /** * 关闭二维码弹窗 */ onCloseQrcodeModal() { this.setData({ showQrcodeModal: false }) }, /** * 保存二维码 */ async onSaveQrcode() { try { const { qrcodeImageUrl } = this.data // 下载图片到本地 const downloadRes = await new Promise((resolve, reject) => { wx.downloadFile({ url: qrcodeImageUrl, success: resolve, fail: reject }) }) if (downloadRes.statusCode !== 200) { throw new Error('下载失败') } // 保存到相册 await new Promise((resolve, reject) => { wx.saveImageToPhotosAlbum({ filePath: downloadRes.tempFilePath, success: resolve, fail: reject }) }) wx.showToast({ title: '保存成功', icon: 'success' }) this.onCloseQrcodeModal() } catch (err) { console.error('保存二维码失败', err) if (err.errMsg && err.errMsg.includes('auth deny')) { wx.showModal({ title: '需要授权', content: '请允许访问相册以保存二维码', confirmText: '去设置', success: (res) => { if (res.confirm) { wx.openSetting() } } }) } else { wx.showToast({ title: '保存失败', icon: 'none' }) } } } })