Initial Commit

This commit is contained in:
yuming
2025-10-26 19:29:30 +08:00
commit 6747ade9c4
33 changed files with 4387 additions and 0 deletions
+263
View File
@@ -0,0 +1,263 @@
// add-anniversary.js
const storage = require('../../utils/storage')
const dateUtils = require('../../utils/date')
Page({
data: {
anniversaryId: null,
personId: null,
personList: [],
personIndex: 0,
selectedPerson: '',
typeList: ['公历生日', '农历生日', '结婚纪念日', '订婚纪念日', '其他纪念日'],
typeIndex: 0,
showCustomType: false,
dateValue: '',
remindDaysList: ['提前3天', '提前7天', '提前14天', '提前30天', '自定义'],
remindDaysIndex: 0,
formData: {
isLunar: false,
type: 'birthday',
customTypeName: '',
solarYear: '',
solarMonth: '',
solarDay: '',
lunarYear: '',
lunarMonth: '',
lunarDay: '',
importance: 'low',
remindEnabled: true,
remindDays: 7,
remark: ''
}
},
onLoad(options) {
// 获取人员列表
const persons = storage.getPersons()
this.setData({ personList: persons })
if (options.personId) {
// 从人员详情页进入
const index = persons.findIndex(p => p.id === options.personId)
if (index !== -1) {
this.setData({
personIndex: index,
personId: options.personId,
selectedPerson: persons[index].name
})
}
}
if (options.id) {
// 编辑模式
this.setData({ anniversaryId: options.id })
this.loadAnniversary(options.id)
} else {
// 设置默认日期为今天
const today = new Date()
this.setData({
dateValue: dateUtils.formatDate(today, 'YYYY-MM-DD')
})
}
},
/**
* 加载纪念日信息(编辑模式)
*/
loadAnniversary(id) {
const anniversaries = storage.getAnniversaries()
const anniversary = anniversaries.find(a => a.id === id)
if (anniversary) {
const date = dateUtils.formatDate(
new Date(anniversary.solarYear, anniversary.solarMonth - 1, anniversary.solarDay),
'YYYY-MM-DD'
)
// 设置类型
const typeIndex = this.getTypeIndex(anniversary.type)
this.setData({
formData: anniversary,
dateValue: date,
typeIndex,
showCustomType: anniversary.type === 'other'
})
wx.setNavigationBarTitle({ title: '编辑纪念日' })
}
},
/**
* 获取类型索引
*/
getTypeIndex(type) {
const indexMap = {
birthday: 0,
lunar_birthday: 1,
wedding: 2,
engagement: 3,
other: 4
}
return indexMap[type] || 0
},
/**
* 选择人员
*/
onPersonChange(e) {
const index = parseInt(e.detail.value)
const person = this.data.personList[index]
this.setData({
personIndex: index,
personId: person.id,
selectedPerson: person.name
})
},
/**
* 选择类型
*/
onTypeChange(e) {
const index = parseInt(e.detail.value)
const types = ['birthday', 'lunar_birthday', 'wedding', 'engagement', 'other']
const isOther = index === 4
this.setData({
typeIndex: index,
showCustomType: isOther,
'formData.type': types[index]
})
},
/**
* 自定义类型输入
*/
onCustomTypeInput(e) {
this.setData({
'formData.customTypeName': e.detail.value
})
},
/**
* 日期类型改变
*/
onDateTypeChange(e) {
const isLunar = e.detail.value === 'lunar'
this.setData({
'formData.isLunar': isLunar
})
},
/**
* 日期改变
*/
onDateChange(e) {
const dateStr = e.detail.value
const parts = dateStr.split('-')
this.setData({
dateValue: dateStr,
'formData.solarYear': parseInt(parts[0]),
'formData.solarMonth': parseInt(parts[1]),
'formData.solarDay': parseInt(parts[2])
})
},
/**
* 重要程度改变
*/
onImportanceChange(e) {
this.setData({
'formData.importance': e.detail.value
})
},
/**
* 提醒开关改变
*/
onRemindEnabledChange(e) {
this.setData({
'formData.remindEnabled': e.detail.value
})
},
/**
* 提醒天数改变
*/
onRemindDaysChange(e) {
const index = parseInt(e.detail.value)
const days = [3, 7, 14, 30, 7][index]
this.setData({
remindDaysIndex: index,
'formData.remindDays': days
})
},
/**
* 备注改变
*/
onRemarkChange(e) {
this.setData({
'formData.remark': e.detail.value
})
},
/**
* 取消
*/
onCancel() {
wx.navigateBack()
},
/**
* 提交
*/
onSubmit() {
const { formData, personId, anniversaryId } = this.data
// 验证关联人员
if (!personId) {
wx.showToast({ title: '请选择关联人员', icon: 'none' })
return
}
// 验证日期
if (!formData.solarYear || !formData.solarMonth || !formData.solarDay) {
wx.showToast({ title: '请选择日期', icon: 'none' })
return
}
// 验证自定义类型
if (formData.type === 'other' && !formData.customTypeName) {
wx.showToast({ title: '请输入自定义类型', icon: 'none' })
return
}
if (anniversaryId) {
// 编辑模式
const success = storage.updateAnniversary(anniversaryId, {
personId,
...formData
})
if (success) {
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => wx.navigateBack(), 1500)
}
} else {
// 新增模式
const newAnniversary = storage.addAnniversary({
personId,
...formData
})
if (newAnniversary) {
wx.showToast({ title: '添加成功', icon: 'success' })
setTimeout(() => wx.navigateBack(), 1500)
}
}
}
})
+101
View File
@@ -0,0 +1,101 @@
<!--add-anniversary.wxml-->
<view class="container">
<view class="form">
<!-- 关联人员 -->
<view class="form-item">
<text class="label required">关联人员</text>
<picker mode="selector" range="{{personList}}" range-key="name" value="{{personIndex}}" bindchange="onPersonChange">
<view class="picker">
<text wx:if="{{selectedPerson}}" class="picker-text">{{selectedPerson}}</text>
<text wx:else class="picker-placeholder">请选择关联人员</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
<!-- 纪念日类型 -->
<view class="form-item">
<text class="label required">纪念日类型</text>
<picker mode="selector" range="{{typeList}}" value="{{typeIndex}}" bindchange="onTypeChange">
<view class="picker">
<text class="picker-text">{{typeList[typeIndex]}}</text>
<text class="picker-arrow"></text>
</view>
</picker>
<input wx:if="{{showCustomType}}" class="input" placeholder="请输入自定义类型" value="{{formData.customTypeName}}" bindinput="onCustomTypeInput" />
</view>
<!-- 日期类型 -->
<view class="form-item">
<text class="label required">日期类型</text>
<radio-group class="radio-group" bindchange="onDateTypeChange">
<label class="radio-item">
<radio value="solar" checked="{{formData.isLunar === false}}" />
<text>公历</text>
</label>
<label class="radio-item">
<radio value="lunar" checked="{{formData.isLunar === true}}" />
<text>农历</text>
</label>
</radio-group>
</view>
<!-- 日期选择 -->
<view class="form-item">
<text class="label required">日期</text>
<picker mode="date" value="{{dateValue}}" bindchange="onDateChange">
<view class="picker">
<text class="picker-text">{{dateValue || '请选择日期'}}</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
<!-- 重要程度 -->
<view class="form-item">
<text class="label">重要程度</text>
<radio-group class="radio-group" bindchange="onImportanceChange">
<label class="radio-item">
<radio value="high" checked="{{formData.importance === 'high'}}" />
<text class="importance-high">非常重要</text>
</label>
<label class="radio-item">
<radio value="medium" checked="{{formData.importance === 'medium'}}" />
<text class="importance-medium">重要</text>
</label>
<label class="radio-item">
<radio value="low" checked="{{formData.importance === 'low' || !formData.importance}}" />
<text class="importance-low">一般</text>
</label>
</radio-group>
</view>
<!-- 提醒设置 -->
<view class="form-item">
<view class="switch-item">
<text class="label">开启提醒</text>
<switch checked="{{formData.remindEnabled}}" bindchange="onRemindEnabledChange" color="#07c160" />
</view>
<picker wx:if="{{formData.remindEnabled}}" mode="selector" range="{{remindDaysList}}" value="{{remindDaysIndex}}" bindchange="onRemindDaysChange">
<view class="picker">
<text class="picker-text">提前{{formData.remindDays}}天提醒</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
<!-- 备注 -->
<view class="form-item">
<text class="label">备注</text>
<textarea class="textarea" placeholder="添加备注信息(可选)" value="{{formData.remark}}" bindinput="onRemarkChange" />
</view>
<!-- 操作按钮 -->
<view class="buttons">
<button class="btn btn-cancel" bindtap="onCancel">取消</button>
<button class="btn btn-submit" bindtap="onSubmit">保存</button>
</view>
</view>
</view>
+139
View File
@@ -0,0 +1,139 @@
/**add-anniversary.wxss**/
.container {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 120rpx;
}
.form {
padding: 32rpx;
}
.form-item {
background-color: #fff;
border-radius: 16rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.label {
font-size: 28rpx;
color: #333;
margin-bottom: 24rpx;
display: block;
}
.label.required::after {
content: ' *';
color: #ff5722;
}
.picker {
background-color: #f5f5f5;
border-radius: 8rpx;
padding: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.picker-text {
font-size: 28rpx;
color: #333;
}
.picker-placeholder {
font-size: 28rpx;
color: #999;
}
.picker-arrow {
font-size: 36rpx;
color: #999;
}
.input {
margin-top: 16rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
padding: 24rpx;
font-size: 28rpx;
}
.radio-group {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.radio-item {
display: flex;
align-items: center;
padding: 16rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
}
.radio-item text {
font-size: 28rpx;
margin-left: 16rpx;
}
.importance-high {
color: #ff5722;
}
.importance-medium {
color: #ff9800;
}
.importance-low {
color: #999;
}
.switch-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
}
.textarea {
background-color: #f5f5f5;
border-radius: 8rpx;
padding: 24rpx;
font-size: 28rpx;
min-height: 160rpx;
}
.buttons {
display: flex;
gap: 24rpx;
margin-top: 40rpx;
}
.btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
border-radius: 16rpx;
font-size: 32rpx;
border: none;
}
.btn-cancel {
background-color: #f5f5f5;
color: #666;
}
.btn-submit {
background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
color: #fff;
}
.btn-cancel::after,
.btn-submit::after {
border: none;
}