【重要修复】重写农历双向转换算法(原来全错): - solarToLunar/lunarToSolar 改用标准算法(基准1900-01-31正月初一,UTC避免时区误差) - 验证:2026春节2-17、中秋9-25、端午6-19、2023闰二月全部正确 【首页大日历】 - 日期数字加大到240rpx,超醒目 - 节假日红色喜庆卡片+红数字(春节/国庆/中秋等法定假日) - 工作日绿色卡片+绿数字(一眼知道要上班) - 周末红色数字+米黄卡片 - 节气显示具体时刻(如 立秋 20:29) - 初一/十五金色标记(可在设置关闭) - 佛历提醒:距下一佛诞还有几天(可在设置开启) 【全屏放大弹窗(老年友好)】 - 大日历卡片/宜忌/详情/节日速查 点击均可全屏放大 - 宜忌放大后字号44rpx,详情放大后40rpx 【月历视图】 - swiper 左右滑动换月,预计算5个月居中显示 - 滑到边缘自动补月,可无限滚动 - 点选日期切回日视图 【节日速查】 - 首页显示近期5个节日(中秋/重阳等)+公历日期+倒计时 - 点击直接跳到该日老黄历 【设置页】 - 新增'显示佛历提醒'开关(默认关) - 新增'初一十五高亮'开关(默认开)
This commit is contained in:
+157
-36
@@ -1,21 +1,40 @@
|
||||
const { getDayInfo, getAlmanacInfo, getMonthCalendar } = require('../../utils/core/index.js');
|
||||
const {
|
||||
getDayInfo, getAlmanacInfo, getMonthCalendar,
|
||||
getLegalHoliday, isWorkday, getUpcomingFestivals, getNextBuddhistFestival
|
||||
} = require('../../utils/core/index.js');
|
||||
const { SOLAR_TERM_TIMES } = require('../../utils/core/data.js');
|
||||
|
||||
function pad(n) { return String(n).padStart(2, '0'); }
|
||||
function fmt(y, m, d) { return `${y}-${pad(m)}-${pad(d)}`; }
|
||||
|
||||
const MONTH_SPAN = 2; // 当前月前后各2个月,共5个月
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 20,
|
||||
navBarHeight: 44,
|
||||
viewMode: 'day', // day | month
|
||||
viewMode: 'day',
|
||||
dayInfo: {},
|
||||
almanac: {},
|
||||
// 月历
|
||||
year: 0,
|
||||
month: 0,
|
||||
legalHoliday: null,
|
||||
workday: true,
|
||||
termTime: '',
|
||||
isFirstOrFifteen: false,
|
||||
nextBuddhist: null,
|
||||
showBuddhist: false,
|
||||
highlightLunar: true,
|
||||
upcoming: [],
|
||||
// 月历 swiper
|
||||
monthList: [], // [{key, year, month, weeks}]
|
||||
monthIndex: 2, // 当前居中
|
||||
currentYear: 0,
|
||||
currentMonth: 0,
|
||||
weekHeaders: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
calendarDays: [],
|
||||
selectedDay: null
|
||||
// 全屏弹窗
|
||||
zoomVisible: false,
|
||||
zoomTitle: '',
|
||||
zoomType: '', // yiji | detail | fest
|
||||
zoomData: null
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -23,18 +42,33 @@ Page({
|
||||
const menu = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null;
|
||||
const statusBarHeight = sys.statusBarHeight || 20;
|
||||
let navBarHeight = 44;
|
||||
if (menu && menu.top) {
|
||||
navBarHeight = (menu.top - statusBarHeight) * 2 + menu.height;
|
||||
}
|
||||
if (menu && menu.top) navBarHeight = (menu.top - statusBarHeight) * 2 + menu.height;
|
||||
this.setData({ statusBarHeight, navBarHeight });
|
||||
this.loadSettings();
|
||||
this.loadDay(new Date());
|
||||
this.loadUpcoming();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadSettings();
|
||||
// 设置可能变化,刷新
|
||||
if (this.data.dayInfo.solarYear) this.refreshDerived();
|
||||
},
|
||||
|
||||
loadSettings() {
|
||||
const s = wx.getStorageSync('lunar-settings') || {};
|
||||
this.setData({
|
||||
showBuddhist: s.showBuddhist === true,
|
||||
highlightLunar: s.highlightLunar !== false
|
||||
});
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
if (this.data.viewMode === 'day') {
|
||||
this.loadDay(new Date());
|
||||
this.loadUpcoming();
|
||||
} else {
|
||||
this.loadCalendar();
|
||||
this.buildMonthList(this.data.currentYear, this.data.currentMonth);
|
||||
}
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
@@ -46,10 +80,26 @@ Page({
|
||||
const d = date.getDate();
|
||||
const dayInfo = getDayInfo(y, m, d);
|
||||
const almanac = getAlmanacInfo(y, m, d);
|
||||
this.setData({ dayInfo, almanac, year: y, month: m });
|
||||
this.setData({ dayInfo, almanac, currentYear: y, currentMonth: m });
|
||||
this.refreshDerived();
|
||||
},
|
||||
|
||||
/** 计算派生数据(节假日/工作日/佛历/初一十五) */
|
||||
refreshDerived() {
|
||||
const { dayInfo, showBuddhist, highlightLunar } = this.data;
|
||||
const { solarYear: y, solarMonth: m, solarDay: d } = dayInfo;
|
||||
const legalHoliday = getLegalHoliday(y, m, d);
|
||||
const workday = isWorkday(y, m, d);
|
||||
const termTime = dayInfo.solarTerm ? (SOLAR_TERM_TIMES[dayInfo.solarTerm] || '') : '';
|
||||
const isFirstOrFifteen = highlightLunar && (dayInfo.lunarDay === 1 || dayInfo.lunarDay === 15);
|
||||
const nextBuddhist = showBuddhist ? getNextBuddhistFestival() : null;
|
||||
this.setData({ legalHoliday, workday, termTime, isFirstOrFifteen, nextBuddhist });
|
||||
},
|
||||
|
||||
loadUpcoming() {
|
||||
this.setData({ upcoming: getUpcomingFestivals(5) });
|
||||
},
|
||||
|
||||
/** 前一天 / 后一天 */
|
||||
prevDay() { this.shiftDay(-1); },
|
||||
nextDay() { this.shiftDay(1); },
|
||||
shiftDay(delta) {
|
||||
@@ -58,45 +108,72 @@ Page({
|
||||
this.loadDay(date);
|
||||
},
|
||||
|
||||
/** 回到今天 */
|
||||
backToday() {
|
||||
this.loadDay(new Date());
|
||||
this.loadUpcoming();
|
||||
},
|
||||
|
||||
/** 切换 日视图/月历视图 */
|
||||
/** 切换 日/月 视图 */
|
||||
toggleView() {
|
||||
const mode = this.data.viewMode === 'day' ? 'month' : 'day';
|
||||
this.setData({ viewMode: mode });
|
||||
if (mode === 'month') {
|
||||
const { dayInfo } = this.data;
|
||||
this.setData({ year: dayInfo.solarYear, month: dayInfo.solarMonth }, () => this.loadCalendar());
|
||||
this.buildMonthList(dayInfo.solarYear, dayInfo.solarMonth);
|
||||
}
|
||||
},
|
||||
|
||||
/** 月历 */
|
||||
loadCalendar() {
|
||||
const { year, month } = this.data;
|
||||
const weeks = getMonthCalendar(year, month);
|
||||
const calendarDays = [];
|
||||
weeks.forEach(w => w.forEach(d => calendarDays.push(d)));
|
||||
this.setData({ calendarDays });
|
||||
/** 构建5个月的数据,居中显示 */
|
||||
buildMonthList(year, month) {
|
||||
const monthList = [];
|
||||
for (let i = -MONTH_SPAN; i <= MONTH_SPAN; i++) {
|
||||
let y = year, m = month + i;
|
||||
while (m < 1) { m += 12; y--; }
|
||||
while (m > 12) { m -= 12; y++; }
|
||||
const weeks = getMonthCalendar(y, m);
|
||||
monthList.push({ key: `${y}-${m}`, year: y, month: m, weeks });
|
||||
}
|
||||
this.setData({ monthList, monthIndex: MONTH_SPAN, currentYear: year, currentMonth: month });
|
||||
},
|
||||
|
||||
prevMonth() {
|
||||
let { year, month } = this.data;
|
||||
month--;
|
||||
if (month < 1) { month = 12; year--; }
|
||||
this.setData({ year, month }, () => this.loadCalendar());
|
||||
/** swiper 切换 */
|
||||
onMonthSwiperChange(e) {
|
||||
const index = e.detail.current;
|
||||
const { monthList } = this.data;
|
||||
const cur = monthList[index];
|
||||
this.setData({ monthIndex: index, currentYear: cur.year, currentMonth: cur.month });
|
||||
|
||||
// 边缘时向对应方向补一个月,保持可无限滚动
|
||||
if (index === 0) {
|
||||
this.prependMonth();
|
||||
} else if (index === monthList.length - 1) {
|
||||
this.appendMonth();
|
||||
}
|
||||
},
|
||||
|
||||
nextMonth() {
|
||||
let { year, month } = this.data;
|
||||
month++;
|
||||
if (month > 12) { month = 1; year++; }
|
||||
this.setData({ year, month }, () => this.loadCalendar());
|
||||
prependMonth() {
|
||||
const { monthList } = this.data;
|
||||
const first = monthList[0];
|
||||
let y = first.year, m = first.month - 1;
|
||||
if (m < 1) { m = 12; y--; }
|
||||
const weeks = getMonthCalendar(y, m);
|
||||
monthList.unshift({ key: `${y}-${m}`, year: y, month: m, weeks });
|
||||
if (monthList.length > 7) monthList.pop();
|
||||
this.setData({ monthList, monthIndex: this.data.monthIndex + 1 });
|
||||
},
|
||||
|
||||
/** 月历中选中某天 → 切回日视图 */
|
||||
appendMonth() {
|
||||
const { monthList } = this.data;
|
||||
const last = monthList[monthList.length - 1];
|
||||
let y = last.year, m = last.month + 1;
|
||||
if (m > 12) { m = 1; y++; }
|
||||
const weeks = getMonthCalendar(y, m);
|
||||
monthList.push({ key: `${y}-${m}`, year: y, month: m, weeks });
|
||||
if (monthList.length > 7) monthList.shift();
|
||||
this.setData({ monthList, monthIndex: this.data.monthIndex - 1 });
|
||||
},
|
||||
|
||||
/** 月历点选某天 → 切回日视图 */
|
||||
selectDay(e) {
|
||||
const date = e.currentTarget.dataset.date;
|
||||
const [y, m, d] = date.split('-').map(Number);
|
||||
@@ -104,13 +181,57 @@ Page({
|
||||
this.setData({ viewMode: 'day' });
|
||||
},
|
||||
|
||||
/** 跳详情页 */
|
||||
goDetail() {
|
||||
const { dayInfo } = this.data;
|
||||
wx.navigateTo({ url: `/pages/day-detail/day-detail?date=${fmt(dayInfo.solarYear, dayInfo.solarMonth, dayInfo.solarDay)}` });
|
||||
},
|
||||
|
||||
/** 跳转到某节日的老黄历 */
|
||||
goFestival(e) {
|
||||
const date = e.currentTarget.dataset.date;
|
||||
const [y, m, d] = date.split('-').map(Number);
|
||||
this.loadDay(new Date(y, m - 1, d));
|
||||
this.setData({ viewMode: 'day' });
|
||||
wx.pageScrollTo && wx.pageScrollTo({ scrollTop: 0, duration: 0 });
|
||||
},
|
||||
|
||||
/** ===== 全屏放大弹窗 ===== */
|
||||
openZoom(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
const { dayInfo, almanac, legalHoliday, termTime } = this.data;
|
||||
let zoomTitle = '';
|
||||
let zoomData = null;
|
||||
if (type === 'yiji') {
|
||||
zoomTitle = `${dayInfo.solarMonth}月${dayInfo.solarDay}日 宜忌`;
|
||||
zoomData = { recommends: almanac.recommends, avoids: almanac.avoids };
|
||||
} else if (type === 'detail') {
|
||||
zoomTitle = `${dayInfo.solarMonth}月${dayInfo.solarDay}日 黄历详情`;
|
||||
zoomData = {
|
||||
lunar: `${dayInfo.lunarMonthName}${dayInfo.lunarDayName}`,
|
||||
ganzhi: `${dayInfo.lunarYearGanzhi}年 ${dayInfo.lunarMonthGanzhi}月 ${dayInfo.lunarDayGanzhi}日`,
|
||||
duty: almanac.duty,
|
||||
twelveStar: `${almanac.twelveStar.name}(${almanac.twelveStar.ecliptic})`,
|
||||
twentyEightStar: almanac.twentyEightStar.name,
|
||||
sixStar: almanac.sixStar,
|
||||
clash: `冲${almanac.clash} 煞${almanac.evilDirection}`,
|
||||
pengZu: almanac.pengZu,
|
||||
legalHoliday,
|
||||
termTime: dayInfo.solarTerm ? `${dayInfo.solarTerm} ${termTime}` : ''
|
||||
};
|
||||
} else if (type === 'fest') {
|
||||
zoomTitle = '近期节日';
|
||||
zoomData = { upcoming: this.data.upcoming };
|
||||
}
|
||||
this.setData({ zoomVisible: true, zoomTitle, zoomType: type, zoomData });
|
||||
},
|
||||
|
||||
closeZoom() {
|
||||
this.setData({ zoomVisible: false });
|
||||
},
|
||||
|
||||
navTo(e) {
|
||||
wx.navigateTo({ url: e.currentTarget.dataset.url });
|
||||
}
|
||||
},
|
||||
|
||||
noop() {}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user