This commit is contained in:
2025-08-13 17:10:28 +08:00
parent af722a2bbc
commit 34a3f7bf1f
4 changed files with 1034 additions and 1 deletions
+26 -1
View File
@@ -40,9 +40,10 @@
<text class="stat-number">{{ petInfo.companionDays || 0 }}</text>
<text class="stat-label">陪伴天数</text>
</view>
<view class="stat-item">
<view class="stat-item clickable" @click="goToWeightManagement">
<text class="stat-number">{{ petInfo.weight || '4.2kg' }}</text>
<text class="stat-label">当前体重</text>
<text class="stat-arrow">›</text>
</view>
<view class="stat-item">
<text class="stat-number">85</text>
@@ -359,6 +360,12 @@ export default {
this.viewRecords()
},
goToWeightManagement() {
uni.navigateTo({
url: `/pages/pets/pet-weight?petId=${this.petId}&petName=${this.petInfo.name}`
})
},
shareProfile() {
uni.showToast({
title: '分享功能开发中',
@@ -555,6 +562,24 @@ export default {
.stat-item {
text-align: center;
position: relative;
&.clickable {
cursor: pointer;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
.stat-arrow {
position: absolute;
top: 8rpx;
right: 8rpx;
font-size: 20rpx;
color: #CCCCCC;
}
}
.stat-number {
font-size: 32rpx;
+664
View File
@@ -0,0 +1,664 @@
<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.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)
}
},
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>