fix: 测试反馈0403修改 — 百科Bug修复/份数→克数/AI对话增强/流式输出

1. [P0] food-encyclopedia: 修复 goToFoodDetail TypeError 报错
   - 增加 item 空值防御性校验
   - 加固 filteredFoodList 过滤无效项

2. [P1] calculator-result: 食物份数建议改为克数
   - 模板展示从"X份"改为"X克"
   - applyResult 数据适配:优先读 gram 字段,兜底 portion * gramPerServing 换算

3. [P2] ai-nutritionist: 新增消息操作按钮(复制/重新生成/删除)
   - AI消息气泡下方新增 msg-actions 按钮组
   - 复制到剪贴板、删除单条消息、重新生成最后一条AI回复

4. [P2] ai-nutritionist + models-api: 启用流式输出改善响应速度
   - 新增 kieaiGeminiChatStream 函数(SSE + enableChunked)
   - sendToAI 优先走流式,失败自动降级为非流式

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
msh-agent
2026-04-11 15:20:10 +08:00
parent 2facd355ab
commit dce899f655
4 changed files with 1124 additions and 156 deletions

View File

@@ -87,27 +87,27 @@
</view>
<view class="nutrition-hint">
<text class="hint-icon">💡</text>
<text class="hint-text">相当于下方表中食物的推荐摄入量</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>
<text class="card-title">每日食物建议</text>
</view>
<view class="food-list">
<view
class="food-item"
v-for="(item, index) in foodList"
<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>
<text class="food-portion">{{ item.gram || item.portion }} </text>
</view>
</view>
</view>
@@ -335,7 +335,11 @@ export default {
}
}
if (Array.isArray(data.foodList)) {
this.foodList = data.foodList
// 份数→克数适配:优先使用 gram 字段,兜底通过 portion * gramPerServing 换算
this.foodList = data.foodList.map(item => ({
...item,
gram: item.gram || (item.portion && item.gramPerServing ? Math.round(item.portion * item.gramPerServing) : null)
}))
}
if (data.mealPlan) {
this.mealPlan = {
@@ -472,52 +476,57 @@ export default {
display: flex;
padding: 0 32rpx;
height: 96rpx;
align-items: center;
/* stretchTab 占满栏高,激活态 border-bottom 才能贴底显示BUG-002 */
align-items: stretch;
position: sticky;
// top: 88rpx;
z-index: 99;
}
/* Tab未激活灰字、透明底边占位无可见下划线激活加粗+主色+橙色底边BUG-002 */
.tab-item {
flex: 1;
height: 100%;
min-height: 75rpx;
min-height: 0;
border-radius: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
transition: all 0.2s ease;
box-sizing: border-box;
/* 未激活明显变灰无下划线BUG-002 */
color: #9ca3af;
font-weight: 400;
border-bottom: 3rpx solid transparent;
.tab-icon {
font-size: 28rpx;
color: inherit;
font-weight: inherit;
}
.tab-text {
font-size: 28rpx;
color: inherit;
font-weight: inherit;
}
/* 激活加粗、主色、橙色底部下划线BUG-002 */
&.active {
background: transparent;
color: #f97316;
font-weight: 700;
border-bottom: 3px solid #f97316;
.tab-text {
color: #f97316;
font-weight: 700;
}
.tab-icon {
color: #f97316;
font-weight: 700;
}
}
text-decoration: none;
border-bottom: 3px solid transparent;
transition: color 0.2s ease, border-color 0.2s ease;
}
.tab-item .tab-icon,
.tab-item .tab-text {
font-size: 28rpx;
}
/* 未激活:灰字、常规字重(显式写到 text 节点,避免小程序不继承 view 颜色) */
.tab-item:not(.active) .tab-icon,
.tab-item:not(.active) .tab-text {
color: #9ca3af;
font-weight: 400;
text-decoration: none;
}
/* 激活:粗体、主色、橙色底边(与未激活同宽底边,避免切换时跳动) */
.tab-item.active {
background: transparent;
color: #f97316;
font-weight: 700;
text-decoration: none;
border-bottom: 3px solid #f97316;
}
.tab-item.active .tab-icon,
.tab-item.active .tab-text {
color: #f97316;
font-weight: 700;
text-decoration: none;
}
/* 内容滚动区域 */