feat: 使用Coze工作流自动补齐帖子营养数据
- 后端: fillNutrition()改用Coze工作流7613879935811354687分析营养成分
- 后端: 新增parseWorkflowResponse/nestedToFlat解析工作流响应
- 前端: 页面加载时自动检测并补齐不完整的营养统计
- 修复: ToolKnowledgeServiceImpl编译错误(Integer转Long)
工作流输出格式: output.{calories,protein,potassium,phosphorus}.{value,unit}
This commit is contained in:
@@ -385,7 +385,7 @@ export default {
|
||||
buildNutritionStatsFromDetailData(data) {
|
||||
if (!data) return []
|
||||
|
||||
// 1) 后端直接返回的 stat 数组(兼容不同命名)
|
||||
// 1) 后端直接返回的 stat 数组或对象(兼容不同命名)
|
||||
const rawStats = data.nutritionStats || data.nutrition_stats
|
||||
if (Array.isArray(rawStats) && rawStats.length > 0) {
|
||||
const mapped = rawStats.map(s => ({
|
||||
@@ -398,6 +398,11 @@ export default {
|
||||
}
|
||||
return mapped
|
||||
}
|
||||
// 1b) 后端返回 nutritionStats 为对象(如 { protein: 56, calories: 200 })时按营养对象解析
|
||||
if (rawStats && typeof rawStats === 'object' && !Array.isArray(rawStats) && Object.keys(rawStats).length > 0) {
|
||||
const statsFromObj = this.buildNutritionStatsFromNutritionObject(rawStats)
|
||||
if (statsFromObj.length > 0 && !statsFromObj.every(s => s.value === '-')) return statsFromObj
|
||||
}
|
||||
|
||||
// 2) nutritionDataJson / nutrition_data_json(兼容后端驼峰与下划线;含 fill-nutrition 的 energyKcal/proteinG/potassiumMg/phosphorusMg、打卡字段 actualEnergy/actualProtein)
|
||||
const jsonRaw = data.nutritionDataJson || data.nutrition_data_json
|
||||
@@ -454,13 +459,42 @@ export default {
|
||||
return []
|
||||
},
|
||||
|
||||
/** 从单一营养对象构建 [{label, value}, ...],统一兼容 energyKcal/proteinG/potassiumMg/phosphorusMg 及 calories/protein、下划线命名 */
|
||||
/**
|
||||
* 从对象中取数值,兼容后端嵌套格式 { calories: { value, unit } } 与扁平格式 energyKcal/proteinG
|
||||
* 嵌套 value 支持 number 或 string(后端 BigDecimal 等可能序列化为字符串)
|
||||
*/
|
||||
readNutritionNumber(obj, ...flatKeys) {
|
||||
if (!obj || typeof obj !== 'object') return null
|
||||
for (const key of flatKeys) {
|
||||
const v = obj[key]
|
||||
if (v == null) continue
|
||||
if (typeof v === 'number' && !Number.isNaN(v)) return v
|
||||
// 嵌套格式 { value, unit }:value 可能为 number 或 string
|
||||
if (typeof v === 'object' && v !== null && 'value' in v) {
|
||||
const val = v.value
|
||||
if (typeof val === 'number' && !Number.isNaN(val)) return val
|
||||
const str = typeof val === 'string' ? val.trim() : (val != null ? String(val) : '')
|
||||
if (str !== '' && str !== 'undefined' && str !== 'null') {
|
||||
const n = parseFloat(str)
|
||||
if (!Number.isNaN(n)) return n
|
||||
}
|
||||
}
|
||||
const s = typeof v === 'string' ? v.trim() : String(v)
|
||||
if (s !== '' && s !== 'undefined' && s !== 'null') {
|
||||
const n = parseFloat(s)
|
||||
if (!Number.isNaN(n)) return n
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
|
||||
/** 从单一营养对象构建 [{label, value}, ...],统一兼容 energyKcal/proteinG、嵌套 calories: { value, unit }、下划线命名 */
|
||||
buildNutritionStatsFromNutritionObject(obj) {
|
||||
if (!obj || typeof obj !== 'object') return []
|
||||
const cal = obj.energyKcal ?? obj.energy_kcal ?? obj.calories ?? obj.energy ?? obj.calorie ?? obj.actualEnergy
|
||||
const pro = obj.proteinG ?? obj.protein_g ?? obj.protein ?? obj.proteins ?? obj.actualProtein
|
||||
const pot = obj.potassiumMg ?? obj.potassium_mg ?? obj.potassium ?? obj.k
|
||||
const pho = obj.phosphorusMg ?? obj.phosphorus_mg ?? obj.phosphorus ?? obj.p
|
||||
const cal = this.readNutritionNumber(obj, 'energyKcal', 'energy_kcal', 'calories', 'energy', 'calorie', 'actualEnergy')
|
||||
const pro = this.readNutritionNumber(obj, 'proteinG', 'protein_g', 'protein', 'proteins', 'actualProtein')
|
||||
const pot = this.readNutritionNumber(obj, 'potassiumMg', 'potassium_mg', 'potassium', 'k')
|
||||
const pho = this.readNutritionNumber(obj, 'phosphorusMg', 'phosphorus_mg', 'phosphorus', 'p')
|
||||
return [
|
||||
{ label: '热量(kcal)', value: cal != null ? String(cal) : '-' },
|
||||
{ label: '蛋白质', value: this.formatNutritionValue(pro, 'g') },
|
||||
@@ -548,8 +582,9 @@ export default {
|
||||
const data = (res && res.data !== undefined && res.data !== null) ? res.data : res
|
||||
if (!data) return
|
||||
const stats = this.buildNutritionStatsFromDetailData(data)
|
||||
if (stats.length > 0) {
|
||||
if (stats.length > 0 && !stats.every(s => s.value === '-' || s.value === '')) {
|
||||
this.$set(this.postData, 'nutritionStats', stats)
|
||||
console.log('[post-detail] 营养数据已补齐:', stats)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('服务端填充帖子营养失败:', e)
|
||||
|
||||
Reference in New Issue
Block a user