/** * 宠物体重管理工具类 * 负责体重数据的存储、分析和AI建议生成 */ class WeightManager { constructor() { this.storageKey = 'pet_weight_records' } /** * 获取宠物的体重记录 * @param {string} petId 宠物ID * @returns {Array} 体重记录数组 */ getWeightRecords(petId) { try { const allRecords = uni.getStorageSync(this.storageKey) || {} let records = allRecords[petId] || [] // 如果没有数据,初始化一些测试数据 if (records.length === 0) { records = this.initializeTestData(petId) allRecords[petId] = records uni.setStorageSync(this.storageKey, allRecords) } return records } catch (error) { console.error('获取体重记录失败:', error) return this.initializeTestData(petId) } } /** * 初始化测试数据 * @param {string} petId 宠物ID * @returns {Array} 测试数据数组 */ initializeTestData(petId) { const now = new Date() const testData = [] // 生成过去3个月的体重数据,模拟真实的体重变化 const baseWeight = 3.8 // 基础体重 const growthRate = 0.015 // 每周增长率 for (let i = 90; i >= 0; i -= 3) { // 每3天一个记录点 const date = new Date(now.getTime() - i * 24 * 60 * 60 * 1000) const weeksPassed = (90 - i) / 7 // 模拟自然的体重增长,加入一些随机波动 let weight = baseWeight + (weeksPassed * growthRate * baseWeight) weight += (Math.random() - 0.5) * 0.1 // 添加±0.05kg的随机波动 weight = Math.round(weight * 10) / 10 // 保留一位小数 testData.push({ id: Date.now() + i, weight: weight, date: date.toISOString(), note: i === 0 ? '最新记录' : '自动生成', timestamp: date.getTime() }) } return testData } /** * 添加体重记录 * @param {string} petId 宠物ID * @param {Object} record 体重记录 */ addWeightRecord(petId, record) { try { const allRecords = uni.getStorageSync(this.storageKey) || {} if (!allRecords[petId]) { allRecords[petId] = [] } const newRecord = { id: Date.now(), weight: record.weight, date: record.date || new Date().toISOString(), note: record.note || '', timestamp: Date.now() } allRecords[petId].push(newRecord) allRecords[petId].sort((a, b) => new Date(a.date) - new Date(b.date)) uni.setStorageSync(this.storageKey, allRecords) return newRecord } catch (error) { console.error('添加体重记录失败:', error) return null } } /** * 获取当前体重 * @param {string} petId 宠物ID * @returns {number} 当前体重 */ getCurrentWeight(petId) { const records = this.getWeightRecords(petId) if (records.length === 0) return 0 return records[records.length - 1].weight } /** * 计算体重变化 * @param {string} petId 宠物ID * @param {number} days 对比天数 * @returns {Object} 变化数据 */ calculateWeightChange(petId, days) { const records = this.getWeightRecords(petId) if (records.length < 2) { return { change: 0, percent: 0, trend: 'stable' } } const now = new Date() const compareDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000) const currentWeight = this.getCurrentWeight(petId) const compareRecord = records.find(record => new Date(record.date) >= compareDate ) || records[0] const change = currentWeight - compareRecord.weight const percent = compareRecord.weight > 0 ? (change / compareRecord.weight) * 100 : 0 let trend = 'stable' if (Math.abs(percent) > 1) { trend = change > 0 ? 'increase' : 'decrease' } return { change: Number(change.toFixed(1)), percent: Number(percent.toFixed(1)), trend: trend, previousWeight: compareRecord.weight } } /** * 生成图表数据 * @param {string} petId 宠物ID * @param {string} timeRange 时间范围 * @returns {Object} 图表数据 */ generateChartData(petId, timeRange) { const records = this.getWeightRecords(petId) if (records.length === 0) { return { categories: [], series: [{ name: "体重", data: [] }] } } let filteredRecords = [] const now = new Date() switch (timeRange) { case 'week': const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000) filteredRecords = records.filter(record => new Date(record.date) >= weekAgo) break case 'month': const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000) filteredRecords = records.filter(record => new Date(record.date) >= monthAgo) break case 'year': const yearAgo = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000) filteredRecords = records.filter(record => new Date(record.date) >= yearAgo) break default: filteredRecords = records } // 如果数据点太少,补充一些模拟数据 if (filteredRecords.length === 0) { filteredRecords = this.generateMockData(timeRange) } const categories = filteredRecords.map(record => { const date = new Date(record.date) if (timeRange === 'year' || timeRange === 'all') { return `${date.getMonth() + 1}月` } else { return `${date.getMonth() + 1}/${date.getDate()}` } }) const data = filteredRecords.map(record => record.weight) return { categories: categories, series: [{ name: "体重", data: data }] } } /** * 生成模拟数据(用于演示) * @param {string} timeRange 时间范围 * @returns {Array} 模拟数据 */ generateMockData(timeRange) { const now = new Date() const mockData = [] const currentWeight = 4.2 switch (timeRange) { case 'week': // 近一周数据:每天一个点 for (let i = 6; i >= 0; i--) { const date = new Date(now.getTime() - i * 24 * 60 * 60 * 1000) const weight = currentWeight - (i * 0.02) + (Math.random() - 0.5) * 0.05 mockData.push({ weight: Math.round(weight * 10) / 10, date: date.toISOString() }) } break case 'month': // 近一月数据:每周一个点 for (let i = 4; i >= 0; i--) { const date = new Date(now.getTime() - i * 7 * 24 * 60 * 60 * 1000) const weight = currentWeight - (i * 0.08) + (Math.random() - 0.5) * 0.1 mockData.push({ weight: Math.round(weight * 10) / 10, date: date.toISOString() }) } break case 'year': // 近一年数据:每两个月一个点 for (let i = 5; i >= 0; i--) { const date = new Date(now.getTime() - i * 60 * 24 * 60 * 60 * 1000) const weight = currentWeight - (i * 0.2) + (Math.random() - 0.5) * 0.15 mockData.push({ weight: Math.round(weight * 10) / 10, date: date.toISOString() }) } break default: // 全部历史:从小猫到现在 const milestones = [ { months: 18, weight: 1.2 }, { months: 15, weight: 1.8 }, { months: 12, weight: 2.5 }, { months: 9, weight: 3.0 }, { months: 6, weight: 3.4 }, { months: 3, weight: 3.8 }, { months: 0, weight: 4.2 } ] milestones.forEach(milestone => { const date = new Date(now.getTime() - milestone.months * 30 * 24 * 60 * 60 * 1000) mockData.push({ weight: milestone.weight, date: date.toISOString() }) }) } return mockData.sort((a, b) => new Date(a.date) - new Date(b.date)) } /** * 生成AI健康分析 * @param {string} petId 宠物ID * @param {Object} petInfo 宠物信息 * @returns {Object} AI分析结果 */ generateAIAnalysis(petId, petInfo) { const currentWeight = this.getCurrentWeight(petId) const weeklyChange = this.calculateWeightChange(petId, 7) const monthlyChange = this.calculateWeightChange(petId, 30) // 根据品种、年龄、性别判断健康范围 const healthRange = this.getHealthyWeightRange(petInfo) const isHealthy = currentWeight >= healthRange.min && currentWeight <= healthRange.max // 健康评估 let healthAssessment = '' if (isHealthy) { healthAssessment = `根据${petInfo.name}的品种(${petInfo.breed})、年龄(${petInfo.age}岁)和性别(${petInfo.gender}),当前体重${currentWeight}kg处于健康范围内(${healthRange.min}-${healthRange.max}kg)。` } else if (currentWeight < healthRange.min) { healthAssessment = `当前体重${currentWeight}kg低于健康范围(${healthRange.min}-${healthRange.max}kg),建议增加营养摄入。` } else { healthAssessment = `当前体重${currentWeight}kg超出健康范围(${healthRange.min}-${healthRange.max}kg),建议控制饮食并增加运动。` } // 趋势分析 let trendAnalysis = '' if (weeklyChange.trend === 'stable') { trendAnalysis = '近期体重保持稳定,这是一个良好的状态。' } else if (weeklyChange.trend === 'increase') { if (weeklyChange.percent > 5) { trendAnalysis = `近期体重上升较快(${weeklyChange.percent}%),需要关注饮食控制。` } else { trendAnalysis = `近期体重呈适度上升趋势(${weeklyChange.percent}%),增长速度适中。` } } else { if (weeklyChange.percent < -5) { trendAnalysis = `近期体重下降较快(${weeklyChange.percent}%),建议检查健康状况。` } else { trendAnalysis = `近期体重呈下降趋势(${weeklyChange.percent}%),请注意营养补充。` } } // 建议 let recommendations = this.generateRecommendations(currentWeight, healthRange, weeklyChange) // 医疗建议 let medicalAdvice = '' if (Math.abs(weeklyChange.percent) > 10 || !isHealthy) { medicalAdvice = '建议咨询兽医,进行专业的健康检查和营养指导。' } return { healthAssessment, trendAnalysis, recommendations, medicalAdvice } } /** * 获取健康体重范围 * @param {Object} petInfo 宠物信息 * @returns {Object} 健康体重范围 */ getHealthyWeightRange(petInfo) { // 简化的品种体重范围映射 const breedRanges = { '橘猫': { min: 3.5, max: 5.5 }, '英短': { min: 3.0, max: 5.0 }, '美短': { min: 3.5, max: 5.5 }, '布偶': { min: 4.0, max: 7.0 }, '波斯': { min: 3.0, max: 5.5 }, '暹罗': { min: 2.5, max: 4.5 } } const baseRange = breedRanges[petInfo.breed] || { min: 3.0, max: 6.0 } // 根据性别调整(公猫通常比母猫重一些) if (petInfo.gender === '公') { baseRange.min += 0.5 baseRange.max += 0.5 } return baseRange } /** * 生成个性化建议 * @param {number} currentWeight 当前体重 * @param {Object} healthRange 健康范围 * @param {Object} weeklyChange 周变化 * @returns {string} 建议内容 */ generateRecommendations(currentWeight, healthRange, weeklyChange) { let recommendations = [] if (currentWeight < healthRange.min) { recommendations.push('增加高质量蛋白质摄入,如优质猫粮、煮熟的鸡胸肉') recommendations.push('少量多餐,每日3-4次定时喂食') recommendations.push('确保充足的饮水') } else if (currentWeight > healthRange.max) { recommendations.push('控制食物分量,减少高热量零食') recommendations.push('增加运动量,每日逗猫棒游戏20-30分钟') recommendations.push('选择低脂肪、高纤维的减肥猫粮') } else { recommendations.push('保持当前的饮食习惯,每日定时定量喂食') recommendations.push('适量运动,如逗猫棒游戏15-20分钟') recommendations.push('定期监测体重变化') } if (weeklyChange.trend === 'increase' && weeklyChange.percent > 3) { recommendations.push('近期体重增长较快,建议减少零食摄入') } else if (weeklyChange.trend === 'decrease' && weeklyChange.percent < -3) { recommendations.push('近期体重下降,注意观察食欲和精神状态') } return recommendations.join(';') + '。' } } export default new WeightManager()