// add-anniversary.js const storage = require('../../utils/storage') const dateUtils = require('../../utils/date') const sync = require('../../utils/sync') const lunar = require('../../utils/lunar') Page({ data: { anniversaryId: null, personId: null, personList: [], inputName: '', typeList: ['生日', '结婚纪念日', '订婚纪念日', '其他纪念日'], typeIndex: 0, showCustomType: false, dateValue: '', remindDaysList: ['提前3天', '提前7天', '提前14天', '提前30天', '自定义'], remindDaysIndex: 0, // UI 反馈:选了农历日期时展示对应农历文本 + 闰月警示 lunarText: '', isLeapMonth: false, formData: { isLunar: false, type: 'birthday', customTypeName: '', solarYear: '', solarMonth: '', solarDay: '', lunarYear: '', lunarMonth: '', lunarDay: '', isLeapMonth: false, importance: 'low', remindEnabled: true, remindDays: 7, remark: '' } }, onLoad(options) { // 获取人员列表用于快捷选择 const persons = storage.getPersons() this.setData({ personList: persons }) if (options.personId) { // 从人员详情页进入,预选关联人员 const person = persons.find(p => p.id === options.personId) if (person) { this.setData({ personId: person.id, inputName: person.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) // 编辑时不允许改关联人员,姓名展示用 personName 或从 personList 查 const person = this.data.personList.find(p => p.id === anniversary.personId) this.setData({ formData: anniversary, dateValue: date, typeIndex, showCustomType: anniversary.type === 'other', personId: anniversary.personId, inputName: person ? person.name : (anniversary.personName || '') }) // 农历日期:编辑时也要回显 if (anniversary.isLunar) this._refreshLunar() wx.setNavigationBarTitle({ title: '编辑纪念日' }) } }, /** * 获取类型索引 * 注:lunar_birthday 是老数据兼容,新 UI 没有这一项,统一映射到「生日」(0) */ getTypeIndex(type) { const indexMap = { birthday: 0, lunar_birthday: 0, wedding: 1, engagement: 2, other: 3 } return indexMap[type] || 0 }, /** * 姓名输入:用户打字时实时更新;点 chip 时也会触发 * 输入框值变了就清掉已绑定的 personId,提交时再按姓名查找/创建 */ onNameInput(e) { const name = e.detail.value const matched = this.data.personList.find(p => p.name === name.trim()) this.setData({ inputName: name, personId: matched ? matched.id : null }) }, /** * 点已有人员快捷 chip */ onPickPerson(e) { const { id, name } = e.currentTarget.dataset this.setData({ personId: id, inputName: name }) }, /** * 选择类型 */ onTypeChange(e) { const index = parseInt(e.detail.value) const types = ['birthday', 'wedding', 'engagement', 'other'] const isOther = index === 3 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 }) this._refreshLunar() }, /** * 日期改变 */ 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]) }) this._refreshLunar() }, /** * 选了"农历"时,把当前公历日期反算成农历,写入 formData + 提示文案 * Why:闰月生日必须在 UI 上让用户确认这是不是他想要的农历日期 */ _refreshLunar() { const { formData } = this.data if (!formData.isLunar || !formData.solarYear || !formData.solarMonth || !formData.solarDay) { this.setData({ lunarText: '', isLeapMonth: false, 'formData.isLeapMonth': false }) return } const solarDate = new Date(formData.solarYear, formData.solarMonth - 1, formData.solarDay) const ld = lunar.solarToLunar(solarDate) this.setData({ lunarText: ld.lunarText, isLeapMonth: ld.isLeap, 'formData.lunarYear': ld.year, 'formData.lunarMonth': ld.month, 'formData.lunarDay': ld.day, 'formData.isLeapMonth': ld.isLeap }) }, /** * 重要程度改变 */ 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) this.setData({ remindDaysIndex: index }) if (index === 4) { // 自定义天数 wx.showModal({ title: '自定义提前天数', editable: true, placeholderText: '请输入天数(1-365)', success: (res) => { if (res.confirm) { const days = parseInt(res.content) if (!days || days < 1 || days > 365) { wx.showToast({ title: '请输入1-365之间的天数', icon: 'none' }) this.setData({ remindDaysIndex: 1, 'formData.remindDays': 7 }) return } this.setData({ 'formData.remindDays': days }) } else { // 取消则回到默认7天 this.setData({ remindDaysIndex: 1, 'formData.remindDays': 7 }) } } }) } else { const days = [3, 7, 14, 30][index] this.setData({ 'formData.remindDays': days }) } }, /** * 备注改变 */ onRemarkChange(e) { this.setData({ 'formData.remark': e.detail.value }) }, /** * 取消 */ onCancel() { wx.navigateBack() }, /** * 提交 */ async onSubmit() { const { formData, anniversaryId, inputName } = this.data let { personId } = this.data // 验证姓名 const name = (inputName || '').trim() if (!name) { 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 (formData.remindEnabled) { try { await this.requestSubscribe() } catch (err) { console.log('用户拒绝订阅消息') } } // 新增模式且没绑定 personId → 按姓名查找或自动创建 if (!anniversaryId && !personId) { const person = storage.ensurePerson(name) if (!person) { wx.showToast({ title: '保存失败', icon: 'none' }) return } personId = person.id } // 农历生日:兜底反算(onDateChange/_refreshLunar 通常已填好,这里防边界) if (formData.isLunar) { const solarDate = new Date(formData.solarYear, formData.solarMonth - 1, formData.solarDay) const lunarDate = lunar.solarToLunar(solarDate) formData.lunarYear = lunarDate.year formData.lunarMonth = lunarDate.month formData.lunarDay = lunarDate.day formData.isLeapMonth = lunarDate.isLeap } const personName = name if (anniversaryId) { // 编辑模式 const success = storage.updateAnniversary(anniversaryId, { personId, personName, ...formData }) if (success) { // 同步到云端 this.syncToCloud(anniversaryId, { personId, personName, ...formData }, 'update') wx.showToast({ title: '保存成功', icon: 'success' }) setTimeout(() => wx.navigateBack(), 1500) } } else { // 新增模式 const newAnniversary = storage.addAnniversary({ personId, personName, ...formData }) if (newAnniversary) { // 同步到云端 this.syncToCloud(newAnniversary.id, newAnniversary, 'add') wx.showToast({ title: '添加成功', icon: 'success' }) setTimeout(() => wx.navigateBack(), 1500) } } }, /** * 请求订阅消息授权 */ requestSubscribe() { return new Promise((resolve, reject) => { wx.requestSubscribeMessage({ tmplIds: ['6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw'], success: (res) => { console.log('订阅消息授权结果:', res) resolve(res) }, fail: (err) => { console.error('订阅消息授权失败:', err) reject(err) } }) }) }, /** * 同步纪念日到后端(失败自动入队,启动时 flush) */ syncToCloud(id, data, action) { const openid = wx.getStorageSync('openid') if (!openid) { console.log('未获取到openid,跳过云端同步') return } sync.syncOrEnqueue({ kind: 'anniversary', action, data: { id, ...data } }) } })