Files
lunar-mini/mini/pages/home/home.js
T
gouki 2bd84eea88 修复节气计算/佛历倒计时/顶部固定高度+老黄历方框
- 节气改用精确查表(2000-2060天文算法生成),修复立秋等大偏差
- 佛历倒计时/节日速查以当前选中日期为基准,切换日期实时更新
- 大日历顶部节日区/佛历区固定高度,空着也占位不再跳动
- 大日期加老黄历式方框(双线边框,节假日红/工作日绿)
2026-08-07 22:57:26 +00:00

241 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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',
dayInfo: {},
almanac: {},
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: ['日', '一', '二', '三', '四', '五', '六'],
// 全屏弹窗
zoomVisible: false,
zoomTitle: '',
zoomType: '', // yiji | detail | fest
zoomData: null
},
onLoad() {
const sys = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync();
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;
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.buildMonthList(this.data.currentYear, this.data.currentMonth);
}
wx.stopPullDownRefresh();
},
/** 加载某日的老黄历 */
loadDay(date) {
const y = date.getFullYear();
const m = date.getMonth() + 1;
const d = date.getDate();
const dayInfo = getDayInfo(y, m, d);
const almanac = getAlmanacInfo(y, m, d);
this.setData({ dayInfo, almanac, currentYear: y, currentMonth: m });
this.refreshDerived();
this.loadUpcoming();
},
/** 计算派生数据(节假日/工作日/佛历/初一十五) */
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(y, m, d) : null;
this.setData({ legalHoliday, workday, termTime, isFirstOrFifteen, nextBuddhist });
},
loadUpcoming() {
const { dayInfo } = this.data;
const { solarYear: y, solarMonth: m, solarDay: d } = dayInfo;
this.setData({ upcoming: getUpcomingFestivals(5, y, m, d) });
},
prevDay() { this.shiftDay(-1); },
nextDay() { this.shiftDay(1); },
shiftDay(delta) {
const { dayInfo } = this.data;
const date = new Date(dayInfo.solarYear, dayInfo.solarMonth - 1, dayInfo.solarDay + delta);
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.buildMonthList(dayInfo.solarYear, dayInfo.solarMonth);
}
},
/** 构建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 });
},
/** 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();
}
},
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);
this.loadDay(new Date(y, m - 1, d));
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() {}
});