feat: 祈福小助手万年历小程序第一期
This commit is contained in:
@@ -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() {}
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "日历",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user