重构首页与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
+16 -15
View File
@@ -9,12 +9,13 @@
"pages/solar-terms/solar-terms",
"pages/settings/settings",
"pages/wish-tree/wish-tree",
"pages/wish-detail/wish-detail"
"pages/wish-detail/wish-detail",
"pages/wiki/wiki"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#C41E3A",
"navigationBarTitleText": "万年历",
"navigationBarTitleText": "老黄历",
"navigationBarTextStyle": "white",
"backgroundColor": "#FFFBF5"
},
@@ -26,15 +27,15 @@
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"text": "老黄历",
"iconPath": "images/home.png",
"selectedIconPath": "images/home-active.png"
},
{
"pagePath": "pages/calendar/calendar",
"text": "日历",
"iconPath": "images/calendar.png",
"selectedIconPath": "images/calendar-active.png"
"pagePath": "pages/wish-tree/wish-tree",
"text": "许愿",
"iconPath": "images/wish.png",
"selectedIconPath": "images/wish-active.png"
},
{
"pagePath": "pages/bazi/bazi",
@@ -43,16 +44,16 @@
"selectedIconPath": "images/bazi-active.png"
},
{
"pagePath": "pages/fortune/fortune",
"text": "运势",
"iconPath": "images/fortune.png",
"selectedIconPath": "images/fortune-active.png"
"pagePath": "pages/wiki/wiki",
"text": "百科",
"iconPath": "images/wiki.png",
"selectedIconPath": "images/wiki-active.png"
},
{
"pagePath": "pages/wish-tree/wish-tree",
"text": "许愿",
"iconPath": "images/wish.png",
"selectedIconPath": "images/wish-active.png"
"pagePath": "pages/settings/settings",
"text": "我的",
"iconPath": "images/me.png",
"selectedIconPath": "images/me-active.png"
}
]
},
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 500 B

+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"
}
+91 -52
View File
@@ -1,54 +1,69 @@
<!-- 自定义导航栏 -->
<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="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 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="text-right">
<text class="text-base">{{dayInfo.weekDay}}</text>
<text class="text-sm text-muted block">{{dayInfo.constellation}}</text>
<view class="almanac-head-right" wx:if="{{dayInfo.isToday}}">
<text class="today-tag">今日</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">
<!-- 大日期 -->
<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>
<!-- 农历信息 -->
<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 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="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 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>
<!-- 黄历详情 -->
@@ -70,26 +85,50 @@
<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-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 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="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="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;
}
+4
View File
@@ -58,6 +58,10 @@ Page({
wx.showToast({ title: '已删除', icon: 'success' });
},
navTo(e) {
wx.navigateTo({ url: e.currentTarget.dataset.url });
},
login() {
wx.getUserProfile({
desc: '用于完善用户资料',
+1 -1
View File
@@ -1,4 +1,4 @@
{
"navigationBarTitleText": "设置",
"navigationBarTitleText": "我的",
"enablePullDownRefresh": false
}
+23 -2
View File
@@ -57,12 +57,33 @@
</view>
</view>
<!-- 功能入口 -->
<view class="card">
<view class="section-title">功能</view>
<view class="menu-item" bindtap="navTo" data-url="/pages/fortune/fortune">
<text class="menu-label">每日运势</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" bindtap="navTo" data-url="/pages/divination/divination">
<text class="menu-label">占卜</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" bindtap="navTo" data-url="/pages/solar-terms/solar-terms">
<text class="menu-label">二十四节气</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" bindtap="navTo" data-url="/pages/calendar/calendar">
<text class="menu-label">月历视图</text>
<text class="menu-arrow"></text>
</view>
</view>
<!-- 关于 -->
<view class="card">
<view class="section-title">关于</view>
<view class="text-sm text-muted">
<text>万年历小程序 v1.0.0</text>
<text class="block mt-1">提供农历、黄历、八字、运势、占卜等功能</text>
<text>老黄历小程序 v1.0.1</text>
<text class="block mt-1">提供农历、黄历、八字、许愿等功能</text>
</view>
</view>
</view>
+21
View File
@@ -45,3 +45,24 @@
.bookmark-item:last-child {
border-bottom: none;
}
.menu-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 0;
border-bottom: 1rpx solid #E8D5C4;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-label {
font-size: 28rpx;
}
.menu-arrow {
color: #C9B8A6;
font-size: 36rpx;
}
+138
View File
@@ -0,0 +1,138 @@
const { SOLAR_TERMS, LUNAR_FESTIVALS, SOLAR_FESTIVALS, HEAVEN_STEMS, EARTH_BRANCHES, ZODIACS } = require('../../utils/core/data.js');
const CATEGORIES = [
{ key: 'all', name: '全部' },
{ key: 'term', name: '二十四节气' },
{ key: 'lunarFest', name: '农历节日' },
{ key: 'solarFest', name: '公历节日' },
{ key: 'ganzhi', name: '干支生肖' },
{ key: 'termExplain', name: '黄历术语' }
];
const TERM_BRIEFS = {
'立春': '春季开始,万物复苏', '雨水': '降雨增多,气温回升', '惊蛰': '春雷惊醒蛰伏动物',
'春分': '昼夜平分,春季过半', '清明': '天气晴朗,草木繁茂', '谷雨': '雨生百谷,播种时节',
'立夏': '夏季开始,万物生长', '小满': '麦类籽粒开始饱满', '芒种': '有芒作物成熟,忙于播种',
'夏至': '白昼最长,盛夏来临', '小暑': '天气开始炎热', '大暑': '一年中最热的时期',
'立秋': '秋季开始,暑去凉来', '处暑': '暑气结束,秋意渐浓', '白露': '天气转凉,出现露水',
'秋分': '昼夜平分,秋季过半', '寒露': '露水更凉,秋意更浓', '霜降': '开始降霜,天气渐冷',
'立冬': '冬季开始,万物收藏', '小雪': '开始降雪,气温下降', '大雪': '降雪增多,天气更冷',
'冬至': '白昼最短,数九开始', '小寒': '天气寒冷,但未到极点', '大寒': '一年中最冷的时期'
};
const TERM_EXPLAINS = [
{ title: '干支纪年', brief: '天干地支组合纪年法', content: '天干有十:甲乙丙丁戊己庚辛壬癸;地支有十二:子丑寅卯辰巳午未申酉戌亥。两者按顺序两两组合,形成六十甲子循环,用于纪年、纪月、纪日、纪时。' },
{ title: '建除十二神', brief: '建、除、满、平、定、执、破、危、成、收、开、闭', content: '建除十二神又称十二值日,是古代择日的重要依据。以月建起建,按地支顺序排列。建日宜出行,除日宜疗病,满日宜嫁娶,平日宜修造,定日宜祈福,执日宜祭祀,破日宜破屋,危日宜安床,成日宜开市,收日宜纳财,开日宜开光,闭日宜安葬。' },
{ title: '黄道吉日', brief: '青龙、明堂、金匮、天德、玉堂、司命为黄道', content: '黄道黑道是古代择日术语。黄道日(青龙、明堂、金匮、天德、玉堂、司命值日)诸事皆宜;黑道日(天刑、朱雀、白虎、天牢、玄武、勾陈值日)宜避凶就吉。' },
{ title: '二十八宿', brief: '古代天文学家将黄道附近的星宿分为二十八组', content: '二十八宿分东方青龙(角亢氐房心尾箕)、北方玄武(斗牛女虚危室壁)、西方白虎(奎娄胃昴毕觜参)、南方朱雀(井鬼柳星张翼轸)四象,每象七宿。古人用二十八宿来判断日子的吉凶。' },
{ title: '六曜', brief: '先胜、友引、先负、佛灭、大安、赤口', content: '六曜起源于中国,后传入日本并广泛流行。大安日诸事皆吉;先胜日上午吉;友引日早晚吉;先负日上午凶;佛灭日大凶;赤口日午凶。以农历月日之和除以六取余数确定。' },
{ title: '彭祖百忌', brief: '每日天干地支对应的禁忌事项', content: '彭祖百忌是古代择日学的重要内容,根据每日的天干地支组合给出相应的禁忌。如"甲不开仓财物耗散,子不问卜自惹祸殃"等,共六十条对应六十甲子。' },
{ title: '冲煞', brief: '日支与某生肖相冲,该生肖之人需谨慎', content: '冲煞指日支与某地支相冲(如子午相冲、丑未相冲等),对应的生肖之人在当日需谨慎行事。煞方指当日凶煞所在的方位,不宜在该方位动土或远行。' },
{ title: '纳音五行', brief: '六十甲子与五行的配合', content: '纳音是将六十甲子与五行相配,每两组干支合为一种纳音,共三十种。如甲子乙丑海中金、丙寅丁卯炉中火等,用于命理分析。' },
{ title: '月相', brief: '朔、上弦、望、下弦的月相变化', content: '农历初一为朔(新月),初七初八为上弦月,十五为望(满月),廿二廿三为下弦月。月相变化影响潮汐,也被古人用于判断吉凶。' },
{ title: '胎神方位', brief: '孕妇需避开的方位', content: '胎神是传统民俗中保护胎儿的神灵,每日所在方位不同。孕妇不宜在胎神方位动土、钉钉或搬动重物,以免惊动胎神。' }
];
function buildEntries() {
const entries = [];
// 二十四节气
SOLAR_TERMS.forEach(name => {
entries.push({
cat: 'term', catName: '节气', title: name,
brief: TERM_BRIEFS[name] || '二十四节气之一',
content: TERM_BRIEFS[name] || '二十四节气之一,是古人根据太阳在黄道上的位置划分的时令节点。',
open: false
});
});
// 农历节日
const seenLunar = new Set();
Object.entries(LUNAR_FESTIVALS).forEach(([key, name]) => {
if (seenLunar.has(name)) return;
seenLunar.add(name);
const [m, d] = key.split('-');
entries.push({
cat: 'lunarFest', catName: '农历节日', title: name,
brief: `农历${m}${d}`,
content: `${name},农历${m}${d}日,是中国传统农历节日。`,
open: false
});
});
// 公历节日
const seenSolar = new Set();
Object.entries(SOLAR_FESTIVALS).forEach(([key, name]) => {
if (seenSolar.has(name)) return;
seenSolar.add(name);
const [m, d] = key.split('-');
entries.push({
cat: 'solarFest', catName: '公历节日', title: name,
brief: `公历${m}${d}`,
content: `${name},公历${m}${d}日。`,
open: false
});
});
// 干支生肖
HEAVEN_STEMS.forEach((s, i) => {
entries.push({
cat: 'ganzhi', catName: '天干', title: s,
brief: `十天干之第${i + 1}`,
content: `${s}为十天干之第${i + 1}位,五行属${['木','木','火','火','土','土','金','金','水','水'][i]},属${i % 2 === 0 ? '阳' : '阴'}`,
open: false
});
});
EARTH_BRANCHES.forEach((b, i) => {
entries.push({
cat: 'ganzhi', catName: '地支', title: `${b}${ZODIACS[i]}`,
brief: `十二地支之第${i + 1}位,生肖属${ZODIACS[i]}`,
content: `${b}为十二地支之第${i + 1}位,生肖属${ZODIACS[i]},五行属${['水','土','木','木','土','火','火','土','金','金','土','水'][i]}`,
open: false
});
});
// 黄历术语
TERM_EXPLAINS.forEach(t => {
entries.push({ cat: 'termExplain', catName: '术语', ...t, open: false });
});
return entries;
}
Page({
data: {
categories: CATEGORIES,
activeCat: 'all',
keyword: '',
entries: [],
filteredEntries: []
},
onLoad() {
const entries = buildEntries();
this.setData({ entries, filteredEntries: entries });
},
switchCat(e) {
this.setData({ activeCat: e.currentTarget.dataset.key }, () => this.filter());
},
onSearch(e) {
this.setData({ keyword: e.detail.value.trim() }, () => this.filter());
},
filter() {
const { entries, activeCat, keyword } = this.data;
let list = entries;
if (activeCat !== 'all') list = list.filter(t => t.cat === activeCat);
if (keyword) list = list.filter(t => t.title.includes(keyword) || t.brief.includes(keyword) || t.content.includes(keyword));
this.setData({ filteredEntries: list });
},
toggleEntry(e) {
const index = e.currentTarget.dataset.index;
const key = `filteredEntries[${index}].open`;
this.setData({ [key]: !this.data.filteredEntries[index].open });
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "百科",
"enablePullDownRefresh": false
}
+37
View File
@@ -0,0 +1,37 @@
<view class="container">
<!-- 搜索 -->
<view class="search-bar">
<input class="search-input" placeholder="搜索节气、节日、术语..." value="{{keyword}}" bindinput="onSearch" confirm-type="search"/>
</view>
<!-- 分类 -->
<scroll-view class="cat-scroll" scroll-x enhanced show-scrollbar="{{false}}">
<view class="cat-list">
<view
class="cat-item {{activeCat === item.key ? 'active' : ''}}"
wx:for="{{categories}}"
wx:key="key"
bindtap="switchCat"
data-key="{{item.key}}"
>{{item.name}}</view>
</view>
</scroll-view>
<!-- 条目列表 -->
<view class="entry-list">
<view class="card entry-card" wx:for="{{filteredEntries}}" wx:key="title" bindtap="toggleEntry" data-index="{{index}}">
<view class="flex justify-between items-center">
<text class="text-lg font-bold font-chinese">{{item.title}}</text>
<text class="badge badge-outline">{{item.catName}}</text>
</view>
<view class="text-sm text-muted mt-1" wx:if="{{!item.open}}">{{item.brief}}</view>
<view class="entry-detail mt-2" wx:if="{{item.open}}">
<text class="text-base">{{item.content}}</text>
</view>
</view>
<view class="text-center text-muted empty-tip" wx:if="{{filteredEntries.length === 0}}">
<text>没有找到相关条目</text>
</view>
</view>
</view>
+56
View File
@@ -0,0 +1,56 @@
.container {
padding: 20rpx;
}
.search-bar {
margin-bottom: 16rpx;
}
.search-input {
background: #FFFFFF;
border: 1rpx solid #E8D5C4;
border-radius: 999rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
}
.cat-scroll {
white-space: nowrap;
margin-bottom: 16rpx;
}
.cat-list {
display: inline-flex;
gap: 16rpx;
padding: 4rpx 0;
}
.cat-item {
display: inline-flex;
padding: 12rpx 28rpx;
border-radius: 999rpx;
font-size: 26rpx;
background: #FFFFFF;
border: 1rpx solid #E8D5C4;
color: #6B5E53;
}
.cat-item.active {
background: #C41E3A;
border-color: #C41E3A;
color: #FFFFFF;
}
.entry-card {
margin-bottom: 16rpx;
}
.entry-detail {
border-top: 1rpx solid #F0E6DA;
padding-top: 16rpx;
line-height: 1.7;
}
.empty-tip {
padding: 80rpx 0;
}