const store = require('../../utils/store.js'); const api = require('../../utils/api.js'); const recordTypes = require('../../utils/recordTypes.js'); const { toastErr } = require('../../utils/ui.js'); function pad2(n) { return n < 10 ? '0' + n : '' + n; } function today() { const d = new Date(); return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate()); } // 同 addrecord:后端用 time.Parse(time.RFC3339) 解 occurred_at,只给日期解不出来会 // 静默回退成 now;时区要带真实偏移,转 UTC 的 Z 形式落库会把边界日期挪一天 function dayToISO(day) { if (!day) return ''; const off = -new Date().getTimezoneOffset(); const sign = off >= 0 ? '+' : '-'; const a = Math.abs(off); return day + 'T12:00:00' + sign + pad2(Math.floor(a / 60)) + ':' + pad2(a % 60); } function fmtDay(iso) { if (!iso) return ''; const d = new Date(iso); return d.getMonth() + 1 + '月' + d.getDate() + '日'; } const PAGE = 50; Page({ data: { bill: {}, cats: [], cat: '', customOn: false, customCat: '', amount: '', date: '', note: '', list: [], saving: false, }, onLoad() { this.setData({ date: today() }); store .ready() .then(() => recordTypes.load()) .then(() => this.loadCats()) .catch((e) => toastErr(e)); }, onShow() { if (this._inited) this.reload(); this._inited = true; }, onReady() { this.reload(); }, // 类别预置读 record_types 里 cost 的字段配置——后台改一处, // 这页和 addrecord 同时生效,不会出现两套类别把账单统计切开 loadCats() { const t = recordTypes.get('cost'); const opt = ((t && t.fields) || []).find((f) => f.kind === 'options'); this.setData({ cats: (opt && opt.options) || [] }); }, reload() { const id = store.currentPetId(); if (!id) return; api .getBill(id, 'month') .then((bill) => this.setData({ bill: bill || {} })) .catch(() => {}); api .getRecords(id, { type: 'cost', page: 1, pageSize: PAGE }) .then((res) => { const now = new Date(); const list = (res.list || []) // 只显示本月:接口按时间倒序返回,这里前端切一刀, // 不为了「本月」再加一个后端参数 .filter((r) => { const d = new Date(r.occurred_at); return d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth(); }) .map((r) => ({ ...r, timeText: fmtDay(r.occurred_at) })); this.setData({ list }); }) .catch(() => {}); }, onAmount(e) { this.setData({ amount: e.detail.value }); }, onPickCat(e) { const v = e.currentTarget.dataset.val; this.setData({ cat: this.data.cat === v ? '' : v, customOn: false, customCat: '' }); }, toggleCustom() { const on = !this.data.customOn; this.setData({ customOn: on, cat: on ? '' : this.data.cat }); }, onCustomCat(e) { this.setData({ customCat: e.detail.value }); }, onDate(e) { this.setData({ date: e.detail.value }); }, onNote(e) { this.setData({ note: e.detail.value }); }, onSave() { if (this.data.saving) return; const id = store.currentPetId(); if (!id) return wx.showToast({ title: '先建一份宠物档案', icon: 'none' }); const amt = parseFloat(this.data.amount); if (!(amt > 0)) return wx.showToast({ title: '填一个金额', icon: 'none' }); const cat = (this.data.customOn ? this.data.customCat : this.data.cat).trim(); if (!cat) return wx.showToast({ title: '选一个类别', icon: 'none' }); this.setData({ saving: true }); // 落的是 type='cost' 的普通记录:金额进 num_value、类别进 category, // 和 addrecord 走同一条路,报告页的账单聚合照样认 api .createRecord(id, { type: 'cost', title: '记账:' + amt + '元 ' + cat, num_value: amt, category: cat, description: (this.data.note || '').trim(), occurred_at: dayToISO(this.data.date), }) .then(() => { this.setData({ saving: false, amount: '', note: '', customCat: '', customOn: false, cat: '' }); wx.showToast({ title: '已记下', icon: 'success' }); this.reload(); }) .catch((e) => { this.setData({ saving: false }); toastErr(e, '保存失败'); }); }, // 长按删除。流水里记错一笔很常见,不给删的话账单就一直是错的 onDelete(e) { const id = e.currentTarget.dataset.id; wx.showModal({ title: '删掉这笔?', content: '删了账单统计会跟着变。', confirmColor: '#EE7D73', success: (r) => { if (!r.confirm) return; api .deleteRecord(id) .then(() => this.reload()) .catch((err) => toastErr(err, '删除失败')); }, }); }, onShareAppMessage() { return { title: '养宠一个月花了多少?', path: '/pages/expense/expense' }; }, });