Gate record features and storage entry points with invitation guidance; enforce record access in the backend. Add homepage greetings, right-swipe profile dismissal, and move the smoking switch to settings. Simplify API base configuration and remove the unused legacy tab bar component.
199 lines
7.3 KiB
JavaScript
199 lines
7.3 KiB
JavaScript
const { withRecordAccess } = require('../../utils/record-access');
|
|
const { tryLoginRenewal } = require('../../utils/subscribe');
|
|
const { itemsOf, startList, applyList, failList, finishList, withListPagination } = require('../../utils/list-pagination');
|
|
const { withDataCache } = require('../../utils/page-cache');
|
|
const { getLayout } = require('../../utils/layout');
|
|
// pages/timeline/timeline.js
|
|
const { api, getImageUrl } = require('../../utils/request');
|
|
|
|
// 重复周期映射
|
|
var repeatUnitMap = { 'day': '天', 'week': '周', 'month': '月', 'year': '年' };
|
|
|
|
// 计算距离今天最近的重复日期(返回 Date 对象,已归零)
|
|
function calcNearestRepeatDate(eventDate, today, interval, unit) {
|
|
var base = new Date(eventDate);
|
|
base.setHours(0,0,0,0);
|
|
if (unit === 'day') {
|
|
var diff = Math.floor((today - base) / 86400000);
|
|
var cycles = Math.floor(diff / interval);
|
|
var nearest = new Date(base.getTime() + cycles * interval * 86400000);
|
|
nearest.setHours(0,0,0,0);
|
|
if (nearest > today) {
|
|
nearest = new Date(nearest.getTime() - interval * 86400000);
|
|
nearest.setHours(0,0,0,0);
|
|
}
|
|
return nearest;
|
|
} else if (unit === 'week') {
|
|
var diff = Math.floor((today - base) / 86400000);
|
|
var cycles = Math.floor(diff / (7 * interval));
|
|
var nearest = new Date(base.getTime() + cycles * 7 * interval * 86400000);
|
|
nearest.setHours(0,0,0,0);
|
|
if (nearest > today) {
|
|
nearest = new Date(nearest.getTime() - 7 * interval * 86400000);
|
|
nearest.setHours(0,0,0,0);
|
|
}
|
|
return nearest;
|
|
} else if (unit === 'month') {
|
|
var nearest = new Date(base);
|
|
nearest.setHours(0,0,0,0);
|
|
while (true) {
|
|
var next = new Date(nearest);
|
|
next.setMonth(next.getMonth() + interval);
|
|
next.setHours(0,0,0,0);
|
|
if (next > today) break;
|
|
nearest = next;
|
|
}
|
|
return nearest;
|
|
} else if (unit === 'year') {
|
|
var nearest = new Date(base);
|
|
nearest.setHours(0,0,0,0);
|
|
while (true) {
|
|
var next = new Date(nearest);
|
|
next.setFullYear(next.getFullYear() + interval);
|
|
next.setHours(0,0,0,0);
|
|
if (next > today) break;
|
|
nearest = next;
|
|
}
|
|
return nearest;
|
|
}
|
|
return new Date(eventDate);
|
|
}
|
|
|
|
Page(withRecordAccess(withDataCache(withListPagination({
|
|
onLoginSubscribeTap: function() { return tryLoginRenewal(); },
|
|
onResize: function() { this.setData(getLayout()); },
|
|
data: { loading: true, loadError: false,
|
|
list: []
|
|
},
|
|
|
|
onLoad: function() {
|
|
this.setData(getLayout());
|
|
this.loadData();
|
|
},
|
|
onShow: function() {
|
|
this.loadData();
|
|
},
|
|
|
|
onPullDownRefresh: async function() {
|
|
await this.loadData();
|
|
wx.stopPullDownRefresh();
|
|
},
|
|
|
|
onShareAppMessage: function() {
|
|
return { title: '让所有的爱有迹可循', path: '/pages/timeline/timeline', imageUrl: '/images/share.png' };
|
|
},
|
|
onShareTimeline: function() {
|
|
return { title: '让所有的爱有迹可循', imageUrl: '/images/share.png' };
|
|
},
|
|
|
|
loadData: async function(page) {
|
|
const ticket = startList(this, page);
|
|
if (!ticket) return;
|
|
try {
|
|
const list = await api.timelineList({page:ticket.page,page_size:20});
|
|
const myUid = wx.getStorageSync('userId');
|
|
var nameMap = {};
|
|
var avatarMap = {};
|
|
try {
|
|
const info = await api.coupleInfo();
|
|
var p1 = info.partner1 || {};
|
|
var p2 = info.partner2 || {};
|
|
if (p1.id) { nameMap[p1.id] = p1.nickname || p1.username || 'TA'; avatarMap[p1.id] = getImageUrl(p1.avatar); }
|
|
if (p2.id) { nameMap[p2.id] = p2.nickname || p2.username || 'TA'; avatarMap[p2.id] = getImageUrl(p2.avatar); }
|
|
} catch (e) {}
|
|
|
|
var today = new Date(); today.setHours(0,0,0,0);
|
|
var items = itemsOf(list).map(function(item, idx) {
|
|
var cid = String(item.created_by) || 0;
|
|
item.creator_name = nameMap[cid] || (cid == myUid ? '我' : 'TA');
|
|
item.creator_avatar = avatarMap[cid] || '';
|
|
item.creator_initial = (item.creator_name || '?')[0].toUpperCase();
|
|
item.side = ((ticket.page-1)*20+idx) % 2 === 0 ? 'left' : 'right';
|
|
item.bg_image_url = item.bg_image ? getImageUrl(item.bg_image) : '';
|
|
|
|
// 计算纪念日/倒数日(支持重复事件)
|
|
if (item.event_date) {
|
|
var ed = new Date(item.event_date.replace(/-/g, '/'));
|
|
ed.setHours(0,0,0,0);
|
|
var repeatInterval = parseInt(item.repeat_interval) || 0;
|
|
var repeatUnit = item.repeat_unit || '';
|
|
|
|
// 计算实际用来对比的基准日期
|
|
if (repeatInterval > 0 && repeatUnit) {
|
|
// 重复事件:以今天的日期为基准,计算最近一次重复的日期
|
|
var baseDate = calcNearestRepeatDate(ed, today, repeatInterval, repeatUnit);
|
|
var diff = Math.floor((today - baseDate) / 86400000);
|
|
if (diff >= 0) {
|
|
item.is_anniversary = true;
|
|
item.days_text = '已过去 ' + diff + ' 天';
|
|
item.date_tag = '纪念日';
|
|
item.repeat_label = repeatUnitMap[repeatUnit] + '重复';
|
|
} else {
|
|
item.is_anniversary = false;
|
|
item.days_text = '还有 ' + Math.abs(diff) + ' 天';
|
|
item.date_tag = '倒数日';
|
|
item.repeat_label = repeatUnitMap[repeatUnit] + '重复';
|
|
}
|
|
} else {
|
|
// 非重复事件:直接用事件日期计算
|
|
var diff = Math.floor((today - ed) / 86400000);
|
|
if (diff >= 0) {
|
|
item.is_anniversary = true;
|
|
item.days_text = '已过去 ' + diff + ' 天';
|
|
item.date_tag = '纪念日';
|
|
} else {
|
|
item.is_anniversary = false;
|
|
item.days_text = '还有 ' + Math.abs(diff) + ' 天';
|
|
item.date_tag = '倒数日';
|
|
}
|
|
}
|
|
} else {
|
|
item.is_anniversary = true;
|
|
item.days_text = '';
|
|
}
|
|
return item;
|
|
});
|
|
applyList(this, ticket, list, items, 'list');
|
|
} catch (e) {
|
|
failList(this,ticket);
|
|
console.error(e);
|
|
wx.showToast({ title: (e && (e.error || e.errMsg || e.message)) || '加载失败', icon: 'none' });
|
|
}
|
|
finally { finishList(this,ticket); }
|
|
},
|
|
|
|
|
|
deleteTimeline: async function(e) {
|
|
var id = e.currentTarget.dataset.id;
|
|
wx.showModal({
|
|
title: '确认删除',
|
|
content: '确定要删除这条记录吗?',
|
|
success: async function(res) {
|
|
if (res.confirm) {
|
|
try {
|
|
await api.timelineDelete({ id: id });
|
|
wx.showToast({ title: '已删除', icon: 'success' });
|
|
// need to re-get this context
|
|
var pages = getCurrentPages();
|
|
var page = pages[pages.length - 1];
|
|
page.loadData();
|
|
} catch (err) {
|
|
wx.showToast({ title: err.error || '删除失败', icon: 'none' });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}, goToPublish: function() { wx.navigateTo({ url: '/pages/publish/publish?type=timeline' }); },
|
|
|
|
goToDetail: function(e) {
|
|
var id = e.currentTarget.dataset.id;
|
|
if (id) {
|
|
wx.navigateTo({ url: '/pages/timeline-detail/timeline-detail?id=' + id });
|
|
}
|
|
},
|
|
|
|
goHome: function() { wx.switchTab({ url: '/pages/index/index' }); },
|
|
goBack: function() { wx.navigateBack(); },
|
|
goProfile: function() { wx.switchTab({ url: '/pages/profile/profile' }); }
|
|
}, 'loadData'), {"loadData": ["timelineList", "coupleInfo"]})));
|