|
|
@@ -1,118 +1,177 @@
|
|
|
<template>
|
|
|
<view class="diet-page">
|
|
|
<scroll-view class="content" scroll-y>
|
|
|
+ <!-- 页面标题区 -->
|
|
|
+ <view class="page-header">
|
|
|
+ <view class="header-icon-wrap">
|
|
|
+ <text class="header-icon">🍽️</text>
|
|
|
+ </view>
|
|
|
+ <view class="header-text">
|
|
|
+ <text class="header-title">饮食推荐</text>
|
|
|
+ <text class="header-subtitle">科学膳食 · 健康生活</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
<!-- 今日共餐摘要 -->
|
|
|
- <view class="card meal-summary-card">
|
|
|
- <view class="card-accent"></view>
|
|
|
- <view class="card-body">
|
|
|
+ <view class="card">
|
|
|
+ <view class="card-header">
|
|
|
+ <view class="card-dot"></view>
|
|
|
<text class="card-title">今日共餐</text>
|
|
|
- <view class="meal-row" v-if="mealSummary.breakfast">
|
|
|
- <text class="meal-label">早餐</text>
|
|
|
- <text class="meal-members">{{ mealSummary.breakfast }}</text>
|
|
|
- </view>
|
|
|
- <view class="meal-row" v-if="mealSummary.lunch">
|
|
|
- <text class="meal-label">午餐</text>
|
|
|
- <text class="meal-members">{{ mealSummary.lunch }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="card-body">
|
|
|
+ <view class="meal-grid">
|
|
|
+ <view class="meal-item" v-if="mealSummary.breakfast">
|
|
|
+ <text class="meal-emoji">🌅</text>
|
|
|
+ <text class="meal-label">早餐</text>
|
|
|
+ <text class="meal-members">{{ mealSummary.breakfast }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="meal-item" v-if="mealSummary.lunch">
|
|
|
+ <text class="meal-emoji">☀️</text>
|
|
|
+ <text class="meal-label">午餐</text>
|
|
|
+ <text class="meal-members">{{ mealSummary.lunch }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="meal-item" v-if="mealSummary.dinner">
|
|
|
+ <text class="meal-emoji">🌙</text>
|
|
|
+ <text class="meal-label">晚餐</text>
|
|
|
+ <text class="meal-members">{{ mealSummary.dinner }}</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="meal-row" v-if="mealSummary.dinner">
|
|
|
- <text class="meal-label">晚餐</text>
|
|
|
- <text class="meal-members">{{ mealSummary.dinner }}</text>
|
|
|
+ <view class="empty-hint" v-if="!mealSummary.breakfast && !mealSummary.lunch && !mealSummary.dinner">
|
|
|
+ <text class="empty-icon">📋</text>
|
|
|
+ <text class="empty-text">尚未配置共餐</text>
|
|
|
+ <text class="empty-sub">点击下方「共餐配置」开始设置</text>
|
|
|
</view>
|
|
|
- <text class="empty-hint" v-if="!mealSummary.breakfast && !mealSummary.lunch && !mealSummary.dinner">
|
|
|
- 尚未配置共餐,请先前往配置
|
|
|
- </text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 食材推荐器 -->
|
|
|
- <view class="card ingredient-card">
|
|
|
- <view class="card-accent"></view>
|
|
|
+ <view class="card">
|
|
|
+ <view class="card-header">
|
|
|
+ <view class="card-dot"></view>
|
|
|
+ <text class="card-title">今日食材推荐</text>
|
|
|
+ </view>
|
|
|
<view class="card-body">
|
|
|
- <view class="section-header">
|
|
|
- <text class="section-title">今日食材推荐</text>
|
|
|
- <view class="action-btns">
|
|
|
- <view class="btn-secondary" @tap="refreshIngredients">换一批</view>
|
|
|
- <view class="btn-primary" @tap="showFoodPicker">添加食材</view>
|
|
|
- <view class="btn-primary" @tap="generateRecipe" :class="{'disabled': selectedIngredients.length === 0}">
|
|
|
- 生成食谱
|
|
|
- </view>
|
|
|
+ <view class="action-bar">
|
|
|
+ <view class="action-btn" @tap="refreshIngredients">
|
|
|
+ <text class="action-btn-text">🔄 换一批</text>
|
|
|
+ </view>
|
|
|
+ <view class="action-btn action-btn-primary" @tap="showFoodPicker">
|
|
|
+ <text class="action-btn-text-primary">+ 添加食材</text>
|
|
|
+ </view>
|
|
|
+ <view class="action-btn action-btn-accent" @tap="generateRecipe" :class="{'action-btn-disabled': selectedIngredients.length === 0}">
|
|
|
+ <text class="action-btn-text-accent">✨ 生成食谱</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
-
|
|
|
+
|
|
|
<view class="ingredient-list" v-if="ingredients.length > 0">
|
|
|
<view class="ingredient-item" v-for="(item, index) in ingredients" :key="getIngredientKey(item, index)">
|
|
|
- <view class="ingredient-info">
|
|
|
- <text class="ingredient-name">{{ item.name }}</text>
|
|
|
- <text class="ingredient-reason" v-if="item.reason">{{ item.reason }}</text>
|
|
|
+ <view class="ingredient-left">
|
|
|
+ <view class="ingredient-badge">
|
|
|
+ <text class="ingredient-badge-text">{{ index + 1 }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="ingredient-info">
|
|
|
+ <text class="ingredient-name">{{ item.name }}</text>
|
|
|
+ <text class="ingredient-reason" v-if="item.reason">{{ item.reason }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="ingredient-remove" @tap="removeIngredient(index)">
|
|
|
+ <text class="remove-text">✕</text>
|
|
|
</view>
|
|
|
- <view class="ingredient-remove" @tap="removeIngredient(index)">✕</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="empty-state" v-else>
|
|
|
- <text>{{ ingredientsLoading ? '加载中...' : '暂无推荐食材' }}</text>
|
|
|
+ <text class="empty-icon">🥬</text>
|
|
|
+ <text class="empty-text">{{ ingredientsLoading ? '加载中...' : '暂无推荐食材' }}</text>
|
|
|
+ <text class="empty-sub" v-if="!ingredientsLoading">点击「添加食材」或「换一批」获取推荐</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 快捷入口 -->
|
|
|
+ <view class="section-label">
|
|
|
+ <text class="section-label-text">常用功能</text>
|
|
|
+ </view>
|
|
|
<view class="nav-grid">
|
|
|
- <view class="nav-item" @tap="navTo('pages/diet/food-query')">
|
|
|
- <text class="nav-icon">🥗</text>
|
|
|
+ <view class="nav-item" @tap="navTo('/pages/diet/food-query')">
|
|
|
+ <view class="nav-icon-wrap nav-icon-green">
|
|
|
+ <text class="nav-icon">🥗</text>
|
|
|
+ </view>
|
|
|
<text class="nav-label">食材查询</text>
|
|
|
</view>
|
|
|
- <view class="nav-item" @tap="navTo('pages/diet/records')">
|
|
|
- <text class="nav-icon">📝</text>
|
|
|
+ <view class="nav-item" @tap="navTo('/pages/diet/records')">
|
|
|
+ <view class="nav-icon-wrap nav-icon-blue">
|
|
|
+ <text class="nav-icon">📝</text>
|
|
|
+ </view>
|
|
|
<text class="nav-label">饮食记录</text>
|
|
|
</view>
|
|
|
- <view class="nav-item" @tap="navTo('pages/diet/preferences')">
|
|
|
- <text class="nav-icon">📋</text>
|
|
|
+ <view class="nav-item" @tap="navTo('/pages/diet/preferences')">
|
|
|
+ <view class="nav-icon-wrap nav-icon-orange">
|
|
|
+ <text class="nav-icon">📋</text>
|
|
|
+ </view>
|
|
|
<text class="nav-label">调研表</text>
|
|
|
</view>
|
|
|
- <view class="nav-item" @tap="navTo('pages/diet/meal-config')">
|
|
|
- <text class="nav-icon">👨👩👧</text>
|
|
|
+ <view class="nav-item" @tap="navTo('/pages/diet/meal-config')">
|
|
|
+ <view class="nav-icon-wrap nav-icon-purple">
|
|
|
+ <text class="nav-icon">👨👩👧</text>
|
|
|
+ </view>
|
|
|
<text class="nav-label">共餐配置</text>
|
|
|
</view>
|
|
|
- <view class="nav-item" @tap="navTo('pages/diet/recommendation')">
|
|
|
- <text class="nav-icon">🍽️</text>
|
|
|
+ <view class="nav-item" @tap="navTo('/pages/diet/recommendation')">
|
|
|
+ <view class="nav-icon-wrap nav-icon-red">
|
|
|
+ <text class="nav-icon">🍽️</text>
|
|
|
+ </view>
|
|
|
<text class="nav-label">食谱推荐</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 本周趋势 -->
|
|
|
- <view class="card trend-card" v-if="trendData.days > 0">
|
|
|
- <view class="card-accent"></view>
|
|
|
- <view class="card-body">
|
|
|
+ <view class="card" v-if="trendData.days > 0">
|
|
|
+ <view class="card-header">
|
|
|
+ <view class="card-dot"></view>
|
|
|
<text class="card-title">本周饮食</text>
|
|
|
- <view class="trend-stats">
|
|
|
- <text class="trend-num">{{ trendData.totalCalories || 0 }}</text>
|
|
|
- <text class="trend-unit">kcal</text>
|
|
|
- <text class="trend-label">总摄入</text>
|
|
|
- </view>
|
|
|
- <view class="trend-stats">
|
|
|
- <text class="trend-num">{{ trendData.days }}</text>
|
|
|
- <text class="trend-unit">天</text>
|
|
|
- <text class="trend-label">记录天数</text>
|
|
|
+ </view>
|
|
|
+ <view class="card-body">
|
|
|
+ <view class="trend-row">
|
|
|
+ <view class="trend-item">
|
|
|
+ <text class="trend-num">{{ trendData.totalCalories || 0 }}</text>
|
|
|
+ <text class="trend-unit">kcal</text>
|
|
|
+ <text class="trend-label">总摄入</text>
|
|
|
+ </view>
|
|
|
+ <view class="trend-divider"></view>
|
|
|
+ <view class="trend-item">
|
|
|
+ <text class="trend-num">{{ trendData.days }}</text>
|
|
|
+ <text class="trend-unit">天</text>
|
|
|
+ <text class="trend-label">记录天数</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
+
|
|
|
+ <!-- 底部留白 -->
|
|
|
+ <view class="bottom-space"></view>
|
|
|
</scroll-view>
|
|
|
|
|
|
<!-- 食材选择弹窗 -->
|
|
|
<view class="modal" v-if="showPicker" @tap="closePicker">
|
|
|
+ <view class="modal-mask"></view>
|
|
|
<view class="modal-content" @tap.stop>
|
|
|
<view class="modal-header">
|
|
|
<text class="modal-title">选择食材</text>
|
|
|
- <text class="modal-close" @tap="closePicker">✕</text>
|
|
|
+ <view class="modal-close" @tap="closePicker">
|
|
|
+ <text class="close-text">✕</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="search-wrap">
|
|
|
+ <input class="search-input" placeholder="搜索食材..." placeholder-style="color:#bbb" v-model="searchQuery" @input="searchFood" />
|
|
|
</view>
|
|
|
- <input class="search-input" placeholder="搜索食材..." v-model="searchQuery" @input="searchFood" />
|
|
|
<scroll-view class="food-list" scroll-y>
|
|
|
<view class="food-item" v-for="food in searchResults" :key="food.id" @tap="addFood(food)">
|
|
|
<text class="food-name">{{ food.name }}</text>
|
|
|
- <text class="food-category">{{ food.category }}</text>
|
|
|
+ <text class="food-tag">{{ food.category }}</text>
|
|
|
</view>
|
|
|
</scroll-view>
|
|
|
<view class="empty-state" v-if="searchResults.length === 0 && searchQuery">
|
|
|
- <text>未找到匹配食材</text>
|
|
|
+ <text class="empty-text">未找到匹配食材</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -124,7 +183,7 @@ import { getDietIngredients, refreshDietIngredients, addDietIngredient, removeDi
|
|
|
import { parseDate } from '@/utils/format.js'
|
|
|
|
|
|
export default {
|
|
|
- data() {
|
|
|
+ data: function() {
|
|
|
return {
|
|
|
familyId: null,
|
|
|
familyMemberId: null,
|
|
|
@@ -139,31 +198,30 @@ export default {
|
|
|
uploadPromptShown: false
|
|
|
}
|
|
|
},
|
|
|
- onLoad() {
|
|
|
+ onLoad: function() {
|
|
|
this.familyId = uni.getStorageSync('familyId')
|
|
|
this.familyMemberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('currentMemberId') || uni.getStorageSync('userId')
|
|
|
this.loadIngredients()
|
|
|
this.loadMealSummary()
|
|
|
},
|
|
|
- onShow() {
|
|
|
+ onShow: function() {
|
|
|
this.loadIngredients()
|
|
|
this.loadMealSummary()
|
|
|
},
|
|
|
methods: {
|
|
|
- navTo(url) {
|
|
|
+ navTo: function(url) {
|
|
|
uni.navigateTo({ url: url })
|
|
|
},
|
|
|
- getIngredientKey(item, index) {
|
|
|
+ getIngredientKey: function(item, index) {
|
|
|
return 'ing-' + (item.id || index)
|
|
|
},
|
|
|
- loadIngredients() {
|
|
|
+ loadIngredients: function() {
|
|
|
this.ingredientsLoading = true
|
|
|
var self = this
|
|
|
getDietIngredients().then(function(res) {
|
|
|
self.ingredientsLoading = false
|
|
|
if (res && res.ingredients) {
|
|
|
self.ingredients = res.ingredients
|
|
|
- // 无推荐食材时弹窗引导上传菌群报告
|
|
|
if (res.ingredients.length === 0 && !self.uploadPromptShown) {
|
|
|
self.uploadPromptShown = true
|
|
|
uni.showModal({
|
|
|
@@ -183,7 +241,7 @@ export default {
|
|
|
self.ingredientsLoading = false
|
|
|
})
|
|
|
},
|
|
|
- refreshIngredients() {
|
|
|
+ refreshIngredients: function() {
|
|
|
var self = this
|
|
|
refreshDietIngredients().then(function(res) {
|
|
|
if (res && res.ingredients) {
|
|
|
@@ -191,24 +249,24 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
- addIngredient(index) {
|
|
|
+ addIngredient: function(index) {
|
|
|
var self = this
|
|
|
var item = this.ingredients[index]
|
|
|
addDietIngredient({ food_id: item.foodId, name: item.name }).then(function(res) {
|
|
|
self.loadIngredients()
|
|
|
})
|
|
|
},
|
|
|
- removeIngredient(index) {
|
|
|
+ removeIngredient: function(index) {
|
|
|
var self = this
|
|
|
var item = this.ingredients[index]
|
|
|
removeDietIngredient({ food_id: item.foodId }).then(function(res) {
|
|
|
self.loadIngredients()
|
|
|
})
|
|
|
},
|
|
|
- generateRecipe() {
|
|
|
+ generateRecipe: function() {
|
|
|
var self = this
|
|
|
var foodIds = this.ingredients.map(function(item) { return { food_id: item.foodId, name: item.name } })
|
|
|
- generateDietRecommendation({
|
|
|
+ generateDietRecommendation({
|
|
|
date: self.formatDate(new Date()),
|
|
|
meal_type: 'all',
|
|
|
selected_foods: JSON.stringify(foodIds)
|
|
|
@@ -216,19 +274,21 @@ export default {
|
|
|
if (res && res.id) {
|
|
|
uni.showToast({ title: '食谱生成成功', icon: 'success' })
|
|
|
setTimeout(function() {
|
|
|
- self.navTo('pages/diet/recommendation')
|
|
|
+ self.navTo('/pages/diet/recommendation')
|
|
|
}, 1000)
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
- formatDate(date) {
|
|
|
+ formatDate: function(date) {
|
|
|
var d = parseDate(date)
|
|
|
if (!d) return ''
|
|
|
- var m = (d.getMonth() + 1).toString().padStart(2, '0')
|
|
|
- var day = d.getDate().toString().padStart(2, '0')
|
|
|
+ var m = (d.getMonth() + 1).toString()
|
|
|
+ if (m.length < 2) m = '0' + m
|
|
|
+ var day = d.getDate().toString()
|
|
|
+ if (day.length < 2) day = '0' + day
|
|
|
return d.getFullYear() + '-' + m + '-' + day
|
|
|
},
|
|
|
- loadMealSummary() {
|
|
|
+ loadMealSummary: function() {
|
|
|
var self = this
|
|
|
var dateType = self.isWeekend(new Date()) ? 'weekend' : 'weekday'
|
|
|
Promise.all([
|
|
|
@@ -241,7 +301,7 @@ export default {
|
|
|
self.mealSummary.dinner = self.parseMembers(results[2])
|
|
|
})
|
|
|
},
|
|
|
- parseMembers(config) {
|
|
|
+ parseMembers: function(config) {
|
|
|
if (!config || !config.participantMemberIds) return ''
|
|
|
try {
|
|
|
var ids = JSON.parse(config.participantMemberIds)
|
|
|
@@ -250,27 +310,26 @@ export default {
|
|
|
return ''
|
|
|
}
|
|
|
},
|
|
|
- isWeekend(date) {
|
|
|
+ isWeekend: function(date) {
|
|
|
var day = date.getDay()
|
|
|
return day === 0 || day === 6
|
|
|
},
|
|
|
- showFoodPicker() {
|
|
|
+ showFoodPicker: function() {
|
|
|
this.showPicker = true
|
|
|
},
|
|
|
- closePicker() {
|
|
|
+ closePicker: function() {
|
|
|
this.showPicker = false
|
|
|
this.searchQuery = ''
|
|
|
this.searchResults = []
|
|
|
},
|
|
|
- searchFood() {
|
|
|
+ searchFood: function() {
|
|
|
if (!this.searchQuery) {
|
|
|
this.searchResults = []
|
|
|
return
|
|
|
}
|
|
|
- // 简化:实际应调用搜索API
|
|
|
this.searchResults = []
|
|
|
},
|
|
|
- addFood(food) {
|
|
|
+ addFood: function(food) {
|
|
|
var self = this
|
|
|
addDietIngredient({ food_id: food.id, name: food.name }).then(function(res) {
|
|
|
self.closePicker()
|
|
|
@@ -284,235 +343,414 @@ export default {
|
|
|
<style scoped>
|
|
|
.diet-page {
|
|
|
min-height: 100vh;
|
|
|
- background-color: #F5F7FA;
|
|
|
+ background: linear-gradient(180deg, #FFF7ED 0%, #FFF3E6 30%, #F5F7FA 100%);
|
|
|
+}
|
|
|
+.content {
|
|
|
+ padding: 24rpx 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 页面头部 */
|
|
|
+.page-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20rpx 0 32rpx;
|
|
|
+}
|
|
|
+.header-icon-wrap {
|
|
|
+ width: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ background: linear-gradient(135deg, #FF8C42, #FFB366);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-right: 24rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.header-icon {
|
|
|
+ font-size: 40rpx;
|
|
|
+}
|
|
|
+.header-text {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
}
|
|
|
-.content {
|
|
|
- flex: 1;
|
|
|
- padding: 30rpx;
|
|
|
+.header-title {
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.header-subtitle {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 4rpx;
|
|
|
}
|
|
|
+
|
|
|
+/* 卡片通用 */
|
|
|
.card {
|
|
|
- display: flex;
|
|
|
- background-color: #FFFFFF;
|
|
|
- border-radius: 20rpx;
|
|
|
- margin-bottom: 30rpx;
|
|
|
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ box-shadow: 0 4rpx 20rpx rgba(255, 140, 66, 0.08);
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
-.card-accent {
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 28rpx 28rpx 0;
|
|
|
+}
|
|
|
+.card-dot {
|
|
|
width: 8rpx;
|
|
|
- background-color: #FF8C42;
|
|
|
+ height: 32rpx;
|
|
|
+ border-radius: 4rpx;
|
|
|
+ background: linear-gradient(180deg, #FF8C42, #FFB366);
|
|
|
+ margin-right: 16rpx;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
-.card-body {
|
|
|
- flex: 1;
|
|
|
- padding: 30rpx;
|
|
|
-}
|
|
|
.card-title {
|
|
|
font-size: 30rpx;
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
- margin-bottom: 20rpx;
|
|
|
- display: block;
|
|
|
}
|
|
|
-.section-header {
|
|
|
+.card-body {
|
|
|
+ padding: 24rpx 28rpx 28rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 共餐格子 */
|
|
|
+.meal-grid {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
+}
|
|
|
+.meal-item {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
align-items: center;
|
|
|
- margin-bottom: 20rpx;
|
|
|
+ background: #FFF8F0;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx 12rpx;
|
|
|
+ margin-left: 12rpx;
|
|
|
+ margin-right: 12rpx;
|
|
|
}
|
|
|
-.section-title {
|
|
|
- font-size: 28rpx;
|
|
|
+.meal-item:first-child {
|
|
|
+ margin-left: 0;
|
|
|
+}
|
|
|
+.meal-item:last-child {
|
|
|
+ margin-right: 0;
|
|
|
+}
|
|
|
+.meal-emoji {
|
|
|
+ font-size: 36rpx;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+}
|
|
|
+.meal-label {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 4rpx;
|
|
|
+}
|
|
|
+.meal-members {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #FF8C42;
|
|
|
font-weight: 600;
|
|
|
- color: #333;
|
|
|
}
|
|
|
-.action-btns {
|
|
|
+
|
|
|
+/* 操作按钮栏 */
|
|
|
+.action-bar {
|
|
|
display: flex;
|
|
|
- gap: 16rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+}
|
|
|
+.action-btn {
|
|
|
+ padding: 14rpx 24rpx;
|
|
|
+ border-radius: 32rpx;
|
|
|
+ background: #F5F5F5;
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+.action-btn:last-child {
|
|
|
+ margin-right: 0;
|
|
|
+}
|
|
|
+.action-btn-primary {
|
|
|
+ background: #FF8C42;
|
|
|
+}
|
|
|
+.action-btn-accent {
|
|
|
+ background: #FFF0E0;
|
|
|
+}
|
|
|
+.action-btn-disabled {
|
|
|
+ opacity: 0.4;
|
|
|
}
|
|
|
-.btn-secondary {
|
|
|
- padding: 12rpx 24rpx;
|
|
|
- border: 1rpx solid #ddd;
|
|
|
- border-radius: 30rpx;
|
|
|
+.action-btn-text {
|
|
|
font-size: 24rpx;
|
|
|
color: #666;
|
|
|
}
|
|
|
-.btn-primary {
|
|
|
- padding: 12rpx 24rpx;
|
|
|
- background-color: #FF8C42;
|
|
|
- color: #FFFFFF;
|
|
|
- border-radius: 30rpx;
|
|
|
+.action-btn-text-primary {
|
|
|
font-size: 24rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
}
|
|
|
-.btn-primary.disabled {
|
|
|
- background-color: #ccc;
|
|
|
+.action-btn-text-accent {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #FF8C42;
|
|
|
}
|
|
|
+
|
|
|
+/* 食材列表 */
|
|
|
.ingredient-list {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 16rpx;
|
|
|
+ margin-top: 8rpx;
|
|
|
}
|
|
|
.ingredient-item {
|
|
|
display: flex;
|
|
|
+ align-items: center;
|
|
|
justify-content: space-between;
|
|
|
+ padding: 20rpx 0;
|
|
|
+ border-bottom: 1rpx solid #F5F5F5;
|
|
|
+}
|
|
|
+.ingredient-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+.ingredient-left {
|
|
|
+ display: flex;
|
|
|
align-items: center;
|
|
|
- padding: 16rpx 0;
|
|
|
- border-bottom: 1rpx solid #f0f0f0;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.ingredient-badge {
|
|
|
+ width: 40rpx;
|
|
|
+ height: 40rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ background: linear-gradient(135deg, #FF8C42, #FFB366);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-right: 20rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.ingredient-badge-text {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
.ingredient-info {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- gap: 4rpx;
|
|
|
+ flex: 1;
|
|
|
}
|
|
|
.ingredient-name {
|
|
|
- font-size: 26rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
color: #333;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
.ingredient-reason {
|
|
|
font-size: 22rpx;
|
|
|
color: #999;
|
|
|
+ margin-top: 4rpx;
|
|
|
}
|
|
|
.ingredient-remove {
|
|
|
- width: 40rpx;
|
|
|
- height: 40rpx;
|
|
|
+ width: 48rpx;
|
|
|
+ height: 48rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999;
|
|
|
-}
|
|
|
-.meal-row {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- padding: 12rpx 0;
|
|
|
- border-bottom: 1rpx solid #f0f0f0;
|
|
|
-}
|
|
|
-.meal-label {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #666;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
-.meal-members {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #FF8C42;
|
|
|
- font-weight: 500;
|
|
|
+.remove-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #ccc;
|
|
|
}
|
|
|
-.empty-hint {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999;
|
|
|
- text-align: center;
|
|
|
- padding: 20rpx 0;
|
|
|
+
|
|
|
+/* 区域标签 */
|
|
|
+.section-label {
|
|
|
+ padding: 8rpx 0 16rpx;
|
|
|
}
|
|
|
-.empty-state {
|
|
|
- text-align: center;
|
|
|
- padding: 40rpx 0;
|
|
|
- font-size: 26rpx;
|
|
|
- color: #999;
|
|
|
+.section-label-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
}
|
|
|
+
|
|
|
+/* 快捷入口网格 */
|
|
|
.nav-grid {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
- justify-content: space-between;
|
|
|
- margin-bottom: 30rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
}
|
|
|
.nav-item {
|
|
|
- width: 30%;
|
|
|
- background-color: #FFFFFF;
|
|
|
- border-radius: 20rpx;
|
|
|
- padding: 30rpx 0;
|
|
|
- margin-bottom: 20rpx;
|
|
|
+ width: 20%;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
|
|
+ padding: 20rpx 0;
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
}
|
|
|
-.nav-icon {
|
|
|
- font-size: 48rpx;
|
|
|
+.nav-icon-wrap {
|
|
|
+ width: 88rpx;
|
|
|
+ height: 88rpx;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
margin-bottom: 12rpx;
|
|
|
}
|
|
|
+.nav-icon-green {
|
|
|
+ background: linear-gradient(135deg, #E8F5E9, #C8E6C9);
|
|
|
+}
|
|
|
+.nav-icon-blue {
|
|
|
+ background: linear-gradient(135deg, #E3F2FD, #BBDEFB);
|
|
|
+}
|
|
|
+.nav-icon-orange {
|
|
|
+ background: linear-gradient(135deg, #FFF3E0, #FFE0B2);
|
|
|
+}
|
|
|
+.nav-icon-purple {
|
|
|
+ background: linear-gradient(135deg, #F3E5F5, #E1BEE7);
|
|
|
+}
|
|
|
+.nav-icon-red {
|
|
|
+ background: linear-gradient(135deg, #FBE9E7, #FFCCBC);
|
|
|
+}
|
|
|
+.nav-icon {
|
|
|
+ font-size: 36rpx;
|
|
|
+}
|
|
|
.nav-label {
|
|
|
- font-size: 24rpx;
|
|
|
+ font-size: 22rpx;
|
|
|
color: #333;
|
|
|
}
|
|
|
-.trend-stats {
|
|
|
+
|
|
|
+/* 趋势卡片 */
|
|
|
+.trend-row {
|
|
|
display: flex;
|
|
|
- align-items: baseline;
|
|
|
- gap: 8rpx;
|
|
|
- margin-bottom: 16rpx;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.trend-item {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.trend-divider {
|
|
|
+ width: 1rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ background: #F0F0F0;
|
|
|
}
|
|
|
.trend-num {
|
|
|
font-size: 48rpx;
|
|
|
- font-weight: 600;
|
|
|
+ font-weight: 700;
|
|
|
color: #FF8C42;
|
|
|
}
|
|
|
.trend-unit {
|
|
|
- font-size: 24rpx;
|
|
|
+ font-size: 22rpx;
|
|
|
color: #999;
|
|
|
+ margin-top: 4rpx;
|
|
|
}
|
|
|
.trend-label {
|
|
|
- font-size: 24rpx;
|
|
|
+ font-size: 22rpx;
|
|
|
color: #666;
|
|
|
- margin-left: auto;
|
|
|
+ margin-top: 4rpx;
|
|
|
}
|
|
|
+
|
|
|
+/* 空状态 */
|
|
|
+.empty-hint {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20rpx 0;
|
|
|
+}
|
|
|
+.empty-state {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 40rpx 0;
|
|
|
+}
|
|
|
+.empty-icon {
|
|
|
+ font-size: 48rpx;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+}
|
|
|
+.empty-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.empty-sub {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #ccc;
|
|
|
+ margin-top: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 弹窗 */
|
|
|
.modal {
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
- background-color: rgba(0, 0, 0, 0.5);
|
|
|
+ z-index: 999;
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
+ align-items: flex-end;
|
|
|
justify-content: center;
|
|
|
- z-index: 999;
|
|
|
+}
|
|
|
+.modal-mask {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
}
|
|
|
.modal-content {
|
|
|
- width: 90%;
|
|
|
- max-height: 80%;
|
|
|
- background-color: #FFFFFF;
|
|
|
- border-radius: 20rpx;
|
|
|
- padding: 30rpx;
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ max-height: 80vh;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 32rpx 32rpx 0 0;
|
|
|
+ padding: 32rpx;
|
|
|
+ z-index: 1;
|
|
|
}
|
|
|
.modal-header {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
align-items: center;
|
|
|
- margin-bottom: 20rpx;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
}
|
|
|
.modal-title {
|
|
|
- font-size: 30rpx;
|
|
|
+ font-size: 32rpx;
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
}
|
|
|
.modal-close {
|
|
|
+ width: 48rpx;
|
|
|
+ height: 48rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.close-text {
|
|
|
font-size: 32rpx;
|
|
|
color: #999;
|
|
|
}
|
|
|
-.search-input {
|
|
|
- border: 1rpx solid #ddd;
|
|
|
- border-radius: 30rpx;
|
|
|
- padding: 16rpx 24rpx;
|
|
|
- font-size: 26rpx;
|
|
|
- background-color: #FAFAFA;
|
|
|
+.search-wrap {
|
|
|
margin-bottom: 20rpx;
|
|
|
}
|
|
|
+.search-input {
|
|
|
+ border: 1rpx solid #eee;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 20rpx 28rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ background: #F8F8F8;
|
|
|
+}
|
|
|
.food-list {
|
|
|
max-height: 500rpx;
|
|
|
- overflow-y: auto;
|
|
|
}
|
|
|
.food-item {
|
|
|
display: flex;
|
|
|
+ align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- padding: 20rpx 0;
|
|
|
- border-bottom: 1rpx solid #f0f0f0;
|
|
|
+ padding: 24rpx 0;
|
|
|
+ border-bottom: 1rpx solid #F5F5F5;
|
|
|
}
|
|
|
.food-name {
|
|
|
- font-size: 26rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
color: #333;
|
|
|
}
|
|
|
-.food-category {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999;
|
|
|
+.food-tag {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #FF8C42;
|
|
|
+ background: #FFF0E0;
|
|
|
+ padding: 6rpx 16rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 底部留白 */
|
|
|
+.bottom-space {
|
|
|
+ height: 40rpx;
|
|
|
}
|
|
|
</style>
|