import type { IHealthRecord, IRecordMeta } from '@/types/record' const MONTH_KEEP = 12 function getMonthKey(timestamp: number) { const d = new Date(timestamp) return `health_${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}` } export function getDateStr(timestamp: number) { const d = new Date(timestamp) return d.toISOString().slice(0, 10) } export function getMonthStr(timestamp: number): string { const d = new Date(timestamp) const y = d.getFullYear() const m = String(d.getMonth() + 1).padStart(2, '0') return `${y}-${m}` } export function getTimeStr(timestamp: number) { const d = new Date(timestamp) return d.toTimeString().slice(0, 5) } function cleanOldMonths() { const cutoff = new Date() cutoff.setMonth(cutoff.getMonth() - MONTH_KEEP) const cutoffKey = `health_${cutoff.getFullYear()}-${String(cutoff.getMonth() + 1).padStart(2, '0')}` const keys = wx.getStorageInfoSync().keys keys.forEach((key) => { if (key.startsWith('health_') && key < cutoffKey) { wx.removeStorageSync(key) } }) } function addRecord(type: string, data: Record, timestamp: number) { const key = getMonthKey(timestamp) const all = wx.getStorageSync(key) || {} const date = getDateStr(timestamp) if (!all[date]) all[date] = [] all[date].push({ id: Date.now() + Math.random().toString(36).slice(2, 6), time: getTimeStr(timestamp), type, ...data, }) wx.setStorageSync(key, all) } export function addWeight(value: number, note: string, timestamp: number) { addRecord('weight', { value, note }, timestamp) } export function addSleep(startTime: number, endTime: number, duration: number, note: string, timestamp: number) { addRecord('sleep', { startTime, endTime, duration, note }, timestamp) } export function addSport(category: string, duration: number, note: string, timestamp: number) { addRecord('sport', { category, duration, note }, timestamp) } export function addBloodPressure(systolic: number, diastolic: number, heartRate: number, note: string, timestamp: number) { addRecord('bloodPressure', { systolic, diastolic, heartRate, note }, timestamp) } export function addBloodSugar(value: number, period: string, note: string, timestamp: number) { addRecord('bloodSugar', { value, period, note }, timestamp) } export function addTemperature(value: number, location: string, note: string, timestamp: number) { addRecord('temperature', { value, location, note }, timestamp) } function getAllMonthKeys(): string[] { return wx.getStorageInfoSync().keys.filter(k => k.startsWith('health_')).sort() } // ─── 根据时间戳反推它属于哪个月的 key ─── function getMonthKeyForTimestamp(timestamp: number): string { const d = new Date(timestamp) return `health_${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}` } // ─── 根据 "YYYY-MM-DD" 反推月份 key ─── function getMonthKeyForDate(dateStr: string): string { const [y, m] = dateStr.split('-') return `health_${y}-${m}` } export function getDayRecords(date: string): IHealthRecord[] { const key = getMonthKeyForDate(date) const all = wx.getStorageSync(key) || {} const dayRecords = all[date] || [] return [...dayRecords].sort((a, b) => a.time.localeCompare(b.time)) } export function getMonthRecords(yearMonth: string, type?: string): IHealthRecord[] { const key = `health_${yearMonth}` const all = wx.getStorageSync(key) || {} const result: IHealthRecord[] = [] Object.keys(all).forEach((date) => { all[date].forEach((r: IHealthRecord) => { if (!type || r.type === type) { result.push({ date, ...r }) } }) }) return sortRecords(result) } // 排序:先按 date 正序,再按 time 正序 function sortRecords(records: IHealthRecord[]): IHealthRecord[] { return records.sort((a, b) => { const dateCmp = a.date.localeCompare(b.date) if (dateCmp !== 0) return dateCmp return a.time.localeCompare(b.time) }) } const META_MAP: Record = { weight: { icon: '⚖️', label: '体重', color: 'bg-[#E89E3A]' }, sleep: { icon: '😴', label: '睡眠', color: 'bg-[#2E5B8C]' }, bloodPressure: { icon: '❤️', label: '血压', color: 'bg-[#C04A3C]' }, bloodSugar: { icon: '📈', label: '血糖', color: 'bg-[#9C27B0]' }, sport: { icon: '🏃', label: '运动', color: 'bg-[#3A7C5B]' }, temperature: { icon: '🌡️', label: '体温', color: 'bg-[#D32F2F]' }, } export function getRecordMeta(type: string): IRecordMeta { return META_MAP[type] || { icon: '📋', label: '其他', color: 'bg-gray-400' } } export function getRecordValue(record: IHealthRecord): string { switch (record.type) { case 'weight': return `${record.value} kg` case 'bloodPressure': return `${record.systolic}/${record.diastolic} mmHg${record.heartRate ? ` · 心率 ${record.heartRate}` : ''}` case 'bloodSugar': return `${record.value} mmol/L · ${record.period}` case 'heartRate': return `${record.value} bpm` case 'temperature': return `${record.value} ℃${record.location ? ` · ${record.location}` : ''}` case 'sport': return `${record.category} · ${record.duration}min` case 'sleep': return `${new Date(record.startTime).toTimeString().slice(0, 5)} ~ ${new Date(record.endTime).toTimeString().slice(0, 5)}(${record.duration}h)` default: return '' } } export function getRecordStatus(record: IHealthRecord): string { switch (record.type) { case 'bloodPressure': if (record.systolic >= 140 || record.diastolic >= 90) return '偏高' if (record.systolic < 90 || record.diastolic < 60) return '偏低' return '正常' case 'bloodSugar': if (record.period.includes('空腹')) { return record.value >= 6.1 ? '偏高' : '正常' } // 餐后 return record.value >= 7.8 ? '偏高' : '正常' case 'heartRate': if (record.value < 60) return '偏慢' if (record.value <= 100) return '正常' return '偏快' case 'temperature': if (record.value < 36.1) return '偏低' if (record.value <= 37.2) return '正常' return '偏高' case 'sport': return record.duration >= 30 ? '达标' : '偏少' case 'sleep': if (record.duration >= 7) return '充足' if (record.duration >= 6) return '良好' return '不足' default: return '未知' } } const WEEKDAY = ['日', '一', '二', '三', '四', '五', '六'] export function groupByDate(records: IHealthRecord[]): Array<{ date: string weekday: string items: IHealthRecord[] }> { const map: Record = {} records.forEach((r) => { if (!r.date) return if (!map[r.date]) map[r.date] = [] map[r.date].push(r) }) return Object.keys(map) .sort((a, b) => b.localeCompare(a)) // 日期倒序,最新的在上 .map(date => ({ date, weekday: WEEKDAY[new Date(date).getDay()], items: map[date].sort((a, b) => a.time.localeCompare(b.time)), // 当天按时间正序 })) }