Use UUID models and soft deletion, persist file relationships with deduplicated monthly MinIO objects, and add admin file management. Update mini-program media handling and add local dev configuration.
209 lines
6.9 KiB
JavaScript
209 lines
6.9 KiB
JavaScript
const { withDataCache } = require('../../utils/page-cache');
|
|
const { getLayout } = require('../../utils/layout');
|
|
// pages/timeline-detail/timeline-detail.js
|
|
const { api, getImageUrl } = require('../../utils/request');
|
|
const { createSwipeBack } = require('../../utils/util');
|
|
|
|
// 重复周期映射
|
|
var repeatUnitMap = { 'day': '天', 'week': '周', 'month': '月', 'year': '年' };
|
|
var weekdayNames = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
|
|
|
// 计算距离今天最近的重复日期
|
|
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(withDataCache({
|
|
onResize: function() { this.setData(getLayout()); },
|
|
data: { loading: true, loadError: false,
|
|
item: null,
|
|
detailId: 0,
|
|
bgImageUrl: '',
|
|
daysNumber: '',
|
|
daysSign: '',
|
|
weekdayText: '',
|
|
isAnniversary: true
|
|
},
|
|
|
|
onLoad: function(options) {
|
|
this.setData(getLayout());
|
|
var id = options.id;
|
|
if (id) {
|
|
this.setData({ detailId: String(id) });
|
|
this.loadDetail(String(id));
|
|
}
|
|
var self = this;
|
|
var swipe = createSwipeBack(function() { wx.navigateBack(); });
|
|
this.onTouchStart = swipe.onTouchStart;
|
|
this.onTouchEnd = swipe.onTouchEnd;
|
|
},
|
|
|
|
retryDetail: function() { this.loadDetail(this.data.detailId); },
|
|
onShow: function() {
|
|
this._syncNavigationColor();
|
|
if (this.data.detailId) {
|
|
this.loadDetail(this.data.detailId);
|
|
}
|
|
},
|
|
|
|
onHide: function() {
|
|
if (wx.setNavigationBarColor) wx.setNavigationBarColor({frontColor:'#000000',backgroundColor:'#FDE4EC'});
|
|
},
|
|
_syncNavigationColor: function() {
|
|
if (wx.setNavigationBarColor) wx.setNavigationBarColor({frontColor:this.data.bgImageUrl?'#ffffff':'#000000',backgroundColor:this.data.bgImageUrl?'#000000':'#FDE4EC'});
|
|
},
|
|
goBack: function() {
|
|
wx.navigateBack({fail:function(){wx.switchTab({url:'/pages/discover/discover'});}});
|
|
},
|
|
|
|
loadDetail: async function(id) {
|
|
if (this._pageLoading) return;
|
|
this._pageLoading = true;
|
|
this.setData({loading: !this._hasCachedData, loadError:false});
|
|
try {
|
|
var item = await api.timelineDetail(id);
|
|
var myUid = wx.getStorageSync('userId');
|
|
var cid = String(item.created_by) || 0;
|
|
|
|
// 获取情侣信息
|
|
try {
|
|
var info = await api.coupleInfo();
|
|
var p1 = info.partner1 || {};
|
|
var p2 = info.partner2 || {};
|
|
var nameMap = {};
|
|
var avatarMap = {};
|
|
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); }
|
|
item.creator_name = nameMap[cid] || (cid == myUid ? '我' : 'TA');
|
|
item.creator_avatar = avatarMap[cid] || '';
|
|
} catch(e) {
|
|
item.creator_name = cid == myUid ? '我' : 'TA';
|
|
item.creator_avatar = '';
|
|
}
|
|
item.creator_initial = (item.creator_name || '?')[0].toUpperCase();
|
|
|
|
// 计算天数
|
|
var today = new Date(); today.setHours(0,0,0,0);
|
|
var daysNumber = '';
|
|
var daysSign = '';
|
|
var isAnniversary = true;
|
|
|
|
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 || '';
|
|
|
|
var diff;
|
|
if (repeatInterval > 0 && repeatUnit) {
|
|
var baseDate = calcNearestRepeatDate(ed, today, repeatInterval, repeatUnit);
|
|
diff = Math.floor((today - baseDate) / 86400000);
|
|
isAnniversary = diff >= 0;
|
|
daysSign = isAnniversary ? '+' : '-';
|
|
daysNumber = Math.abs(diff);
|
|
item.repeat_label = repeatUnitMap[repeatUnit] + '重复';
|
|
} else {
|
|
diff = Math.floor((today - ed) / 86400000);
|
|
isAnniversary = diff >= 0;
|
|
daysSign = isAnniversary ? '+' : '-';
|
|
daysNumber = Math.abs(diff);
|
|
}
|
|
}
|
|
|
|
// 星期
|
|
var eventDateObj = new Date(item.event_date.replace(/-/g, '/'));
|
|
var weekdayText = weekdayNames[eventDateObj.getDay()] || '';
|
|
|
|
item.is_anniversary = isAnniversary;
|
|
this.setData({
|
|
item: item,
|
|
daysNumber: daysNumber,
|
|
daysSign: daysSign,
|
|
weekdayText: weekdayText,
|
|
isAnniversary: isAnniversary
|
|
});
|
|
|
|
// 从API数据加载背景图
|
|
this.loadBgImage();
|
|
|
|
} catch(e) {
|
|
this.setData({loadError:true});
|
|
console.error(e);
|
|
wx.showToast({ title: (e && (e.error || e.errMsg || e.message)) || '加载失败', icon: 'none' });
|
|
}
|
|
finally { this._pageLoading = false; this.setData({loading:false}); }
|
|
},
|
|
|
|
// ===== 背景图片 =====
|
|
loadBgImage: function() {
|
|
var item = this.data.item;
|
|
if (item && item.bg_image) {
|
|
var fullUrl = getImageUrl(item.bg_image);
|
|
this.setData({ bgImageUrl: fullUrl });
|
|
} else {
|
|
this.setData({ bgImageUrl: '' });
|
|
}
|
|
this._syncNavigationColor();
|
|
},
|
|
|
|
// ===== 编辑 =====
|
|
goEdit: function() {
|
|
var item = this.data.item;
|
|
if (item && item.id) {
|
|
wx.navigateTo({
|
|
url: '/pages/publish/publish?type=timeline&edit=' + item.id
|
|
});
|
|
}
|
|
},
|
|
|
|
// ===== 导航 =====
|
|
goBack: function() { wx.navigateBack(); },
|
|
goHome: function() { wx.switchTab({ url: '/pages/index/index' }); },
|
|
goProfile: function() { wx.switchTab({ url: '/pages/profile/profile' }); }
|
|
}, {"loadDetail": ["timelineDetail", "coupleInfo"]}));
|