- Update Maven compiler plugin to support Lombok annotation processing - Add deploy.conf for automated deployment - Update backend models and controllers - Update frontend pages and API
993 lines
20 KiB
Vue
993 lines
20 KiB
Vue
<template>
|
||
<view class="result-page">
|
||
<!-- 加载中 -->
|
||
<view v-if="loading" class="loading-wrap">
|
||
<view class="loading-inner">
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
</view>
|
||
<!-- 加载失败 -->
|
||
<view v-else-if="loadError" class="error-wrap">
|
||
<text class="error-text">{{ loadError }}</text>
|
||
<view class="retry-btn" v-if="resultId" @click="loadResult">重新加载</view>
|
||
<view class="retry-btn" v-else @click="goBackToCalculator">返回重新计算</view>
|
||
</view>
|
||
<!-- 正常内容 -->
|
||
<template v-else>
|
||
<!-- Tab切换 -->
|
||
<view class="tab-container">
|
||
<view
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 'overview' }"
|
||
@click="switchTab('overview')"
|
||
>
|
||
<text class="tab-icon">📊</text>
|
||
<text class="tab-text">健康概览</text>
|
||
</view>
|
||
<view
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 'meal' }"
|
||
@click="switchTab('meal')"
|
||
>
|
||
<text class="tab-icon">🍽️</text>
|
||
<text class="tab-text">营养配餐</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<scroll-view class="content-scroll" scroll-y>
|
||
<!-- 健康概览Tab内容 -->
|
||
<view v-if="currentTab === 'overview'" class="tab-content">
|
||
<!-- 您的健康数据卡片 -->
|
||
<view class="data-card">
|
||
<view class="card-header">
|
||
<text class="card-icon">💪</text>
|
||
<text class="card-title">您的健康数据</text>
|
||
</view>
|
||
<view class="data-grid">
|
||
<view class="data-item">
|
||
<text class="data-label">eGFR数值</text>
|
||
<text class="data-value">{{ healthData.eGFR }}</text>
|
||
<text class="data-unit">ml/min/1.73²m</text>
|
||
</view>
|
||
<view class="data-item">
|
||
<text class="data-label">标准体重</text>
|
||
<text class="data-value">{{ healthData.standardWeight }}</text>
|
||
<text class="data-unit">东方人标准</text>
|
||
</view>
|
||
<view class="data-item">
|
||
<text class="data-label">体重指数</text>
|
||
<text class="data-value">{{ healthData.bmi }}</text>
|
||
<text class="data-unit">{{ healthData.bmiStatus }}</text>
|
||
</view>
|
||
<view class="data-item">
|
||
<text class="data-label">CKD分期</text>
|
||
<text class="data-value ckd-stage">{{ healthData.ckdStage }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 每日营养目标卡片 -->
|
||
<view class="data-card">
|
||
<view class="card-header">
|
||
<text class="card-icon">🎯</text>
|
||
<text class="card-title">每日营养目标</text>
|
||
</view>
|
||
<view class="nutrition-goals">
|
||
<view class="goal-item protein">
|
||
<text class="goal-label">蛋白质</text>
|
||
<text class="goal-value">{{ nutritionGoals.protein }}</text>
|
||
<text class="goal-unit">克/天</text>
|
||
</view>
|
||
<view class="goal-item energy">
|
||
<text class="goal-label">能量</text>
|
||
<text class="goal-value">{{ nutritionGoals.energy }}</text>
|
||
<text class="goal-unit">千卡/天</text>
|
||
</view>
|
||
</view>
|
||
<view class="nutrition-hint">
|
||
<text class="hint-icon">💡</text>
|
||
<text class="hint-text">相当于下方表中食物的推荐摄入量</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 食物份数建议卡片 -->
|
||
<view class="data-card">
|
||
<view class="card-header">
|
||
<text class="card-icon">🥗</text>
|
||
<text class="card-title">食物份数建议</text>
|
||
</view>
|
||
<view class="food-list">
|
||
<view
|
||
class="food-item"
|
||
v-for="(item, index) in foodList"
|
||
:key="index"
|
||
>
|
||
<view class="food-info">
|
||
<view class="food-number">{{ item.number }}</view>
|
||
<text class="food-name">{{ item.name }}</text>
|
||
</view>
|
||
<text class="food-portion">{{ item.portion }} 份</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 温馨提示 -->
|
||
<view class="tip-box">
|
||
<text class="tip-icon">💡</text>
|
||
<view class="tip-content">
|
||
<text class="tip-title">温馨提示</text>
|
||
<text class="tip-text">以上计算结果仅供参考,具体饮食方案请咨询专业营养师或医生。</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 联系专业营养师按钮 -->
|
||
<view class="contact-btn" @click="contactNutritionist">
|
||
<text>联系专业营养师</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 营养配餐Tab内容 -->
|
||
<view v-if="currentTab === 'meal'" class="tab-content meal-content">
|
||
<!-- 早餐 -->
|
||
<view class="meal-section">
|
||
<view class="meal-header">
|
||
<view class="meal-icon">🌅</view>
|
||
<text class="meal-title">早餐</text>
|
||
</view>
|
||
<view class="meal-items">
|
||
<view
|
||
class="meal-item"
|
||
v-for="(item, index) in mealPlan.breakfast"
|
||
:key="index"
|
||
>
|
||
<view class="meal-image">
|
||
<image :src="item.image" mode="aspectFill"></image>
|
||
<view class="meal-number">{{ index + 1 }}</view>
|
||
</view>
|
||
<view class="meal-info">
|
||
<text class="meal-name">{{ item.name }}</text>
|
||
<view class="ingredient-tags">
|
||
<view
|
||
class="ingredient-tag"
|
||
v-for="(ingredient, i) in item.ingredients"
|
||
:key="i"
|
||
>
|
||
{{ ingredient }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 午餐 -->
|
||
<view class="meal-section">
|
||
<view class="meal-header">
|
||
<view class="meal-icon">☀️</view>
|
||
<text class="meal-title">午餐</text>
|
||
</view>
|
||
<view class="meal-items">
|
||
<view
|
||
class="meal-item"
|
||
v-for="(item, index) in mealPlan.lunch"
|
||
:key="index"
|
||
>
|
||
<view class="meal-image">
|
||
<image :src="item.image" mode="aspectFill"></image>
|
||
<view class="meal-number">{{ index + 1 }}</view>
|
||
</view>
|
||
<view class="meal-info">
|
||
<text class="meal-name">{{ item.name }}</text>
|
||
<view class="ingredient-tags">
|
||
<view
|
||
class="ingredient-tag"
|
||
v-for="(ingredient, i) in item.ingredients"
|
||
:key="i"
|
||
>
|
||
{{ ingredient }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 晚餐 -->
|
||
<view class="meal-section">
|
||
<view class="meal-header">
|
||
<view class="meal-icon">🌙</view>
|
||
<text class="meal-title">晚餐</text>
|
||
</view>
|
||
<view class="meal-items">
|
||
<view
|
||
class="meal-item"
|
||
v-for="(item, index) in mealPlan.dinner"
|
||
:key="index"
|
||
>
|
||
<view class="meal-image">
|
||
<image :src="item.image" mode="aspectFill"></image>
|
||
<view class="meal-number">{{ index + 1 }}</view>
|
||
</view>
|
||
<view class="meal-info">
|
||
<text class="meal-name">{{ item.name }}</text>
|
||
<view class="ingredient-tags">
|
||
<view
|
||
class="ingredient-tag"
|
||
v-for="(ingredient, i) in item.ingredients"
|
||
:key="i"
|
||
>
|
||
{{ ingredient }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 重要提示 -->
|
||
<view class="tips-card">
|
||
<view class="tips-header">
|
||
<text class="tips-icon">⚠️</text>
|
||
<text class="tips-title">重要提示</text>
|
||
</view>
|
||
<view class="tips-list">
|
||
<view
|
||
class="tip-item"
|
||
v-for="(tip, index) in importantTips"
|
||
:key="index"
|
||
>
|
||
<text class="tip-dot">・</text>
|
||
<text class="tip-text">{{ tip }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 采纳计划按钮 -->
|
||
<view class="adopt-btn" @click="adoptPlan">
|
||
<text class="adopt-icon">✅</text>
|
||
<text class="adopt-text">采纳计划,开始打卡</text>
|
||
</view>
|
||
|
||
<!-- 联系专业营养师按钮 -->
|
||
<view class="contact-btn" @click="contactNutritionist">
|
||
<text>联系专业营养师</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部安全距离 -->
|
||
<view class="safe-bottom"></view>
|
||
</scroll-view>
|
||
</template>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { getCalculatorResult } from '@/api/tool.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
currentTab: 'overview',
|
||
loading: true,
|
||
loadError: '',
|
||
resultId: null,
|
||
healthData: {
|
||
eGFR: '--',
|
||
standardWeight: '--',
|
||
bmi: '--',
|
||
bmiStatus: '--',
|
||
ckdStage: '--'
|
||
},
|
||
nutritionGoals: {
|
||
protein: '--',
|
||
energy: '--'
|
||
},
|
||
foodList: [],
|
||
mealPlan: {
|
||
breakfast: [],
|
||
lunch: [],
|
||
dinner: []
|
||
},
|
||
importantTips: []
|
||
}
|
||
},
|
||
onLoad(options) {
|
||
const id = options.id || options.resultId
|
||
if (id) {
|
||
this.resultId = Number(id)
|
||
this.loadResult()
|
||
} else {
|
||
this.loading = false
|
||
this.loadError = '暂无计算结果,请先完成营养计算'
|
||
}
|
||
},
|
||
methods: {
|
||
async loadResult() {
|
||
if (!this.resultId) return
|
||
this.loading = true
|
||
this.loadError = ''
|
||
try {
|
||
const res = await getCalculatorResult(this.resultId)
|
||
const data = res.data || res
|
||
this.applyResult(data)
|
||
} catch (e) {
|
||
const msg = (e && (e.message || e.msg)) || '加载失败,请重试'
|
||
this.loadError = msg
|
||
}
|
||
this.loading = false
|
||
},
|
||
applyResult(data) {
|
||
if (!data) return
|
||
if (data.healthData) {
|
||
this.healthData = {
|
||
eGFR: data.healthData.eGFR ?? '--',
|
||
standardWeight: data.healthData.standardWeight ?? '--',
|
||
bmi: data.healthData.bmi ?? '--',
|
||
bmiStatus: data.healthData.bmiStatus ?? '--',
|
||
ckdStage: data.healthData.ckdStage ?? '--'
|
||
}
|
||
}
|
||
if (data.nutritionGoals) {
|
||
this.nutritionGoals = {
|
||
protein: data.nutritionGoals.protein ?? '--',
|
||
energy: data.nutritionGoals.energy ?? '--'
|
||
}
|
||
}
|
||
if (Array.isArray(data.foodList)) {
|
||
this.foodList = data.foodList
|
||
}
|
||
if (data.mealPlan) {
|
||
this.mealPlan = {
|
||
breakfast: Array.isArray(data.mealPlan.breakfast) ? data.mealPlan.breakfast : [],
|
||
lunch: Array.isArray(data.mealPlan.lunch) ? data.mealPlan.lunch : [],
|
||
dinner: Array.isArray(data.mealPlan.dinner) ? data.mealPlan.dinner : []
|
||
}
|
||
}
|
||
if (Array.isArray(data.importantTips)) {
|
||
this.importantTips = data.importantTips
|
||
}
|
||
},
|
||
goBackToCalculator() {
|
||
uni.navigateBack({
|
||
delta: 1,
|
||
fail: () => {
|
||
uni.redirectTo({
|
||
url: '/pages/tool/calculator'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
switchTab(tab) {
|
||
this.currentTab = tab
|
||
},
|
||
contactNutritionist() {
|
||
// #ifdef MP-WEIXIN
|
||
const openConversation =
|
||
typeof uni.openCustomerServiceConversation === 'function'
|
||
? uni.openCustomerServiceConversation
|
||
: (typeof wx !== 'undefined' && typeof wx.openCustomerServiceConversation === 'function'
|
||
? wx.openCustomerServiceConversation
|
||
: null);
|
||
if (!openConversation) {
|
||
uni.showToast({
|
||
title: '当前微信版本暂不支持客服会话,请到「我的-联系客服」',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
openConversation({
|
||
showMessageCard: true,
|
||
success: () => {},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '打开客服失败,请到「我的-联系客服」',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
// #endif
|
||
|
||
// #ifndef MP-WEIXIN
|
||
uni.showToast({
|
||
title: '请在微信小程序中联系客服',
|
||
icon: 'none'
|
||
});
|
||
// #endif
|
||
},
|
||
async adoptPlan() {
|
||
if (!this.resultId) {
|
||
uni.showToast({ title: '暂无计算结果', icon: 'none' })
|
||
return
|
||
}
|
||
// 防止重复点击
|
||
if (this._adoptingPlan) return
|
||
this._adoptingPlan = true
|
||
try {
|
||
const { adoptNutritionPlan } = await import('@/api/tool.js')
|
||
await adoptNutritionPlan(this.resultId)
|
||
uni.showToast({ title: '采纳成功', icon: 'success' })
|
||
uni.navigateTo({
|
||
url: `/pages/tool/checkin-publish?planId=${this.resultId}`
|
||
})
|
||
} catch (e) {
|
||
const msg = (e && (e.message || e.msg)) || '采纳失败'
|
||
uni.showToast({ title: msg, icon: 'none' })
|
||
} finally {
|
||
this._adoptingPlan = false
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.result-page {
|
||
min-height: 100vh;
|
||
background-color: #f4f5f7;
|
||
}
|
||
|
||
/* 加载中 / 错误态 */
|
||
.loading-wrap,
|
||
.error-wrap {
|
||
min-height: 60vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 48rpx;
|
||
}
|
||
|
||
.loading-inner {
|
||
text-align: center;
|
||
}
|
||
|
||
.loading-text {
|
||
font-size: 28rpx;
|
||
color: #9fa5c0;
|
||
}
|
||
|
||
.error-wrap {
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.error-text {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
text-align: center;
|
||
}
|
||
|
||
.retry-btn {
|
||
padding: 20rpx 48rpx;
|
||
background: #ff6b35;
|
||
color: #fff;
|
||
font-size: 28rpx;
|
||
border-radius: 48rpx;
|
||
}
|
||
|
||
/* Tab切换 */
|
||
.tab-container {
|
||
background: #ffffff;
|
||
border-bottom: 1rpx solid #d0dbea;
|
||
display: flex;
|
||
padding: 0 32rpx;
|
||
height: 96rpx;
|
||
align-items: center;
|
||
position: sticky;
|
||
// top: 88rpx;
|
||
z-index: 99;
|
||
}
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
height: 100%;
|
||
min-height: 75rpx;
|
||
border-radius: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 16rpx;
|
||
transition: all 0.3s;
|
||
border-bottom: none;
|
||
box-sizing: border-box;
|
||
color: #9ca3af;
|
||
font-weight: 400;
|
||
|
||
.tab-icon {
|
||
font-size: 28rpx;
|
||
color: #9ca3af;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.tab-text {
|
||
font-size: 28rpx;
|
||
color: #9ca3af;
|
||
font-weight: 400;
|
||
}
|
||
|
||
&.active {
|
||
background: transparent;
|
||
border-bottom: 3px solid #f97316;
|
||
color: #f97316;
|
||
font-weight: 700;
|
||
|
||
.tab-text {
|
||
color: #f97316;
|
||
font-weight: 700;
|
||
}
|
||
.tab-icon {
|
||
color: #f97316;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 内容滚动区域 */
|
||
.content-scroll {
|
||
height: calc(100vh - 184rpx);
|
||
}
|
||
|
||
.tab-content {
|
||
padding: 32rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 32rpx;
|
||
}
|
||
|
||
/* 数据卡片 */
|
||
.data-card {
|
||
background: #ffffff;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 24rpx;
|
||
padding: 40rpx;
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
margin-bottom: 32rpx;
|
||
|
||
.card-icon {
|
||
font-size: 48rpx;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 32rpx;
|
||
color: #2e3e5c;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
/* 健康数据网格 */
|
||
.data-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.data-item {
|
||
background: #f4f5f7;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 24rpx;
|
||
padding: 30rpx 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
|
||
.data-label {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
}
|
||
|
||
.data-value {
|
||
font-size: 40rpx;
|
||
color: #3e5481;
|
||
font-weight: 500;
|
||
|
||
&.ckd-stage {
|
||
font-size: 32rpx;
|
||
}
|
||
}
|
||
|
||
.data-unit {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
}
|
||
}
|
||
|
||
/* 营养目标 */
|
||
.nutrition-goals {
|
||
display: flex;
|
||
gap: 24rpx;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.goal-item {
|
||
flex: 1;
|
||
border-radius: 24rpx;
|
||
padding: 32rpx 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
|
||
&.protein {
|
||
background: #fff5f0;
|
||
border: 1rpx solid rgba(255, 107, 53, 0.3);
|
||
|
||
.goal-label {
|
||
color: #ff6b35;
|
||
}
|
||
|
||
.goal-value {
|
||
color: #ff6b35;
|
||
}
|
||
|
||
.goal-unit {
|
||
color: rgba(255, 107, 53, 0.7);
|
||
}
|
||
}
|
||
|
||
&.energy {
|
||
background: #fff4e6;
|
||
border: 1rpx solid rgba(255, 165, 0, 0.3);
|
||
|
||
.goal-label {
|
||
color: #ff9800;
|
||
}
|
||
|
||
.goal-value {
|
||
color: #ff9800;
|
||
}
|
||
|
||
.goal-unit {
|
||
color: rgba(255, 152, 0, 0.7);
|
||
}
|
||
}
|
||
|
||
.goal-label {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.goal-value {
|
||
font-size: 48rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.goal-unit {
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
|
||
.nutrition-hint {
|
||
background: #f4f5f7;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
|
||
.hint-icon {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.hint-text {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
/* 食物列表 */
|
||
.food-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.food-item {
|
||
background: #f4f5f7;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 24rpx;
|
||
padding: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.food-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
|
||
.food-number {
|
||
width: 56rpx;
|
||
height: 56rpx;
|
||
background: #ffffff;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24rpx;
|
||
color: #3e5481;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.food-name {
|
||
font-size: 28rpx;
|
||
color: #3e5481;
|
||
}
|
||
}
|
||
|
||
.food-portion {
|
||
font-size: 28rpx;
|
||
color: #ff6b35;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 温馨提示 */
|
||
.tip-box {
|
||
background: #e3f2fd;
|
||
border: 1rpx solid #64b5f6;
|
||
border-radius: 24rpx;
|
||
padding: 32rpx;
|
||
display: flex;
|
||
gap: 20rpx;
|
||
align-items: flex-start;
|
||
|
||
.tip-icon {
|
||
font-size: 40rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.tip-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
|
||
.tip-title {
|
||
font-size: 28rpx;
|
||
color: #1976d2;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.tip-text {
|
||
font-size: 24rpx;
|
||
color: #1565c0;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 联系营养师按钮 */
|
||
.contact-btn {
|
||
width: calc(100% - 64rpx);
|
||
height: 96rpx;
|
||
background: #ffffff;
|
||
border: 2rpx solid #ff6b35;
|
||
border-radius: 50rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin: 0 32rpx 24rpx;
|
||
|
||
text {
|
||
font-size: 28rpx;
|
||
color: #ff6b35;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
/* 空状态 */
|
||
.empty-placeholder {
|
||
padding: 200rpx 0;
|
||
text-align: center;
|
||
color: #9fa5c0;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
/* 营养配餐内容 */
|
||
.meal-content {
|
||
padding: 0;
|
||
gap: 0;
|
||
}
|
||
|
||
/* 餐次区块 */
|
||
.meal-section {
|
||
background: #ffffff;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 24rpx;
|
||
margin: 0 32rpx 32rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.meal-header {
|
||
background: linear-gradient(180deg, #f8f9fa 0%, #f4f5f7 100%);
|
||
border-bottom: 1rpx solid #d0dbea;
|
||
padding: 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.meal-icon {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
background: #ffffff;
|
||
border: 2rpx solid rgba(255, 136, 68, 0.3);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 48rpx;
|
||
}
|
||
|
||
.meal-title {
|
||
font-size: 28rpx;
|
||
color: #2e3e5c;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 菜品列表 */
|
||
.meal-items {
|
||
padding: 32rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.meal-item {
|
||
background: #ffffff;
|
||
border: 1rpx solid #d0dbea;
|
||
border-radius: 24rpx;
|
||
padding: 16rpx;
|
||
display: flex;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.meal-image {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
background: #f4f5f7;
|
||
flex-shrink: 0;
|
||
|
||
image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.meal-number {
|
||
position: absolute;
|
||
left: 12rpx;
|
||
top: 12rpx;
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
background: linear-gradient(135deg, #ff8844 0%, #ff7722 100%);
|
||
border: 2rpx solid #ffffff;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24rpx;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.meal-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
padding: 8rpx 0;
|
||
}
|
||
|
||
.meal-name {
|
||
font-size: 28rpx;
|
||
color: #2e3e5c;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.ingredient-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.ingredient-tag {
|
||
background: linear-gradient(135deg, #fff8f0 0%, #fff5eb 100%);
|
||
border: 1rpx solid rgba(255, 136, 68, 0.3);
|
||
border-radius: 12rpx;
|
||
padding: 8rpx 16rpx;
|
||
font-size: 24rpx;
|
||
color: #ff7722;
|
||
}
|
||
|
||
/* 重要提示卡片 */
|
||
.tips-card {
|
||
background: #fff3e0;
|
||
border: 1rpx solid #ffb74d;
|
||
border-radius: 24rpx;
|
||
margin: 0 32rpx 32rpx;
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.tips-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
margin-bottom: 24rpx;
|
||
|
||
.tips-icon {
|
||
font-size: 40rpx;
|
||
}
|
||
|
||
.tips-title {
|
||
font-size: 28rpx;
|
||
color: #e65100;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.tips-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.tip-item {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
align-items: flex-start;
|
||
|
||
.tip-dot {
|
||
font-size: 28rpx;
|
||
color: #e65100;
|
||
line-height: 1;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.tip-text {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #f57c00;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
|
||
/* 采纳计划按钮 */
|
||
.adopt-btn {
|
||
width: calc(100% - 64rpx);
|
||
height: 96rpx;
|
||
background: #ff6b35;
|
||
border-radius: 50rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 16rpx;
|
||
margin: 0 32rpx 24rpx;
|
||
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1), 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.adopt-icon {
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.adopt-text {
|
||
font-size: 28rpx;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
/* 底部安全距离 */
|
||
.safe-bottom {
|
||
height: 40rpx;
|
||
}
|
||
</style>
|