feat: 祈福小助手万年历小程序第一期

This commit is contained in:
gouki
2026-08-06 08:47:09 +00:00
commit a3e6aa9c01
136 changed files with 16597 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
// app.js
App({
onLaunch() {
// 初始化本地存储
const settings = wx.getStorageSync('lunar-settings');
if (!settings) {
wx.setStorageSync('lunar-settings', {
theme: 'light',
weekStartDay: 0,
ziHourSect: 'lateZiNextDay',
solarTime: true,
});
}
const profiles = wx.getStorageSync('lunar-user-profiles');
if (!profiles) {
wx.setStorageSync('lunar-user-profiles', { profiles: [], activeIndex: 0 });
}
const bookmarks = wx.getStorageSync('lunar-bookmarks');
if (!bookmarks) {
wx.setStorageSync('lunar-bookmarks', []);
}
},
globalData: {
// 全局共享数据
},
});
+60
View File
@@ -0,0 +1,60 @@
{
"pages": [
"pages/home/home",
"pages/calendar/calendar",
"pages/day-detail/day-detail",
"pages/bazi/bazi",
"pages/fortune/fortune",
"pages/divination/divination",
"pages/solar-terms/solar-terms",
"pages/settings/settings"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#C41E3A",
"navigationBarTitleText": "万年历",
"navigationBarTextStyle": "white",
"backgroundColor": "#FFFBF5"
},
"tabBar": {
"color": "#9E8E7E",
"selectedColor": "#C41E3A",
"backgroundColor": "#FFFFFF",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/home/home",
"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/bazi/bazi",
"text": "八字",
"iconPath": "images/bazi.png",
"selectedIconPath": "images/bazi-active.png"
},
{
"pagePath": "pages/fortune/fortune",
"text": "运势",
"iconPath": "images/fortune.png",
"selectedIconPath": "images/fortune-active.png"
},
{
"pagePath": "pages/settings/settings",
"text": "设置",
"iconPath": "images/settings.png",
"selectedIconPath": "images/settings-active.png"
}
]
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}
+153
View File
@@ -0,0 +1,153 @@
/* app.wxss — 全局样式 */
page {
background-color: #FFFBF5;
color: #1A1A1A;
font-family: 'PingFang SC', 'Noto Sans SC', 'Hiragino Sans GB', system-ui, -apple-system, sans-serif;
font-size: 28rpx;
line-height: 1.5;
}
/* 中文衬线字体 */
.font-chinese {
font-family: 'Noto Serif SC', 'STSong', 'SimSun', 'Songti SC', serif;
}
/* 卡片基础样式 */
.card {
background-color: #FFFFFF;
border-radius: 24rpx;
border: 1rpx solid #E8D5C4;
padding: 24rpx;
margin-bottom: 16rpx;
}
/* 徽章 */
.badge {
display: inline-flex;
align-items: center;
padding: 4rpx 16rpx;
border-radius: 999rpx;
font-size: 20rpx;
font-weight: 500;
}
.badge-lucky {
background-color: #FEF2F2;
color: #C41E3A;
}
.badge-unlucky {
background-color: #F1F5F9;
color: #546E7A;
}
.badge-outline {
border: 1rpx solid #E8D5C4;
color: #6B5E53;
background: transparent;
}
.badge-festival {
background-color: #C41E3A;
color: #FFFFFF;
}
/* 按钮 */
.btn-primary {
background-color: #C41E3A;
color: #FFFFFF;
border-radius: 16rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
font-weight: 500;
border: none;
}
.btn-primary:active {
background-color: #8B1A2B;
}
.btn-outline {
background-color: transparent;
border: 2rpx solid #E8D5C4;
color: #1A1A1A;
border-radius: 16rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
}
.btn-ghost {
background-color: transparent;
color: #1A1A1A;
border-radius: 16rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
}
/* 文本颜色 */
.text-primary { color: #C41E3A; }
.text-secondary { color: #6B5E53; }
.text-muted { color: #9E8E7E; }
.text-lucky { color: #C41E3A; }
.text-unlucky { color: #546E7A; }
/* 背景色 */
.bg-card { background-color: #FFFFFF; }
.bg-page { background-color: #FFFBF5; }
/* 边框 */
.border { border: 1rpx solid #E8D5C4; }
.border-b { border-bottom: 1rpx solid #E8D5C4; }
/* 布局 */
.flex { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.flex-1 { flex: 1; }
.text-center { text-align: center; }
/* 间距 */
.mt-1 { margin-top: 8rpx; }
.mt-2 { margin-top: 16rpx; }
.mb-1 { margin-bottom: 8rpx; }
.mb-2 { margin-bottom: 16rpx; }
.p-2 { padding: 16rpx; }
.p-3 { padding: 24rpx; }
/* 圆角 */
.rounded { border-radius: 16rpx; }
.rounded-lg { border-radius: 24rpx; }
.rounded-full { border-radius: 999rpx; }
/* 字号 */
.text-xs { font-size: 20rpx; }
.text-sm { font-size: 24rpx; }
.text-base { font-size: 28rpx; }
.text-lg { font-size: 32rpx; }
.text-xl { font-size: 36rpx; }
.text-2xl { font-size: 48rpx; }
.text-3xl { font-size: 60rpx; }
/* 字重 */
.font-medium { font-weight: 500; }
.font-bold { font-weight: 700; }
/* 网格 */
.grid { display: grid; }
.grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
.grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
.grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
.grid-cols-7 { grid-template-columns: repeat(7, 1fr); }
.gap-1 { gap: 8rpx; }
.gap-2 { gap: 16rpx; }
.gap-3 { gap: 24rpx; }
/* 隐藏 */
.hidden { display: none; }
/* 滚动 */
.scroll-x {
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
/* 安全区域 */
.safe-area-bottom {
padding-bottom: env(safe-area-inset-bottom);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

+78
View File
@@ -0,0 +1,78 @@
const { birthInfoToBazi, analyzeElementBalance } = require('../../utils/core/index.js');
Page({
data: {
gender: 'male',
birthDate: '1990-01-01',
birthTime: '12:00',
ziSect: 'lateZiNextDay',
bazi: null,
pillars: [],
elements: [],
elementAnalysis: {}
},
onLoad() {
// 尝试从本地存储恢复
const saved = wx.getStorageSync('lunar-bazi-input');
if (saved) {
this.setData(saved);
}
},
setGender(e) {
this.setData({ gender: e.currentTarget.dataset.g });
},
setZiSect(e) {
this.setData({ ziSect: e.currentTarget.dataset.s });
},
onDateChange(e) {
this.setData({ birthDate: e.detail.value });
},
onTimeChange(e) {
this.setData({ birthTime: e.detail.value });
},
calculate() {
const { gender, birthDate, birthTime, ziSect } = this.data;
const [year, month, day] = birthDate.split('-').map(Number);
const [hour, minute] = birthTime.split(':').map(Number);
const bazi = birthInfoToBazi({ year, month, day, hour, minute, gender, ziSect });
const elementAnalysis = analyzeElementBalance(bazi.eightChar);
const pillars = [
{ label: '年柱', ...bazi.eightChar.yearPillar },
{ label: '月柱', ...bazi.eightChar.monthPillar },
{ label: '日柱', ...bazi.eightChar.dayPillar },
{ label: '时柱', ...bazi.eightChar.hourPillar }
];
const total = elementAnalysis.total || 1;
const elements = [
{ name: '木', count: elementAnalysis.wood, percent: Math.round(elementAnalysis.wood / total * 100) },
{ name: '火', count: elementAnalysis.fire, percent: Math.round(elementAnalysis.fire / total * 100) },
{ name: '土', count: elementAnalysis.earth, percent: Math.round(elementAnalysis.earth / total * 100) },
{ name: '金', count: elementAnalysis.metal, percent: Math.round(elementAnalysis.metal / total * 100) },
{ name: '水', count: elementAnalysis.water, percent: Math.round(elementAnalysis.water / total * 100) }
];
this.setData({ bazi, pillars, elements, elementAnalysis });
// 保存输入
wx.setStorageSync('lunar-bazi-input', { gender, birthDate, birthTime, ziSect });
// 保存八字供运势页使用
wx.setStorageSync('lunar-user-bazi', bazi);
},
reset() {
this.setData({ bazi: null });
},
goFortune() {
wx.switchTab({ url: '/pages/fortune/fortune' });
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "八字排盘",
"enablePullDownRefresh": false
}
+104
View File
@@ -0,0 +1,104 @@
<view class="container">
<!-- 输入表单 -->
<view class="card" wx:if="{{!bazi}}">
<view class="section-title">输入出生信息</view>
<view class="form-item">
<text class="form-label">性别</text>
<view class="flex gap-2">
<view class="btn-outline {{gender === 'male' ? 'active' : ''}}" bindtap="setGender" data-g="male">男</view>
<view class="btn-outline {{gender === 'female' ? 'active' : ''}}" bindtap="setGender" data-g="female">女</view>
</view>
</view>
<view class="form-item">
<text class="form-label">出生日期</text>
<picker mode="date" value="{{birthDate}}" bindchange="onDateChange">
<view class="picker-input">{{birthDate}}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">出生时间</text>
<picker mode="time" value="{{birthTime}}" bindchange="onTimeChange">
<view class="picker-input">{{birthTime}}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">子时流派</text>
<view class="flex gap-2">
<view class="btn-outline {{ziSect === 'lateZiNextDay' ? 'active' : ''}}" bindtap="setZiSect" data-s="lateZiNextDay">晚子时日柱算次日</view>
<view class="btn-outline {{ziSect === 'lateZiSameDay' ? 'active' : ''}}" bindtap="setZiSect" data-s="lateZiSameDay">晚子时日柱算当日</view>
</view>
</view>
<view class="btn-primary mt-2" bindtap="calculate">排盘</view>
</view>
<!-- 八字结果 -->
<block wx:if="{{bazi}}">
<!-- 四柱 -->
<view class="card">
<view class="section-title">四柱八字</view>
<view class="grid grid-cols-4 gap-2">
<view class="pillar" wx:for="{{pillars}}" wx:key="label">
<text class="pillar-label">{{item.label}}</text>
<text class="pillar-ganzhi">{{item.ganzhi}}</text>
<text class="pillar-ten">{{item.tenStar || '日主'}}</text>
</view>
</view>
</view>
<!-- 五行分析 -->
<view class="card">
<view class="section-title">五行分析</view>
<view class="element-bar">
<view class="element-item" wx:for="{{elements}}" wx:key="name">
<text class="element-name">{{item.name}}</text>
<view class="element-track">
<view class="element-fill" style="width: {{item.percent}}%"></view>
</view>
<text class="element-count">{{item.count}}</text>
</view>
</view>
<view class="mt-2 text-sm text-muted">
日主:{{bazi.eightChar.dayMaster}} | dominant: {{elementAnalysis.dominant}} | weakest: {{elementAnalysis.weakest}}
</view>
</view>
<!-- 大运 -->
<view class="card">
<view class="section-title">大运</view>
<scroll-view scroll-x class="scroll-x">
<view class="flex gap-2">
<view class="fortune-item" wx:for="{{bazi.decadeFortunes}}" wx:key="index">
<text class="text-sm text-muted">{{item.startAge}}-{{item.endAge}}岁</text>
<text class="text-base font-medium">{{item.ganzhi}}</text>
<text class="text-xs text-muted">{{item.startYear}}-{{item.endYear}}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 流年 -->
<view class="card">
<view class="section-title">流年</view>
<scroll-view scroll-x class="scroll-x">
<view class="flex gap-2">
<view class="fortune-item" wx:for="{{bazi.annualFortunes}}" wx:key="year">
<text class="text-sm text-muted">{{item.age}}岁</text>
<text class="text-base font-medium">{{item.ganzhi}}</text>
<text class="text-xs text-muted">{{item.year}}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 操作 -->
<view class="flex gap-2 mt-2">
<view class="btn-outline flex-1 text-center" bindtap="reset">重新排盘</view>
<view class="btn-primary flex-1 text-center" bindtap="goFortune">看运势</view>
</view>
</block>
</view>
+107
View File
@@ -0,0 +1,107 @@
.container {
padding: 20rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.form-item {
margin-bottom: 24rpx;
}
.form-label {
font-size: 24rpx;
color: #6B5E53;
margin-bottom: 8rpx;
display: block;
}
.picker-input {
padding: 20rpx;
background: #FFFBF5;
border-radius: 12rpx;
border: 1rpx solid #E8D5C4;
}
.btn-outline.active {
background: #C41E3A;
color: #FFFFFF;
border-color: #C41E3A;
}
.pillar {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx;
background: #FFFBF5;
border-radius: 12rpx;
}
.pillar-label {
font-size: 20rpx;
color: #9E8E7E;
}
.pillar-ganzhi {
font-size: 36rpx;
font-weight: 700;
color: #C41E3A;
margin: 8rpx 0;
}
.pillar-ten {
font-size: 20rpx;
color: #6B5E53;
}
.element-bar {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.element-item {
display: flex;
align-items: center;
gap: 12rpx;
}
.element-name {
width: 60rpx;
font-size: 24rpx;
}
.element-track {
flex: 1;
height: 16rpx;
background: #E8D5C4;
border-radius: 8rpx;
overflow: hidden;
}
.element-fill {
height: 100%;
background: #C41E3A;
border-radius: 8rpx;
}
.element-count {
width: 60rpx;
text-align: right;
font-size: 24rpx;
}
.fortune-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 16rpx 24rpx;
background: #FFFBF5;
border-radius: 12rpx;
min-width: 160rpx;
}
+86
View File
@@ -0,0 +1,86 @@
const { getMonthCalendar } = require('../../utils/core/index.js');
Page({
data: {
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
weekHeaders: ['日', '一', '二', '三', '四', '五', '六'],
calendarDays: [],
selectedDay: null,
showMonthPicker: false,
years: [],
months: [1,2,3,4,5,6,7,8,9,10,11,12],
pickerValue: [0, 0]
},
onLoad() {
const years = [];
for (let y = 1900; y <= 2100; y++) years.push(y);
this.setData({ years });
this.loadCalendar();
},
loadCalendar() {
const { year, month } = this.data;
const weeks = getMonthCalendar(year, month);
const calendarDays = [];
weeks.forEach(week => {
week.forEach(day => calendarDays.push(day));
});
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());
},
showPicker() {
const { year, month } = this.data;
this.setData({
showMonthPicker: true,
pickerValue: [year - 1900, month - 1]
});
},
hidePicker() {
this.setData({ showMonthPicker: false });
},
pickerChange(e) {
this.setData({ pickerValue: e.detail.value });
},
confirmPicker() {
const { pickerValue, years, months } = this.data;
this.setData({
year: years[pickerValue[0]],
month: months[pickerValue[1]],
showMonthPicker: false
}, () => this.loadCalendar());
},
selectDay(e) {
const date = e.currentTarget.dataset.date;
const day = this.data.calendarDays.find(d => d.solarDate === date);
this.setData({ selectedDay: day });
},
goDetail() {
const { selectedDay } = this.data;
if (selectedDay) {
wx.navigateTo({ url: `/pages/day-detail/day-detail?date=${selectedDay.solarDate}` });
}
},
noop() {}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "日历",
"enablePullDownRefresh": false
}
+60
View File
@@ -0,0 +1,60 @@
<view class="container">
<!-- 年月选择器 -->
<view class="card flex justify-between items-center">
<view class="btn-ghost" bindtap="prevMonth"></view>
<view class="text-xl font-bold" bindtap="showPicker">{{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 class="card mt-2" wx:if="{{selectedDay}}">
<view class="flex justify-between items-center">
<view>
<text class="text-lg font-bold">{{selectedDay.solarDate}}</text>
<text class="text-sm text-muted block">{{selectedDay.lunarMonthName}}{{selectedDay.lunarDayName}}</text>
</view>
<view class="btn-primary" bindtap="goDetail">详情</view>
</view>
</view>
</view>
<!-- 年月选择弹窗 -->
<view class="picker-mask {{showMonthPicker ? 'show' : ''}}" bindtap="hidePicker">
<view class="picker-panel" catchtap="noop">
<view class="picker-header">
<text bindtap="hidePicker">取消</text>
<text class="font-bold">选择年月</text>
<text bindtap="confirmPicker">确定</text>
</view>
<picker-view class="picker-view" value="{{pickerValue}}" bindchange="pickerChange">
<picker-view-column>
<view wx:for="{{years}}" wx:key="*this" class="picker-item">{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{months}}" wx:key="*this" class="picker-item">{{item}}月</view>
</picker-view-column>
</picker-view>
</view>
</view>
+92
View File
@@ -0,0 +1,92 @@
.container {
padding: 20rpx;
}
.day-cell {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 12rpx 4rpx;
background: #FFFFFF;
border-radius: 12rpx;
min-height: 100rpx;
}
.day-cell.today {
background: #C41E3A;
color: #FFFFFF;
}
.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;
}
.picker-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 100;
display: none;
}
.picker-mask.show {
display: block;
}
.picker-panel {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #FFFFFF;
border-radius: 24rpx 24rpx 0 0;
}
.picker-header {
display: flex;
justify-content: space-between;
padding: 24rpx;
border-bottom: 1rpx solid #E8D5C4;
}
.picker-view {
height: 400rpx;
}
.picker-item {
text-align: center;
line-height: 68rpx;
font-size: 32rpx;
}
+43
View File
@@ -0,0 +1,43 @@
const { getDayInfo, getAlmanacInfo } = require('../../utils/core/index.js');
Page({
data: {
date: '',
dayInfo: {},
almanac: {}
},
onLoad(options) {
const date = options.date || new Date().toISOString().split('T')[0];
this.setData({ date });
this.loadData(date);
},
loadData(dateStr) {
const [year, month, day] = dateStr.split('-').map(Number);
const dayInfo = getDayInfo(year, month, day);
const almanac = getAlmanacInfo(year, month, day);
this.setData({ dayInfo, almanac });
},
addBookmark() {
const bookmarks = wx.getStorageSync('lunar-bookmarks') || [];
const { dayInfo } = this.data;
const exists = bookmarks.some(b => b.date === dayInfo.solarDate);
if (!exists) {
bookmarks.push({
date: dayInfo.solarDate,
lunarDate: `${dayInfo.lunarMonthName}${dayInfo.lunarDayName}`,
note: ''
});
wx.setStorageSync('lunar-bookmarks', bookmarks);
wx.showToast({ title: '已收藏', icon: 'success' });
} else {
wx.showToast({ title: '已收藏过', icon: 'none' });
}
},
goBazi() {
wx.navigateTo({ url: '/pages/bazi/bazi' });
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "日详情",
"enablePullDownRefresh": false
}
+147
View File
@@ -0,0 +1,147 @@
<view class="container">
<!-- 日期头部 -->
<view class="card header-card">
<view class="text-center">
<text class="text-3xl font-bold">{{dayInfo.solarDay}}</text>
<text class="text-lg text-muted block">{{dayInfo.solarYear}}年{{dayInfo.solarMonth}}月 {{dayInfo.weekDay}}</text>
</view>
<view class="flex justify-center gap-2 mt-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="section-title">农历</view>
<view class="grid grid-cols-2 gap-2">
<view class="info-item">
<text class="text-xs text-muted">农历日期</text>
<text class="text-base font-medium">{{dayInfo.lunarYear}}年{{dayInfo.lunarMonthName}}{{dayInfo.lunarDayName}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">生肖</text>
<text class="text-base font-medium">{{dayInfo.zodiac}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">干支</text>
<text class="text-base font-medium">{{dayInfo.lunarYearGanzhi}}年 {{dayInfo.lunarMonthGanzhi}}月 {{dayInfo.lunarDayGanzhi}}日</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">月相</text>
<text class="text-base font-medium">{{dayInfo.moonPhase}}</text>
</view>
</view>
</view>
<!-- 宜忌 -->
<view class="card">
<view class="section-title">宜忌</view>
<view class="flex gap-2">
<view class="flex-1">
<text class="text-lucky font-bold">宜</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>
<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="section-title">黄历</view>
<view class="grid grid-cols-2 gap-2">
<view class="info-item">
<text class="text-xs text-muted">值神</text>
<text class="text-base font-medium">{{almanac.duty}}{{almanac.dutyLuck === 'good' ? '吉' : almanac.dutyLuck === 'bad' ? '凶' : '平'}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">黄道黑道</text>
<text class="text-base font-medium">{{almanac.twelveStar.name}}{{almanac.twelveStar.ecliptic}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">二十八宿</text>
<text class="text-base font-medium">{{almanac.twentyEightStar.name}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">九星</text>
<text class="text-base font-medium">{{almanac.nineStar.name}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">六曜</text>
<text class="text-base font-medium">{{almanac.sixStar}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">小六壬</text>
<text class="text-base font-medium">{{almanac.minorRen.name}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">纳音</text>
<text class="text-base font-medium">{{almanac.nayin}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">胎神</text>
<text class="text-base font-medium">{{almanac.fetus.position}}</text>
</view>
</view>
</view>
<!-- 冲煞 -->
<view class="card">
<view class="section-title">冲煞</view>
<view class="grid grid-cols-2 gap-2">
<view class="info-item">
<text class="text-xs text-muted">冲</text>
<text class="text-base font-medium">{{almanac.clash}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">害</text>
<text class="text-base font-medium">{{almanac.harm}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">合</text>
<text class="text-base font-medium">{{almanac.combine}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">煞方</text>
<text class="text-base font-medium">{{almanac.evilDirection}}</text>
</view>
</view>
</view>
<!-- 彭祖百忌 -->
<view class="card">
<view class="section-title">彭祖百忌</view>
<text class="text-base">{{almanac.pengZu}}</text>
</view>
<!-- 时辰黄历 -->
<view class="card">
<view class="section-title">时辰黄历</view>
<view class="hour-list">
<view class="hour-item" wx:for="{{almanac.hourDetails}}" wx:key="name">
<view class="flex justify-between items-center">
<text class="font-medium">{{item.name}}{{item.range}}</text>
<text class="text-sm text-muted">{{item.ganzhi}}</text>
</view>
<view class="flex gap-2 mt-1">
<text class="text-xs text-muted">值神:{{item.twelveStar}}</text>
<text class="text-xs text-muted">九星:{{item.nineStar}}</text>
</view>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="flex gap-2 mt-2">
<view class="btn-outline flex-1 text-center" bindtap="addBookmark">收藏</view>
<view class="btn-primary flex-1 text-center" bindtap="goBazi">排八字</view>
</view>
</view>
+41
View File
@@ -0,0 +1,41 @@
.container {
padding: 20rpx;
}
.header-card {
background: linear-gradient(135deg, #C41E3A 0%, #8B1A2B 100%);
color: #FFFFFF;
border: none;
padding: 40rpx 24rpx;
}
.header-card .text-muted {
color: rgba(255,255,255,0.7);
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.info-item {
padding: 16rpx;
background: #FFFBF5;
border-radius: 12rpx;
}
.hour-list {
max-height: 600rpx;
overflow-y: auto;
}
.hour-item {
padding: 16rpx;
border-bottom: 1rpx solid #E8D5C4;
}
.hour-item:last-child {
border-bottom: none;
}
+64
View File
@@ -0,0 +1,64 @@
const { calculatePlumBlossom, calculateBoneWeight, HEAVEN_STEMS, EARTH_BRANCHES, LUNAR_MONTH_NAMES, LUNAR_DAY_NAMES, HOUR_NAMES } = require('../../utils/core/index.js');
Page({
data: {
plumDate: new Date().toISOString().split('T')[0],
plumTime: '12:00',
plumResult: null,
yearGanzhiList: [],
monthList: LUNAR_MONTH_NAMES,
dayList: LUNAR_DAY_NAMES,
hourList: HOUR_NAMES,
boneYearIndex: 0,
boneMonthIndex: 0,
boneDayIndex: 0,
boneHourIndex: 0,
boneResult: null
},
onLoad() {
const yearGanzhiList = [];
for (let i = 0; i < 60; i++) {
yearGanzhiList.push(HEAVEN_STEMS[i % 10] + EARTH_BRANCHES[i % 12]);
}
this.setData({ yearGanzhiList });
},
onPlumDateChange(e) {
this.setData({ plumDate: e.detail.value });
},
onPlumTimeChange(e) {
this.setData({ plumTime: e.detail.value });
},
calcPlum() {
const { plumDate, plumTime } = this.data;
const [year, month, day] = plumDate.split('-').map(Number);
const [hour] = plumTime.split(':').map(Number);
const result = calculatePlumBlossom(year, month, day, hour);
this.setData({ plumResult: result });
},
onBoneYearChange(e) {
this.setData({ boneYearIndex: e.detail.value });
},
onBoneMonthChange(e) {
this.setData({ boneMonthIndex: e.detail.value });
},
onBoneDayChange(e) {
this.setData({ boneDayIndex: e.detail.value });
},
onBoneHourChange(e) {
this.setData({ boneHourIndex: e.detail.value });
},
calcBone() {
const { boneYearIndex, boneMonthIndex, boneDayIndex, boneHourIndex } = this.data;
const result = calculateBoneWeight(boneYearIndex, boneMonthIndex + 1, boneDayIndex + 1, boneHourIndex);
this.setData({ boneResult: result });
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "占卜",
"enablePullDownRefresh": false
}
+110
View File
@@ -0,0 +1,110 @@
<view class="container">
<!-- 梅花易数 -->
<view class="card">
<view class="section-title">梅花易数</view>
<view class="form-item">
<text class="form-label">起卦时间</text>
<picker mode="date" value="{{plumDate}}" bindchange="onPlumDateChange">
<view class="picker-input">{{plumDate}}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">时辰</text>
<picker mode="time" value="{{plumTime}}" bindchange="onPlumTimeChange">
<view class="picker-input">{{plumTime}}</view>
</picker>
</view>
<view class="btn-primary" bindtap="calcPlum">起卦</view>
</view>
<!-- 梅花易数结果 -->
<view class="card" wx:if="{{plumResult}}">
<view class="section-title">卦象</view>
<view class="hexagram-display">
<view class="trigram-row">
<text class="trigram-symbol">{{plumResult.upperTrigram.symbol}}</text>
<text class="trigram-name">{{plumResult.upperTrigram.name}}{{plumResult.upperTrigram.element}}</text>
</view>
<view class="trigram-row">
<text class="trigram-symbol">{{plumResult.lowerTrigram.symbol}}</text>
<text class="trigram-name">{{plumResult.lowerTrigram.name}}{{plumResult.lowerTrigram.element}}</text>
</view>
</view>
<view class="mt-2">
<text class="text-lg font-bold">{{plumResult.originalHexagram.name}}</text>
<text class="text-sm text-muted block mt-1">第{{plumResult.changingLine}}爻动</text>
</view>
<view class="mt-2 p-2 bg-page rounded">
<text class="text-sm">{{plumResult.originalHexagram.judgment}}</text>
</view>
<view class="mt-2 p-2 bg-page rounded">
<text class="text-sm">{{plumResult.originalHexagram.image}}</text>
</view>
<view class="mt-2" wx:if="{{plumResult.transformedHexagram}}">
<text class="text-base font-medium">变卦:{{plumResult.transformedHexagram.name}}</text>
</view>
<view class="mt-2 text-sm text-muted">
体用关系:{{plumResult.relationship}}
</view>
</view>
<!-- 称骨算命 -->
<view class="card mt-2">
<view class="section-title">称骨算命</view>
<view class="form-item">
<text class="form-label">出生年份(干支)</text>
<picker mode="selector" range="{{yearGanzhiList}}" value="{{boneYearIndex}}" bindchange="onBoneYearChange">
<view class="picker-input">{{yearGanzhiList[boneYearIndex]}}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">农历月份</text>
<picker mode="selector" range="{{monthList}}" value="{{boneMonthIndex}}" bindchange="onBoneMonthChange">
<view class="picker-input">{{monthList[boneMonthIndex]}}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">农历日期</text>
<picker mode="selector" range="{{dayList}}" value="{{boneDayIndex}}" bindchange="onBoneDayChange">
<view class="picker-input">{{dayList[boneDayIndex]}}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">时辰</text>
<picker mode="selector" range="{{hourList}}" value="{{boneHourIndex}}" bindchange="onBoneHourChange">
<view class="picker-input">{{hourList[boneHourIndex]}}</view>
</picker>
</view>
<view class="btn-primary" bindtap="calcBone">算命</view>
</view>
<!-- 称骨结果 -->
<view class="card" wx:if="{{boneResult}}">
<view class="section-title">称骨结果</view>
<view class="text-center">
<text class="text-3xl font-bold">{{boneResult.totalLiang}}两{{boneResult.totalQian}}钱</text>
<text class="badge {{boneResult.fortune.includes('上') ? 'badge-lucky' : boneResult.fortune.includes('下') ? 'badge-unlucky' : 'badge-outline'}} ml-2">{{boneResult.fortune}}</text>
</view>
<view class="mt-2 p-3 bg-page rounded">
<text class="text-base">{{boneResult.interpretation}}</text>
</view>
<view class="grid grid-cols-4 gap-2 mt-2">
<view class="text-center">
<text class="text-xs text-muted">年</text>
<text class="text-base font-medium block">{{boneResult.yearWeight}}钱</text>
</view>
<view class="text-center">
<text class="text-xs text-muted">月</text>
<text class="text-base font-medium block">{{boneResult.monthWeight}}钱</text>
</view>
<view class="text-center">
<text class="text-xs text-muted">日</text>
<text class="text-base font-medium block">{{boneResult.dayWeight}}钱</text>
</view>
<view class="text-center">
<text class="text-xs text-muted">时</text>
<text class="text-base font-medium block">{{boneResult.hourWeight}}钱</text>
</view>
</view>
</view>
</view>
+52
View File
@@ -0,0 +1,52 @@
.container {
padding: 20rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.form-item {
margin-bottom: 24rpx;
}
.form-label {
font-size: 24rpx;
color: #6B5E53;
margin-bottom: 8rpx;
display: block;
}
.picker-input {
padding: 20rpx;
background: #FFFBF5;
border-radius: 12rpx;
border: 1rpx solid #E8D5C4;
}
.hexagram-display {
display: flex;
flex-direction: column;
align-items: center;
padding: 24rpx;
background: #FFFBF5;
border-radius: 16rpx;
}
.trigram-row {
display: flex;
align-items: center;
gap: 16rpx;
margin: 8rpx 0;
}
.trigram-symbol {
font-size: 64rpx;
}
.trigram-name {
font-size: 28rpx;
}
+47
View File
@@ -0,0 +1,47 @@
const { calculateDailyFortune } = require('../../utils/core/index.js');
Page({
data: {
hasBazi: false,
fortune: null,
scoreLevelText: ''
},
onShow() {
this.loadFortune();
},
onPullDownRefresh() {
this.loadFortune();
wx.stopPullDownRefresh();
},
loadFortune() {
const bazi = wx.getStorageSync('lunar-user-bazi');
if (!bazi) {
this.setData({ hasBazi: false, fortune: null });
return;
}
const today = new Date();
const fortune = calculateDailyFortune(bazi.eightChar, today);
const levelMap = {
great: '大吉',
good: '吉',
fair: '平',
poor: '凶',
bad: '大凶'
};
this.setData({
hasBazi: true,
fortune,
scoreLevelText: levelMap[fortune.scoreLevel] || '平'
});
},
goBazi() {
wx.switchTab({ url: '/pages/bazi/bazi' });
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "每日运势",
"enablePullDownRefresh": true
}
+98
View File
@@ -0,0 +1,98 @@
<view class="container">
<!-- 无八字提示 -->
<view class="card text-center" wx:if="{{!hasBazi}}">
<text class="text-lg text-muted">请先排八字以查看每日运势</text>
<view class="btn-primary mt-2" bindtap="goBazi">去排八字</view>
</view>
<!-- 运势内容 -->
<block wx:if="{{hasBazi && fortune}}">
<!-- 总分卡片 -->
<view class="card score-card">
<view class="text-center">
<text class="score-value">{{fortune.overallScore}}</text>
<text class="score-level">{{scoreLevelText}}</text>
</view>
<view class="text-sm text-muted text-center mt-1">{{fortune.date}} {{fortune.lunarDate}}</view>
</view>
<!-- 幸运元素 -->
<view class="card">
<view class="section-title">幸运元素</view>
<view class="grid grid-cols-2 gap-2">
<view class="info-item">
<text class="text-xs text-muted">幸运色</text>
<text class="text-base font-medium">{{fortune.luckyMeta.colors.join('、')}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">幸运数字</text>
<text class="text-base font-medium">{{fortune.luckyMeta.numbers.join('、')}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">幸运方位</text>
<text class="text-base font-medium">{{fortune.luckyMeta.direction}}</text>
</view>
<view class="info-item">
<text class="text-xs text-muted">五行</text>
<text class="text-base font-medium">{{fortune.luckyMeta.element}}</text>
</view>
</view>
</view>
<!-- 四柱关系 -->
<view class="card">
<view class="section-title">四柱与今日关系</view>
<view class="relation-list">
<view class="relation-item" wx:for="{{fortune.pillarRelationships}}" wx:key="pillar">
<view class="flex justify-between items-center">
<text class="font-medium">{{item.pillarLabel}}</text>
<text class="text-sm {{item.score >= 0 ? 'text-lucky' : 'text-unlucky'}}">{{item.score > 0 ? '+' : ''}}{{item.score}}</text>
</view>
<view class="text-sm text-muted mt-1">
{{item.userGanzhi}} vs {{item.dayGanzhi}}
</view>
<view class="flex flex-wrap gap-1 mt-1">
<text class="badge badge-outline" wx:if="{{item.stemTenStar}}">{{item.stemTenStar}}</text>
<text class="badge badge-lucky" wx:if="{{item.stemCombine}}">天干合</text>
<text class="badge badge-unlucky" wx:if="{{item.stemOpposite}}">天干冲</text>
<text class="badge badge-lucky" wx:if="{{item.branchCombine}}">地支合</text>
<text class="badge badge-unlucky" wx:if="{{item.branchOpposite}}">地支冲</text>
</view>
</view>
</view>
</view>
<!-- 建议 -->
<view class="card">
<view class="section-title">今日建议</view>
<view class="suggestion-list">
<view class="suggestion-item" wx:for="{{fortune.suggestions}}" wx:key="*this">
<text class="text-base">{{item}}</text>
</view>
</view>
</view>
<!-- 分项得分 -->
<view class="card">
<view class="section-title">分项运势</view>
<view class="grid grid-cols-2 gap-2">
<view class="info-item text-center">
<text class="text-xs text-muted">爱情</text>
<text class="text-xl font-bold {{fortune.categoryScores.love >= 0 ? 'text-lucky' : 'text-unlucky'}}">{{fortune.categoryScores.love}}</text>
</view>
<view class="info-item text-center">
<text class="text-xs text-muted">事业</text>
<text class="text-xl font-bold {{fortune.categoryScores.career >= 0 ? 'text-lucky' : 'text-unlucky'}}">{{fortune.categoryScores.career}}</text>
</view>
<view class="info-item text-center">
<text class="text-xs text-muted">财运</text>
<text class="text-xl font-bold {{fortune.categoryScores.wealth >= 0 ? 'text-lucky' : 'text-unlucky'}}">{{fortune.categoryScores.wealth}}</text>
</view>
<view class="info-item text-center">
<text class="text-xs text-muted">健康</text>
<text class="text-xl font-bold {{fortune.categoryScores.health >= 0 ? 'text-lucky' : 'text-unlucky'}}">{{fortune.categoryScores.health}}</text>
</view>
</view>
</view>
</block>
</view>
+47
View File
@@ -0,0 +1,47 @@
.container {
padding: 20rpx;
}
.score-card {
background: linear-gradient(135deg, #C41E3A 0%, #8B1A2B 100%);
color: #FFFFFF;
border: none;
padding: 40rpx 24rpx;
}
.score-value {
font-size: 80rpx;
font-weight: 700;
}
.score-level {
font-size: 32rpx;
margin-left: 16rpx;
opacity: 0.9;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.info-item {
padding: 16rpx;
background: #FFFBF5;
border-radius: 12rpx;
}
.relation-item {
padding: 16rpx;
border-bottom: 1rpx solid #E8D5C4;
}
.relation-item:last-child {
border-bottom: none;
}
.suggestion-item {
padding: 12rpx 0;
}
+28
View File
@@ -0,0 +1,28 @@
const { getTodayInfo, getAlmanacInfo } = require('../../utils/core/index.js');
Page({
data: {
dayInfo: {},
almanac: {}
},
onLoad() {
this.loadData();
},
onPullDownRefresh() {
this.loadData();
wx.stopPullDownRefresh();
},
loadData() {
const dayInfo = getTodayInfo();
const almanac = getAlmanacInfo(dayInfo.solarYear, dayInfo.solarMonth, dayInfo.solarDay);
this.setData({ dayInfo, almanac });
},
navTo(e) {
const url = e.currentTarget.dataset.url;
wx.navigateTo({ url });
}
});
+5
View File
@@ -0,0 +1,5 @@
{
"navigationBarTitleText": "万年历",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}
+94
View File
@@ -0,0 +1,94 @@
<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>
</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>
</view>
</view>
+31
View File
@@ -0,0 +1,31 @@
.container {
padding: 20rpx;
padding-bottom: 40rpx;
}
.date-card {
background: linear-gradient(135deg, #C41E3A 0%, #8B1A2B 100%);
color: #FFFFFF;
border: none;
}
.date-card .text-muted {
color: rgba(255,255,255,0.7);
}
.quick-entry {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24rpx;
background: #FFFFFF;
border-radius: 16rpx;
border: 1rpx solid #E8D5C4;
}
.quick-icon {
width: 64rpx;
height: 64rpx;
margin-bottom: 8rpx;
}
+74
View File
@@ -0,0 +1,74 @@
Page({
data: {
userInfo: null,
weekStartDay: 0,
ziHourSect: 'lateZiNextDay',
solarTime: true,
bookmarks: []
},
onLoad() {
this.loadSettings();
this.loadBookmarks();
},
onShow() {
this.loadBookmarks();
},
loadSettings() {
const settings = wx.getStorageSync('lunar-settings') || {};
this.setData({
weekStartDay: settings.weekStartDay || 0,
ziHourSect: settings.ziHourSect || 'lateZiNextDay',
solarTime: settings.solarTime !== false
});
},
saveSettings() {
const { weekStartDay, ziHourSect, solarTime } = this.data;
wx.setStorageSync('lunar-settings', { weekStartDay, ziHourSect, solarTime });
},
loadBookmarks() {
const bookmarks = wx.getStorageSync('lunar-bookmarks') || [];
this.setData({ bookmarks });
},
setWeekStart(e) {
this.setData({ weekStartDay: Number(e.currentTarget.dataset.v) });
this.saveSettings();
},
setZiSect(e) {
this.setData({ ziHourSect: e.currentTarget.dataset.v });
this.saveSettings();
},
onSolarTimeChange(e) {
this.setData({ solarTime: e.detail.value });
this.saveSettings();
},
removeBookmark(e) {
const date = e.currentTarget.dataset.date;
let bookmarks = this.data.bookmarks.filter(b => b.date !== date);
wx.setStorageSync('lunar-bookmarks', bookmarks);
this.setData({ bookmarks });
wx.showToast({ title: '已删除', icon: 'success' });
},
login() {
wx.getUserProfile({
desc: '用于完善用户资料',
success: (res) => {
this.setData({ userInfo: res.userInfo });
wx.setStorageSync('lunar-user-info', res.userInfo);
wx.showToast({ title: '登录成功', icon: 'success' });
},
fail: () => {
wx.showToast({ title: '登录失败', icon: 'none' });
}
});
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false
}
+68
View File
@@ -0,0 +1,68 @@
<view class="container">
<!-- 用户信息 -->
<view class="card">
<view class="section-title">用户信息</view>
<view class="flex items-center gap-2" wx:if="{{userInfo}}">
<image src="{{userInfo.avatarUrl}}" class="avatar" mode="aspectFill"/>
<view>
<text class="text-base font-medium">{{userInfo.nickName}}</text>
<text class="text-xs text-muted block">已登录</text>
</view>
</view>
<view class="btn-primary" wx:else bindtap="login">微信登录</view>
</view>
<!-- 偏好设置 -->
<view class="card">
<view class="section-title">偏好设置</view>
<view class="setting-item">
<text class="setting-label">周起始日</text>
<view class="flex gap-2">
<view class="btn-outline {{weekStartDay === 0 ? 'active' : ''}}" bindtap="setWeekStart" data-v="0">周日</view>
<view class="btn-outline {{weekStartDay === 1 ? 'active' : ''}}" bindtap="setWeekStart" data-v="1">周一</view>
</view>
</view>
<view class="setting-item">
<text class="setting-label">子时流派</text>
<view class="flex gap-2">
<view class="btn-outline {{ziHourSect === 'lateZiNextDay' ? 'active' : ''}}" bindtap="setZiSect" data-v="lateZiNextDay">晚子时算次日</view>
<view class="btn-outline {{ziHourSect === 'lateZiSameDay' ? 'active' : ''}}" bindtap="setZiSect" data-v="lateZiSameDay">晚子时算当日</view>
</view>
</view>
<view class="setting-item">
<text class="setting-label">真太阳时校正</text>
<switch checked="{{solarTime}}" bindchange="onSolarTimeChange" color="#C41E3A"/>
</view>
</view>
<!-- 收藏管理 -->
<view class="card">
<view class="section-title">我的收藏</view>
<view class="bookmark-list" wx:if="{{bookmarks.length > 0}}">
<view class="bookmark-item" wx:for="{{bookmarks}}" wx:key="date">
<view class="flex justify-between items-center">
<view>
<text class="text-base font-medium">{{item.date}}</text>
<text class="text-xs text-muted block">{{item.lunarDate}}</text>
</view>
<view class="btn-ghost text-unlucky" bindtap="removeBookmark" data-date="{{item.date}}">删除</view>
</view>
</view>
</view>
<view class="text-center text-muted" wx:else>
<text>暂无收藏</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>
</view>
</view>
</view>
+47
View File
@@ -0,0 +1,47 @@
.container {
padding: 20rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.setting-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #E8D5C4;
}
.setting-item:last-child {
border-bottom: none;
}
.setting-label {
font-size: 28rpx;
}
.btn-outline.active {
background: #C41E3A;
color: #FFFFFF;
border-color: #C41E3A;
}
.bookmark-item {
padding: 16rpx 0;
border-bottom: 1rpx solid #E8D5C4;
}
.bookmark-item:last-child {
border-bottom: none;
}
+36
View File
@@ -0,0 +1,36 @@
const { SOLAR_TERMS, SOLAR_TERM_DATES } = require('../../utils/core/index.js');
Page({
data: {
year: new Date().getFullYear(),
terms: []
},
onLoad() {
this.loadTerms();
},
loadTerms() {
const { year } = this.data;
const today = new Date();
const terms = [];
for (let m = 0; m < 12; m++) {
for (let t = 0; t < 2; t++) {
const termIndex = m * 2 + t;
const day = SOLAR_TERM_DATES[m][t];
const dateStr = `${year}-${String(m + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
const termDate = new Date(year, m, day);
terms.push({
name: SOLAR_TERMS[termIndex],
date: dateStr,
isPast: termDate < today
});
}
}
// 按日期排序
terms.sort((a, b) => new Date(a.date) - new Date(b.date));
this.setData({ terms });
}
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "二十四节气",
"enablePullDownRefresh": false
}
+16
View File
@@ -0,0 +1,16 @@
<view class="container">
<view class="card">
<view class="section-title">{{year}}年二十四节气</view>
<view class="term-list">
<view class="term-item" wx:for="{{terms}}" wx:key="name">
<view class="flex justify-between items-center">
<view>
<text class="text-base font-medium">{{item.name}}</text>
<text class="text-xs text-muted block">{{item.date}}</text>
</view>
<text class="badge {{item.isPast ? 'badge-outline' : 'badge-lucky'}}">{{item.isPast ? '已过' : '未来'}}</text>
</view>
</view>
</view>
</view>
</view>
+24
View File
@@ -0,0 +1,24 @@
.container {
padding: 20rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 16rpx;
color: #C41E3A;
}
.term-list {
display: flex;
flex-direction: column;
}
.term-item {
padding: 20rpx 0;
border-bottom: 1rpx solid #E8D5C4;
}
.term-item:last-child {
border-bottom: none;
}
+51
View File
@@ -0,0 +1,51 @@
{
"description": "万年历小程序",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"bundle": false,
"userConfirmedBundleSwitch": false,
"urlCheck": true,
"scopeDataCheck": false,
"coverView": true,
"es6": true,
"postcss": true,
"compileHotReLoad": false,
"lazyloadPlaceholderEnable": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"newFeature": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"useIsolateContext": true,
"nodeModules": false,
"enhance": true,
"useMultiFrameRuntime": true,
"useApiHook": true,
"useApiHostProcess": true,
"showShadowRootInWxmlPanel": true,
"packNpmManually": false,
"enableEngineNative": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"showES6CompileOption": false,
"minifyWXML": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
}
},
"compileType": "miniprogram",
"libVersion": "3.4.0",
"appid": "touristappid",
"projectname": "lunar-mini",
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"rules": [
{
"action": "allow",
"page": "*"
}
]
}
+406
View File
@@ -0,0 +1,406 @@
/**
* 农历数据表 1900-2100
* 数据来源:香港天文台
* 每年一个整数,bit 表示:
* 1-12: 1-12月大小月 (1=大月30天, 0=小月29天)
* 13-16: 闰月月份 (0=无闰月)
* 17: 闰月大小 (1=大月, 0=小月)
*/
const LUNAR_INFO = [
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0,
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6,
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0,
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4,
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0,
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160,
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252,
0x0d520
];
/** 天干 */
const HEAVEN_STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
/** 地支 */
const EARTH_BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
/** 生肖 */
const ZODIACS = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];
/** 农历月份名 */
const LUNAR_MONTH_NAMES = ['正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '冬月', '腊月'];
/** 农历日期名 */
const LUNAR_DAY_NAMES = [
'初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十',
'十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
'廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十'
];
/** 星期名 */
const WEEK_NAMES = ['日', '一', '二', '三', '四', '五', '六'];
/** 星座 */
const CONSTELLATIONS = ['摩羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '摩羯座'];
/** 星座日期边界 */
const CONSTELLATION_DATES = [20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22];
/** 二十四节气名 */
const SOLAR_TERMS = [
'冬至', '小寒', '大寒', '立春', '雨水', '惊蛰',
'春分', '清明', '谷雨', '立夏', '小满', '芒种',
'夏至', '小暑', '大暑', '立秋', '处暑', '白露',
'秋分', '寒露', '霜降', '立冬', '小雪', '大雪'
];
/** 二十四节气大致日期(每月两个) */
const SOLAR_TERM_DATES = [
[6, 21], // 小寒, 大寒 (1月)
[4, 19], // 立春, 雨水 (2月)
[6, 21], // 惊蛰, 春分 (3月)
[5, 20], // 清明, 谷雨 (4月)
[6, 21], // 立夏, 小满 (5月)
[6, 21], // 芒种, 夏至 (6月)
[7, 23], // 小暑, 大暑 (7月)
[8, 23], // 立秋, 处暑 (8月)
[8, 23], // 白露, 秋分 (9月)
[8, 24], // 寒露, 霜降 (10月)
[8, 22], // 立冬, 小雪 (11月)
[7, 22] // 大雪, 冬至 (12月)
];
/** 公历节日 */
const SOLAR_FESTIVALS = {
'1-1': '元旦', '2-14': '情人节', '3-8': '妇女节', '3-12': '植树节',
'4-1': '愚人节', '5-1': '劳动节', '5-4': '青年节', '6-1': '儿童节',
'7-1': '建党节', '8-1': '建军节', '9-10': '教师节', '10-1': '国庆节',
'12-24': '平安夜', '12-25': '圣诞节'
};
/** 农历节日 */
const LUNAR_FESTIVALS = {
'1-1': '春节', '1-15': '元宵节', '2-2': '龙抬头', '5-5': '端午节',
'7-7': '七夕', '7-15': '中元节', '8-15': '中秋节', '9-9': '重阳节',
'12-8': '腊八节', '12-23': '小年', '12-30': '除夕'
};
/** 佛教节日 */
const BUDDHIST_FESTIVALS = {
'1-1': '弥勒菩萨圣诞', '2-8': '释迦牟尼佛出家日', '2-15': '释迦牟尼佛涅槃日',
'2-19': '观音菩萨圣诞', '2-21': '普贤菩萨圣诞', '3-16': '准提菩萨圣诞',
'4-4': '文殊菩萨圣诞', '4-8': '释迦牟尼佛圣诞(浴佛节)', '5-3': '伽蓝菩萨圣诞',
'6-3': '韦驮菩萨圣诞', '6-19': '观音菩萨成道日', '7-13': '大势至菩萨圣诞',
'7-15': '盂兰盆节(佛欢喜日)', '7-30': '地藏菩萨圣诞', '8-22': '燃灯佛圣诞',
'9-19': '观音菩萨出家日', '9-30': '药师佛圣诞', '10-5': '达摩祖师诞辰',
'11-17': '阿弥陀佛圣诞', '12-8': '释迦牟尼佛成道日(腊八)', '12-29': '华严菩萨圣诞'
};
/** 纳音表 */
const NAYIN_TABLE = [
'海中金', '炉中火', '大林木', '路旁土', '剑锋金', '山头火',
'涧下水', '城头土', '白蜡金', '杨柳木', '泉中水', '屋上土',
'霹雳火', '松柏木', '长流水', '沙中金', '山下火', '平地木',
'壁上土', '金箔金', '覆灯火', '天河水', '大驿土', '钗钏金',
'桑柘木', '大溪水', '沙中土', '天上火', '石榴木', '大海水'
];
/** 时辰名 */
const HOUR_NAMES = ['子时', '丑时', '寅时', '卯时', '辰时', '巳时', '午时', '未时', '申时', '酉时', '戌时', '亥时'];
/** 时辰时间范围 */
const HOUR_RANGES = ['23:00-01:00', '01:00-03:00', '03:00-05:00', '05:00-07:00', '07:00-09:00', '09:00-11:00', '11:00-13:00', '13:00-15:00', '15:00-17:00', '17:00-19:00', '19:00-21:00', '21:00-23:00'];
/** 建除十二神 */
const DUTY_NAMES = ['建', '除', '满', '平', '定', '执', '破', '危', '成', '收', '开', '闭'];
/** 黄道黑道 */
const TWELVE_STARS = ['青龙', '明堂', '天刑', '朱雀', '金匮', '天德', '白虎', '玉堂', '天牢', '玄武', '司命', '勾陈'];
/** 二十八宿 */
const TWENTY_EIGHT_STARS = [
'角木蛟', '亢金龙', '氐土貉', '房日兔', '心月狐', '尾火虎', '箕水豹',
'斗木獬', '牛金牛', '女土蝠', '虚日鼠', '危月燕', '室火猪', '壁水貐',
'奎木狼', '娄金狗', '胃土雉', '昴日鸡', '毕月乌', '觜火猴', '参水猿',
'井木犴', '鬼金羊', '柳土獐', '星日马', '张月鹿', '翼火蛇', '轸水蚓'
];
/** 九星 */
const NINE_STARS = ['一白', '二黑', '三碧', '四绿', '五黄', '六白', '七赤', '八白', '九紫'];
/** 六曜 */
const SIX_STARS = ['大安', '留连', '速喜', '赤口', '小吉', '空亡'];
/** 彭祖百忌 */
const PENG_ZU = {
stems: ['甲不开仓', '乙不栽植', '丙不修灶', '丁不剃头', '戊不受田', '己不破券', '庚不经络', '辛不合酱', '壬不泱水', '癸不词讼'],
branches: ['子不问卜', '丑不冠带', '寅不祭祀', '卯不穿井', '辰不哭泣', '巳不远行', '午不苫盖', '未不服药', '申不安床', '酉不会客', '戌不吃犬', '亥不嫁娶']
};
/** 五行 */
const ELEMENTS = ['木', '火', '土', '金', '水'];
/** 天干五行 */
const STEM_ELEMENTS = { '甲': '木', '乙': '木', '丙': '火', '丁': '火', '戊': '土', '己': '土', '庚': '金', '辛': '金', '壬': '水', '癸': '水' };
/** 地支五行 */
const BRANCH_ELEMENTS = { '子': '水', '丑': '土', '寅': '木', '卯': '木', '辰': '土', '巳': '火', '午': '火', '未': '土', '申': '金', '酉': '金', '戌': '土', '亥': '水' };
/** 天干阴阳 */
const STEM_YINYANG = { '甲': 'yang', '乙': 'yin', '丙': 'yang', '丁': 'yin', '戊': 'yang', '己': 'yin', '庚': 'yang', '辛': 'yin', '壬': 'yang', '癸': 'yin' };
/** 地支阴阳 */
const BRANCH_YINYANG = { '子': 'yang', '丑': 'yin', '寅': 'yang', '卯': 'yin', '辰': 'yang', '巳': 'yin', '午': 'yang', '未': 'yin', '申': 'yang', '酉': 'yin', '戌': 'yang', '亥': 'yin' };
/** 地支藏干 */
const HIDE_STEMS = {
'子': [{ stem: '癸', type: '本气' }],
'丑': [{ stem: '己', type: '本气' }, { stem: '癸', type: '中气' }, { stem: '辛', type: '余气' }],
'寅': [{ stem: '甲', type: '本气' }, { stem: '丙', type: '中气' }, { stem: '戊', type: '余气' }],
'卯': [{ stem: '乙', type: '本气' }],
'辰': [{ stem: '戊', type: '本气' }, { stem: '乙', type: '中气' }, { stem: '癸', type: '余气' }],
'巳': [{ stem: '丙', type: '本气' }, { stem: '庚', type: '中气' }, { stem: '戊', type: '余气' }],
'午': [{ stem: '丁', type: '本气' }, { stem: '己', type: '中气' }],
'未': [{ stem: '己', type: '本气' }, { stem: '丁', type: '中气' }, { stem: '乙', type: '余气' }],
'申': [{ stem: '庚', type: '本气' }, { stem: '壬', type: '中气' }, { stem: '戊', type: '余气' }],
'酉': [{ stem: '辛', type: '本气' }],
'戌': [{ stem: '戊', type: '本气' }, { stem: '辛', type: '中气' }, { stem: '丁', type: '余气' }],
'亥': [{ stem: '壬', type: '本气' }, { stem: '甲', type: '中气' }]
};
/** 十二长生 */
const TERRAINS = ['长生', '沐浴', '冠带', '临官', '帝旺', '衰', '病', '死', '墓', '绝', '胎', '养'];
/** 十神 */
const TEN_STARS = ['比肩', '劫财', '食神', '伤官', '偏财', '正财', '七杀', '正官', '偏印', '正印'];
/** 地支六合 */
const BRANCH_COMBINE = { '子': '丑', '丑': '子', '寅': '亥', '亥': '寅', '卯': '戌', '戌': '卯', '辰': '酉', '酉': '辰', '巳': '申', '申': '巳', '午': '未', '未': '午' };
/** 地支六冲 */
const BRANCH_OPPOSITE = { '子': '午', '午': '子', '丑': '未', '未': '丑', '寅': '申', '申': '寅', '卯': '酉', '酉': '卯', '辰': '戌', '戌': '辰', '巳': '亥', '亥': '巳' };
/** 地支六害 */
const BRANCH_HARM = { '子': '未', '未': '子', '丑': '午', '午': '丑', '寅': '巳', '巳': '寅', '卯': '辰', '辰': '卯', '申': '亥', '亥': '申', '酉': '戌', '戌': '酉' };
/** 地支相刑 */
const BRANCH_PUNISH = [
['寅', '巳'], ['巳', '申'], ['申', '寅'],
['丑', '戌'], ['戌', '未'], ['未', '丑'],
['子', '卯'], ['卯', '子'],
['辰', '辰'], ['午', '午'], ['酉', '酉'], ['亥', '亥']
];
/** 地支三合局 */
const THREE_COMBINES = {
'水局': ['申', '子', '辰'],
'木局': ['亥', '卯', '未'],
'火局': ['寅', '午', '戌'],
'金局': ['巳', '酉', '丑']
};
/** 天干合 */
const STEM_COMBINE = { '甲': '己', '己': '甲', '乙': '庚', '庚': '乙', '丙': '辛', '辛': '丙', '丁': '壬', '壬': '丁', '戊': '癸', '癸': '戊' };
/** 天干冲 */
const STEM_OPPOSITE = { '甲': '庚', '庚': '甲', '乙': '辛', '辛': '乙', '丙': '壬', '壬': '丙', '丁': '癸', '癸': '丁' };
/** 五行相生 */
const GENERATES = { '木': '火', '火': '土', '土': '金', '金': '水', '水': '木' };
/** 五行相克 */
const KILLS = { '木': '土', '土': '水', '水': '火', '火': '金', '金': '木' };
/** 八卦 */
const TRIGRAMS = [
null,
{ index: 1, name: '乾', symbol: '☰', element: '金', direction: '西北', nature: '天', trait: '健', body: '首' },
{ index: 2, name: '兑', symbol: '☱', element: '金', direction: '西', nature: '泽', trait: '悦', body: '口' },
{ index: 3, name: '离', symbol: '☲', element: '火', direction: '南', nature: '火', trait: '丽', body: '目' },
{ index: 4, name: '震', symbol: '☳', element: '木', direction: '东', nature: '雷', trait: '动', body: '足' },
{ index: 5, name: '巽', symbol: '☴', element: '木', direction: '东南', nature: '风', trait: '入', body: '股' },
{ index: 6, name: '坎', symbol: '☵', element: '水', direction: '北', nature: '水', trait: '陷', body: '耳' },
{ index: 7, name: '艮', symbol: '☶', element: '土', direction: '东北', nature: '山', trait: '止', body: '手' },
{ index: 8, name: '坤', symbol: '☷', element: '土', direction: '西南', nature: '地', trait: '顺', body: '腹' }
];
/** 六十四卦数据 */
const HEXAGRAMS = {
'1,1': { name: '乾为天', judgment: '大哉乾元,万物资始,乃统天。云行雨施,品物流形', image: '天行健,君子以自强不息', lines: ['潜龙勿用', '见龙在田,利见大人', '君子终日乾乾,夕惕若厉', '或跃在渊,无咎', '飞龙在天,利见大人', '亢龙有悔'] },
'1,5': { name: '天风姤', judgment: '姤,遇也,柔遇刚也。天地相遇,品物咸章', image: '天下有风,姤。后以施命诰四方', lines: ['系于金柅,贞吉', '包有鱼,无咎', '臀无肤,其行次且', '包无鱼,起凶', '以杞包瓜,含章', '姤其角,吝'] },
'1,7': { name: '天山遁', judgment: '遁亨,遁而亨也。刚当位而应,与时行也', image: '天下有山,遁。君子以远小人,不恶而严', lines: ['遁尾厉,勿用有攸往', '执之用黄牛之革', '系遁,有疾厉', '好遁,君子吉', '嘉遁,贞吉', '肥遁,无不利'] },
'1,8': { name: '天地否', judgment: '否之匪人,不利君子贞。大往小来', image: '天地不交,否。君子以俭德辟难', lines: ['拔茅茹,以其汇,贞吉', '包承,小人吉,大人否', '包羞', '有命无咎,畴离祉', '休否,大人吉', '倾否,先否后喜'] },
'5,8': { name: '风地观', judgment: '观,盥而不荐,有孚颙若。观天之神道而四时不忒', image: '风行地上,观。先王以省方观民设教', lines: ['童观,小人无咎', '窥观,利女贞', '观我生进退', '观国之光,利用宾于王', '观我生,君子无咎', '观其生,君子无咎'] },
'7,8': { name: '山地剥', judgment: '剥,剥也,柔变刚也。不利有攸往', image: '山附于地,剥。上以厚下安宅', lines: ['剥床以足,蔑贞凶', '剥床以辨,蔑贞凶', '剥之无咎', '剥床以肤,凶', '贯鱼以宫人宠,无不利', '硕果不食,君子得舆'] },
'3,8': { name: '火地晋', judgment: '晋,进也。明出地上,顺而丽乎大明', image: '明出地上,晋。君子以自昭明德', lines: ['晋如摧如,贞吉', '晋如愁如,贞吉', '众允,悔亡', '晋如鼫鼠,贞厉', '悔亡,失得勿恤', '晋其角,维用伐邑'] },
'3,1': { name: '火天大有', judgment: '大有,柔得尊位,大中而上下应之', image: '火在天上,大有。君子以遏恶扬善,顺天休命', lines: ['无交害,匪咎', '大车以载,有攸往', '公用亨于天子', '匪其彭,无咎', '厥孚交如,威如', '自天佑之,吉无不利'] },
'6,6': { name: '坎为水', judgment: '习坎,重险也。水流而不盈,行险而不失其信', image: '水洊至,习坎。君子以常德行习教事', lines: ['习坎,入于坎窞', '坎有险,求小得', '来之坎坎,险且枕', '樽酒簋贰,用缶', '坎不盈,祗既平', '系用徽纆,寘于丛棘'] },
'6,2': { name: '水泽节', judgment: '节亨,苦节不可贞', image: '泽上有水,节。君子以制数度议德行', lines: ['不出户庭,无咎', '不出门庭,凶', '不节若,则嗟若', '安节,亨', '甘节,吉', '苦节,贞凶'] },
'6,4': { name: '水雷屯', judgment: '屯,刚柔始交而难生。动乎险中,大亨贞', image: '云雷屯,君子以经纶', lines: ['磐桓,利居贞', '屯如邅如,乘马班如', '即鹿无虞,惟入于林中', '乘马班如,求婚媾', '屯其膏,小贞吉', '乘马班如,泣血涟如'] },
'6,3': { name: '水火既济', judgment: '既济亨,小者亨也。利贞,初吉终乱', image: '水在火上,既济。君子以思患而豫防之', lines: ['曳其轮,濡其尾', '妇丧其茀,勿逐', '高宗伐鬼方,三年克之', '繻有衣袽,终日戒', '东邻杀牛,不如西邻', '濡其首,厉'] },
'2,3': { name: '泽火革', judgment: '革,水火相息。天地革而四时成', image: '泽中有火,革。君子以治历明时', lines: ['巩用黄牛之革', '巳日乃革之,征吉', '征凶,贞厉', '悔亡,有孚改命', '大人虎变,未占有孚', '君子豹变,小人革面'] },
'4,3': { name: '雷火丰', judgment: '丰,大也。明以动,故丰', image: '雷电皆至,丰。君子以折狱致刑', lines: ['遇其配主,虽旬无咎', '丰其蔀,日中见斗', '丰其沛,日中见沬', '丰其蔀,日中见斗', '来章,有庆誉', '丰其屋,蔀其家'] },
'8,3': { name: '地火明夷', judgment: '明夷,利艰贞。明入地中,明夷', image: '明入地中,明夷。君子以莅众用晦而明', lines: ['明夷于飞,垂其翼', '明夷,夷于左股', '明夷于南狩,得其大首', '入于左腹,获明夷之心', '箕子之明夷,利贞', '不明晦,初登于天'] },
'8,6': { name: '地水师', judgment: '师,众也。贞,丈人吉,无咎', image: '地中有水,师。君子以容民畜众', lines: ['师出以律,否臧凶', '在师中,吉无咎', '师或舆尸,凶', '师左次,无咎', '田有禽,利执言', '大君有命,开国承家'] },
'7,7': { name: '艮为山', judgment: '艮,止也。时止则止,时行则行', image: '兼山,艮。君子以思不出其位', lines: ['艮其趾,无咎', '艮其腓,不拯其随', '艮其限,列其夤', '艮其身,无咎', '艮其辅,言有序', '敦艮,吉'] },
'7,3': { name: '山火贲', judgment: '贲亨,柔来而文刚,故亨', image: '山下有火,贲。君子以明庶政无敢折狱', lines: ['贲其趾,舍车而徒', '贲其须', '贲如濡如,永贞吉', '贲如皤如,白马翰如', '贲于丘园,束帛戋戋', '白贲,无咎'] },
'7,1': { name: '山天大畜', judgment: '大畜,刚健笃实辉光,日新其德', image: '天在山中,大畜。君子以多识前言往行', lines: ['有厉,利已', '舆说輹', '良马逐,利艰贞', '童牛之牿,元吉', '豮豕之牙,吉', '何天之衢,亨'] },
'7,2': { name: '山泽损', judgment: '损,损下益上,其道上行', image: '山下有泽,损。君子以惩忿窒欲', lines: ['已事遄往,无咎', '利贞,征凶,弗损益之', '三人行则损一人', '损其疾,使遄有喜', '或益之十朋之龟', '弗损益之,无咎'] },
'3,2': { name: '火泽睽', judgment: '睽,火动而上,泽动而下', image: '上火下泽,睽。君子以同而异', lines: ['悔亡,丧马勿逐', '遇主于巷,无咎', '见舆曳,其牛掣', '睽孤,遇元夫', '悔亡,厥宗噬肤', '睽孤,见豕负涂'] },
'1,2': { name: '天泽履', judgment: '履,柔履刚也。说而应乎乾', image: '上天下泽,履。君子以辩上下定民志', lines: ['素履往,无咎', '履道坦坦,幽人贞吉', '眇能视,跛能履', '履虎尾,愬愬终吉', '夬履,贞厉', '视履考祥,其旋元吉'] },
'5,2': { name: '风泽中孚', judgment: '中孚,柔在内而刚得中', image: '泽上有风,中孚。君子以议狱缓死', lines: ['虞吉,有它不燕', '鸣鹤在阴,其子和之', '得敌,或鼓或罢', '月几望,马匹亡', '有孚挛如,无咎', '翰音登于天,贞凶'] },
'5,7': { name: '风山渐', judgment: '渐,女归吉也。进得位,往有功也', image: '山上有木,渐。君子以居贤德善俗', lines: ['鸿渐于干,小子厉', '鸿渐于磐,饮食衎衎', '鸿渐于陆,夫征不复', '鸿渐于木,或得其桷', '鸿渐于陵,妇三岁不孕', '鸿渐于逵,其羽可用为仪'] },
'4,4': { name: '震为雷', judgment: '震亨。震来虩虩,笑言哑哑,震惊百里', image: '洊雷,震。君子以恐惧修省', lines: ['震来虩虩,后笑言哑哑', '震来厉,亿丧贝', '震苏苏,震行无眚', '震遂泥', '震往来厉,亿无丧', '震索索,视矍矍'] },
'4,8': { name: '雷地豫', judgment: '豫,刚应而志行,顺以动', image: '雷出地奋,豫。先王以作乐崇德', lines: ['鸣豫,凶', '介于石,不终日', '盱豫悔,迟有悔', '由豫,大有得', '贞疾,恒不死', '冥豫,成有渝'] },
'4,6': { name: '雷水解', judgment: '解,险以动,动而免乎险', image: '雷雨作,解。君子以赦过宥罪', lines: ['无咎', '田获三狐,得黄矢', '负且乘,致寇至', '解而拇,朋至斯孚', '君子维有解,吉', '公用射隼于高墉之上'] },
'4,5': { name: '雷风恒', judgment: '恒,久也。刚上而柔下', image: '雷风,恒。君子以立不易方', lines: ['浚恒,贞凶', '悔亡', '不恒其德,或承之羞', '田无禽', '恒其德,贞妇人吉', '振恒,凶'] },
'8,5': { name: '地风升', judgment: '柔以时升,巽而顺,刚中而应', image: '地中生木,升。君子以顺德积小以高大', lines: ['允升,大吉', '孚乃利用禴,无咎', '升虚邑', '王用亨于岐山', '贞吉,升阶', '冥升,利于不息之贞'] },
'6,5': { name: '水风井', judgment: '井,改邑不改井,无丧无得', image: '木上有水,井。君子以劳民劝相', lines: ['井泥不食,旧井无禽', '井谷射鲋,瓮敝漏', '井渫不食,为我心恻', '井甃,无咎', '井洌,寒泉食', '井收勿幕,有孚元吉'] },
'2,5': { name: '泽风大过', judgment: '大过,大者过也。栋桡,本末弱也', image: '泽灭木,大过。君子以独立不惧遁世无闷', lines: ['藉用白茅,无咎', '枯杨生稊,老夫得其女妻', '栋桡,凶', '栋隆,吉', '枯杨生华,老妇得士夫', '过涉灭顶,凶'] },
'2,4': { name: '泽雷随', judgment: '随,刚来而下柔,动而说', image: '泽中有雷,随。君子以向晦入宴息', lines: ['官有渝,贞吉', '系小子,失丈夫', '系丈夫,失小子', '随有获,贞凶', '孚于嘉,吉', '拘系之,乃从维之'] },
'5,5': { name: '巽为风', judgment: '重巽以申命,刚巽乎中正而志行', image: '随风,巽。君子以申命行事', lines: ['进退,利武人之贞', '巽在床下,用史巫纷若', '频巽,吝', '悔亡,田获三品', '贞吉,悔亡无不利', '巽在床下,丧其资斧'] },
'5,1': { name: '风天小畜', judgment: '小畜,柔得位而上下应之', image: '风行天上,小畜。君子以懿文德', lines: ['复自道,何其咎', '牵复,吉', '舆说辐,夫妻反目', '有孚,血去惕出', '有孚挛如,富以其邻', '既雨既处,尚德载'] },
'5,3': { name: '风火家人', judgment: '家人,女正位乎内,男正位乎外', image: '风自火出,家人。君子以言有物而行有恒', lines: ['闲有家,悔亡', '无攸遂,在中馈', '家人嗃嗃,悔厉吉', '富家,大吉', '王假有家,勿恤', '有孚威如,终吉'] },
'5,4': { name: '风雷益', judgment: '益,损上益下,民说无疆', image: '风雷,益。君子以见善则迁有过则改', lines: ['利用为大作,元吉', '或益之十朋之龟', '益之用凶事,无咎', '中行告公从,利用为依迁国', '有孚惠心,勿问元吉', '莫益之,或击之'] },
'1,4': { name: '天雷无妄', judgment: '无妄,刚自外来而为主于内', image: '天下雷行,无妄。先王以茂对时育万物', lines: ['无妄,往吉', '不耕获,不菑畬', '无妄之灾,或系之牛', '可贞,无咎', '无妄之疾,勿药有喜', '无妄,行有眚'] },
'3,4': { name: '火雷噬嗑', judgment: '噬嗑亨,利用狱。刚柔分动而明', image: '雷电噬嗑,先王以明罚敕法', lines: ['屦校灭趾,无咎', '噬肤灭鼻,无咎', '噬腊肉,遇毒', '噬干胏,得金矢', '噬干肉,得黄金', '何校灭耳,凶'] },
'7,4': { name: '山雷颐', judgment: '颐,贞吉。观颐,自求口实', image: '山下有雷,颐。君子以慎言语节饮食', lines: ['舍尔灵龟,观我朵颐', '颠颐,拂经于丘颐', '拂颐,贞凶', '颠颐,吉', '拂经,居贞吉', '由颐,厉吉,利涉大川'] },
'7,5': { name: '山风蛊', judgment: '蛊,元亨。利涉大川,先甲三日后甲三日', image: '山下有风,蛊。君子以振民育德', lines: ['干父之蛊,有子考无咎', '干母之蛊,不可贞', '干父之蛊,小有悔', '裕父之蛊,往见吝', '干父之蛊,用誉', '不事王侯,高尚其事'] },
'3,3': { name: '离为火', judgment: '离,丽也。日月丽乎天,百谷草木丽乎土', image: '明两作,离。大人以继明照于四方', lines: ['履错然,敬之无咎', '黄离,元吉', '日昃之离,不鼓缶而歌', '突如其来如,焚如死如弃如', '出涕沱若,戚嗟若', '王用出征,有嘉折首'] },
'3,7': { name: '火山旅', judgment: '旅,小亨。旅贞吉', image: '山上有火,旅。君子以明慎用刑而不留狱', lines: ['旅琐琐,斯其所取灾', '旅即次,怀其资', '旅焚其次,丧其童仆', '旅于处,得其资斧', '射雉,一矢亡', '鸟焚其巢,旅人先笑后号咷'] },
'3,5': { name: '火风鼎', judgment: '鼎,象也。以木巽火,亨饪也', image: '木上有火,鼎。君子以正位凝命', lines: ['鼎颠趾,利出否', '鼎有实,我仇有疾', '鼎耳革,其行塞', '鼎折足,覆公餗', '鼎黄耳金铉,利贞', '鼎玉铉,大吉'] },
'3,6': { name: '火水未济', judgment: '未济亨,小狐汔济,濡其尾', image: '火在水上,未济。君子以慎辨物居方', lines: ['濡其尾,吝', '曳其轮,贞吉', '未济,征凶', '贞吉,悔亡', '贞吉,无悔', '有孚于饮酒,无咎'] },
'7,6': { name: '山水蒙', judgment: '蒙亨。匪我求童蒙,童蒙求我', image: '山下出泉,蒙。君子以果行育德', lines: ['发蒙,利用刑人', '包蒙,吉', '勿用取女,见金夫', '困蒙,吝', '童蒙,吉', '击蒙,不利为寇'] },
'5,6': { name: '风水涣', judgment: '涣亨。王假有庙,利涉大川', image: '风行水上,涣。先王以享于帝立庙', lines: ['用拯马壮,吉', '涣奔其机,悔亡', '涣其躬,无悔', '涣其群,元吉', '涣汗其大号', '涣其血,去逖出'] },
'1,6': { name: '天水讼', judgment: '讼,上刚下险,险而健,讼', image: '天与水违行,讼。君子以作事谋始', lines: ['不永所事,小有言', '不克讼,归而逋', '食旧德,贞厉终吉', '不克讼,复即命渝', '讼,元吉', '或锡之鞶带,终朝三褫'] },
'1,3': { name: '天火同人', judgment: '同人,柔得位得中而应乎乾', image: '天与火,同人。君子以类族辨物', lines: ['同人于门,无咎', '同人于宗,吝', '伏戎于莽,升其高陵', '乘其墉,弗克攻', '同人先号咷而后笑', '同人于郊,无悔'] },
'8,8': { name: '坤为地', judgment: '至哉坤元,万物资生,乃顺承天', image: '地势坤,君子以厚德载物', lines: ['履霜,坚冰至', '直方大,不习无不利', '含章可贞,或从王事', '括囊,无咎无誉', '黄裳,元吉', '龙战于野,其血玄黄'] },
'8,4': { name: '地雷复', judgment: '复亨。出入无疾,朋来无咎', image: '雷在地中,复。先王以至日闭关', lines: ['不远复,无祗悔', '休复,吉', '频复,厉', '中行独复', '敦复,无悔', '迷复,凶有灾眚'] },
'8,2': { name: '地泽临', judgment: '临,刚浸而长,说而顺', image: '泽上有地,临。君子以教思无穷容保民无疆', lines: ['咸临,贞吉', '咸临,吉无不利', '甘临,无攸利', '至临,无咎', '知临,大君之宜', '敦临,吉无咎'] },
'8,1': { name: '地天泰', judgment: '泰,小往大来,吉亨。天地交而万物通', image: '天地交,泰。后以财成天地之道', lines: ['拔茅茹,以其汇', '包荒,用冯河', '无平不陂,无往不复', '翩翩,不富以其邻', '帝乙归妹,以祉元吉', '城复于隍,勿用师'] },
'4,1': { name: '雷天大壮', judgment: '大壮,大者壮也。刚以动,故壮', image: '雷在天上,大壮。君子以非礼勿履', lines: ['壮于趾,征凶', '贞吉', '小人用壮,君子用罔', '贞吉,悔亡', '丧羊于易,无悔', '羝羊触藩,不能退'] },
'2,1': { name: '泽天夬', judgment: '夬,决也,刚决柔也。健而说,决而和', image: '泽上于天,夬。君子以施禄及下', lines: ['壮于前趾,往不胜为咎', '惕号,莫夜有戎', '壮于頄,有凶', '臀无肤,其行次且', '苋陆夬夬,中行无咎', '无号,终有凶'] },
'6,1': { name: '水天需', judgment: '需,须也。险在前也,刚健而不陷', image: '云上于天,需。君子以饮食宴乐', lines: ['需于郊,利用恒', '需于沙,小有言', '需于泥,致寇至', '需于血,出自穴', '需于酒食,贞吉', '入于穴,有不速之客三人来'] },
'6,8': { name: '水地比', judgment: '比,吉也。比,辅也,下顺从也', image: '地上有水,比。先王以建万国亲诸侯', lines: ['有孚比之,无咎', '比之自内,贞吉', '比之匪人', '外比之,贞吉', '显比,王用三驱', '比之无首,凶'] },
'2,2': { name: '兑为泽', judgment: '兑,说也。刚中而柔外,说以利贞', image: '丽泽,兑。君子以朋友讲习', lines: ['和兑,吉', '孚兑,吉', '来兑,凶', '商兑未宁,介疾有喜', '孚于剥,有厉', '引兑'] },
'2,6': { name: '泽水困', judgment: '困,刚掩也。险以说,困而不失其所', image: '泽无水,困。君子以致命遂志', lines: ['臀困于株木,入于幽谷', '困于酒食,朱绂方来', '困于石,据于蒺藜', '来徐徐,困于金车', '劓刖,困于赤绂', '困于葛藟,于臲兀'] },
'2,8': { name: '泽地萃', judgment: '萃,聚也。顺以说,刚中而应', image: '泽上于地,萃。君子以除戎器戒不虞', lines: ['有孚不终,乃乱乃萃', '引吉,无咎', '萃如嗟如,无攸利', '大吉,无咎', '萃有位,无咎', '赍咨涕洟,无咎'] },
'2,7': { name: '泽山咸', judgment: '咸,感也。柔上而刚下,二气感应以相与', image: '山上有泽,咸。君子以虚受人', lines: ['咸其拇', '咸其腓,凶', '咸其股,执其随', '贞吉,悔亡', '咸其脢,无悔', '咸其辅颊舌'] },
'6,7': { name: '水山蹇', judgment: '蹇,难也,险在前也。见险而能止', image: '山上有水,蹇。君子以反身修德', lines: ['往蹇,来誉', '王臣蹇蹇,匪躬之故', '往蹇,来反', '往蹇,来连', '大蹇,朋来', '往蹇,来硕'] },
'8,7': { name: '地山谦', judgment: '谦亨。天道下济而光明,地道卑而上行', image: '地中有山,谦。君子以裒多益寡称物平施', lines: ['谦谦君子,用涉大川', '鸣谦,贞吉', '劳谦君子,有终吉', '无不利,撝谦', '不富以其邻,利用侵伐', '鸣谦,利用行师'] },
'4,7': { name: '雷山小过', judgment: '小过,小者过而亨也。过以利贞', image: '山上有雷,小过。君子以行过乎恭', lines: ['飞鸟以凶', '过其祖,遇其妣', '弗过防之,从或戕之', '无咎,弗过遇之', '密云不雨,自我西郊', '弗遇过之,飞鸟离之'] },
'4,2': { name: '雷泽归妹', judgment: '归妹,天地之大义也。天地不交而万物不兴', image: '泽上有雷,归妹。君子以永终知敝', lines: ['归妹以娣,跛能履', '眇能视,利幽人之贞', '归妹以须,反归以娣', '归妹愆期,迟归有时', '帝乙归妹,其君之袂', '女承筐无实,士刲羊无血'] }
};
/** 称骨年表 */
const YEAR_WEIGHTS = {
0: 12, 1: 9, 2: 6, 3: 7, 4: 12, 5: 5, 6: 9, 7: 8, 8: 7, 9: 8,
10: 15, 11: 9, 12: 16, 13: 8, 14: 8, 15: 19, 16: 12, 17: 6, 18: 8, 19: 7,
20: 5, 21: 15, 22: 6, 23: 16, 24: 15, 25: 7, 26: 9, 27: 12, 28: 10, 29: 7,
30: 15, 31: 6, 32: 5, 33: 14, 34: 14, 35: 9, 36: 7, 37: 7, 38: 9, 39: 12,
40: 8, 41: 7, 42: 13, 43: 5, 44: 14, 45: 5, 46: 9, 47: 17, 48: 5, 49: 7,
50: 12, 51: 8, 52: 8, 53: 6, 54: 19, 55: 6, 56: 8, 57: 16, 58: 10, 59: 6
};
/** 称骨月表 */
const MONTH_WEIGHTS = { 1: 6, 2: 7, 3: 18, 4: 9, 5: 5, 6: 16, 7: 9, 8: 15, 9: 18, 10: 8, 11: 9, 12: 5 };
/** 称骨日表 */
const DAY_WEIGHTS = {
1: 5, 2: 10, 3: 8, 4: 15, 5: 16, 6: 15, 7: 8, 8: 16, 9: 8, 10: 16,
11: 9, 12: 17, 13: 8, 14: 17, 15: 10, 16: 8, 17: 9, 18: 18, 19: 5, 20: 15,
21: 10, 22: 9, 23: 8, 24: 9, 25: 15, 26: 18, 27: 7, 28: 8, 29: 16, 30: 6
};
/** 称骨时表 */
const HOUR_WEIGHTS = { 0: 16, 1: 6, 2: 7, 3: 10, 4: 9, 5: 16, 6: 10, 7: 8, 8: 8, 9: 9, 10: 6, 11: 6 };
/** 称骨歌诀 */
const BONE_INTERPRETATIONS = {
21: { text: '短命非业谓大凶,平生灾难事重重,凶祸频临陷逆境,终世困苦事不成。', fortune: '下' },
22: { text: '身寒骨冷苦伶仃,此命推来行乞人,劳劳碌碌无度日,终年打拱过平生。', fortune: '下' },
23: { text: '此命推来骨格轻,求谋作事事难成,妻儿兄弟应难许,别处他乡作散人。', fortune: '下' },
24: { text: '此命推来福禄无,门庭困苦总难荣,六亲骨肉皆无靠,流浪他乡作老翁。', fortune: '下' },
25: { text: '此命推来祖业微,门庭营度似稀奇,六亲骨肉如冰炭,一世勤劳自把持。', fortune: '中下' },
26: { text: '平生衣禄苦中求,独自营谋事不休,离祖出门宜早计,晚来衣禄自无休。', fortune: '中下' },
27: { text: '一生作事少商量,难靠祖宗怎主张,独马单枪空做去,早年晚岁总无长。', fortune: '中下' },
28: { text: '一生行事似飘蓬,祖宗产业在梦中,若不过房改名姓,也当移徒二三通。', fortune: '中下' },
29: { text: '初年运限未曾亨,纵有功名在后成,须过四旬才可立,移居改姓始为良。', fortune: '中' },
30: { text: '劳劳碌碌苦中求,东奔西走何日休,若使终身勤与俭,老来稍可免忧愁。', fortune: '中' },
31: { text: '忙忙碌碌苦中求,何日云开见日头,难得祖基家可立,中年衣食渐无忧。', fortune: '中' },
32: { text: '初年运蹇事难谋,渐有财源如水流,到得中年衣食旺,那时名利一齐收。', fortune: '中上' },
33: { text: '早年做事事难成,百年勤劳枉费心,半世自如流水去,后来运到始得金。', fortune: '中上' },
34: { text: '此命福气果如何,僧道门中衣禄多,离祖出家方为妙,朝晚拜佛念弥陀。', fortune: '中上' },
35: { text: '生平福量不周全,祖业根基觉少传,营事生涯宜守旧,时来衣食胜从前。', fortune: '中' },
36: { text: '不须劳碌过平生,独自成家福不轻,早有福星常照命,任君行去百般成。', fortune: '上' },
37: { text: '此命般般事不成,弟兄少力自孤行,虽然祖业须微有,来得明时去不明。', fortune: '中下' },
38: { text: '一身骨肉最清高,早入簧门姓氏标,待到年将三十六,蓝衫脱去换红袍。', fortune: '上' },
39: { text: '此命终身运不通,劳劳作事尽皆空,苦心竭力成家计,到得那时在梦中。', fortune: '中下' },
40: { text: '平生衣禄是绵长,件件心中自主张,前面风霜多受过,后来必定享安康。', fortune: '上' },
41: { text: '此命推来自不同,为人能干异凡庸,中年还有逍遥福,不比前时运未通。', fortune: '上' },
42: { text: '得宽怀处且宽怀,何用双眉皱不开,若使中年命运济,那时名利一齐来。', fortune: '上' },
43: { text: '为人心性最聪明,作事轩昂近贵人,衣禄一生天注定,不须劳碌是丰亨。', fortune: '上上' },
44: { text: '万事由天莫苦求,须知福碌赖人修,当年财帛难如意,晚景欣然便不忧。', fortune: '中上' },
45: { text: '名利推求竟若何,前番辛苦后奔波,命中难养男和女,骨肉扶持也不多。', fortune: '中' },
46: { text: '东西南北尽皆通,出姓移居更觉隆,衣禄无穷无数定,中年晚景一般同。', fortune: '上' },
47: { text: '此命推求旺末年,妻荣子贵自怡然,平生原有滔滔福,可卜财源若水泉。', fortune: '上' },
48: { text: '初年运道未曾通,几许蹉跎命亦穷,兄弟六亲无依靠,一生事业晚来整。', fortune: '中' },
49: { text: '此命推来福不轻,自成自立显门庭,从来富贵人钦敬,使婢差奴过一生。', fortune: '上' },
50: { text: '为利为名终日劳,中年福禄也多遭,老来自有财星照,不比前番目下高。', fortune: '上' },
51: { text: '一世荣华事事通,不须劳碌自亨通,兄弟叔侄皆如意,家业成时福禄宏。', fortune: '上' },
52: { text: '一世亨通事事能,不须劳苦自然宁,宗族有光欣喜甚,家产丰盈自称心。', fortune: '上' },
53: { text: '此格推来福泽宏,兴家立业在其中,一生衣食安排定,却是人间一福翁。', fortune: '上' },
54: { text: '此命推来厚且清,诗书满腹看功成,丰衣足食自然稳,正是人间有福人。', fortune: '上上' },
55: { text: '走马扬鞭争利名,少年作事费筹论,一朝福禄源源至,富贵荣华显六亲。', fortune: '上' },
56: { text: '此格推来礼义通,一身福禄用无穷,甜酸苦辣皆尝过,滚滚财源稳且丰。', fortune: '上' },
57: { text: '福禄丰盈万事全,一身荣耀乐天年,名扬威震人争羡,此世逍遥宛似仙。', fortune: '上上' },
58: { text: '平生福禄自然来,名利双全福禄偕,雁塔题名为贵客,紫袍玉带走金阶。', fortune: '上' },
59: { text: '细推此格妙且清,必定财高礼义通,甲第之中应有分,扬鞭走马显威荣。', fortune: '上' },
60: { text: '一朝金榜快题名,显祖荣宗大器成,衣禄定然无欠缺,田园财帛更丰盈。', fortune: '上上' },
61: { text: '不作朝中金榜客,定为世上一财翁,聪明天赋经书熟,名显高科自是荣。', fortune: '上上' },
62: { text: '此命生来福不穷,读书必定显亲宗,紫衣玉带为卿相,富贵荣华孰与同。', fortune: '上上' },
63: { text: '命主为官福禄长,得来富贵定非常,名题雁塔传金榜,定中高科天下扬。', fortune: '上上' },
64: { text: '此命生成福不轻,读书必定有功名,果然富贵前生定,一世荣华事事成。', fortune: '上上' },
65: { text: '细推此命福不轻,安国安邦极品人,文纷雕梁徽富贵,威声照耀四方闻。', fortune: '上上' },
66: { text: '此命推来福且宏,荣华富贵自然通,命中注定衣禄足,一世亨通稳且丰。', fortune: '上上' },
67: { text: '此命生来福自宏,田园家业最高隆,平生衣禄丰盈足,一世荣华万事通。', fortune: '上上' },
68: { text: '富贵荣华莫强求,强求不出反成羞,有福之人还自至,无福之人反成忧。', fortune: '中' },
69: { text: '君是人间前禄星,一生富贵众人钦,纵然福禄由天定,安享荣华过一生。', fortune: '上上' },
70: { text: '此命推来福禄宏,不须劳碌过平生,妻儿和顺皆如意,家道兴隆福自成。', fortune: '上' },
71: { text: '此命生来大不同,公侯卿相在其中,一生自有逍遥福,富贵荣华极品隆。', fortune: '上上' },
72: { text: '此命生来福泽长,兴家立业有祯祥,一生自有逍遥福,富贵荣华极品良。', fortune: '上上' }
};
module.exports = {
LUNAR_INFO,
HEAVEN_STEMS,
EARTH_BRANCHES,
ZODIACS,
LUNAR_MONTH_NAMES,
LUNAR_DAY_NAMES,
WEEK_NAMES,
CONSTELLATIONS,
CONSTELLATION_DATES,
SOLAR_TERMS,
SOLAR_TERM_DATES,
SOLAR_FESTIVALS,
LUNAR_FESTIVALS,
BUDDHIST_FESTIVALS,
NAYIN_TABLE,
HOUR_NAMES,
HOUR_RANGES,
DUTY_NAMES,
TWELVE_STARS,
TWENTY_EIGHT_STARS,
NINE_STARS,
SIX_STARS,
PENG_ZU,
ELEMENTS,
STEM_ELEMENTS,
BRANCH_ELEMENTS,
STEM_YINYANG,
BRANCH_YINYANG,
HIDE_STEMS,
TERRAINS,
TEN_STARS,
BRANCH_COMBINE,
BRANCH_OPPOSITE,
BRANCH_HARM,
BRANCH_PUNISH,
THREE_COMBINES,
STEM_COMBINE,
STEM_OPPOSITE,
GENERATES,
KILLS,
TRIGRAMS,
HEXAGRAMS,
YEAR_WEIGHTS,
MONTH_WEIGHTS,
DAY_WEIGHTS,
HOUR_WEIGHTS,
BONE_INTERPRETATIONS
};
File diff suppressed because it is too large Load Diff