pet/pages/pets/pet-weight.vue

672 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="weight-container">
<!-- 当前体重状态卡片 -->
<view class="current-weight-card">
<view class="weight-header">
<text class="pet-name">{{ petName }}的体重管理</text>
<text class="last-update">最后更新{{ lastUpdateTime }}</text>
</view>
<view class="weight-display">
<view class="current-weight">
<text class="weight-value">{{ currentWeight }}</text>
<text class="weight-unit">kg</text>
</view>
<view class="weight-status" :class="weightStatusClass">
<text class="status-text">{{ weightStatusText }}</text>
</view>
</view>
</view>
<!-- 体重对比仪表盘 -->
<view class="comparison-dashboard">
<view class="dashboard-header">
<text class="dashboard-title">📊 体重变化对比</text>
</view>
<view class="comparison-grid">
<view class="comparison-item">
<view class="comparison-icon">📈</view>
<view class="comparison-content">
<text class="comparison-label">较上周</text>
<text class="comparison-value" :class="weeklyChangeClass">
{{ weeklyChange }}
</text>
<text class="comparison-percent" :class="weeklyChangeClass">
{{ weeklyPercent }}
</text>
</view>
</view>
<view class="comparison-item">
<view class="comparison-icon">📊</view>
<view class="comparison-content">
<text class="comparison-label">较上月</text>
<text class="comparison-value" :class="monthlyChangeClass">
{{ monthlyChange }}
</text>
<text class="comparison-percent" :class="monthlyChangeClass">
{{ monthlyPercent }}
</text>
</view>
</view>
</view>
</view>
<!-- 时间维度切换 -->
<view class="time-selector">
<view class="selector-header">
<text class="selector-title">📅 时间范围</text>
</view>
<view class="time-tabs">
<view
class="time-tab"
:class="{ active: activeTab === tab.key }"
v-for="tab in timeTabs"
:key="tab.key"
@click="switchTimeRange(tab.key)"
>
<text class="tab-text">{{ tab.label }}</text>
</view>
</view>
</view>
<!-- 体重变化图表 -->
<view class="chart-container">
<view class="chart-header">
<text class="chart-title">📈 {{ currentTimeRange }}体重趋势</text>
</view>
<qiun-data-charts
type="line"
:opts="chartOpts"
:chartData="chartData"
:canvas2d="true"
:canvasId="'weightChart'"
:canvas-id="'weightChart'"
/>
</view>
<!-- AI分析卡片 -->
<view class="ai-analysis-card">
<view class="analysis-header">
<text class="analysis-title">🤖 AI健康分析</text>
<view class="analysis-badge">
<text class="badge-text">智能分析</text>
</view>
</view>
<view class="analysis-content">
<view class="analysis-section">
<text class="section-title">📋 健康评估</text>
<text class="section-content">{{ healthAssessment }}</text>
</view>
<view class="analysis-section">
<text class="section-title">📈 趋势分析</text>
<text class="section-content">{{ trendAnalysis }}</text>
</view>
<view class="analysis-section">
<text class="section-title">💡 建议</text>
<text class="section-content">{{ recommendations }}</text>
</view>
<view class="analysis-section" v-if="medicalAdvice">
<text class="section-title">⚠️ 医疗建议</text>
<text class="section-content warning">{{ medicalAdvice }}</text>
</view>
</view>
</view>
<!-- 添加体重记录按钮 -->
<view class="add-weight-btn" @click="addWeightRecord">
<text class="add-btn-text">+ 添加体重记录</text>
</view>
</view>
</template>
<script>
import weightManager from '@/utils/weightManager.js'
export default {
data() {
return {
petId: '',
petName: '',
petInfo: {},
currentWeight: '4.2',
lastUpdateTime: '2024-01-20 14:30',
weightStatusText: '健康范围',
weightStatusClass: 'healthy',
// 体重变化数据
weeklyChange: '+0.1kg',
weeklyPercent: '+2.4%',
weeklyChangeClass: 'increase',
monthlyChange: '+0.3kg',
monthlyPercent: '+7.1%',
monthlyChangeClass: 'increase',
// 时间维度选项
activeTab: 'week',
timeTabs: [
{ key: 'week', label: '近一周' },
{ key: 'month', label: '近一月' },
{ key: 'year', label: '近一年' },
{ key: 'all', label: '全部历史' }
],
currentTimeRange: '近一周',
// 图表配置
chartOpts: {
color: ["#FF8A80", "#64B5F6"],
padding: [15, 15, 0, 15],
enableScroll: false,
legend: {
show: false
},
xAxis: {
disableGrid: true,
fontSize: 10,
fontColor: "#666666"
},
yAxis: {
gridType: "dash",
dashLength: 2,
fontSize: 10,
fontColor: "#666666"
},
extra: {
line: {
type: "curve",
width: 2,
activeType: "hollow"
}
}
},
// 图表数据
chartData: {},
// AI分析内容
healthAssessment: '根据小橘的品种橘猫、年龄2岁和性别当前体重4.2kg处于健康范围内。成年橘猫的理想体重通常在3.5-5.5kg之间。',
trendAnalysis: '近期体重呈稳定上升趋势,增长速度适中。这种增长模式符合健康成长规律,无需过度担心。',
recommendations: '建议保持当前的饮食习惯每日定时定量喂食。增加适量运动如逗猫棒游戏15-20分钟。定期监测体重变化。',
medicalAdvice: ''
}
},
onLoad(options) {
this.petId = options.petId || ''
this.petName = options.petName || '宠物'
this.loadPetInfo()
this.initializeTestDataIfNeeded()
this.loadWeightData()
this.generateChartData()
},
methods: {
loadPetInfo() {
try {
const pets = uni.getStorageSync('pets') || []
this.petInfo = pets.find(pet => pet.id == this.petId) || {
id: this.petId,
name: this.petName,
breed: '橘猫',
age: 2,
gender: '公'
}
} catch (error) {
console.error('加载宠物信息失败:', error)
}
},
initializeTestDataIfNeeded() {
// 检查是否已有体重数据,如果没有则初始化测试数据
const records = weightManager.getWeightRecords(this.petId)
console.log(`宠物 ${this.petId} 的体重记录数量:`, records.length)
},
loadWeightData() {
// 获取当前体重
this.currentWeight = weightManager.getCurrentWeight(this.petId) || 4.2
// 计算体重变化
const weeklyChange = weightManager.calculateWeightChange(this.petId, 7)
const monthlyChange = weightManager.calculateWeightChange(this.petId, 30)
// 更新周变化数据
this.weeklyChange = weeklyChange.change >= 0 ? `+${weeklyChange.change}kg` : `${weeklyChange.change}kg`
this.weeklyPercent = weeklyChange.percent >= 0 ? `+${weeklyChange.percent}%` : `${weeklyChange.percent}%`
this.weeklyChangeClass = weeklyChange.trend
// 更新月变化数据
this.monthlyChange = monthlyChange.change >= 0 ? `+${monthlyChange.change}kg` : `${monthlyChange.change}kg`
this.monthlyPercent = monthlyChange.percent >= 0 ? `+${monthlyChange.percent}%` : `${monthlyChange.percent}%`
this.monthlyChangeClass = monthlyChange.trend
// 判断健康状态
const healthRange = weightManager.getHealthyWeightRange(this.petInfo)
if (this.currentWeight >= healthRange.min && this.currentWeight <= healthRange.max) {
this.weightStatusText = '健康范围'
this.weightStatusClass = 'healthy'
} else if (this.currentWeight < healthRange.min) {
this.weightStatusText = '偏轻'
this.weightStatusClass = 'warning'
} else {
this.weightStatusText = '偏重'
this.weightStatusClass = 'warning'
}
// 生成AI分析
const aiAnalysis = weightManager.generateAIAnalysis(this.petId, this.petInfo)
this.healthAssessment = aiAnalysis.healthAssessment
this.trendAnalysis = aiAnalysis.trendAnalysis
this.recommendations = aiAnalysis.recommendations
this.medicalAdvice = aiAnalysis.medicalAdvice
// 更新最后更新时间
const records = weightManager.getWeightRecords(this.petId)
if (records.length > 0) {
const lastRecord = records[records.length - 1]
const lastDate = new Date(lastRecord.date)
this.lastUpdateTime = `${lastDate.getMonth() + 1}-${lastDate.getDate()} ${lastDate.getHours()}:${lastDate.getMinutes().toString().padStart(2, '0')}`
}
},
switchTimeRange(timeKey) {
this.activeTab = timeKey
const timeMap = {
'week': '近一周',
'month': '近一月',
'year': '近一年',
'all': '全部历史'
}
this.currentTimeRange = timeMap[timeKey]
this.generateChartData()
},
generateChartData() {
// 使用 weightManager 生成图表数据
this.chartData = weightManager.generateChartData(this.petId, this.activeTab)
},
addWeightRecord() {
uni.showModal({
title: '添加体重记录',
editable: true,
placeholderText: '请输入体重(kg)',
success: (res) => {
if (res.confirm && res.content) {
const weight = parseFloat(res.content)
if (weight && weight > 0 && weight < 20) {
const record = weightManager.addWeightRecord(this.petId, {
weight: weight,
date: new Date().toISOString(),
note: '手动添加'
})
if (record) {
uni.showToast({
title: '添加成功',
icon: 'success'
})
// 重新加载数据
this.loadWeightData()
this.generateChartData()
} else {
uni.showToast({
title: '添加失败',
icon: 'error'
})
}
} else {
uni.showToast({
title: '请输入有效的体重值',
icon: 'error'
})
}
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.weight-container {
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
min-height: 100vh;
padding: 20rpx;
}
/* 当前体重状态卡片 */
.current-weight-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.weight-header {
text-align: center;
margin-bottom: 32rpx;
.pet-name {
font-size: 32rpx;
font-weight: bold;
color: #333333;
display: block;
margin-bottom: 8rpx;
}
.last-update {
font-size: 22rpx;
color: #999999;
display: block;
}
}
.weight-display {
text-align: center;
.current-weight {
margin-bottom: 20rpx;
.weight-value {
font-size: 72rpx;
font-weight: bold;
color: #FF8A80;
}
.weight-unit {
font-size: 32rpx;
color: #666666;
margin-left: 8rpx;
}
}
.weight-status {
padding: 12rpx 24rpx;
border-radius: 20rpx;
display: inline-block;
&.healthy {
background: #E8F5E8;
color: #4CAF50;
}
&.warning {
background: #FFF3E0;
color: #FF9800;
}
&.danger {
background: #FFEBEE;
color: #F44336;
}
.status-text {
font-size: 24rpx;
font-weight: 500;
}
}
}
}
/* 体重对比仪表盘 */
.comparison-dashboard {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.dashboard-header {
margin-bottom: 28rpx;
.dashboard-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.comparison-grid {
display: flex;
gap: 20rpx;
.comparison-item {
flex: 1;
background: rgba(255, 138, 128, 0.05);
border-radius: 20rpx;
padding: 24rpx;
display: flex;
align-items: center;
gap: 16rpx;
.comparison-icon {
font-size: 32rpx;
width: 48rpx;
text-align: center;
}
.comparison-content {
flex: 1;
.comparison-label {
font-size: 22rpx;
color: #999999;
display: block;
margin-bottom: 8rpx;
}
.comparison-value {
font-size: 28rpx;
font-weight: bold;
display: block;
margin-bottom: 4rpx;
&.increase {
color: #FF8A80;
}
&.decrease {
color: #4CAF50;
}
&.stable {
color: #666666;
}
}
.comparison-percent {
font-size: 20rpx;
display: block;
&.increase {
color: #FF8A80;
}
&.decrease {
color: #4CAF50;
}
&.stable {
color: #666666;
}
}
}
}
}
}
/* 时间维度切换 */
.time-selector {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.selector-header {
margin-bottom: 28rpx;
.selector-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.time-tabs {
display: flex;
gap: 12rpx;
.time-tab {
flex: 1;
text-align: center;
padding: 16rpx 12rpx;
border-radius: 16rpx;
background: rgba(255, 138, 128, 0.1);
transition: all 0.3s ease;
&.active {
background: #FF8A80;
.tab-text {
color: white;
}
}
&:active {
transform: scale(0.95);
}
.tab-text {
font-size: 24rpx;
font-weight: 500;
color: #666666;
}
}
}
}
/* 图表容器 */
.chart-container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.chart-header {
margin-bottom: 28rpx;
.chart-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
}
/* AI分析卡片 */
.ai-analysis-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.analysis-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 28rpx;
.analysis-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
.analysis-badge {
background: linear-gradient(135deg, #64B5F6, #81C784);
border-radius: 20rpx;
padding: 8rpx 16rpx;
.badge-text {
font-size: 20rpx;
color: white;
font-weight: 500;
}
}
}
.analysis-content {
.analysis-section {
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
.section-title {
font-size: 26rpx;
font-weight: bold;
color: #333333;
margin-bottom: 12rpx;
display: block;
}
.section-content {
font-size: 24rpx;
color: #666666;
line-height: 1.6;
display: block;
&.warning {
color: #FF9800;
background: #FFF3E0;
padding: 16rpx;
border-radius: 12rpx;
}
}
}
}
}
/* 添加体重记录按钮 */
.add-weight-btn {
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
border-radius: 28rpx;
padding: 24rpx;
text-align: center;
margin-bottom: 40rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.3);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
}
.add-btn-text {
font-size: 32rpx;
font-weight: bold;
color: white;
}
}
</style>