const store = require('../../utils/store.js'); const api = require('../../utils/api.js'); // "2026-07-04" → "7月4日" function fmtMD(date) { if (!date) return ''; const p = date.split('-'); if (p.length < 3) return ''; return +p[1] + '月' + +p[2] + '日'; } function pad2(n) { return n < 10 ? '0' + n : '' + n; } function buildCells(year, month, taskedDays, today) { const first = new Date(year, month - 1, 1); const lead = (first.getDay() + 6) % 7; // 周一为一周起点 const daysInMonth = new Date(year, month, 0).getDate(); const set = {}; (taskedDays || []).forEach((d) => (set[d] = true)); const cells = []; for (let i = 0; i < lead; i++) cells.push({ day: 0 }); for (let d = 1; d <= daysInMonth; d++) { cells.push({ day: d, date: year + '-' + pad2(month) + '-' + pad2(d), tasked: !!set[d], today: d === today }); } return cells; } Page({ data: { pet: {}, planView: 'timeline', plan: null, calCells: [], calLabel: '', calLoaded: false, selectedCalDate: '', dayDetail: null, aiInput: '', aiPlan: null, aiBusy: false, sheetShow: false, sheetType: '', }, onLoad() { this._unsub = store.subscribe((pet) => { this.setData({ pet, calLoaded: false }); this.loadTimeline(); if (this.data.planView === 'calendar') this.loadCalendar(); }); }, onUnload() { if (this._unsub) this._unsub(); }, onShow() { if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: 1 }); } store .ready() .then(() => { this.setData({ pet: store.getPet() }); this.loadTimeline(); }) .catch((e) => wx.showToast({ title: e.message || '加载失败', icon: 'none' })); }, loadTimeline() { const id = store.currentPetId(); if (!id) return; api .getPlan(id) .then((plan) => { if (plan && plan.tasks) { plan.tasks = plan.tasks.map((t) => ({ ...t, dateLabel: fmtMD(t.date) })); } this.setData({ plan }); }) .catch(() => this.setData({ plan: null })); }, loadCalendar() { const id = store.currentPetId(); if (!id) return; api .planCalendar(id) .then((res) => { this.setData({ calCells: buildCells(res.year, res.month, res.tasked_days, res.today), calLabel: `${res.year} 年 ${res.month} 月`, calLoaded: true, }); if (res.today) { this.selectCalDay(res.year + '-' + pad2(res.month) + '-' + pad2(res.today)); } }) .catch(() => {}); }, onTapCalDay(e) { const date = e.currentTarget.dataset.date; if (date) this.selectCalDay(date); }, selectCalDay(date) { const id = store.currentPetId(); if (!id) return; this.setData({ selectedCalDate: date }); api .dayPlan(id, date) .then((res) => { const nodes = (res.plan_nodes || []).map((n) => ({ title: n.title, desc: n.description, done: n.done })); const tasks = (res.tasks || []).map((t) => ({ title: t.title, desc: t.description, done: t.done })); const reminders = (res.reminders || []).map((r) => ({ title: r.title })); this.setData({ dayDetail: { date, nodes, tasks, reminders, empty: !nodes.length && !tasks.length && !reminders.length }, }); }) .catch(() => {}); }, switchPlanView(e) { const view = e.currentTarget.dataset.view; this.setData({ planView: view }); if (view === 'calendar' && !this.data.calLoaded) this.loadCalendar(); }, // 计划明细勾选 toggleTimelineTask(e) { const id = e.currentTarget.dataset.id; api.togglePlanTask(id).then(() => this.loadTimeline()).catch(() => {}); }, // AI 计划 onAiInput(e) { this.setData({ aiInput: e.detail.value }); }, genAIPlan() { const id = store.currentPetId(); const input = (this.data.aiInput || '').trim(); if (!id || !input) { wx.showToast({ title: '先描述一下情况', icon: 'none' }); return; } this.setData({ aiBusy: true }); wx.showLoading({ title: 'AI 生成中...' }); api .createAIPlan(id, input) .then((plan) => { wx.hideLoading(); this.setData({ aiPlan: plan, aiBusy: false }); }) .catch((err) => { wx.hideLoading(); this.setData({ aiBusy: false }); wx.showToast({ title: err.message || '生成失败', icon: 'none' }); }); }, applyAIPlan() { const p = this.data.aiPlan; if (!p) return; api .applyAIPlan(p.id) .then(() => wx.showToast({ title: '已加入我的计划', icon: 'success' })) .catch((err) => wx.showToast({ title: err.message || '加入失败', icon: 'none' })); }, openSheet(e) { const type = e.currentTarget.dataset.type; if (!type) return; // 无关联动作的计划项只可勾选,不弹层 this.setData({ sheetType: type, sheetShow: true }); }, closeSheet() { this.setData({ sheetShow: false }); }, onAddPet() { this.setData({ sheetType: 'addPet', sheetShow: true }); }, onFab() { this.setData({ sheetType: 'ai', sheetShow: true }); }, onShareAppMessage() { return { title: '我给毛孩子做了份养护计划', path: '/pages/plan/plan' }; }, onShareTimeline() { return { title: '我给毛孩子做了份养护计划' }; }, });