首页老黄历全面升级 + 修复农历转换核心bug
Publish Mini Program Dev Version / publish (push) Successful in 2m8s

【重要修复】重写农历双向转换算法(原来全错):
- 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:
gouki
2026-08-07 12:49:57 +00:00
parent 5d40019ea5
commit 82c1a8d694
11 changed files with 1636 additions and 425 deletions
+157 -36
View File
@@ -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() {}
});
+170 -51
View File
@@ -12,24 +12,26 @@
<!-- 日视图:老黄历 -->
<scroll-view class="page-body" scroll-y wx:if="{{viewMode === 'day'}}" style="padding-top: {{statusBarHeight + navBarHeight}}px;">
<view class="container">
<!-- 大日历卡片 -->
<view class="almanac-card">
<!-- 大日历卡片(点击放大) -->
<view class="almanac-card {{legalHoliday ? 'is-holiday' : (workday ? 'is-workday' : 'is-weekend')}}" bindtap="openZoom" data-type="detail">
<!-- 顶部:公历 -->
<view class="almanac-head">
<view class="almanac-head-left">
<text class="almanac-year">{{dayInfo.solarYear}}年{{dayInfo.solarMonth}}月</text>
<text class="almanac-week">{{dayInfo.weekDay}} · {{dayInfo.constellation}}</text>
</view>
<view class="almanac-head-right" wx:if="{{dayInfo.isToday}}">
<text class="today-tag">今日</text>
<view class="head-tags">
<text class="today-tag" wx:if="{{dayInfo.isToday}}">今日</text>
<text class="lunar-tag" wx:if="{{isFirstOrFifteen}}">{{dayInfo.lunarDay === 1 ? '初一' : '十五'}}</text>
</view>
</view>
<!-- 大日期 -->
<view class="almanac-day-row">
<view class="day-arrow" bindtap="prevDay"></view>
<view class="almanac-day-num font-chinese">{{dayInfo.solarDay}}</view>
<view class="day-arrow" bindtap="nextDay"></view>
<view class="almanac-day-row" catchtap="noop">
<view class="day-arrow" catchtap="prevDay"></view>
<view class="almanac-day-num font-chinese {{legalHoliday ? 'num-holiday' : (workday ? 'num-workday' : 'num-weekend')}}">{{dayInfo.solarDay}}</view>
<view class="day-arrow" catchtap="nextDay"></view>
</view>
<!-- 农历 -->
@@ -38,14 +40,27 @@
<text class="almanac-lunar-sub">{{dayInfo.lunarYearGanzhi}}年 {{dayInfo.lunarMonthGanzhi}}月 {{dayInfo.lunarDayGanzhi}}日 · 属{{dayInfo.zodiac}}</text>
</view>
<!-- 节日/节气 -->
<view class="almanac-fest" wx:if="{{dayInfo.lunarFestival || dayInfo.solarFestival || dayInfo.solarTerm}}">
<text class="badge badge-festival" wx:if="{{dayInfo.lunarFestival}}">{{dayInfo.lunarFestival}}</text>
<text class="badge badge-festival" wx:if="{{dayInfo.solarFestival}}">{{dayInfo.solarFestival}}</text>
<text class="badge badge-outline" wx:if="{{dayInfo.solarTerm}}">{{dayInfo.solarTerm}}</text>
<!-- 节日/节气/佛历 -->
<view class="almanac-fest" wx:if="{{legalHoliday || dayInfo.lunarFestival || dayInfo.solarFestival || dayInfo.solarTerm}}">
<text class="badge badge-holiday" wx:if="{{legalHoliday}}">{{legalHoliday}}</text>
<text class="badge badge-festival" wx:if="{{dayInfo.lunarFestival && !legalHoliday}}">{{dayInfo.lunarFestival}}</text>
<text class="badge badge-festival" wx:if="{{dayInfo.solarFestival && !legalHoliday}}">{{dayInfo.solarFestival}}</text>
<text class="badge badge-term" wx:if="{{dayInfo.solarTerm}}">{{dayInfo.solarTerm}}{{termTime ? ' ' + termTime : ''}}</text>
</view>
<!-- 宜忌 -->
<!-- 佛历提醒 -->
<view class="buddhist-tip" wx:if="{{showBuddhist && nextBuddhist}}" catchtap="noop">
<text class="buddhist-text">🪷 距 {{nextBuddhist.name}} 还有 {{nextBuddhist.daysLeft}} 天({{nextBuddhist.solarDate}}</text>
</view>
<!-- 工作日/节假日提示 -->
<view class="day-type-tip {{legalHoliday ? 'tip-holiday' : (workday ? 'tip-workday' : 'tip-weekend')}}">
{{legalHoliday ? legalHoliday + ' · 放假' : (workday ? '工作日 · 上班' : '周末 · 休息')}}
</view>
</view>
<!-- 宜忌(点击放大) -->
<view class="card yiji-card" bindtap="openZoom" data-type="yiji">
<view class="yiji-row">
<view class="yiji-col">
<view class="yiji-title yi">宜</view>
@@ -61,13 +76,11 @@
</view>
</view>
</view>
<!-- 回今天 -->
<view class="back-today" wx:if="{{!dayInfo.isToday}}" bindtap="backToday">回到今天</view>
<view class="zoom-hint">点击放大 🔍</view>
</view>
<!-- 黄历详情 -->
<view class="card">
<!-- 黄历详情(点击放大) -->
<view class="card" bindtap="openZoom" data-type="detail">
<view class="grid grid-cols-2 gap-2">
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">值神</text>
@@ -94,41 +107,147 @@
<text class="text-base font-medium block">{{almanac.pengZu}}</text>
</view>
</view>
<view class="btn-primary mt-2 detail-btn" bindtap="goDetail">查看详情</view>
</view>
</view>
</scroll-view>
<!-- 月历视图 -->
<scroll-view class="page-body" scroll-y wx:if="{{viewMode === 'month'}}" style="padding-top: {{statusBarHeight + navBarHeight}}px;">
<view class="container">
<!-- 年月切换 -->
<view class="card flex justify-between items-center">
<view class="btn-ghost" bindtap="prevMonth"></view>
<view class="text-xl font-bold">{{year}}年{{month}}月</view>
<view class="btn-ghost" bindtap="nextMonth"></view>
<view class="zoom-hint">点击放大 🔍</view>
</view>
<!-- 星期头 -->
<view class="grid grid-cols-7 gap-1 mb-1">
<view class="text-center text-sm text-muted" wx:for="{{weekHeaders}}" wx:key="*this">{{item}}</view>
</view>
<!-- 日历网格 -->
<view class="grid grid-cols-7 gap-1">
<view
class="day-cell {{item.isToday ? 'today' : ''}} {{item.solarMonth !== month ? 'other-month' : ''}}"
wx:for="{{calendarDays}}"
wx:key="solarDate"
bindtap="selectDay"
data-date="{{item.solarDate}}"
>
<text class="day-number">{{item.solarDay}}</text>
<text class="day-lunar {{item.lunarFestival || item.solarFestival ? 'festival' : ''}}">
{{item.lunarFestival || item.solarFestival || item.lunarDayName}}
</text>
<view class="day-dot" wx:if="{{item.isTermDay}}"></view>
<!-- 节日速查 -->
<view class="card" bindtap="openZoom" data-type="fest">
<view class="section-title">节日速查</view>
<view class="fest-quick">
<view class="fest-quick-item" wx:for="{{upcoming}}" wx:key="name" catchtap="goFestival" data-date="{{item.solarDate}}">
<text class="fest-name">{{item.name}}</text>
<text class="fest-date">{{item.solarMonth}}月{{item.solarDay}}日</text>
<text class="fest-left {{item.daysLeft === 0 ? 'is-today' : ''}}">{{item.daysLeft === 0 ? '今天' : item.daysLeft + '天后'}}</text>
</view>
</view>
</view>
<!-- 回今天 -->
<view class="back-today" wx:if="{{!dayInfo.isToday}}" bindtap="backToday">回到今天</view>
</view>
</scroll-view>
<!-- 月历视图:swiper 上下/左右滚动换月 -->
<view class="page-body month-body" wx:if="{{viewMode === 'month'}}" style="padding-top: {{statusBarHeight + navBarHeight}}px;">
<view class="month-header">
<text class="month-title font-chinese">{{currentYear}}年{{currentMonth}}月</text>
<text class="month-hint">上下或左右滑动换月</text>
</view>
<view class="grid grid-cols-7 week-head">
<view class="text-center week-cell" wx:for="{{weekHeaders}}" wx:key="*this">{{item}}</view>
</view>
<swiper
class="month-swiper"
vertical="{{false}}"
circular="{{false}}"
current="{{monthIndex}}"
bindchange="onMonthSwiperChange"
duration="300"
>
<swiper-item wx:for="{{monthList}}" wx:key="key">
<scroll-view scroll-y class="month-scroll">
<view class="grid grid-cols-7 month-grid">
<view
class="day-cell {{d.isToday ? 'today' : ''}} {{d.solarMonth !== item.month ? 'other-month' : ''}}"
wx:for="{{item.weeks}}"
wx:for-item="week"
wx:key="week"
>
<block wx:for="{{week}}" wx:for-item="d" wx:key="solarDate">
<view
class="day-cell-inner {{d.isToday ? 'today' : ''}} {{d.solarMonth !== item.month ? 'other-month' : ''}}"
bindtap="selectDay"
data-date="{{d.solarDate}}"
>
<text class="day-number">{{d.solarDay}}</text>
<text class="day-lunar {{d.lunarFestival || d.solarFestival ? 'festival' : ''}}">
{{d.lunarFestival || d.solarFestival || d.lunarDayName}}
</text>
<view class="day-dot" wx:if="{{d.isTermDay}}"></view>
</view>
</block>
</view>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
<!-- 全屏放大弹窗(老年友好) -->
<view class="zoom-mask {{zoomVisible ? 'show' : ''}}" bindtap="closeZoom">
<view class="zoom-panel" catchtap="noop">
<view class="zoom-header">
<text class="zoom-title font-chinese">{{zoomTitle}}</text>
<view class="zoom-close" bindtap="closeZoom">✕</view>
</view>
<!-- 宜忌放大 -->
<scroll-view scroll-y class="zoom-body" wx:if="{{zoomType === 'yiji' && zoomData}}">
<view class="zoom-yiji-block">
<view class="zoom-yiji-title yi">宜</view>
<view class="zoom-yiji-items">
<text class="zoom-yiji-item yi" wx:for="{{zoomData.recommends}}" wx:key="*this">{{item}}</text>
</view>
</view>
<view class="zoom-yiji-block">
<view class="zoom-yiji-title ji">忌</view>
<view class="zoom-yiji-items">
<text class="zoom-yiji-item ji" wx:for="{{zoomData.avoids}}" wx:key="*this">{{item}}</text>
</view>
</view>
</scroll-view>
<!-- 详情放大 -->
<scroll-view scroll-y class="zoom-body" wx:if="{{zoomType === 'detail' && zoomData}}">
<view class="zoom-detail-row" wx:if="{{zoomData.legalHoliday}}">
<text class="zoom-detail-label">节假日</text>
<text class="zoom-detail-value holiday">{{zoomData.legalHoliday}}</text>
</view>
<view class="zoom-detail-row" wx:if="{{zoomData.termTime}}">
<text class="zoom-detail-label">节气</text>
<text class="zoom-detail-value">{{zoomData.termTime}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">农历</text>
<text class="zoom-detail-value">{{zoomData.lunar}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">干支</text>
<text class="zoom-detail-value">{{zoomData.ganzhi}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">值神</text>
<text class="zoom-detail-value">{{zoomData.duty}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">黄道</text>
<text class="zoom-detail-value">{{zoomData.twelveStar}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">二十八宿</text>
<text class="zoom-detail-value">{{zoomData.twentyEightStar}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">六曜</text>
<text class="zoom-detail-value">{{zoomData.sixStar}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">冲煞</text>
<text class="zoom-detail-value">{{zoomData.clash}}</text>
</view>
<view class="zoom-detail-row">
<text class="zoom-detail-label">彭祖百忌</text>
<text class="zoom-detail-value">{{zoomData.pengZu}}</text>
</view>
</scroll-view>
<!-- 节日放大 -->
<scroll-view scroll-y class="zoom-body" wx:if="{{zoomType === 'fest' && zoomData}}">
<view class="zoom-fest-row" wx:for="{{zoomData.upcoming}}" wx:key="name" bindtap="goFestival" data-date="{{item.solarDate}}">
<text class="zoom-fest-name">{{item.name}}</text>
<text class="zoom-fest-date">{{item.solarDate}}</text>
<text class="zoom-fest-left {{item.daysLeft === 0 ? 'is-today' : ''}}">{{item.daysLeft === 0 ? '今天' : '还有' + item.daysLeft + '天'}}</text>
</view>
</scroll-view>
</view>
</view>
+373 -41
View File
@@ -42,7 +42,6 @@
min-width: 96rpx;
}
/* 页面主体 */
.page-body {
box-sizing: border-box;
min-height: 100vh;
@@ -55,12 +54,30 @@
/* ===== 老黄历大日历卡片 ===== */
.almanac-card {
background: linear-gradient(160deg, #FFFFFF 0%, #FFF8EF 100%);
border: 1rpx solid #E8D5C4;
border-radius: 24rpx;
padding: 32rpx 24rpx;
padding: 32rpx 24rpx 24rpx;
margin-bottom: 16rpx;
position: relative;
border: 2rpx solid #E8D5C4;
background: #FFFFFF;
}
/* 节假日:喜庆红 */
.almanac-card.is-holiday {
background: linear-gradient(160deg, #FFF5F4 0%, #FFE8E4 100%);
border-color: #C41E3A;
}
/* 工作日:清新绿 */
.almanac-card.is-workday {
background: linear-gradient(160deg, #F4FBF5 0%, #E6F5E9 100%);
border-color: #4CAF50;
}
/* 周末:米黄 */
.almanac-card.is-weekend {
background: linear-gradient(160deg, #FFFBF0 0%, #FFF3DC 100%);
border-color: #E0A93E;
}
.almanac-head {
@@ -81,6 +98,11 @@
margin-left: 16rpx;
}
.head-tags {
display: flex;
gap: 12rpx;
}
.today-tag {
background: #C41E3A;
color: #FFFFFF;
@@ -89,37 +111,48 @@
border-radius: 999rpx;
}
.lunar-tag {
background: #E0A93E;
color: #FFFFFF;
font-size: 20rpx;
padding: 4rpx 20rpx;
border-radius: 999rpx;
}
/* 大日期 */
.almanac-day-row {
display: flex;
align-items: center;
justify-content: center;
margin: 16rpx 0 8rpx;
margin: 8rpx 0;
}
.almanac-day-num {
font-size: 160rpx;
font-size: 240rpx;
font-weight: 700;
color: #C41E3A;
line-height: 1.1;
min-width: 320rpx;
line-height: 1.05;
min-width: 400rpx;
text-align: center;
}
.num-holiday { color: #C41E3A; }
.num-workday { color: #2E7D32; }
.num-weekend { color: #C41E3A; }
.day-arrow {
font-size: 64rpx;
font-size: 72rpx;
color: #C9B8A6;
padding: 0 32rpx;
padding: 0 28rpx;
}
/* 农历 */
.almanac-lunar {
text-align: center;
margin-bottom: 16rpx;
margin-bottom: 12rpx;
}
.almanac-lunar-main {
font-size: 44rpx;
font-size: 48rpx;
font-weight: 600;
color: #1A1A1A;
display: block;
@@ -136,15 +169,72 @@
.almanac-fest {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 12rpx;
margin-bottom: 16rpx;
margin-bottom: 12rpx;
}
.badge-holiday {
background: #C41E3A;
color: #FFFFFF;
font-size: 24rpx;
padding: 6rpx 24rpx;
}
.badge-festival {
background: #C41E3A;
color: #FFFFFF;
}
.badge-term {
background: #2E7D32;
color: #FFFFFF;
}
/* 佛历提醒 */
.buddhist-tip {
text-align: center;
padding: 12rpx;
margin-bottom: 8rpx;
}
.buddhist-text {
font-size: 26rpx;
color: #B8860B;
}
/* 工作日/节假日提示 */
.day-type-tip {
text-align: center;
font-size: 28rpx;
font-weight: 600;
padding: 12rpx;
border-radius: 12rpx;
margin-top: 8rpx;
}
.tip-holiday {
color: #C41E3A;
background: rgba(196, 30, 58, 0.08);
}
.tip-workday {
color: #2E7D32;
background: rgba(46, 125, 50, 0.08);
}
.tip-weekend {
color: #C41E3A;
background: rgba(196, 30, 58, 0.08);
}
/* 宜忌 */
.yiji-card {
position: relative;
}
.yiji-row {
display: flex;
border-top: 1rpx solid #F0E6DA;
padding-top: 24rpx;
}
.yiji-col {
@@ -171,15 +261,8 @@
flex-shrink: 0;
}
.yiji-title.yi {
background: #C41E3A;
color: #FFFFFF;
}
.yiji-title.ji {
background: #546E7A;
color: #FFFFFF;
}
.yiji-title.yi { background: #C41E3A; color: #FFFFFF; }
.yiji-title.ji { background: #546E7A; color: #FFFFFF; }
.yiji-items {
display: flex;
@@ -189,22 +272,69 @@
}
.yiji-item {
font-size: 24rpx;
font-size: 26rpx;
padding: 4rpx 14rpx;
border-radius: 8rpx;
}
.yiji-item.yi {
background: #FEF2F2;
.yiji-item.yi { background: #FEF2F2; color: #C41E3A; }
.yiji-item.ji { background: #F1F5F9; color: #546E7A; }
.zoom-hint {
text-align: center;
font-size: 20rpx;
color: #C9B8A6;
margin-top: 12rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.yiji-item.ji {
background: #F1F5F9;
color: #546E7A;
/* 节日速查 */
.fest-quick {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.fest-quick-item {
display: flex;
align-items: center;
padding: 16rpx;
background: #FFFBF5;
border-radius: 12rpx;
gap: 16rpx;
}
.fest-name {
font-size: 28rpx;
font-weight: 600;
min-width: 120rpx;
}
.fest-date {
font-size: 24rpx;
color: #9E8E7E;
flex: 1;
}
.fest-left {
font-size: 24rpx;
color: #C41E3A;
font-weight: 500;
}
.fest-left.is-today {
background: #C41E3A;
color: #FFFFFF;
padding: 2rpx 16rpx;
border-radius: 999rpx;
}
/* 回到今天 */
.back-today {
text-align: center;
margin-top: 20rpx;
@@ -213,37 +343,86 @@
padding: 12rpx;
}
.detail-btn {
/* ===== 月历视图 ===== */
.month-body {
display: flex;
flex-direction: column;
height: 100vh;
box-sizing: border-box;
}
.month-header {
text-align: center;
padding: 16rpx 0 8rpx;
}
.month-title {
font-size: 40rpx;
font-weight: 700;
color: #C41E3A;
display: block;
}
.month-hint {
font-size: 20rpx;
color: #C9B8A6;
}
.week-head {
padding: 0 20rpx;
margin-bottom: 4rpx;
}
.week-cell {
font-size: 24rpx;
color: #9E8E7E;
padding: 8rpx 0;
}
.month-swiper {
flex: 1;
height: 100%;
}
.month-scroll {
height: 100%;
}
.month-grid {
padding: 0 20rpx;
gap: 8rpx;
}
/* ===== 月历 ===== */
.day-cell {
background: transparent;
}
.day-cell-inner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 12rpx 4rpx;
padding: 16rpx 4rpx;
background: #FFFFFF;
border-radius: 12rpx;
min-height: 100rpx;
min-height: 110rpx;
}
.day-cell.today {
.day-cell-inner.today {
background: #C41E3A;
color: #FFFFFF;
}
.day-cell.today .day-lunar {
.day-cell-inner.today .day-lunar {
color: rgba(255, 255, 255, 0.8);
}
.day-cell.other-month {
opacity: 0.4;
.day-cell-inner.other-month {
opacity: 0.35;
}
.day-number {
font-size: 28rpx;
font-size: 30rpx;
font-weight: 500;
}
@@ -265,3 +444,156 @@
background: #C41E3A;
margin-top: 4rpx;
}
/* ===== 全屏放大弹窗 ===== */
.zoom-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 200;
display: none;
}
.zoom-mask.show {
display: flex;
align-items: center;
justify-content: center;
}
.zoom-panel {
width: 92%;
max-height: 86%;
background: #FFFFFF;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.zoom-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 28rpx;
background: #C41E3A;
}
.zoom-title {
color: #FFFFFF;
font-size: 36rpx;
font-weight: 600;
}
.zoom-close {
color: #FFFFFF;
font-size: 44rpx;
width: 64rpx;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
}
.zoom-body {
padding: 32rpx 28rpx;
max-height: 70vh;
}
/* 宜忌放大 */
.zoom-yiji-block {
margin-bottom: 40rpx;
}
.zoom-yiji-title {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 52rpx;
font-weight: 700;
margin-bottom: 24rpx;
}
.zoom-yiji-title.yi { background: #C41E3A; color: #FFFFFF; }
.zoom-yiji-title.ji { background: #546E7A; color: #FFFFFF; }
.zoom-yiji-items {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.zoom-yiji-item {
font-size: 44rpx;
padding: 16rpx 32rpx;
border-radius: 16rpx;
font-weight: 500;
}
.zoom-yiji-item.yi { background: #FEF2F2; color: #C41E3A; }
.zoom-yiji-item.ji { background: #F1F5F9; color: #546E7A; }
/* 详情放大 */
.zoom-detail-row {
display: flex;
padding: 24rpx 0;
border-bottom: 1rpx solid #F0E6DA;
align-items: center;
}
.zoom-detail-label {
width: 200rpx;
font-size: 36rpx;
color: #9E8E7E;
flex-shrink: 0;
}
.zoom-detail-value {
font-size: 40rpx;
font-weight: 600;
color: #1A1A1A;
flex: 1;
}
.zoom-detail-value.holiday {
color: #C41E3A;
}
/* 节日放大 */
.zoom-fest-row {
display: flex;
align-items: center;
padding: 28rpx 0;
border-bottom: 1rpx solid #F0E6DA;
gap: 24rpx;
}
.zoom-fest-name {
font-size: 44rpx;
font-weight: 600;
min-width: 200rpx;
}
.zoom-fest-date {
font-size: 36rpx;
color: #9E8E7E;
flex: 1;
}
.zoom-fest-left {
font-size: 36rpx;
color: #C41E3A;
font-weight: 500;
}
.zoom-fest-left.is-today {
background: #C41E3A;
color: #FFFFFF;
padding: 4rpx 24rpx;
border-radius: 999rpx;
}