|
|
@@ -0,0 +1,150 @@
|
|
|
+<template>
|
|
|
+ <view class="page">
|
|
|
+ <view class="nav-bar">
|
|
|
+ <view class="nav-back" @click="goBack"><text class="back-text">‹ 返回</text></view>
|
|
|
+ <text class="nav-title">体脂秤数据确认</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <scroll-view class="content" scroll-y>
|
|
|
+ <!-- 已识别指标 -->
|
|
|
+ <view class="card">
|
|
|
+ <view class="card-accent"></view>
|
|
|
+ <view class="card-body">
|
|
|
+ <text class="card-title">AI 已识别指标</text>
|
|
|
+ <text class="card-subtitle">请确认并补充成员信息后保存</text>
|
|
|
+
|
|
|
+ <view v-if="metrics.length === 0" class="empty-state">
|
|
|
+ <text>未识别到指标,请重新拍照</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-for="(m, i) in metrics" :key="i" class="metric-row">
|
|
|
+ <text class="metric-name">{{ m.name }}</text>
|
|
|
+ <view class="metric-val-wrap">
|
|
|
+ <input class="metric-val" type="digit" v-model="m.value" placeholder="数值" />
|
|
|
+ <text class="metric-unit">{{ m.unit || '' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 绑定成员 -->
|
|
|
+ <view class="card">
|
|
|
+ <view class="card-accent"></view>
|
|
|
+ <view class="card-body">
|
|
|
+ <text class="card-title">绑定成员</text>
|
|
|
+ <picker mode="selector" :range="memberList" range-key="nickname" @change="onMemberChange">
|
|
|
+ <view class="picker-row">
|
|
|
+ <text class="picker-text">{{ currentMember ? currentMember.nickname : '选择成员' }}</text>
|
|
|
+ <text class="picker-arrow">›</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="save-bar">
|
|
|
+ <button class="save-btn" :disabled="saving" @click="save">{{ saving ? '保存中...' : '保存指标' }}</button>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { saveBodyFatMetrics } from '../../utils/api.js'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ metrics: [],
|
|
|
+ memberList: [],
|
|
|
+ currentMember: null,
|
|
|
+ saving: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad: function(options) {
|
|
|
+ if (options.metrics) {
|
|
|
+ try { this.metrics = JSON.parse(decodeURIComponent(options.metrics)) } catch (e) {}
|
|
|
+ }
|
|
|
+ this.loadMembers()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ loadMembers: function() {
|
|
|
+ var self = this
|
|
|
+ var token = uni.getStorageSync('token')
|
|
|
+ uni.request({
|
|
|
+ url: config.API_BASE_URL + '/api/family/member/list',
|
|
|
+ method: 'POST',
|
|
|
+ data: { visibleOnly: true },
|
|
|
+ header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token },
|
|
|
+ success: function(res) {
|
|
|
+ if (res.data && res.data.code === 200 && res.data.data) {
|
|
|
+ self.memberList = res.data.data
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onMemberChange: function(e) {
|
|
|
+ var idx = parseInt(e.detail.value)
|
|
|
+ if (idx >= 0 && idx < this.memberList.length) {
|
|
|
+ this.currentMember = this.memberList[idx]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ goBack: function() {
|
|
|
+ uni.navigateBack()
|
|
|
+ },
|
|
|
+ save: function() {
|
|
|
+ var self = this
|
|
|
+ if (!self.currentMember) {
|
|
|
+ uni.showToast({ title: '请选择成员', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (self.metrics.length === 0) {
|
|
|
+ uni.showToast({ title: '无可保存的指标', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.saving = true
|
|
|
+ saveBodyFatMetrics({
|
|
|
+ memberId: self.currentMember.id,
|
|
|
+ metrics: self.metrics
|
|
|
+ }).then(function(res) {
|
|
|
+ self.saving = false
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ uni.showToast({ title: '保存成功', icon: 'success' })
|
|
|
+ setTimeout(function() { uni.navigateBack() }, 1000)
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: (res && res.message) || '保存失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ }).catch(function() {
|
|
|
+ self.saving = false
|
|
|
+ uni.showToast({ title: '网络错误', icon: 'none' })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.page { min-height: 100vh; background: #F5F7FA; padding-bottom: 140rpx; }
|
|
|
+.nav-bar { display: flex; align-items: center; padding: 24rpx 30rpx; background: #fff; }
|
|
|
+.nav-back { margin-right: 20rpx; }
|
|
|
+.back-text { font-size: 28rpx; color: #333; }
|
|
|
+.nav-title { font-size: 32rpx; font-weight: bold; color: #333; }
|
|
|
+.content { height: calc(100vh - 100rpx); }
|
|
|
+.card { margin: 24rpx 30rpx; background: #fff; border-radius: 16rpx; overflow: hidden; }
|
|
|
+.card-accent { height: 6rpx; background: linear-gradient(90deg, #F97316, #F59E0B); }
|
|
|
+.card-body { padding: 24rpx; }
|
|
|
+.card-title { font-size: 30rpx; font-weight: bold; color: #333; display: block; }
|
|
|
+.card-subtitle { font-size: 24rpx; color: #999; margin-top: 6rpx; display: block; }
|
|
|
+.empty-state { padding: 40rpx 0; text-align: center; color: #999; font-size: 26rpx; }
|
|
|
+.metric-row { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 0; border-bottom: 1rpx solid #F0F0F0; }
|
|
|
+.metric-row:last-child { border-bottom: none; }
|
|
|
+.metric-name { font-size: 28rpx; color: #333; }
|
|
|
+.metric-val-wrap { display: flex; align-items: center; }
|
|
|
+.metric-val { height: 56rpx; background: #F5F7FA; border-radius: 10rpx; padding: 0 16rpx; font-size: 28rpx; width: 160rpx; text-align: right; }
|
|
|
+.metric-unit { font-size: 26rpx; color: #999; margin-left: 8rpx; }
|
|
|
+.picker-row { display: flex; align-items: center; justify-content: space-between; padding: 16rpx 0; }
|
|
|
+.picker-text { font-size: 28rpx; color: #333; }
|
|
|
+.picker-arrow { font-size: 28rpx; color: #999; }
|
|
|
+.save-bar { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; padding: 20rpx 30rpx; padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); }
|
|
|
+.save-btn { width: 100%; background: #F97316; color: #fff; border-radius: 44rpx; height: 84rpx; line-height: 84rpx; font-size: 32rpx; }
|
|
|
+.save-btn[disabled] { opacity: 0.6; }
|
|
|
+</style>
|