feat: 更新前端多个页面和后端服务
- 前端: 更新AI营养师、计算器、打卡、食物详情等页面 - 前端: 更新食物百科、知识详情、营养知识页面 - 前端: 更新社区首页 - 后端: 更新ToolKieAIServiceImpl服务 - API: 更新models-api.js和user.js
This commit is contained in:
@@ -14,13 +14,13 @@
|
||||
<scroll-view class="content-scroll" scroll-y>
|
||||
<!-- 食物大图 -->
|
||||
<view class="food-image-section">
|
||||
<image class="food-image" :src="foodData.image || defaultFoodData.image" mode="aspectFill"></image>
|
||||
<image class="food-image" :src="displayImage" mode="aspectFill"></image>
|
||||
<view class="image-overlay"></view>
|
||||
<view class="food-info-overlay">
|
||||
<view class="food-name-overlay">{{ foodData.name || '—' }}</view>
|
||||
<view class="food-name-overlay">{{ displayName }}</view>
|
||||
<view class="food-tags">
|
||||
<view class="food-tag category">{{ foodData.category || '—' }}</view>
|
||||
<view class="food-tag safe">{{ foodData.safetyTag || '—' }}</view>
|
||||
<view class="food-tag category">{{ displayCategory }}</view>
|
||||
<view class="food-tag safe">{{ displaySafetyTag }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -34,7 +34,7 @@
|
||||
<view class="key-nutrients-grid">
|
||||
<view
|
||||
class="nutrient-card"
|
||||
v-for="(nutrient, index) in foodData.keyNutrients"
|
||||
v-for="(nutrient, index) in displayKeyNutrients"
|
||||
:key="index"
|
||||
>
|
||||
<text class="nutrient-name">{{ nutrient.name }}</text>
|
||||
@@ -56,7 +56,7 @@
|
||||
<view class="nutrition-table">
|
||||
<view
|
||||
class="nutrition-row"
|
||||
v-for="(item, index) in foodData.nutritionTable"
|
||||
v-for="(item, index) in displayNutritionTable"
|
||||
:key="index"
|
||||
>
|
||||
<view class="nutrition-left">
|
||||
@@ -132,21 +132,58 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 保证 .food-name-overlay / .nutrient-card / .nutrition-row 在 defaultFoodData 状态下也有非空数据可渲染
|
||||
displayName() {
|
||||
return (this.foodData && this.foodData.name) ? this.foodData.name : (this.defaultFoodData.name || '—')
|
||||
},
|
||||
displayCategory() {
|
||||
return (this.foodData && this.foodData.category) ? this.foodData.category : (this.defaultFoodData.category || '—')
|
||||
},
|
||||
displaySafetyTag() {
|
||||
return (this.foodData && this.foodData.safetyTag) ? this.foodData.safetyTag : (this.defaultFoodData.safetyTag || '—')
|
||||
},
|
||||
displayImage() {
|
||||
return (this.foodData && this.foodData.image) ? this.foodData.image : (this.defaultFoodData.image || '')
|
||||
},
|
||||
displayKeyNutrients() {
|
||||
const arr = this.foodData && this.foodData.keyNutrients
|
||||
if (Array.isArray(arr) && arr.length > 0) return arr
|
||||
const def = this.defaultFoodData.keyNutrients
|
||||
return Array.isArray(def) && def.length > 0 ? def : [{ name: '—', value: '—', unit: '', status: '—' }]
|
||||
},
|
||||
displayNutritionTable() {
|
||||
const arr = this.foodData && this.foodData.nutritionTable
|
||||
if (Array.isArray(arr) && arr.length > 0) return arr
|
||||
const def = this.defaultFoodData.nutritionTable
|
||||
return Array.isArray(def) && def.length > 0 ? def : [{ name: '—', value: '—', unit: '', level: 'low', levelText: '—' }]
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.pageParams = { id: options.id || '', name: options.name || '' }
|
||||
options = options || {}
|
||||
// 若列表误将 name 传成 id(如 id=羊肉(熟)),用 id 作为展示用 name,避免请求接口 400
|
||||
const rawId = options.id
|
||||
const rawName = options.name
|
||||
const hasNonNumericId = rawId !== undefined && rawId !== '' && isNaN(Number(rawId))
|
||||
const displayName = rawName || (hasNonNumericId ? rawId : '')
|
||||
this.pageParams = {
|
||||
id: (rawId !== undefined && rawId !== '') ? String(rawId) : '',
|
||||
name: (displayName !== undefined && displayName !== '') ? String(displayName) : ''
|
||||
}
|
||||
// 打印入参便于排查:后端详情接口仅接受 Long 类型 id,传 name 会导致 400
|
||||
console.log('[food-detail] onLoad options:', options)
|
||||
console.log('[food-detail] onLoad pageParams (id/name):', this.pageParams)
|
||||
const rawId = options.id
|
||||
const isNumericId = rawId !== undefined && rawId !== '' && !isNaN(Number(rawId))
|
||||
if (isNumericId) {
|
||||
this.loadFoodData(Number(rawId))
|
||||
} else if (options.name) {
|
||||
// 无有效 id 仅有 name 时,不请求接口(避免传 name 导致后端 NumberFormatException),直接展示默认数据 + 当前名称
|
||||
const numId = Number(rawId)
|
||||
console.log('[food-detail] 使用数字 id 请求详情,不传 name 字段:', numId)
|
||||
this.loadFoodData(numId)
|
||||
} else if (this.pageParams.name) {
|
||||
// 无有效 id、仅有 name 时,不请求接口(避免传 name 导致后端 NumberFormatException),直接展示默认数据 + 当前名称
|
||||
this.loadError = '暂无该食物详情数据,展示参考数据'
|
||||
this.applyDefaultFoodData(false)
|
||||
try {
|
||||
this.foodData.name = decodeURIComponent(String(options.name))
|
||||
this.foodData.name = decodeURIComponent(this.pageParams.name)
|
||||
} catch (e) {}
|
||||
} else {
|
||||
this.applyDefaultFoodData()
|
||||
@@ -192,8 +229,10 @@ export default {
|
||||
console.log('[food-detail] getFoodDetail request param:', { id, type: typeof id })
|
||||
try {
|
||||
const res = await getFoodDetail(id)
|
||||
const data = res.data || res
|
||||
console.log('[food-detail] getFoodDetail 响应:', data ? { hasName: !!data.name, hasImage: !!data.image, keys: Object.keys(data) } : null)
|
||||
// 打印响应结构便于确认:request 成功时 resolve 的是 res.data,即 { code: 200, data: {...} }
|
||||
console.log('[food-detail] getFoodDetail 响应结构:', res ? { hasData: !!res.data, code: res.code, keys: Object.keys(res || {}) } : null)
|
||||
const data = res.data != null ? res.data : res
|
||||
console.log('[food-detail] getFoodDetail 解析后 data:', data ? { hasName: !!data.name, hasImage: !!data.image, keys: Object.keys(data) } : null)
|
||||
if (data && data.name) {
|
||||
// 解析API返回的食物数据
|
||||
this.foodData = {
|
||||
@@ -219,12 +258,14 @@ export default {
|
||||
uni.showToast({ title: '数据加载失败', icon: 'none' })
|
||||
}
|
||||
} catch (error) {
|
||||
const errMsg = (error && (error.message || error.msg || error.errMsg || error)) ? String(error.message || error.msg || error.errMsg || error) : '未知错误'
|
||||
// a. 将 loadError 置为具体错误信息(用于调试):兼容 Error、{ message/msg }、字符串
|
||||
const errMsg = (error && (error.message || error.msg || error.errMsg))
|
||||
? String(error.message || error.msg || error.errMsg)
|
||||
: (typeof error === 'string' ? error : (error ? String(error) : '未知错误'))
|
||||
console.error('[food-detail] 加载食物数据失败:', error)
|
||||
console.error('[food-detail] loadError(用于调试):', errMsg)
|
||||
// a. 将 loadError 置为具体错误信息(用于调试)
|
||||
this.loadError = errMsg
|
||||
// b. 使用 defaultFoodData 填充页面,保证用户能看到基础界面;不清空 loadError 以便展示「当前数据来自缓存」提示
|
||||
// b. 使用 defaultFoodData 填充页面,保证用户能看到基础界面而不是空白
|
||||
this.applyDefaultFoodData(false)
|
||||
// 若有入参 name,用其覆盖展示名称,避免显示默认「五谷香」
|
||||
if (this.pageParams && this.pageParams.name) {
|
||||
@@ -232,7 +273,7 @@ export default {
|
||||
this.foodData.name = decodeURIComponent(String(this.pageParams.name))
|
||||
} catch (e) {}
|
||||
}
|
||||
// c. 页面已通过 v-if="loadError" 显示「当前数据来自缓存,可能不是最新」;再弹出轻提示
|
||||
// c. 页面通过 v-if="loadError" 显示「当前数据来自缓存,可能不是最新」;再弹出轻提示
|
||||
uni.showToast({
|
||||
title: '数据加载失败',
|
||||
icon: 'none'
|
||||
|
||||
Reference in New Issue
Block a user