| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- <template>
- <view class="water-container">
- <view class="nav-bar">
- <text class="nav-back" @click="goBack">‹ 返回</text>
- <text class="nav-title">饮水记录</text>
- <view class="nav-placeholder"></view>
- </view>
- <view class="section-card">
- <view class="section-title">今日饮水</view>
- <view class="water-progress">
- <view class="water-circle">
- <text class="water-amount">{{ todayTotal }}ml</text>
- <text class="water-target">/ {{ dailyTarget }}ml</text>
- </view>
- <view class="progress-bar-bg">
- <view class="progress-bar-fill" :style="'width:' + Math.min(100, todayTotal/dailyTarget*100) + '%'"></view>
- </view>
- </view>
- <view class="quick-add-btns">
- <text class="quick-btn" @click="addWater(100)">+100ml</text>
- <text class="quick-btn" @click="addWater(200)">+200ml</text>
- <text class="quick-btn" @click="addWater(300)">+300ml</text>
- <text class="quick-btn" @click="addWater(500)">+500ml</text>
- </view>
- <view class="input-row">
- <text class="input-label">自定义</text>
- <input class="input-field" v-model="customAmount" type="number" placeholder="输入ml" />
- <text class="input-unit" @click="addWater(parseInt(customAmount))">添加</text>
- </view>
- </view>
- <view class="section-card">
- <view class="section-title">今日饮水记录</view>
- <view class="record-list">
- <view class="record-item" v-for="(r, idx) in todayRecords" :key="idx">
- <text class="record-icon">💧</text>
- <text class="record-amount">{{ r.amountMl }}ml</text>
- <text class="record-time">{{ r.createdAt ? r.createdAt.substring(11,16) : '' }}</text>
- </view>
- <view class="record-empty" v-if="todayRecords.length === 0"><text>今天还没喝水,快去喝水吧!</text></view>
- </view>
- </view>
- <view class="section-card">
- <view class="section-title">本周饮水趋势</view>
- <view class="week-chart">
- <view class="day-bar" v-for="(day, idx) in weekData" :key="idx">
- <view class="bar-fill" :style="'height:' + Math.min(100, day.amount/dailyTarget*100) + '%'"></view>
- <text class="bar-label">{{ day.label }}</text>
- </view>
- </view>
- </view>
- <view class="bottom-spacer"></view>
- </view>
- </template>
- <script>
- import config from '@/config.js'
- export default {
- data() {
- return {
- childId: null,
- customAmount: '',
- todayRecords: [],
- weekData: [
- { label: '周一', amount: 0 }, { label: '周二', amount: 0 }, { label: '周三', amount: 0 },
- { label: '周四', amount: 0 }, { label: '周五', amount: 0 }, { label: '周六', amount: 0 }, { label: '周日', amount: 0 }
- ],
- dailyTarget: 1500
- }
- },
- computed: {
- todayTotal: function() {
- return this.todayRecords.reduce(function(sum, r) { return sum + (r.amountMl || 0) }, 0)
- }
- },
- onLoad: function(options) {
- this.childId = options.childId ? parseInt(options.childId) : null
- if (this.childId) this.loadRecords()
- },
- methods: {
- addWater: function(ml) {
- if (!ml || ml <= 0) return
- uni.showLoading({ title: '记录中...' })
- healthRequest('/api/health/water/create', {
- childId: this.childId,
- memberId: this.childId,
- amountMl: ml
- }).then(function() {
- uni.hideLoading()
- this.customAmount = ''
- this.loadRecords()
- }.bind(this)).catch(function() {
- uni.hideLoading()
- uni.showToast({ title: '记录失败', icon: 'none' })
- })
- },
- loadRecords: function() {
- var self = this
- healthRequest('/api/health/water/list', { childId: this.childId }).then(function(res) {
- if (res.data) {
- self.todayRecords = res.data.today || res.data.list || res.data
- if (res.data.week) self.weekData = res.data.week
- if (res.data.dailyTarget) self.dailyTarget = res.data.dailyTarget
- }
- }).catch(function() {})
- },
- goBack: function() { uni.navigateBack() }
- }
- }
- function healthRequest(url, data) {
- var token = uni.getStorageSync('token')
- return new Promise(function(resolve, reject) {
- uni.request({
- url: config.API_BASE_URL + url,
- method: 'POST',
- data: data,
- header: { 'Content-Type': 'application/json', 'Authorization': token ? 'Bearer ' + token : '' },
- success: function(res) { if (res.data.code === 200) resolve(res.data); else reject(res.data) },
- fail: function(err) { reject(err) }
- })
- })
- }
- </script>
- <style scoped>
- .water-container { min-height: 100vh; background: #f5f7fa; padding-bottom: 60rpx; }
- .nav-bar { position: sticky; top: 0; background: #fff; display: flex; flex-direction: row; align-items: center; justify-content: space-between; padding: 20rpx 30rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06); z-index: 100; }
- .nav-back { font-size: 32rpx; color: #5B9BD5; }
- .nav-title { font-size: 32rpx; font-weight: bold; color: #333; }
- .nav-placeholder { width: 80rpx; }
- .section-card { margin: 20rpx 30rpx; background: #fff; border-radius: 20rpx; padding: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
- .section-title { font-size: 30rpx; font-weight: bold; color: #333; margin-bottom: 20rpx; }
- .water-progress { display: flex; flex-direction: column; align-items: center; margin-bottom: 20rpx; }
- .water-circle { display: flex; flex-direction: column; align-items: center; margin-bottom: 16rpx; }
- .water-amount { font-size: 56rpx; font-weight: bold; color: #2196F3; }
- .water-target { font-size: 24rpx; color: #999; }
- .progress-bar-bg { width: 100%; height: 20rpx; background: #E3F2FD; border-radius: 10rpx; overflow: hidden; }
- .progress-bar-fill { height: 100%; background: linear-gradient(90deg, #42A5F5, #2196F3); border-radius: 10rpx; transition: width 0.3s; }
- .quick-add-btns { display: flex; flex-direction: row; justify-content: space-around; margin-bottom: 16rpx; }
- .quick-btn { background: #E3F2FD; color: #1565C0; font-size: 26rpx; padding: 12rpx 24rpx; border-radius: 20rpx; }
- .input-row { display: flex; flex-direction: row; align-items: center; }
- .input-label { font-size: 26rpx; color: #666; width: 100rpx; }
- .input-field { flex: 1; background: #f5f7fa; border-radius: 12rpx; padding: 14rpx 16rpx; font-size: 28rpx; }
- .input-unit { font-size: 26rpx; color: #2196F3; padding: 14rpx 20rpx; }
- .record-list { display: flex; flex-direction: column; }
- .record-item { display: flex; flex-direction: row; align-items: center; padding: 10rpx 0; border-bottom: 1rpx solid #f5f5f5; }
- .record-icon { font-size: 28rpx; margin-right: 12rpx; }
- .record-amount { font-size: 28rpx; color: #333; flex: 1; }
- .record-time { font-size: 22rpx; color: #999; }
- .record-empty { text-align: center; padding: 30rpx; color: #999; font-size: 26rpx; }
- .week-chart { display: flex; flex-direction: row; align-items: flex-end; justify-content: space-around; height: 200rpx; }
- .day-bar { display: flex; flex-direction: column; align-items: center; width: 60rpx; }
- .bar-fill { width: 40rpx; background: linear-gradient(180deg, #42A5F5, #1565C0); border-radius: 8rpx 8rpx 0 0; min-height: 4rpx; }
- .bar-label { font-size: 20rpx; color: #999; margin-top: 8rpx; }
- .bottom-spacer { height: 60rpx; }
- </style>
|