const { tryLoginRenewal } = require('../../utils/subscribe'); const announcementSession = require('../../utils/announcement-session'); const { itemsOf, totalOf } = require('../../utils/list-pagination'); let lastLocationReport = 0; let locationReportUser = null; const { withDataCache } = require('../../utils/page-cache'); const { getLayout } = require('../../utils/layout'); // pages/index/index.js const { api, getImageUrl } = require('../../utils/request'); const { diaryEntry } = require('../../utils/journal'); const { saveScrollPosition, resetScrollOnTabShow } = require('../../utils/scroll-pos'); Page(withDataCache({ onLoginSubscribeTap: function() { return tryLoginRenewal(); }, onResize: function() { this.setData(getLayout()); }, data: { showAnnouncement:false, announcement:null, userId: null, coupleId: null, partnerName: '和TA', loveStartDate: '', daysCount: '?', daysLabel: '已注册', datePrefix: '注册于', partner1AvatarUrl: '', partner2AvatarUrl: '', partner1Initial: '', partner2Initial: '', partner1Birthday: '', partner2Birthday: '', partner1Name: '?', partner2Name: '?', partner1Location: '', partner2Location: '', coupleDistance: '', stats: { timeline: 0, album: 0, diary: 0, songs: 0, checkin: 0, pet: 0 }, bgImage: '', scrollTop: 0, refreshing: false, relationshipKnown: false, homeError: false, statsLoading: true, statsError: false, recentDiary: [], recentAlbums: [], upcomingMemory: null }, onLoad: function() { this.setData(getLayout()); this.setData({ userId: wx.getStorageSync('userId'), coupleId: wx.getStorageSync('coupleId'), scrollTop: 0 }); this.loadBg(); this.loadData(); }, onShow: function() { this._announcementActive=true; this.loadAnnouncement(); resetScrollOnTabShow(this, 'index'); const tabBar = this.getTabBar && this.getTabBar(); if (tabBar) tabBar.syncActive(); var prevCoupleId = this.data.coupleId; var curCoupleId = wx.getStorageSync('coupleId'); this.setData({ userId: wx.getStorageSync('userId'), coupleId: curCoupleId }); // 检查是否已被解绑(之前有 coupleId 但被清除了) if (prevCoupleId && !curCoupleId) { wx.reLaunch({ url: '/pages/index/index' }); return; } this.loadBg(); this.loadData(); this.fetchIpLocation(); }, onHide: function() { this._announcementActive=false; }, onUnload: function() { this._announcementActive=false; }, loadAnnouncement: function() { if(this._announcementLoading)return this._announcementLoading; this._announcementLoading=(async()=>{ try { const notice=await api.announcement(); if(this._announcementActive===false)return; const userId=wx.getStorageSync('userId'); const show=announcementSession.shouldShow(notice,userId); this.setData({announcement:notice, showAnnouncement:show}); if(show)announcementSession.markShown(notice,userId); } catch(e) {} // 公告读取失败不阻塞首页。 })().finally(()=>{this._announcementLoading=null;}); return this._announcementLoading; }, closeAnnouncement: function() { this.setData({showAnnouncement:false}); }, preventNoticeMove: function() {}, // 保存滚动位置 onScroll: function(e) { this._scrollTop = e.detail.scrollTop; saveScrollPosition('index', e.detail.scrollTop); }, _loadingData: false, _daysSince: function(dateStr) { if (!dateStr) return '?'; var parts = dateStr.substring(0, 10).split('-').map(Number); if (parts.length !== 3 || parts.some(isNaN) || parts[0] < 1970 || parts[1] < 1 || parts[1] > 12 || parts[2] < 1 || parts[2] > 31) return '?'; var start = new Date(parts[0], parts[1] - 1, parts[2]); if (start.getFullYear() !== parts[0] || start.getMonth() !== parts[1] - 1 || start.getDate() !== parts[2]) return '?'; var now = new Date(); var today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); return Math.max(0, Math.round((today - start) / 86400000)); }, loadData: async function() { var self = this; // 防止并发重复加载 if (this._loadingData) return; this._loadingData = true; this.setData({ homeError: false }); try { const info = await api.coupleInfo(); this.setData({userId: wx.getStorageSync('userId')}); this.setData({ relationshipKnown: true }); // 未绑定情侣时显示用户注册时间和默认信息 if (info.not_bound) { wx.removeStorageSync('coupleId'); var p1 = info.partner1 || {}; let daysCount = '?'; let loveStartDate = ''; if (info.love_start_date) { daysCount = this._daysSince(info.love_start_date); var parts = info.love_start_date.split('-'); loveStartDate = parseInt(parts[0]) + '年' + parseInt(parts[1]) + '月' + parseInt(parts[2]) + '日'; } this.setData({ coupleId: null, partner1AvatarUrl: getImageUrl(p1.avatar), partner1Name: p1.nickname || '未命名', partner1Initial: (p1.nickname || '未命名')[0], partner1Birthday: '', partner1Location: p1.location || '', partner2AvatarUrl: '', partner2Name: '未绑定', partner2Initial: '?', partner2Birthday: '', partner2Location: '', daysCount: daysCount, daysLabel: '已注册', datePrefix: '注册于', loveStartDate: loveStartDate, coupleDistance: '', stats: { timeline: 0, album: 0, diary: 0, songs: 0, checkin: 0, pet: 0 } }); await this.loadStats(); return; } // 同步情侣ID:红包/邀请创建后分享人刷新即可识别 if (info.id) { var prevCid = wx.getStorageSync('coupleId'); if (prevCid != info.id) { wx.setStorageSync('coupleId', info.id); } } const myUid = this.data.userId; var p1 = info.partner1 || {}; var p2 = info.partner2 || {}; if (p2.id == myUid) { var tmp = p1; p1 = p2; p2 = tmp; } let daysCount = '?'; let loveStartDate = ''; var togetherStart = info.love_start_date || (info.created_at || '').substring(0, 10); if (togetherStart) { daysCount = this._daysSince(togetherStart); var parts = togetherStart.split('-'); loveStartDate = parseInt(parts[0]) + '年' + parseInt(parts[1]) + '月' + parseInt(parts[2]) + '日'; } function getBirthdayText(birthday) { if (!birthday) return ''; var t = new Date(); t.setHours(0,0,0,0); var p = birthday.split('-'); if (p.length !== 3) return ''; var nb = new Date(t.getFullYear(), parseInt(p[1])-1, parseInt(p[2])); if (nb < t) nb.setFullYear(nb.getFullYear()+1); var c = Math.ceil((nb - t) / 86400000); if (c === 0) return '今天!'; if (c === 1) return '1天'; if (!Number.isFinite(c)) return ''; return c + '天'; } // 双方相距距离(后端基于双方经纬度用 Haversine 公式计算,单位:公里) var coupleDistance = ''; if (info.distance !== null && info.distance !== undefined && info.distance !== '') { var d = parseFloat(info.distance); if (!isNaN(d)) { coupleDistance = d < 1 ? '相距 ' + Math.round(d * 1000) + ' 米' : '相距 ' + d.toFixed(1) + ' 公里'; } } var dn = { coupleId: info.id, daysCount: daysCount, daysLabel: '我们在一起', datePrefix: '始于', loveStartDate: loveStartDate, partner1AvatarUrl: getImageUrl(p1.avatar), partner2AvatarUrl: getImageUrl(p2.avatar), partner1Name: p1.nickname || p1.username || '?', partner2Name: p2.nickname || p2.username || '?', partner1Initial: (p1.nickname || p1.username || '?')[0], partner2Initial: (p2.nickname || p2.username || '?')[0], partner1Birthday: getBirthdayText(p1.birthday), partner2Birthday: getBirthdayText(p2.birthday), partner1Location: (p1.location && !/^-?\d+(\.\d+)?,-?\d+(\.\d+)?$/.test(p1.location)) ? p1.location : '', partner2Location: (p2.location && !/^-?\d+(\.\d+)?,-?\d+(\.\d+)?$/.test(p2.location)) ? p2.location : '', coupleDistance: coupleDistance }; this.setData(dn); await this.loadStats(); } catch (e) { this.setData({ homeError: true, relationshipKnown: !!this._hasCachedData, statsLoading: false, statsError: true }); console.error(e); } finally { this._loadingData = false; } }, loadStats: async function() { this.setData({ statsLoading: !this._hasCachedData, statsError: false }); try { const [timeline, album, diary, songs, checkin, pet] = await Promise.all([ api.timelineList(), api.albumList(), api.diaryList(), api.songsList(), api.checkinList(), this.data.coupleId ? api.petInfo() : Promise.resolve({ has_pet: false }) ]); var photoCount = album && album.photo_total != null ? Number(album.photo_total) : itemsOf(album).reduce((sum,item)=>sum+(Number(item.photo_count)||0),0); var petLevel = 0; if (pet && pet.has_pet && pet.pet) { petLevel = parseInt(pet.pet.level || 0); } var recentDiary = ((diary && diary.items) || []).slice(0, 1).map(diaryEntry); var today = new Date(); today.setHours(0,0,0,0); var future = itemsOf(timeline).filter(function(item) { return item.event_date && new Date(item.event_date.replace(/-/g, '/')) >= today; }).sort(function(a,b) { return a.event_date.localeCompare(b.event_date); }); var next = timeline && !Array.isArray(timeline) && 'upcoming' in timeline ? timeline.upcoming : future[0]; this.setData({ recentDiary: recentDiary, recentAlbums: itemsOf(album).filter(function(item) { return !!item.cover; }).slice(0,3).map(function(item) { return { id:item.id, title:item.title || '我们的相册', cover:getImageUrl(item.cover) }; }), upcomingMemory: next ? { title: next.title || '下一个记忆日', date: next.event_date, dateMonth: next.event_date.slice(5,7), dateDay: next.event_date.slice(8,10), days: Math.ceil((new Date(next.event_date.replace(/-/g, '/')) - today) / 86400000) } : null, stats: { timeline: totalOf(timeline), album: photoCount, diary: (diary && diary.total) ? diary.total : 0, songs: totalOf(songs), checkin: (checkin && checkin.checkin_log_total !== undefined) ? checkin.checkin_log_total : ((checkin && checkin.items) ? checkin.items.length : (Array.isArray(checkin) ? checkin.length : 0)), pet: petLevel } }); } catch (e) { console.error(e); this.setData({ statsError: true }); } finally { this.setData({ statsLoading: false }); } }, // 获取本机经纬度并上报后端解析地址(后端按距离判断是否重新解析,超过5km才更新),并刷新首页双方地址显示 fetchIpLocation: function() { const locationUser = wx.getStorageSync('userId'); if (locationReportUser === locationUser && Date.now() - lastLocationReport < 300000) return; locationReportUser = locationUser; lastLocationReport = Date.now(); var self = this; var report = function(lat, lng) { var data = {}; if (lat && lng) { data.lat = lat; data.lng = lng; } api.updateIpLocation(data).then(function(resp) { if (resp && resp.location) { self.loadData(); } }).catch(function() { lastLocationReport = 0; }); }; // 优先用模糊定位获取经纬度(getFuzzyLocation 与 getLocation 互斥,统一用模糊定位) if (wx.getFuzzyLocation) { wx.getFuzzyLocation({ type: 'gcj02', success: function(res) { report(res.latitude, res.longitude); }, fail: function() { report(0, 0); } }); } else { report(0, 0); } }, // 背景图以接口返回为准 loadBg: function() { var self = this; return api.getBgConfig().then(function(cfg) { self.setData({ bgImage: cfg && cfg.image ? getImageUrl(cfg.image) : '' }); }).catch(function(e){ console.warn('loadBg error:', e && (e.error || e._statusCode || e)); }); }, // 跳转前保存当前滚动位置 _savePosBeforeLeave: function() { saveScrollPosition('index', this._scrollTop == null ? this.data.scrollTop : this._scrollTop); }, // 页面跳转 goToDiary: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/diary/diary' }); }, goToProfile: function() { this._savePosBeforeLeave(); wx.switchTab({ url: '/pages/profile/profile' }); }, goToTimeline: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/timeline/timeline' }); }, goToAlbum: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/albums/albums' }); }, goToSongs: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/lovewords/lovewords' }); }, goToCheckin: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/punch/punch' }); }, goToPet: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/pet/pet' }); }, goToPeriod: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/period/period' }); }, bindPartner: function() { getApp().globalData.openProfileBind = true; wx.switchTab({ url: '/pages/profile/profile' }); }, openJournalEntry: function(e) { wx.navigateTo({ url: '/pages/diary_detail/diary_detail?id=' + e.currentTarget.dataset.id }); }, writeDiary: function() { wx.navigateTo({ url: '/pages/publish/publish?type=diary' }); }, openAlbumPreview: function(e) { wx.navigateTo({ url: '/pages/album/album?album_id=' + e.currentTarget.dataset.id }); }, openRecentDiary: function(e) { wx.navigateTo({ url: '/pages/diary_detail/diary_detail?id=' + e.currentTarget.dataset.id }); }, showMore: function() { wx.switchTab({ url: '/pages/discover/discover' }); }, onPullDownRefresh: async function() { await this.loadData(); this.loadBg(); wx.stopPullDownRefresh(); }, onRefresh: async function() { this.setData({ refreshing: true }); try { await this.loadData(); this.loadBg(); } catch (e) { console.error('下拉刷新失败', e); } finally { this.setData({ refreshing: false }); } }, // 分享到好友 onShareAppMessage: function() { return { title: '让所有的爱有迹可循', path: '/pages/index/index', imageUrl: '/images/share.png' }; }, // 分享到朋友圈 onShareTimeline: function() { return { title: '让所有的爱有迹可循', query: '', imageUrl: '/images/share.png' }; } }, {"loadData": ["coupleInfo", "timelineList", "albumList", "diaryList", "songsList", "checkinList", "petInfo", "getBgConfig"]}));