重构首页与tabBar:老黄历大日历+月历切换,新增百科页
Publish Mini Program Dev Version / publish (push) Successful in 3m16s

tabBar(5个,全部带图标):
- 老黄历(首页) / 许愿 / 八字 / 百科(新) / 我的(原设置)
- 移除日历tab,月历并入首页左上角切换
- 移除运势tab,改从'我的'页进入

首页重构:
- custom 导航栏,标题'老黄历'
- 老式万年历大日历卡片:大日期+农历+干支+宜忌
- 左右箭头切换日期,'回到今天'
- 左上角'月历/日历'切换按钮,月历视图复用原日历网格
- 月历点选日期自动切回日视图

新增百科页:
- 二十四节气/农历节日/公历节日/干支生肖/黄历术语 分类
- 搜索 + 展开详情

我的页(原设置):
- 新增功能入口:每日运势/占卜/二十四节气/月历视图
This commit is contained in:
gouki
2026-08-07 08:55:17 +00:00
parent ce7d5ecdc7
commit 5d40019ea5
23 changed files with 777 additions and 139 deletions
+98 -10
View File
@@ -1,28 +1,116 @@
const { getTodayInfo, getAlmanacInfo } = require('../../utils/core/index.js');
const { getDayInfo, getAlmanacInfo, getMonthCalendar } = require('../../utils/core/index.js');
function pad(n) { return String(n).padStart(2, '0'); }
function fmt(y, m, d) { return `${y}-${pad(m)}-${pad(d)}`; }
Page({
data: {
statusBarHeight: 20,
navBarHeight: 44,
viewMode: 'day', // day | month
dayInfo: {},
almanac: {}
almanac: {},
// 月历
year: 0,
month: 0,
weekHeaders: ['日', '一', '二', '三', '四', '五', '六'],
calendarDays: [],
selectedDay: null
},
onLoad() {
this.loadData();
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.loadDay(new Date());
},
onPullDownRefresh() {
this.loadData();
if (this.data.viewMode === 'day') {
this.loadDay(new Date());
} else {
this.loadCalendar();
}
wx.stopPullDownRefresh();
},
loadData() {
const dayInfo = getTodayInfo();
const almanac = getAlmanacInfo(dayInfo.solarYear, dayInfo.solarMonth, dayInfo.solarDay);
this.setData({ dayInfo, almanac });
/** 加载某日的老黄历 */
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, year: y, month: m });
},
/** 前一天 / 后一天 */
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());
},
/** 切换 日视图/月历视图 */
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());
}
},
/** 月历 */
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 });
},
prevMonth() {
let { year, month } = this.data;
month--;
if (month < 1) { month = 12; year--; }
this.setData({ year, month }, () => this.loadCalendar());
},
nextMonth() {
let { year, month } = this.data;
month++;
if (month > 12) { month = 1; year++; }
this.setData({ year, month }, () => this.loadCalendar());
},
/** 月历中选中某天 → 切回日视图 */
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)}` });
},
navTo(e) {
const url = e.currentTarget.dataset.url;
wx.navigateTo({ url });
wx.navigateTo({ url: e.currentTarget.dataset.url });
}
});
+1 -1
View File
@@ -1,5 +1,5 @@
{
"navigationBarTitleText": "万年历",
"navigationStyle": "custom",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}
+131 -92
View File
@@ -1,95 +1,134 @@
<view class="container">
<!-- 顶部日期卡片 -->
<view class="card date-card">
<view class="flex justify-between items-center">
<view>
<text class="text-3xl font-bold">{{dayInfo.solarDay}}</text>
<text class="text-lg text-muted ml-2">{{dayInfo.solarMonth}}月{{dayInfo.solarYear}}年</text>
</view>
<view class="text-right">
<text class="text-base">{{dayInfo.weekDay}}</text>
<text class="text-sm text-muted block">{{dayInfo.constellation}}</text>
</view>
<image class="settings-entry" src="/images/settings.png" mode="aspectFit" bindtap="navTo" data-url="/pages/settings/settings"></image>
</view>
<view class="mt-2 flex items-center gap-2">
<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>
</view>
<!-- 农历信息 -->
<view class="card">
<view class="flex justify-between items-center">
<view>
<text class="text-2xl font-bold font-chinese">{{dayInfo.lunarMonthName}}{{dayInfo.lunarDayName}}</text>
<text class="text-sm text-muted block mt-1">{{dayInfo.lunarYearGanzhi}}年 {{dayInfo.lunarMonthGanzhi}}月 {{dayInfo.lunarDayGanzhi}}日</text>
</view>
<view class="text-right">
<text class="text-lg font-medium">{{dayInfo.zodiac}}年</text>
<text class="text-sm text-muted block">{{dayInfo.moonPhase}}</text>
</view>
</view>
</view>
<!-- 宜忌 -->
<view class="card">
<view class="flex gap-2 mb-2">
<view class="flex-1">
<text class="text-lucky font-bold text-lg">宜</text>
<view class="flex flex-wrap gap-1 mt-1">
<text class="badge badge-lucky" wx:for="{{almanac.recommends}}" wx:key="*this">{{item}}</text>
</view>
</view>
<view class="flex-1">
<text class="text-unlucky font-bold text-lg">忌</text>
<view class="flex flex-wrap gap-1 mt-1">
<text class="badge badge-unlucky" wx:for="{{almanac.avoids}}" wx:key="*this">{{item}}</text>
</view>
</view>
</view>
</view>
<!-- 黄历详情 -->
<view class="card">
<view class="grid grid-cols-2 gap-2">
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">值神</text>
<text class="text-base font-medium block">{{almanac.duty}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">黄道</text>
<text class="text-base font-medium block">{{almanac.twelveStar.name}}{{almanac.twelveStar.ecliptic}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">二十八宿</text>
<text class="text-base font-medium block">{{almanac.twentyEightStar.name}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">六曜</text>
<text class="text-base font-medium block">{{almanac.sixStar}}</text>
</view>
</view>
</view>
<!-- 快捷入口 -->
<view class="grid grid-cols-4 gap-2 mt-2">
<view class="quick-entry" bindtap="navTo" data-url="/pages/calendar/calendar">
<image src="/images/calendar.png" class="quick-icon" mode="aspectFit"/>
<text class="text-sm">日历</text>
</view>
<view class="quick-entry" bindtap="navTo" data-url="/pages/bazi/bazi">
<image src="/images/bazi.png" class="quick-icon" mode="aspectFit"/>
<text class="text-sm">八字</text>
</view>
<view class="quick-entry" bindtap="navTo" data-url="/pages/fortune/fortune">
<image src="/images/fortune.png" class="quick-icon" mode="aspectFit"/>
<text class="text-sm">运势</text>
</view>
<view class="quick-entry" bindtap="navTo" data-url="/pages/divination/divination">
<image src="/images/divination.png" class="quick-icon" mode="aspectFit"/>
<text class="text-sm">占卜</text>
<!-- 自定义导航栏 -->
<view class="custom-nav" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-inner" style="height: {{navBarHeight}}px;">
<view class="nav-toggle" bindtap="toggleView">
<text class="nav-toggle-text">{{viewMode === 'day' ? '月历' : '日历'}}</text>
</view>
<text class="nav-title font-chinese">老黄历</text>
<view class="nav-right"></view>
</view>
</view>
<!-- 日视图:老黄历 -->
<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-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>
</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>
<!-- 农历 -->
<view class="almanac-lunar">
<text class="almanac-lunar-main font-chinese">{{dayInfo.lunarMonthName}}{{dayInfo.lunarDayName}}</text>
<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>
<!-- 宜忌 -->
<view class="yiji-row">
<view class="yiji-col">
<view class="yiji-title yi">宜</view>
<view class="yiji-items">
<text class="yiji-item yi" wx:for="{{almanac.recommends}}" wx:key="*this">{{item}}</text>
</view>
</view>
<view class="yiji-divider"></view>
<view class="yiji-col">
<view class="yiji-title ji">忌</view>
<view class="yiji-items">
<text class="yiji-item ji" wx:for="{{almanac.avoids}}" wx:key="*this">{{item}}</text>
</view>
</view>
</view>
<!-- 回今天 -->
<view class="back-today" wx:if="{{!dayInfo.isToday}}" bindtap="backToday">回到今天</view>
</view>
<!-- 黄历详情 -->
<view class="card">
<view class="grid grid-cols-2 gap-2">
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">值神</text>
<text class="text-base font-medium block">{{almanac.duty}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">黄道</text>
<text class="text-base font-medium block">{{almanac.twelveStar.name}}{{almanac.twelveStar.ecliptic}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">二十八宿</text>
<text class="text-base font-medium block">{{almanac.twentyEightStar.name}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">六曜</text>
<text class="text-base font-medium block">{{almanac.sixStar}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">冲煞</text>
<text class="text-base font-medium block">冲{{almanac.clash}} 煞{{almanac.evilDirection}}</text>
</view>
<view class="p-2 bg-page rounded">
<text class="text-xs text-muted">彭祖百忌</text>
<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>
<!-- 星期头 -->
<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>
</view>
</view>
</scroll-view>
+247 -18
View File
@@ -1,38 +1,267 @@
/* 自定义导航栏 */
.custom-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
background: #C41E3A;
z-index: 100;
}
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
}
.nav-toggle {
min-width: 96rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
border: 1rpx solid rgba(255, 255, 255, 0.5);
border-radius: 999rpx;
padding: 0 20rpx;
}
.nav-toggle-text {
color: #FFFFFF;
font-size: 24rpx;
}
.nav-title {
color: #FFFFFF;
font-size: 34rpx;
font-weight: 600;
letter-spacing: 4rpx;
}
.nav-right {
min-width: 96rpx;
}
/* 页面主体 */
.page-body {
box-sizing: border-box;
min-height: 100vh;
}
.container {
padding: 20rpx;
padding-bottom: 40rpx;
}
.date-card {
background: linear-gradient(135deg, #C41E3A 0%, #8B1A2B 100%);
/* ===== 老黄历大日历卡片 ===== */
.almanac-card {
background: linear-gradient(160deg, #FFFFFF 0%, #FFF8EF 100%);
border: 1rpx solid #E8D5C4;
border-radius: 24rpx;
padding: 32rpx 24rpx;
margin-bottom: 16rpx;
position: relative;
}
.almanac-head {
display: flex;
justify-content: space-between;
align-items: center;
}
.almanac-year {
font-size: 30rpx;
color: #6B5E53;
font-weight: 500;
}
.almanac-week {
font-size: 24rpx;
color: #9E8E7E;
margin-left: 16rpx;
}
.today-tag {
background: #C41E3A;
color: #FFFFFF;
border: none;
font-size: 20rpx;
padding: 4rpx 20rpx;
border-radius: 999rpx;
}
.date-card .text-muted {
color: rgba(255,255,255,0.7);
/* 大日期 */
.almanac-day-row {
display: flex;
align-items: center;
justify-content: center;
margin: 16rpx 0 8rpx;
}
.quick-entry {
.almanac-day-num {
font-size: 160rpx;
font-weight: 700;
color: #C41E3A;
line-height: 1.1;
min-width: 320rpx;
text-align: center;
}
.day-arrow {
font-size: 64rpx;
color: #C9B8A6;
padding: 0 32rpx;
}
/* 农历 */
.almanac-lunar {
text-align: center;
margin-bottom: 16rpx;
}
.almanac-lunar-main {
font-size: 44rpx;
font-weight: 600;
color: #1A1A1A;
display: block;
}
.almanac-lunar-sub {
font-size: 24rpx;
color: #9E8E7E;
display: block;
margin-top: 8rpx;
}
/* 节日 */
.almanac-fest {
display: flex;
justify-content: center;
gap: 12rpx;
margin-bottom: 16rpx;
}
/* 宜忌 */
.yiji-row {
display: flex;
border-top: 1rpx solid #F0E6DA;
padding-top: 24rpx;
}
.yiji-col {
flex: 1;
display: flex;
gap: 16rpx;
}
.yiji-divider {
width: 1rpx;
background: #F0E6DA;
margin: 0 16rpx;
}
.yiji-title {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
font-weight: 700;
flex-shrink: 0;
}
.yiji-title.yi {
background: #C41E3A;
color: #FFFFFF;
}
.yiji-title.ji {
background: #546E7A;
color: #FFFFFF;
}
.yiji-items {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
align-content: flex-start;
}
.yiji-item {
font-size: 24rpx;
padding: 4rpx 14rpx;
border-radius: 8rpx;
}
.yiji-item.yi {
background: #FEF2F2;
color: #C41E3A;
}
.yiji-item.ji {
background: #F1F5F9;
color: #546E7A;
}
/* 回到今天 */
.back-today {
text-align: center;
margin-top: 20rpx;
color: #C41E3A;
font-size: 26rpx;
padding: 12rpx;
}
.detail-btn {
text-align: center;
}
/* ===== 月历 ===== */
.day-cell {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24rpx;
padding: 12rpx 4rpx;
background: #FFFFFF;
border-radius: 16rpx;
border: 1rpx solid #E8D5C4;
border-radius: 12rpx;
min-height: 100rpx;
}
.quick-icon {
width: 64rpx;
height: 64rpx;
margin-bottom: 8rpx;
.day-cell.today {
background: #C41E3A;
color: #FFFFFF;
}
.settings-entry {
width: 44rpx;
height: 44rpx;
margin-left: 16rpx;
opacity: 0.6;
.day-cell.today .day-lunar {
color: rgba(255, 255, 255, 0.8);
}
.day-cell.other-month {
opacity: 0.4;
}
.day-number {
font-size: 28rpx;
font-weight: 500;
}
.day-lunar {
font-size: 20rpx;
color: #9E8E7E;
margin-top: 4rpx;
}
.day-lunar.festival {
color: #C41E3A;
font-weight: 500;
}
.day-dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: #C41E3A;
margin-top: 4rpx;
}