Initial commit: MSH System\n\n- msh_single_uniapp: Vue 2 + UniApp 前端(微信小程序/H5/App/支付宝小程序)\n- msh_crmeb_22: Spring Boot 2.2 后端(C端API/管理端/业务逻辑)\n- models-integration: AI服务集成(Coze/KieAI/腾讯ASR)\n- docs: 产品文档与设计稿
This commit is contained in:
534
msh_single_uniapp/pages/tool/food-encyclopedia.vue
Normal file
534
msh_single_uniapp/pages/tool/food-encyclopedia.vue
Normal file
@@ -0,0 +1,534 @@
|
||||
<template>
|
||||
<view class="food-page">
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-container">
|
||||
<view class="search-box">
|
||||
<text class="search-icon">🔍</text>
|
||||
<input
|
||||
class="search-input"
|
||||
v-model="searchText"
|
||||
placeholder="搜索食物名称..."
|
||||
placeholder-style="color: #9fa5c0"
|
||||
@input="handleSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分类标签 -->
|
||||
<scroll-view class="category-scroll" scroll-x>
|
||||
<view class="category-list">
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'all' }"
|
||||
@click="selectCategory('all')"
|
||||
>
|
||||
<text>全部</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'grain' }"
|
||||
@click="selectCategory('grain')"
|
||||
>
|
||||
<text class="category-icon">🌾</text>
|
||||
<text>谷薯类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'vegetable' }"
|
||||
@click="selectCategory('vegetable')"
|
||||
>
|
||||
<text class="category-icon">🥬</text>
|
||||
<text>蔬菜类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'fruit' }"
|
||||
@click="selectCategory('fruit')"
|
||||
>
|
||||
<text class="category-icon">🍎</text>
|
||||
<text>水果类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'meat' }"
|
||||
@click="selectCategory('meat')"
|
||||
>
|
||||
<text class="category-icon">🍖</text>
|
||||
<text>肉蛋类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'seafood' }"
|
||||
@click="selectCategory('seafood')"
|
||||
>
|
||||
<text class="category-icon">🐟</text>
|
||||
<text>水产类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'dairy' }"
|
||||
@click="selectCategory('dairy')"
|
||||
>
|
||||
<text class="category-icon">🥛</text>
|
||||
<text>奶类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'bean' }"
|
||||
@click="selectCategory('bean')"
|
||||
>
|
||||
<text class="category-icon">🫘</text>
|
||||
<text>豆类</text>
|
||||
</view>
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: currentCategory === 'nut' }"
|
||||
@click="selectCategory('nut')"
|
||||
>
|
||||
<text class="category-icon">🥜</text>
|
||||
<text>坚果类</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 食物列表 -->
|
||||
<scroll-view class="food-scroll" scroll-y>
|
||||
<view class="food-list-container">
|
||||
<view class="food-count">共 {{ filteredFoodList.length }} 种食物</view>
|
||||
<view class="food-list">
|
||||
<view
|
||||
class="food-item"
|
||||
v-for="(item, index) in filteredFoodList"
|
||||
:key="index"
|
||||
@click="goToFoodDetail(item)"
|
||||
>
|
||||
<view class="food-image-wrapper">
|
||||
<image class="food-image" :src="item.image" mode="aspectFill"></image>
|
||||
<view v-if="item.warning" class="warning-badge">⚠️</view>
|
||||
</view>
|
||||
<view class="food-info">
|
||||
<view class="food-header">
|
||||
<view class="food-name-wrapper">
|
||||
<text class="food-name">{{ item.name }}</text>
|
||||
<view class="safety-tag" :class="item.safetyClass">
|
||||
<text>{{ item.safety }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="category-badge">
|
||||
<text>{{ item.category }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nutrition-list">
|
||||
<view
|
||||
class="nutrition-item"
|
||||
v-for="(nut, idx) in item.nutrition"
|
||||
:key="idx"
|
||||
>
|
||||
<text class="nutrition-label">{{ nut.label }}</text>
|
||||
<text class="nutrition-value" :class="nut.colorClass">{{ nut.value }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchText: '',
|
||||
currentCategory: 'all',
|
||||
searchTimer: null,
|
||||
foodList: [
|
||||
{
|
||||
name: '香蕉',
|
||||
category: '水果类',
|
||||
safety: '谨慎吃',
|
||||
safetyClass: 'careful',
|
||||
image: 'https://www.figma.com/api/mcp/asset/480782b7-5802-454c-9021-fad8cce6c195',
|
||||
warning: true,
|
||||
nutrition: [
|
||||
{ label: '蛋白质', value: '1.4g', colorClass: 'green' },
|
||||
{ label: '钾', value: '330mg', colorClass: 'red' },
|
||||
{ label: '磷', value: '28mg', colorClass: 'orange' }
|
||||
],
|
||||
categoryType: 'fruit'
|
||||
},
|
||||
{
|
||||
name: '玉米笋(罐头)',
|
||||
category: '蔬菜类',
|
||||
safety: '放心吃',
|
||||
safetyClass: 'safe',
|
||||
image: 'https://www.figma.com/api/mcp/asset/59db0f38-437e-4dfa-8fc6-d3eb6d2e9840',
|
||||
warning: false,
|
||||
nutrition: [
|
||||
{ label: '钾', value: '36mg', colorClass: 'green' },
|
||||
{ label: '钙', value: '6mg', colorClass: 'green' },
|
||||
{ label: '磷', value: '4mg', colorClass: 'green' }
|
||||
],
|
||||
categoryType: 'vegetable'
|
||||
},
|
||||
{
|
||||
name: '五谷香',
|
||||
category: '谷薯类',
|
||||
safety: '放心吃',
|
||||
safetyClass: 'safe',
|
||||
image: 'https://www.figma.com/api/mcp/asset/61347bd7-1ab4-485f-b8d0-09c7ede49fe6',
|
||||
warning: false,
|
||||
nutrition: [
|
||||
{ label: '钾', value: '7mg', colorClass: 'green' },
|
||||
{ label: '钙', value: '2mg', colorClass: 'green' },
|
||||
{ label: '磷', value: '13mg', colorClass: 'green' }
|
||||
],
|
||||
categoryType: 'grain'
|
||||
},
|
||||
{
|
||||
name: '糯米粥',
|
||||
category: '谷薯类',
|
||||
safety: '放心吃',
|
||||
safetyClass: 'safe',
|
||||
image: 'https://www.figma.com/api/mcp/asset/cf95c2ea-9fb0-4e40-b134-39873207f769',
|
||||
warning: false,
|
||||
nutrition: [
|
||||
{ label: '钾', value: '13mg', colorClass: 'green' },
|
||||
{ label: '钙', value: '7mg', colorClass: 'green' },
|
||||
{ label: '磷', value: '20mg', colorClass: 'green' }
|
||||
],
|
||||
categoryType: 'grain'
|
||||
},
|
||||
{
|
||||
name: '苹果',
|
||||
category: '水果类',
|
||||
safety: '限量吃',
|
||||
safetyClass: 'limited',
|
||||
image: 'https://www.figma.com/api/mcp/asset/4bc870ef-b16d-496b-b9ed-16f2cb9a53e1',
|
||||
warning: false,
|
||||
nutrition: [
|
||||
{ label: '蛋白质', value: '0.4g', colorClass: 'green' },
|
||||
{ label: '钾', value: '119mg', colorClass: 'orange' },
|
||||
{ label: '磷', value: '12mg', colorClass: 'green' }
|
||||
],
|
||||
categoryType: 'fruit'
|
||||
},
|
||||
{
|
||||
name: '西兰花',
|
||||
category: '蔬菜类',
|
||||
safety: '谨慎吃',
|
||||
safetyClass: 'careful',
|
||||
image: 'https://www.figma.com/api/mcp/asset/eb858cbc-78cb-46b1-a9a6-8cc9684dabba',
|
||||
warning: false,
|
||||
nutrition: [
|
||||
{ label: '蛋白质', value: '4.1g', colorClass: 'orange' },
|
||||
{ label: '钾', value: '316mg', colorClass: 'red' },
|
||||
{ label: '磷', value: '72mg', colorClass: 'red' }
|
||||
],
|
||||
categoryType: 'vegetable'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredFoodList() {
|
||||
return this.foodList
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options && options.category) {
|
||||
this.currentCategory = options.category;
|
||||
}
|
||||
this.loadFoodList();
|
||||
},
|
||||
methods: {
|
||||
async loadFoodList() {
|
||||
try {
|
||||
const { getFoodList } = await import('@/api/tool.js');
|
||||
const result = await getFoodList({
|
||||
category: this.currentCategory === 'all' ? '' : this.currentCategory,
|
||||
page: 1,
|
||||
limit: 100
|
||||
});
|
||||
if (result.data && result.data.list) {
|
||||
this.foodList = result.data.list;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载食物列表失败:', error);
|
||||
}
|
||||
},
|
||||
async selectCategory(category) {
|
||||
this.currentCategory = category;
|
||||
// 切换分类时清空搜索文本,避免搜索状态与分类状态冲突
|
||||
this.searchText = '';
|
||||
if (this.searchTimer) {
|
||||
clearTimeout(this.searchTimer);
|
||||
}
|
||||
await this.loadFoodList();
|
||||
},
|
||||
handleSearch() {
|
||||
// 防抖:300ms 内不重复触发搜索请求
|
||||
if (this.searchTimer) {
|
||||
clearTimeout(this.searchTimer);
|
||||
}
|
||||
this.searchTimer = setTimeout(async () => {
|
||||
if (this.searchText.trim()) {
|
||||
try {
|
||||
const { searchFood } = await import('@/api/tool.js');
|
||||
const result = await searchFood({
|
||||
keyword: this.searchText.trim(),
|
||||
page: 1,
|
||||
limit: 100
|
||||
});
|
||||
if (result.data && result.data.list) {
|
||||
this.foodList = result.data.list;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索失败:', error);
|
||||
}
|
||||
} else {
|
||||
await this.loadFoodList();
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
goToFoodDetail(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/tool/food-detail?id=${item.name}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.food-page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f4f5f7;
|
||||
}
|
||||
|
||||
/* 搜索框 */
|
||||
.search-container {
|
||||
background: #ffffff;
|
||||
padding: 32rpx;
|
||||
border-bottom: 1rpx solid #d0dbea;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
background: #ffffff;
|
||||
border: 1rpx solid #d0dbea;
|
||||
border-radius: 50rpx;
|
||||
padding: 0 32rpx;
|
||||
|
||||
.search-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
color: #3e5481;
|
||||
}
|
||||
}
|
||||
|
||||
/* 分类标签 */
|
||||
.category-scroll {
|
||||
background: #ffffff;
|
||||
border-bottom: 1rpx solid #d0dbea;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.category-list {
|
||||
display: flex;
|
||||
padding: 32rpx;
|
||||
gap: 16rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
height: 67rpx;
|
||||
padding: 0 32rpx;
|
||||
border-radius: 50rpx;
|
||||
border: 1rpx solid #d0dbea;
|
||||
background: #ffffff;
|
||||
white-space: nowrap;
|
||||
|
||||
.category-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
color: #9fa5c0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #ff6b35;
|
||||
border-color: #ff6b35;
|
||||
|
||||
text {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 食物列表 */
|
||||
.food-scroll {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.food-list-container {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.food-count {
|
||||
font-size: 28rpx;
|
||||
color: #9fa5c0;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.food-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.food-item {
|
||||
background: #ffffff;
|
||||
border: 1rpx solid #d0dbea;
|
||||
border-radius: 32rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.food-image-wrapper {
|
||||
position: relative;
|
||||
width: 192rpx;
|
||||
height: 192rpx;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
background: #f4f5f7;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.food-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.warning-badge {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
left: 8rpx;
|
||||
background: #ff6464;
|
||||
border-radius: 12rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.food-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.food-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.food-name-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.food-name {
|
||||
font-size: 28rpx;
|
||||
color: #2e3e5c;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.safety-tag {
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 50rpx;
|
||||
font-size: 24rpx;
|
||||
|
||||
&.safe {
|
||||
background: #e3fff1;
|
||||
color: #1fcc79;
|
||||
}
|
||||
|
||||
&.careful {
|
||||
background: #ffe8e8;
|
||||
color: #ff6464;
|
||||
}
|
||||
|
||||
&.limited {
|
||||
background: #fff8e1;
|
||||
color: #ff9800;
|
||||
}
|
||||
}
|
||||
|
||||
.category-badge {
|
||||
background: #fff5f0;
|
||||
border: 1rpx solid #ff6b35;
|
||||
border-radius: 12rpx;
|
||||
padding: 4rpx 16rpx;
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #ff6b35;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.nutrition-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.nutrition-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.nutrition-label {
|
||||
font-size: 24rpx;
|
||||
color: #9fa5c0;
|
||||
}
|
||||
|
||||
.nutrition-value {
|
||||
font-size: 24rpx;
|
||||
|
||||
&.green {
|
||||
color: #1fcc79;
|
||||
}
|
||||
|
||||
&.red {
|
||||
color: #ff6464;
|
||||
}
|
||||
|
||||
&.orange {
|
||||
color: #ff9800;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user