feat: 集成 KieAI 服务,移除 models-integration 子项目
- 添加 Gemini 2.5 Flash 对话接口(流式+非流式) - 添加 NanoBanana 图像生成/编辑接口 - 添加 Sora2 视频生成接口(文生视频、图生视频、去水印) - 移除 models-integration 子项目(功能已迁移至主后端) - 新增测试文档和 Playwright E2E 配置 - 更新前端页面和 API 接口 - 更新后端配置和日志处理
This commit is contained in:
251
scripts/fix-bugs-scheduled.sh
Executable file
251
scripts/fix-bugs-scheduled.sh
Executable file
@@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# MSH Bug 自动修复 + 回归测试 定时任务主脚本
|
||||
#
|
||||
# 对应 bug 清单(来自手工测试报告 + Playwright 回归结果):
|
||||
# BUG-001 打卡积分显示提前跳变 & 累加逻辑未生效
|
||||
# BUG-002 食谱计算器结果页 Tab 选中样式不明显
|
||||
# BUG-003 食物百科列表缺配图与营养简介
|
||||
# BUG-004 食物百科详情页提示「数据加载失败」
|
||||
# BUG-005 AI 营养师始终返回固定默认答复
|
||||
# BUG-006 「健康知识」与「营养知识」名称不统一
|
||||
# BUG-007 饮食指南 / 科普文章详情页无任何内容
|
||||
# BUG-008 帖子详情页营养统计数据未显示
|
||||
# BUG-009 社区帖子类型命名未统一为中文
|
||||
#
|
||||
# 总时间估算(含 Playwright 验证):≤ 5 h
|
||||
# 执行顺序:先修快速项(风险低),后修复杂项,最后全量回归
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ─── 路径配置 ──────────────────────────────────────────────────────────────
|
||||
WORKSPACE="/Users/apple/scott2026/msh-system"
|
||||
SCRIPTS_DIR="$WORKSPACE/scripts"
|
||||
LOG_DIR="$WORKSPACE/scripts/logs"
|
||||
CURSOR="/Applications/Cursor.app/Contents/Resources/app/bin/cursor"
|
||||
PW="npx playwright test tests/e2e/bug-regression.spec.ts --project=mobile-chrome --reporter=list"
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
MAIN_LOG="$LOG_DIR/fix-bugs-$(date '+%Y%m%d_%H%M').log"
|
||||
LOCK_FILE="$LOG_DIR/fix-bugs.lock"
|
||||
|
||||
# ─── 锁:防止多实例并发 ────────────────────────────────────────────────────
|
||||
if [ -e "$LOCK_FILE" ]; then
|
||||
echo "[SKIP] 已有一个修复任务在运行 (lock: $LOCK_FILE),退出。" >&2
|
||||
exit 0
|
||||
fi
|
||||
trap 'rm -f "$LOCK_FILE"' EXIT
|
||||
touch "$LOCK_FILE"
|
||||
|
||||
# ─── 日志工具 ─────────────────────────────────────────────────────────────
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$MAIN_LOG"; }
|
||||
phase() {
|
||||
echo "" | tee -a "$MAIN_LOG"
|
||||
echo "═══════════════════════════════════════════════" | tee -a "$MAIN_LOG"
|
||||
log "▶ $*"
|
||||
echo "═══════════════════════════════════════════════" | tee -a "$MAIN_LOG"
|
||||
}
|
||||
|
||||
# ─── Cursor Agent 调用工具 ────────────────────────────────────────────────
|
||||
# 参数: $1=bug_id $2=prompt文本
|
||||
run_agent() {
|
||||
local bug_id="$1"
|
||||
local prompt="$2"
|
||||
local agent_log="$LOG_DIR/agent-${bug_id}-$(date '+%H%M%S').log"
|
||||
|
||||
log "[${bug_id}] 启动 Cursor Agent 修复..."
|
||||
"$CURSOR" agent --print --trust --model auto \
|
||||
--workspace "$WORKSPACE" \
|
||||
"$prompt" 2>&1 | tee -a "$agent_log" >> "$MAIN_LOG" || true
|
||||
log "[${bug_id}] Agent 执行完成 → $agent_log"
|
||||
}
|
||||
|
||||
# ─── Playwright 局部验证 ──────────────────────────────────────────────────
|
||||
# 参数: $1=grep_pattern (匹配用例名)
|
||||
run_partial_test() {
|
||||
local pattern="$1"
|
||||
log "[TEST] 验证: $pattern"
|
||||
cd "$WORKSPACE"
|
||||
$PW --grep "$pattern" 2>&1 | tee -a "$MAIN_LOG" || true
|
||||
}
|
||||
|
||||
# ─── 全量回归 ────────────────────────────────────────────────────────────
|
||||
run_full_regression() {
|
||||
log "[TEST] 全量回归测试..."
|
||||
cd "$WORKSPACE"
|
||||
$PW 2>&1 | tee -a "$MAIN_LOG" || true
|
||||
log "[TEST] 全量回归完成,报告: tests/e2e/reports/index.html"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# 开始
|
||||
# =============================================================================
|
||||
|
||||
START_TS=$(date +%s)
|
||||
phase "阶段 0 — 基线确认(运行回归测试,记录当前失败情况)"
|
||||
# 软失败:仅记录,不中断脚本
|
||||
cd "$WORKSPACE"
|
||||
$PW 2>&1 | tee -a "$MAIN_LOG" || true
|
||||
log "基线记录完成"
|
||||
|
||||
# =============================================================================
|
||||
# 阶段 1:快速修复(~60 min)
|
||||
# BUG-002 Tab 样式 | BUG-006 名称统一 | BUG-009 中文命名
|
||||
# =============================================================================
|
||||
|
||||
phase "阶段 1 — 快速修复(BUG-002, BUG-006, BUG-009)"
|
||||
|
||||
run_agent "BUG-002" "修复 BUG-002:
|
||||
文件:msh_single_uniapp/pages/tool/calculator-result.vue
|
||||
问题:食谱计算器结果页的「健康概览」和「营养配餐」两个 Tab 切换后,选中与未选中的视觉差异不明显,用户难以辨识当前激活项。
|
||||
要求:
|
||||
1. 增强 .tab-item.active 的视觉样式,例如:加粗字体(font-weight: 700)、橙色底部下划线(border-bottom: 3px solid #f97316)、字色变为主色(color: #f97316)。
|
||||
2. 未激活 Tab 字色应明显变灰(color: #9ca3af),不加下划线。
|
||||
3. 不得修改 Tab 的 JS 逻辑,只改 CSS 样式。
|
||||
4. 修改前先阅读该文件的 .tab-container / .tab-item / .tab-item.active 样式。
|
||||
请执行修改。"
|
||||
|
||||
run_agent "BUG-006" "修复 BUG-006:
|
||||
文件:msh_single_uniapp/pages/tool_main/index.vue 以及 msh_single_uniapp/pages/tool/nutrition-knowledge.vue
|
||||
问题:主页「健康知识」区块标题与营养知识页面导航栏标题命名不一致,一处用「健康知识」,另一处用「营养知识」。
|
||||
要求:
|
||||
1. 先阅读两个文件,确认各自现有文案。
|
||||
2. 统一将两处名称改为「健康知识」(若现在 nutrition-knowledge.vue 导航栏写的是「营养知识」,改成「健康知识」)。
|
||||
3. 仅修改文案字符串,不改动任何逻辑或样式。
|
||||
请执行修改。"
|
||||
|
||||
run_agent "BUG-009" "修复 BUG-009:
|
||||
文件:msh_single_uniapp/pages/tool_main/community.vue
|
||||
问题:社区页面的 Tab 标签(推荐/最新/关注/热门)和帖子类型标签(.type-tag / .meal-tag)中存在英文命名或非中文命名,需统一为中文。
|
||||
要求:
|
||||
1. 阅读 community.vue 的 template 部分,找出所有 Tab 文案和帖子类型标签文案。
|
||||
2. 将所有英文或拼音命名改为对应中文(如 recommend→推荐, latest→最新 等)。
|
||||
3. 检查数据中的类型字段(如 type: 'breakfast'),如显示时有 label 映射,确保 label 均为中文。
|
||||
4. 不改动路由、接口调用等逻辑。
|
||||
请执行修改。"
|
||||
|
||||
log "[阶段1] 阶段1修复完成,进行局部验证..."
|
||||
run_partial_test "TC-B02|TC-B06|TC-B09"
|
||||
|
||||
# =============================================================================
|
||||
# 阶段 2:中等难度修复(~60 min)
|
||||
# BUG-001 打卡积分 | BUG-007 文章详情内容
|
||||
# =============================================================================
|
||||
|
||||
phase "阶段 2 — 中等修复(BUG-001, BUG-007)"
|
||||
|
||||
run_agent "BUG-001" "修复 BUG-001(共两个子问题):
|
||||
文件:msh_single_uniapp/pages/tool/checkin.vue
|
||||
|
||||
子问题 A — 打卡前积分提前跳变:
|
||||
点击「立即打卡」后,在页面跳转前,前端已将积分 +30 显示出来,造成视觉误导。
|
||||
修复:handleCheckin 方法中,不得在 API 返回成功前修改 currentPoints。
|
||||
仅在 API 调用成功、且获取到服务端最新积分后才更新 currentPoints(优先用服务端返回的值,不做前端本地累加)。
|
||||
|
||||
子问题 B — 打卡成功后积分未实际增加:
|
||||
后端积分累加逻辑可能未被正确触发。
|
||||
修复:
|
||||
1. 阅读 handleCheckin 中的 API 调用,确认调用的是 /api/front/user/checkin 或类似接口。
|
||||
2. 若调用成功,再发请求 GET /api/front/user/info 刷新用户积分,并将返回值赋给 currentPoints。
|
||||
3. 不可使用硬编码 +30;积分值必须来自服务端响应。
|
||||
请先阅读文件,再执行修改。
|
||||
"
|
||||
|
||||
run_agent "BUG-007" "修复 BUG-007:
|
||||
文件:msh_single_uniapp/pages/tool/nutrition-knowledge.vue
|
||||
问题:切换到「饮食指南」或「科普文章」Tab 后,列表为空(guideList / articleList 均为 []),点击条目进入详情页后也无任何内容,页面一片空白。
|
||||
要求:
|
||||
1. 阅读 loadKnowledgeList 方法和 getKnowledgeList API 调用。
|
||||
2. 如果 API 正常但数据为空,请检查请求参数(type 字段的值是否正确:guide / article)。
|
||||
3. 如果 API 失败,添加 catch 后的错误提示(uni.showToast)并确保 guideList / articleList 不被设为 undefined。
|
||||
4. 在 onLoad 中,若没有 id 参数,应默认加载当前 tab 对应的列表(当前为 nutrients,应在 switchTab 后加载 guide/articles 列表)。
|
||||
5. 修复详情页跳转:goToDetail 方法中,确保 knowledgeId 或 id 字段存在才跳转,否则提示「暂无详情」。
|
||||
请先阅读文件,再执行修改。"
|
||||
|
||||
log "[阶段2] 阶段2修复完成,进行局部验证..."
|
||||
run_partial_test "TC-B01|TC-B07"
|
||||
|
||||
# =============================================================================
|
||||
# 阶段 3:数据展示修复(~60 min)
|
||||
# BUG-003 食物列表 | BUG-008 营养统计
|
||||
# =============================================================================
|
||||
|
||||
phase "阶段 3 — 数据展示修复(BUG-003, BUG-008)"
|
||||
|
||||
run_agent "BUG-003" "修复 BUG-003:
|
||||
文件:msh_single_uniapp/pages/tool/food-encyclopedia.vue
|
||||
问题:食物百科全部列表页中,所有食物条目均未展示配图(.food-image)和营养简介(.nutrition-item)。
|
||||
要求:
|
||||
1. 阅读 food-encyclopedia.vue 的 template 中 .food-item 部分,找到 .food-image 的 :src 绑定和 .nutrition-item 的 v-for 数据来源。
|
||||
2. 检查数据加载方法(如 loadFoodList 或 getFoodList API),确认响应数据结构,找出 image/imageUrl/img 字段和 nutrition/nutrients 字段。
|
||||
3. 修复字段映射:确保 .food-image 的 :src 绑定到正确字段(如 item.imageUrl || item.image),且 .nutrition-item 遍历正确的数组(如 item.nutrients || item.nutritions)。
|
||||
4. 若图片字段为空,显示一个默认占位图(可使用已有的本地资源或灰色背景)。
|
||||
请先阅读文件和相关 API 文件(api/tool.js),再执行修改。"
|
||||
|
||||
run_agent "BUG-008" "修复 BUG-008:
|
||||
文件:msh_single_uniapp/pages/tool/post-detail.vue
|
||||
问题:帖子详情页中,营养统计数据(.nutrition-stats-card)不显示,.stat-item 数组为空。
|
||||
要求:
|
||||
1. 阅读 post-detail.vue 的 data 中 postData.nutritionStats 的初始化和赋值逻辑。
|
||||
2. 找到加载帖子详情的方法(如 loadPostDetail),确认后端响应中是否有 nutritionStats 字段。
|
||||
3. 若后端无该字段,根据帖子关联的饮食打卡数据(如 dietaryData / mealData),计算蛋白质、热量、钾、磷等关键营养素,填充 nutritionStats 数组格式:[{label:'蛋白质', value:'56g'}, ...]。
|
||||
4. 若后端有该字段但字段名不一致,修复映射。
|
||||
5. 营养统计卡片的显示条件(v-if)应改为:nutritionStats.length > 0,而不是依赖后端字段存在性。
|
||||
请先阅读文件,再执行修改。"
|
||||
|
||||
log "[阶段3] 阶段3修复完成,进行局部验证..."
|
||||
run_partial_test "TC-B03|TC-B08"
|
||||
|
||||
# =============================================================================
|
||||
# 阶段 4:复杂修复(~90 min)
|
||||
# BUG-004 食物详情 | BUG-005 AI 回复
|
||||
# =============================================================================
|
||||
|
||||
phase "阶段 4 — 复杂修复(BUG-004, BUG-005)"
|
||||
|
||||
run_agent "BUG-004" "修复 BUG-004:
|
||||
文件:msh_single_uniapp/pages/tool/food-detail.vue
|
||||
问题:点击任意食物条目进入详情页,提示「数据加载失败」,页面无法正常展示食物名称、营养成分等信息。
|
||||
要求:
|
||||
1. 阅读 food-detail.vue 的 onLoad 和数据加载方法(如 loadFoodDetail)。
|
||||
2. 打印或记录 API 请求参数(id、name 等),确认传参是否正确。
|
||||
3. 如果 API 调用失败,catch 块中不要只 showToast,应同时:
|
||||
a. 将 loadError 置为具体错误信息(用于调试),
|
||||
b. 使用 defaultFoodData 填充页面,保证用户能看到基础界面而不是空白,
|
||||
c. 在页面显示「当前数据来自缓存,可能不是最新」提示。
|
||||
4. 确认 .food-name-overlay / .nutrient-card / .nutrition-row 等元素在 defaultFoodData 状态下也能正常渲染(数据不为空数组/空字符串)。
|
||||
5. 如果问题是 API 路径或参数有误(如 id 传了 name 字段),同时修复调用参数。
|
||||
请先阅读文件和 api/tool.js,再执行修改。"
|
||||
|
||||
run_agent "BUG-005" "修复 BUG-005(对话接口已改为 KieAI Gemini chat,若仍有固定回复再修):
|
||||
文件:msh_single_uniapp/pages/tool/ai-nutritionist.vue、api/models-api.js
|
||||
后端:msh_crmeb_22 的 /api/front/kieai/gemini/chat(ToolKieAIServiceImpl.geminiChat)
|
||||
|
||||
要求:
|
||||
1. 文本对话必须走 KieAI Gemini 大模型:调用 POST /api/front/kieai/gemini/chat,请求体为 { messages: [{ role: 'user', content: 用户输入 }], stream: false }。
|
||||
2. 前端从响应 data.choices[0].message.content 取回复并展示,不得使用 getAIResponse 等固定话术作为接口成功时的回复。
|
||||
3. 若后端 ToolKieAIServiceImpl.geminiChat 或 buildGeminiRequestBody 中存在硬编码 prompt,改为使用 request.getMessages() 透传用户内容。
|
||||
4. 不修改 UI 布局,仅保证数据流:用户输入 → kieai/gemini/chat → 展示模型返回内容。"
|
||||
|
||||
log "[阶段4] 阶段4修复完成,进行局部验证..."
|
||||
run_partial_test "TC-B04|TC-B05"
|
||||
|
||||
# =============================================================================
|
||||
# 阶段 5:全量回归 + 报告
|
||||
# =============================================================================
|
||||
|
||||
phase "阶段 5 — 全量回归测试 + 报告生成"
|
||||
|
||||
run_full_regression
|
||||
|
||||
END_TS=$(date +%s)
|
||||
ELAPSED=$(( END_TS - START_TS ))
|
||||
ELAPSED_MIN=$(( ELAPSED / 60 ))
|
||||
|
||||
log "────────────────────────────────────────────────"
|
||||
log "全部阶段完成!总耗时:${ELAPSED_MIN} 分钟(${ELAPSED} 秒)"
|
||||
log "回归报告:$WORKSPACE/tests/e2e/reports/index.html"
|
||||
log "详细日志:$MAIN_LOG"
|
||||
log "────────────────────────────────────────────────"
|
||||
32
scripts/logs/agent-BUG-001-102447.log
Normal file
32
scripts/logs/agent-BUG-001-102447.log
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
已按 BUG-001 的两个子问题改好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
**子问题 A — 打卡前积分不提前跳变**
|
||||
|
||||
- **逻辑**:在 `handleCheckin` 里,**只有**在 `setSignIntegral()` 成功返回之后才更新状态和积分。
|
||||
- **具体**:
|
||||
- 先 `await setSignIntegral()`,不成功会进 `catch`,不会改 `currentPoints`。
|
||||
- 成功后再 `this.todaySigned = true`,然后再用服务端数据更新 `currentPoints`。
|
||||
- 全程没有在接口成功前修改 `currentPoints`,也没有任何前端本地 `+30`。
|
||||
|
||||
---
|
||||
|
||||
**子问题 B — 打卡成功后用服务端积分刷新**
|
||||
|
||||
- **接口确认**:打卡接口仍是 `setSignIntegral()`(`user/sign/integral`),对应后端 `/api/front/user/sign/integral`,即签到/打卡接口。
|
||||
- **刷新积分**:打卡成功后用「用户信息」接口刷新积分:
|
||||
- 先调 `getUserInfo()`(即 GET `/api/front/user`,即 user info 接口)。
|
||||
- 从返回里取 `integral` 或 `points`,赋给 `currentPoints`(优先 `integral`)。
|
||||
- 若 user info 里没有积分字段,再请求 `getUserPoints()`(`tool/points/info`),用其返回的 `totalPoints` / `points` / `availablePoints` 更新 `currentPoints`。
|
||||
- **禁止硬编码**:积分只来自上述两个接口的返回值,没有写死 `+30`。
|
||||
|
||||
---
|
||||
|
||||
**代码改动要点**
|
||||
|
||||
1. 引入并调用 `getUserInfo`。
|
||||
2. 在 `await setSignIntegral()` 成功后,先 `getUserInfo()`,用 `userRes.data.integral ?? userRes.data.points` 更新 `currentPoints`。
|
||||
3. 仅当 user info 无积分时,再 `getUserPoints()` 并以其结果更新 `currentPoints`。
|
||||
4. 注释中写明:不在 API 成功前改 `currentPoints`,且用 GET user info 刷新积分、禁止前端本地 +30。
|
||||
35
scripts/logs/agent-BUG-001-165818.log
Normal file
35
scripts/logs/agent-BUG-001-165818.log
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
已按 BUG-001 的两个子问题改好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
### 子问题 A — 打卡前积分不再提前跳变
|
||||
|
||||
- **原逻辑**:点击「立即打卡」后先执行 `uni.navigateTo`,再执行 `this.currentPoints += 30`,在接口返回前就改动了积分。
|
||||
- **现逻辑**:
|
||||
- 在 `handleCheckin` 中**不再**在接口成功前修改 `currentPoints`。
|
||||
- 仅当签到接口调用成功,并且用 `getUserPoints()` 拿到服务端最新积分后,才给 `currentPoints` 赋值(见下)。
|
||||
|
||||
---
|
||||
|
||||
### 子问题 B — 打卡成功后用服务端积分更新
|
||||
|
||||
- **原逻辑**:没有调用任何打卡/签到接口,只在前端写死 `currentPoints += 30`,后端没有参与积分变更。
|
||||
- **现逻辑**:
|
||||
1. **调用签到接口**:使用现有接口 `GET /api/front/user/sign/integral`(`@/api/user.js` 中的 `setSignIntegral()`),与需求中的「/api/front/user/checkin 或类似接口」一致,用于触发后端签到与积分累加。
|
||||
2. **成功后刷新积分**:签到成功后请求 `getUserPoints()`(对应后端 `GET .../tool/points/info`),用返回的积分更新页面。
|
||||
3. **积分来源**:
|
||||
`currentPoints` 只从接口赋值:
|
||||
`pointsRes.data.totalPoints ?? pointsRes.data.points ?? pointsRes.data.availablePoints ?? 0`
|
||||
不再使用硬编码的 +30。
|
||||
4. **错误与跳转**:若签到或拉取积分失败,会 `uni.showToast` 提示并 `return`,不跳转;只有成功后才 `uni.navigateTo('/pages/tool/checkin-publish')`。
|
||||
|
||||
---
|
||||
|
||||
### 其它修改
|
||||
|
||||
- **loadCheckinData**:积分取值改为优先使用服务端字段,与上面一致:
|
||||
`currentPoints = pointsRes.data.totalPoints ?? pointsRes.data.points ?? 0`
|
||||
这样列表和打卡页的积分都来自服务端。
|
||||
|
||||
需求里提到的「GET /api/front/user/info」在当前项目里没有对应接口;用户积分接口是 `GET /api/front/tool/points/info`(`getUserPoints()`),因此用该接口的返回值刷新并赋值给 `currentPoints`。若后续后端提供 `/api/front/user/info` 并返回积分,只需在成功后再调该接口,用其返回的积分更新 `currentPoints` 即可。
|
||||
16
scripts/logs/agent-BUG-002-102156.log
Normal file
16
scripts/logs/agent-BUG-002-102156.log
Normal file
@@ -0,0 +1,16 @@
|
||||
Connection lost, reconnecting...
|
||||
Retry attempt 1...
|
||||
|
||||
已按 BUG-002 要求只改了 CSS,未动任何 JS,修改如下:
|
||||
|
||||
**1. 未激活 Tab(`.tab-item`)**
|
||||
- 在根级增加 `color: #9ca3af`,保证整项为灰色。
|
||||
- 下划线保持 `border-bottom: 3px solid transparent`,无可见下划线。
|
||||
|
||||
**2. 激活 Tab(`.tab-item.active`)**
|
||||
- `border-bottom: 3px solid #f97316`,橙色底线下划线(由原 6rpx 改为 3px)。
|
||||
- `color: #f97316`,主色字色。
|
||||
- `font-weight: 700`,加粗。
|
||||
- 保留内部 `.tab-text`、`.tab-icon` 的 `#f97316` 与 `.tab-text` 的 `font-weight: 700`。
|
||||
|
||||
这样「健康概览」和「营养配餐」切换时,激活项为橙色加粗+橙色下划线,未激活为灰色且无下划线,对比更清晰。
|
||||
15
scripts/logs/agent-BUG-002-165157.log
Normal file
15
scripts/logs/agent-BUG-002-165157.log
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
已按 BUG-002 要求只改了 CSS,未动任何 JS。修改总结如下:
|
||||
|
||||
### 1. 未激活 Tab(`.tab-item`)
|
||||
- **字色**:`.tab-text` 与 `.tab-icon` 均为 `#9ca3af`
|
||||
- **下划线**:无实线,用 `border-bottom: 6rpx solid transparent` 占位,避免切换时高度抖动
|
||||
- 其它:`height: 100%`、`min-height: 75rpx`,让底部边框落在 tab 栏最下方;`border-radius: 0`,改为下划线式 tab
|
||||
|
||||
### 2. 激活 Tab(`.tab-item.active`)
|
||||
- **字重**:`.tab-text` 设为 `font-weight: 700`
|
||||
- **下划线**:`border-bottom: 6rpx solid #f97316`(与要求 3px 等效,用 6rpx 保持与页面其它 rpx 一致)
|
||||
- **字色**:`.tab-text`、`.tab-icon` 均为 `color: #f97316`
|
||||
- **背景**:`background: transparent`,去掉原来的橙色块,只保留下划线样式
|
||||
|
||||
效果:当前选中的「健康概览」或「营养配餐」会以**加粗 + 橙色字 + 橙色底线下划线**显示,未选中的 Tab 为**灰色字、无下划线**,视觉区分更明显。
|
||||
44
scripts/logs/agent-BUG-003-102846.log
Normal file
44
scripts/logs/agent-BUG-003-102846.log
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
BUG-003 已按你的要求修好,修改总结如下。
|
||||
|
||||
## 1. Template 与数据来源(确认)
|
||||
|
||||
- **`.food-image` 的 `:src`**:绑定为 `getFoodImage(item)`,由该方法统一取图并处理占位。
|
||||
- **`.nutrition-item` 的 v-for**:遍历 `(item.nutrition || [])`,数据在 `normalizeFoodItem` 里统一整理成 `nutrition` 数组。
|
||||
|
||||
## 2. 后端数据结构(api/tool.js + ToolFoodServiceImpl)
|
||||
|
||||
- **列表/搜索** 返回每条为:`id`, `name`, `image`, `category`, `energy`, `protein`, `potassium`, `phosphorus`, `suitabilityLevel`。
|
||||
没有 `nutrition`/`nutrients` 数组,营养来自扁平字段。
|
||||
|
||||
## 3. 具体修改
|
||||
|
||||
**(1)图片字段与占位**
|
||||
|
||||
- 在 **`getFoodImage(item)`** 中:
|
||||
- 统一取 `item.imageUrl || item.image || item.img`。
|
||||
- 若为相对路径(以 `/` 开头且非 `//`),用 `HTTP_REQUEST_URL` 拼成完整 URL。
|
||||
- 无有效 URL 时返回已有的灰色 SVG 占位图(`defaultPlaceholder`)。
|
||||
|
||||
**(2)营养字段与列表**
|
||||
|
||||
- 在 **`normalizeFoodItem(item)`** 中:
|
||||
- **图片**:同样做 image/imageUrl/img 兼容和相对路径补全,并写入 `image` / `imageUrl`,保证列表项有统一图源。
|
||||
- **营养**:
|
||||
- 若有 `item.nutrition` 数组,按 `{ label, value, colorClass }` 规范化(兼容 `name`/`labelName`)。
|
||||
- 否则若有 `item.nutrients`,同样规范化后当作 `nutrition`。
|
||||
- 否则用后端扁平字段组装:能量、蛋白质、钾、磷、钠、钙(有值才加),保证列表有 `nutrition` 数组供 `.nutrition-item` 使用。
|
||||
|
||||
**(3)列表数据来源**
|
||||
|
||||
- `loadFoodList` 和搜索回调中,列表来源改为:
|
||||
`result.data.list || (Array.isArray(result.data) ? result.data : [])`,再对每一项执行 `normalizeFoodItem`,避免因接口形态不同导致列表为空。
|
||||
|
||||
**(4)配置**
|
||||
|
||||
- 顶部增加:`import { HTTP_REQUEST_URL } from '@/config/app.js'`,用于相对路径补全。
|
||||
|
||||
效果上:
|
||||
|
||||
- `.food-image` 会正确显示后端返回的图(含相对路径补全),无图时显示灰色占位图。
|
||||
- `.nutrition-item` 会正确展示营养简介(来自后端扁平字段或已有的 nutrition/nutrients 数组)。
|
||||
39
scripts/logs/agent-BUG-003-170607.log
Normal file
39
scripts/logs/agent-BUG-003-170607.log
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
BUG-003 已按你的要求修好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题原因
|
||||
|
||||
- **后端列表接口**(`getFoodList` / `searchFood`)返回的是:`id, name, image, energy, protein, suitabilityLevel`,没有 `nutrition` 数组,也没有 `category`、`potassium`、`phosphorus`。
|
||||
- 模板里用的是 `item.image`、`item.nutrition`。当接口替换掉本地 mock 后,`item.nutrition` 为 `undefined`,营养简介不渲染;图片若为空也没有占位。
|
||||
|
||||
## 2. 修改内容
|
||||
|
||||
### 前端 `msh_single_uniapp/pages/tool/food-encyclopedia.vue`
|
||||
|
||||
**模板:**
|
||||
|
||||
- **`.food-image` 的 `:src`**:改为 `getFoodImage(item)`,内部使用 `item.imageUrl || item.image || item.img`,都没有时用占位图。
|
||||
- **`.nutrition-item` 的 `v-for`**:改为 `v-for="(nut, idx) in (item.nutrition || [])"`,并给 `nut.colorClass` 加了默认 `'green'`,避免无数据或缺字段时报错。
|
||||
- **分类与安全标签**:`item.category` 为空时不渲染分类徽章(`v-if="item.category"`);安全标签增加 `item.safetyClass || 'safe'`、`item.safety || '—'` 兜底。
|
||||
- **列表 `:key`**:改为 `item.id != null ? item.id : index`,便于接口数据稳定渲染。
|
||||
|
||||
**逻辑:**
|
||||
|
||||
- **`defaultPlaceholder`**:在 `data()` 里增加灰色 SVG 的 data URL,作为无图时的占位图(与 `.food-image-wrapper` 的灰色风格一致)。
|
||||
- **`getFoodImage(item)`**:返回 `item.imageUrl || item.image || item.img`,若都为空则返回 `defaultPlaceholder`。
|
||||
- **`normalizeFoodItem(item)`**:把接口数据统一成列表项结构:
|
||||
- 图片:沿用 `image` / `imageUrl` / `img`(展示由 `getFoodImage` 处理)。
|
||||
- 安全:若已有 `safety`/`safetyClass` 则保留,否则按 `suitabilityLevel` 映射(suitable→放心吃/safe,moderate→限量吃/limited,restricted/forbidden→谨慎吃/careful)。
|
||||
- 营养:若已有 `item.nutrition` 数组则直接用;否则用接口字段组装:能量、蛋白质、钾、磷(有值才加),格式为 `{ label, value, colorClass }`。
|
||||
- **列表赋值**:`loadFoodList` 和搜索分支里,对 `result.data.list` 做 `(result.data.list || []).map(item => this.normalizeFoodItem(item))` 再赋给 `foodList`,保证每条都有 `nutrition` 和可用的图片、安全、分类展示。
|
||||
|
||||
### 后端 `msh_crmeb_22/.../ToolFoodServiceImpl.java`
|
||||
|
||||
- 列表/搜索的 map 中增加:`category`、`potassium`、`phosphorus`,这样前端 `normalizeFoodItem` 能拼出更完整的营养简介,分类徽章也能显示。
|
||||
|
||||
效果:
|
||||
|
||||
- 配图:有图用接口的 `image`(或 `imageUrl`/`img`),无图用灰色占位图。
|
||||
- 营养简介:接口有 `nutrition` 用接口的,没有则用能量/蛋白质/钾/磷自动组一条,`.nutrition-item` 始终有稳定数据源可遍历。
|
||||
48
scripts/logs/agent-BUG-004-103510.log
Normal file
48
scripts/logs/agent-BUG-004-103510.log
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
BUG-004 已按你的要求修好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
## 根因
|
||||
|
||||
- 后端详情接口 **只接受 Long 类型 id**(`ToolController#getFoodDetail(Long id)`)。
|
||||
- 列表里部分条目没有 `id`,`food-encyclopedia` 用 `item.name` 当 id 传,例如 `id=羊肉(熟)`,后端报 `NumberFormatException`,请求失败,页面只弹出「数据加载失败」且内容空白。
|
||||
|
||||
---
|
||||
|
||||
## 修改说明
|
||||
|
||||
### 1. `msh_single_uniapp/pages/tool/food-encyclopedia.vue`
|
||||
|
||||
- **只传数字 id**:仅在 `item.id` 为有效数字时拼进 `id` 参数;否则不传 `id`,避免把名称当 id 传给后端。
|
||||
- **始终传 name**:跳转时带上 `name`(有则 `id=xxx&name=xxx`,无 id 则只传 `name=xxx`),详情页在失败或无 id 时用 name 展示。
|
||||
|
||||
### 2. `msh_single_uniapp/pages/tool/food-detail.vue`
|
||||
|
||||
- **入参与日志**
|
||||
- 使用 `pageParams: { id, name }` 保存入参。
|
||||
- `onLoad` 里打印:`console.log('[food-detail] onLoad params:', this.pageParams)`。
|
||||
- `loadFoodData` 里打印:`console.log('[food-detail] getFoodDetail request param:', { id, type: typeof id })`。
|
||||
|
||||
- **只对数字 id 调接口**
|
||||
- 仅当 `options.id` 能解析为数字时才调用 `loadFoodData(Number(options.id))`。
|
||||
- 仅有 `options.name` 时:不请求接口,直接 `loadError = '暂无该食物详情数据,展示参考数据'`,用 `applyDefaultFoodData(false)` 填充,并把 `foodData.name` 设为解码后的 `options.name`。
|
||||
|
||||
- **API 失败时(catch)**
|
||||
- **a.** `loadError = errMsg`(具体错误信息,便于调试)。
|
||||
- **b.** `applyDefaultFoodData(false)`,用 `defaultFoodData` 填满页面,保证有名称、分类、关键营养、营养成分表等。
|
||||
- **c.** 若有 `pageParams.name`,用其覆盖 `foodData.name`,避免显示默认「五谷香」。
|
||||
- 再 `showToast('数据加载失败')`。
|
||||
- `loadError` 有值时,页面顶部已有「当前数据来自缓存,可能不是最新」的提示(原有 `v-if="loadError"` 的 `.cache-notice`)。
|
||||
|
||||
- **保证列表能渲染**
|
||||
- `applyDefaultFoodData` 中保证 `name/category/safetyTag/image` 有默认值,`keyNutrients`、`nutritionTable` 用 `defaultFoodData` 的非空数组拷贝,确保 `.food-name-overlay`、`.nutrient-card`、`.nutrition-row` 在默认数据下也能正常渲染。
|
||||
- 成功拿到 API 数据时,用 `ensureNonEmptyArray(parseKeyNutrients(data), defaultFoodData.keyNutrients)` 等,避免解析出空数组导致列表为空。
|
||||
|
||||
---
|
||||
|
||||
效果简述:
|
||||
|
||||
- 列表点有**数字 id** 的条目:正常请求详情并展示;失败时用默认数据 + 入参 name(若有)+ 缓存提示 + Toast。
|
||||
- 列表点**无 id、只有 name** 的条目:不请求接口,直接展示默认数据 + 该 name + 缓存提示,不再报错或空白。
|
||||
- 控制台可看到 `onLoad params` 和 `getFoodDetail request param`,便于确认传参是否正确。
|
||||
67
scripts/logs/agent-BUG-004-171409.log
Normal file
67
scripts/logs/agent-BUG-004-171409.log
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
BUG-004 已按你的要求修好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
## 1. 根因(API 参数错误)
|
||||
|
||||
- **后端**:`ToolController.getFoodDetail(@PathVariable Long id)` 只接受 **Long 类型 id**。
|
||||
- **前端**:食物百科列表跳转详情时用了 **`item.name`**(如「羊肉(熟)」「儿童营养饼干」),导致后端报 `NumberFormatException`,接口失败,页面只提示「数据加载失败」。
|
||||
|
||||
日志中可见:`Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'`.
|
||||
|
||||
---
|
||||
|
||||
## 2. 修改内容
|
||||
|
||||
### 2.1 `msh_single_uniapp/pages/tool/food-encyclopedia.vue`
|
||||
|
||||
- **跳转参数**:改为传 **`item.id`**(后端列表返回的 `id`),不再传 `item.name`。
|
||||
- 若某条没有 `id`,则回退为 `item.name`,并对 name 做 `encodeURIComponent`,避免中文等字符在 URL 里出错。
|
||||
|
||||
```javascript
|
||||
// 后端详情接口需要 Long 类型 id,传 id 而非 name
|
||||
const id = item.id != null ? item.id : item.name
|
||||
url: `/pages/tool/food-detail?id=${encodeURIComponent(id)}`
|
||||
```
|
||||
|
||||
这样从列表点进详情会带正确的 id,接口可正常返回数据。
|
||||
|
||||
---
|
||||
|
||||
### 2.2 `msh_single_uniapp/pages/tool/food-detail.vue`
|
||||
|
||||
1. **请求参数打印**
|
||||
- `onLoad`:`console.log('[food-detail] onLoad params:', { id: options.id, name: options.name })`
|
||||
- `loadFoodData`:`console.log('[food-detail] getFoodDetail request param:', { id, type: typeof id })`
|
||||
便于确认传参是否正确。
|
||||
|
||||
2. **`loadError` 与调试**
|
||||
- 增加 `loadError: ''`。
|
||||
- 在 `loadFoodData` 的 **catch** 里把 `loadError` 设为具体错误信息(`error.message || error.msg || error`),便于调试。
|
||||
|
||||
3. **失败时用默认数据 + 缓存提示**
|
||||
- 抽取 **`applyDefaultFoodData(clearError)`**:用 `defaultFoodData` 填充 `foodData`,并对 `keyNutrients`、`nutritionTable` 做数组拷贝,保证不为空数组、能正常渲染 `.food-name-overlay` / `.nutrient-card` / `.nutrition-row`。
|
||||
- 在 catch 里:先设置 `loadError`,再调用 `applyDefaultFoodData(false)`(不再清空 `loadError`),并保留原有 `showToast('数据加载失败')`。
|
||||
- 无入参时仍走默认数据,此时调用 `applyDefaultFoodData()` 会清空 `loadError`。
|
||||
|
||||
4. **「当前数据来自缓存」提示**
|
||||
- 当 `loadError` 有值时,在页面顶部展示提示条:「当前数据来自缓存,可能不是最新」,并增加 `.cache-notice` 样式。
|
||||
|
||||
5. **默认数据下的展示**
|
||||
- `defaultFoodData` 已包含完整的 `name`、`category`、`safetyTag`、`image`、`keyNutrients`、`nutritionTable`(均为非空数组),应用 `applyDefaultFoodData` 后,`.food-name-overlay`、`.nutrient-card`、`.nutrition-row` 在默认数据下也能正常渲染。
|
||||
|
||||
6. **样式**
|
||||
- 为 `.nutrition-dot` 增加 `&.high`,避免后端返回 `level: 'high'` 时缺样式。
|
||||
|
||||
---
|
||||
|
||||
## 3. 行为小结
|
||||
|
||||
| 场景 | 行为 |
|
||||
|----------------|------|
|
||||
| 列表点击条目 | 传 `item.id`,详情接口用 id 请求,正常展示该食物。 |
|
||||
| 接口失败/异常 | 设置 `loadError`、用 `defaultFoodData` 填页面、Toast「数据加载失败」、顶部显示「当前数据来自缓存,可能不是最新」,名称/营养成分等仍可正常显示。 |
|
||||
| 无 id/name 入参 | 直接使用默认数据,不显示缓存提示。 |
|
||||
|
||||
按当前逻辑,从食物百科点进详情应能正常看到名称和营养成分;若接口仍失败,会显示默认示例数据并提示「当前数据来自缓存,可能不是最新」,同时控制台和 `loadError` 可用来排查具体错误。
|
||||
46
scripts/logs/agent-BUG-005-103833.log
Normal file
46
scripts/logs/agent-BUG-005-103833.log
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
BUG-005 已按你的要求修好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
## 1. 前端 `msh_single_uniapp/pages/tool/ai-nutritionist.vue`
|
||||
|
||||
**已做修改:**
|
||||
|
||||
- **文本/多模态统一走 KieAI Gemini**
|
||||
逻辑本来就是:`sendToAI` 里对 `text` 和 `multimodal` 都调用 `api.kieaiGeminiChat({ messages, stream: false })`,请求体为 `{ messages: [{ role: 'user', content: 用户输入或图+文 }], stream: false }`,未改。
|
||||
|
||||
- **成功时只展示接口返回内容**
|
||||
- 回复**仅**从 `response.data.choices[0].message.content` 取值并展示。
|
||||
- 已改为显式使用 `msgObj.content`(不再用 `choice.message.text` 等),并在注释中写明“仅使用接口返回的 content,禁止固定话术”。
|
||||
|
||||
- **删除固定话术 `getAIResponse`**
|
||||
- 已移除整个 `getAIResponse(question)` 方法(原关键词匹配的固定回复)。
|
||||
- 成功时不再使用任何固定话术,只展示接口返回内容。
|
||||
|
||||
- **未动 UI**
|
||||
仅改数据流与回复来源,布局和样式未改。
|
||||
|
||||
---
|
||||
|
||||
## 2. 前端 `msh_single_uniapp/api/models-api.js`
|
||||
|
||||
- **未改**
|
||||
`kieaiGeminiChat` 已正确:
|
||||
- POST `/api/front/kieai/gemini/chat`
|
||||
- 请求体为 `{ messages, stream }`(你要求的 `{ messages: [{ role: 'user', content: 用户输入 }], stream: false }` 已满足)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 后端 `msh_crmeb_22`(ToolKieAIServiceImpl / buildGeminiRequestBody)
|
||||
|
||||
- **未改**
|
||||
已确认:
|
||||
- `buildGeminiRequestBody` 完全用 `request.getMessages()` 透传,没有硬编码 prompt。
|
||||
- `geminiChat` 只是用该 body 调 KieAI,无额外固定内容。
|
||||
|
||||
因此后端无需修改。
|
||||
|
||||
---
|
||||
|
||||
当前数据流为:**用户输入 → POST /api/front/kieai/gemini/chat(body: messages + stream: false)→ 前端从 `data.choices[0].message.content` 取回复并展示**,且成功时不再使用任何固定话术。
|
||||
45
scripts/logs/agent-BUG-005-171812.log
Normal file
45
scripts/logs/agent-BUG-005-171812.log
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
BUG-005 相关修改已按你的要求做完,结论与改动如下。
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题原因
|
||||
|
||||
- **前端**:创建对话后从 `response.data.chat` 取 `conversation_id`、`id`,但后端返回的是 `CozeBaseResponse.success(resp)`,`data` 就是 Coze 的 CreateChatResp,没有嵌套的 `chat`,且多为 camelCase(如 `conversationID`)。因此取不到会话/聊天 ID,轮询失败,请求在 catch 里走本地兜底 `getAIResponse(content)`,看起来就像“固定一段话”。
|
||||
- **后端**:Coze 实现里没有发现硬编码占位词,用户内容来自 `additionalMessages[0].content`。已做的修改是“无用户消息时不发请求”的防护。
|
||||
|
||||
---
|
||||
|
||||
## 2. 前端修改(`msh_single_uniapp/pages/tool/ai-nutritionist.vue`)
|
||||
|
||||
- **创建对话响应解析**
|
||||
- 兼容 `response.data.chat` 与 `response.data`。
|
||||
- 兼容 `conversation_id` / `conversationID` / `conversationId` 和 `id`。
|
||||
- 只有拿到 `conversationId` 和 `chatId` 后才调用 `pollChatStatus`,否则抛出明确错误。
|
||||
- **轮询状态**
|
||||
- 使用 `const chatObj = res.data.chat || res.data` 再取 `status`,避免因结构不同取不到状态。
|
||||
- **消息列表**
|
||||
- 支持 `res.data.messages` 或 `res.data` 为数组两种结构,用 `rawMessages` 统一处理,保证 AI 回复用 `role: 'ai', content: msg.content` 正确 push 到 `messageList`。
|
||||
|
||||
未改 UI,只修了数据流;`sendMessage` / `sendToAI` 里用的始终是 `inputText.trim()` → `content`,请求体已正确带用户输入。
|
||||
|
||||
---
|
||||
|
||||
## 3. 后端修改(`ToolCozeServiceImpl.java`)
|
||||
|
||||
- **无用户消息时不调用 Coze**
|
||||
- `chat()` 与 `chatStream()` 中:若 `buildMessages(request)` 为空,则不再调用 Coze,直接返回错误(如“请提供对话内容”),避免“空请求”导致平台返回欢迎语等固定回复。
|
||||
|
||||
未改动 `ToolKieAIServiceImpl.java`:该文件是 Gemini 对话实现,营养师页走的是 Coze(`/api/front/coze/chat`);且其中没有硬编码占位词,prompt 来自 `KieAIGeminiChatRequest.getMessages()`,因此按要求未修改。
|
||||
|
||||
---
|
||||
|
||||
## 4. 修改汇总
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|----------|
|
||||
| `ai-nutritionist.vue` | 修正 create-chat 响应解析(data / data.chat、camel/snake);轮询与消息列表兼容不同返回结构;保证 AI 回复写入 `messageList`。 |
|
||||
| `ToolCozeServiceImpl.java` | 在 `chat` / `chatStream` 中增加“无用户消息则不请求 Coze”的校验。 |
|
||||
| `ToolKieAIServiceImpl.java` | 未修改(非本接口且无硬编码)。 |
|
||||
|
||||
按当前逻辑,用户输入会正确传到 Coze,且能正确解析创建对话与轮询结果,AI 的真实回复会显示在列表中,而不再被固定兜底文案覆盖。
|
||||
19
scripts/logs/agent-BUG-006-102242.log
Normal file
19
scripts/logs/agent-BUG-006-102242.log
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
检查结果如下:
|
||||
|
||||
**1. `msh_single_uniapp/pages/tool_main/index.vue`**
|
||||
- 第 66 行功能入口标题:`<view class="function-title">健康知识</view>` → 已是「健康知识」
|
||||
- 第 126 行区块标题:`<text class="section-title">健康知识</text>` → 已是「健康知识」
|
||||
|
||||
**2. `msh_single_uniapp/pages/tool/nutrition-knowledge.vue`**
|
||||
- 页面内没有设置导航栏标题的文案(没有「营养知识」或「健康知识」字符串)
|
||||
- 该页导航栏标题由 `pages.json` 配置
|
||||
|
||||
**3. `pages.json`(nutrition-knowledge 页配置)**
|
||||
- 第 1018 行:`"navigationBarTitleText": "健康知识"` → 已是「健康知识」
|
||||
|
||||
因此,当前代码里:
|
||||
- 主页「健康知识」区块和功能入口均为「健康知识」
|
||||
- 营养知识页的导航栏标题在 `pages.json` 中也是「健康知识」
|
||||
|
||||
两处命名已统一为「健康知识」,**无需再改任何文件**。若你本地或某次构建里仍看到「营养知识」,请说明是在哪个页面、哪一行或哪个配置(例如是否改过 `pages.json`),我可以按那个位置再帮你对一下。
|
||||
18
scripts/logs/agent-BUG-006-165332.log
Normal file
18
scripts/logs/agent-BUG-006-165332.log
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
BUG-006 已按「统一为健康知识」处理,修改如下。
|
||||
|
||||
**1. 确认的现有文案**
|
||||
- **tool_main/index.vue**
|
||||
- 下方区块标题(第125行):`健康知识`
|
||||
- 四大入口里对应卡片标题(第65行):`营养知识`
|
||||
- **营养知识页导航栏**
|
||||
- 在 **pages.json** 里配置:`nutrition-knowledge` 的 `navigationBarTitleText` 为 `营养知识`
|
||||
- **nutrition-knowledge.vue** 内没有设置导航栏标题的文案。
|
||||
|
||||
**2. 已做修改(仅文案,未改逻辑与样式)**
|
||||
- **msh_single_uniapp/pages/tool_main/index.vue**
|
||||
- 四大入口卡片标题:`营养知识` → `健康知识`(第67行 `function-title`)。
|
||||
- **msh_single_uniapp/pages.json**
|
||||
- `nutrition-knowledge` 页的 `navigationBarTitleText`:`营养知识` → `健康知识`。
|
||||
|
||||
现在主页入口卡片、主页「健康知识」区块和营养知识页导航栏都统一为「健康知识」。`nutrition-knowledge.vue` 未改,因为导航栏标题是在 `pages.json` 里配置的。
|
||||
37
scripts/logs/agent-BUG-007-102627.log
Normal file
37
scripts/logs/agent-BUG-007-102627.log
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
BUG-007 已按你的要求改完,修改总结如下:
|
||||
|
||||
### 1. **`loadKnowledgeList` 与 API 调用**
|
||||
|
||||
- **根因**:在 `rawList.map` 里用了 `formatKnowledgeTime(...)` 未加 `this.`,在 API 有数据时会报错(如 "formatKnowledgeTime is not a function"),进入 catch,列表不会被赋值,所以一直为空。
|
||||
- **修改**:改为 `this.formatKnowledgeTime(...)`,确保在 map 里正确调用组件方法。
|
||||
|
||||
### 2. **请求参数 type**
|
||||
|
||||
- type 已与后端一致:`guide` / `article`(注释里也写明了)。
|
||||
|
||||
### 3. **API 失败时的处理**
|
||||
|
||||
- catch 里已有 `uni.showToast` 提示。
|
||||
- 在 catch 中保证不把列表置为 undefined:
|
||||
`this.guideList = this.guideList ?? []`、`this.articleList = this.articleList ?? []`,出错时仍保持为数组。
|
||||
|
||||
### 4. **响应数据结构兼容**
|
||||
|
||||
- 增加对两种返回形式的兼容:
|
||||
- `result.data.list` 为数组时用 `result.data.list`;
|
||||
- 若 `result.data` 本身是数组则用 `result.data`。
|
||||
这样无论后端用分页对象还是直接数组,都能正确取到列表。
|
||||
|
||||
### 5. **onLoad 无 id 时的逻辑**
|
||||
|
||||
- 有 `id`:调用 `switchTab('articles')`,会触发 `loadKnowledgeList` 拉取科普文章列表。
|
||||
- 无 `id`:显式保持 `currentTab = 'nutrients'`;用户切到「饮食指南」或「科普文章」时由 `switchTab` 触发 `loadKnowledgeList`,与需求一致。
|
||||
|
||||
### 6. **详情页跳转 `goToDetail`**
|
||||
|
||||
- 已有「无 id 不跳转」的逻辑,本次只做了小加固:
|
||||
- 若 `!item` 也先提示「暂无详情」再 return;
|
||||
- 仅当 `knowledgeId` 或 `id` 存在且有效时才 `navigateTo`,否则一律提示「暂无详情」。
|
||||
|
||||
当前无新的 lint 报错。若后端库里没有 type 为 `guide` / `article` 的数据,列表仍会为空,但会正常显示「暂无饮食指南数据」/「暂无科普文章数据」;若详情页打开仍空白,需要再确认详情页是否应调 `tool/knowledge/detail/:id` 而不是文章接口。
|
||||
26
scripts/logs/agent-BUG-007-170040.log
Normal file
26
scripts/logs/agent-BUG-007-170040.log
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
BUG-007 已按你的要求修好,修改总结如下:
|
||||
|
||||
### 1. **`loadKnowledgeList` 与 API**
|
||||
- **请求参数**:`type` 已按 tab 传 `guide` / `article`(与后端 `type` 一致),并显式用 `typeParam` 传参。
|
||||
- **响应处理**:用 `Array.isArray(result.data.list)` 判断,只把合法数组赋给列表,否则用 `[]`,避免赋成 `undefined`。
|
||||
- **列表赋值**:用 `currentTab === 'articles'` 分支给 `articleList` 赋值,与「科普文章」tab 一致。
|
||||
|
||||
### 2. **错误处理**
|
||||
- 在 `catch` 里增加 `uni.showToast`,文案为 `error.message` / `error.msg` 或「加载列表失败」。
|
||||
- 在 `catch` 中**不**对 `guideList` / `articleList` 赋值,保持为初始的 `[]`,避免变成 `undefined`。
|
||||
|
||||
### 3. **onLoad 与无 id 时的列表**
|
||||
- 无 `id` 时不再在 onLoad 里调用 `loadKnowledgeList()`(当前 tab 为 nutrients,调用也会直接 return)。
|
||||
- 列表只在「切换 tab」时加载:`switchTab('guide')` / `switchTab('articles')` 内会调用 `loadKnowledgeList()`,从而加载对应 guide/article 列表。
|
||||
|
||||
### 4. **详情跳转 `goToDetail`**
|
||||
- 先取 `id = item.knowledgeId ?? item.id`,再判断 `id === undefined || id === null || id === ''`。
|
||||
- 无有效 id 时:`uni.showToast({ title: '暂无详情', icon: 'none' })` 并 return,不跳转。
|
||||
- 有 id 时才 `navigateTo` 到 `/pages/news/news_details/index?id=${id}`。
|
||||
|
||||
### 5. **列表展示与后端字段**
|
||||
- 后端返回 `summary`、`viewCount`、`publishedAt` 等,模板用的是 `desc`、`time`、`views`、`icon`。
|
||||
- 在赋值前对列表做了一层映射:`desc` ← summary、`time` ← 格式化 `publishedAt`/`createdAt`、`views` ← viewCount、`icon` 默认 `'📄'`,并增加了 `formatKnowledgeTime` 做日期格式化。
|
||||
|
||||
按当前逻辑:切换「饮食指南」或「科普文章」会请求 `type=guide` / `type=article` 并正确赋给 `guideList`/`articleList`;请求失败会 toast 且列表保持为 `[]`;只有存在 `knowledgeId` 或 `id` 时才跳转详情,否则提示「暂无详情」。
|
||||
42
scripts/logs/agent-BUG-008-103247.log
Normal file
42
scripts/logs/agent-BUG-008-103247.log
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
BUG-008 已按你的要求修好,修改总结如下。
|
||||
|
||||
---
|
||||
|
||||
## 1. 逻辑与数据流(已确认)
|
||||
|
||||
- **`postData.nutritionStats`**:在 `data()` 里初始化为 `[]`;在 `formatPostData()` 里由 `buildNutritionStatsFromDetailData(data)` 得到并赋值。
|
||||
- **加载入口**:`loadPostData(id)` 调 `getCommunityDetail(id)`,再用返回的 `data` 做 `formatPostData(data)`。
|
||||
- **后端社区详情**:返回 `nutritionDataJson`、`checkInRecordId`,**没有** `nutritionStats` 数组。
|
||||
`buildNutritionStatsFromDetailData` 已支持:
|
||||
- `nutritionStats` / `nutrition_stats`
|
||||
- `nutritionDataJson` / `nutrition_data_json`(解析出 calories、protein、potassium、phosphorus)
|
||||
- `dietaryData` / `mealData` / `dietary_data` / `meal_data`
|
||||
- **打卡详情**:当详情里没有营养数据但有 `checkInRecordId` 时,会再调 `getCheckinDetail(checkInRecordId)`;返回里有 `actualEnergy`、`actualProtein`,已用 `buildNutritionStatsFromCheckinDetail` 转成 `[{label, value}, ...]` 并写回 `postData.nutritionStats`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 实际修改内容
|
||||
|
||||
**(1)用打卡详情补全营养数据并等待完成**
|
||||
|
||||
- 原来:`fillNutritionStatsFromCheckin(data.checkInRecordId)` 未 `await`,页面先渲染,营养卡常为空。
|
||||
- 现在:在「无营养数据 + 有 checkInRecordId」时改为 **`await this.fillNutritionStatsFromCheckin(data.checkInRecordId)`**,在加载结束前就拿到打卡详情并填好 `nutritionStats`,营养卡能稳定显示。
|
||||
|
||||
**(2)显示条件改为“只看数组长度”且做防御**
|
||||
|
||||
- 要求:v-if 用 `nutritionStats.length > 0`,不依赖后端是否返回某字段。
|
||||
- 实现:
|
||||
- 增加计算属性 **`nutritionStatsLength`**:
|
||||
`(postData && postData.nutritionStats)` 且为数组时返回 `length`,否则为 `0`,避免 `nutritionStats` 未定义时报错。
|
||||
- 营养统计卡片的 v-if 改为:**`v-if="nutritionStatsLength > 0"`**。
|
||||
这样显示只依赖「当前页面的 nutritionStats 数组是否有项」,与后端字段名无关。
|
||||
|
||||
---
|
||||
|
||||
## 3. 未改动的部分(已符合需求)
|
||||
|
||||
- 后端无 `nutritionStats` 时,已通过「打卡详情」的 `actualEnergy`、`actualProtein` 等计算并填充 `nutritionStats`(格式 `[{label:'蛋白质', value:'56g'}, ...]`),无需再改。
|
||||
- 后端有 `nutritionDataJson` 等不同命名时,`buildNutritionStatsFromDetailData` 里已有多种字段名和 `dietaryData`/`mealData` 的兼容,无需额外映射修改。
|
||||
|
||||
当前逻辑是:先尝试从详情/`nutritionDataJson`/饮食数据得到 `nutritionStats`;若仍为空且存在 `checkInRecordId`,则 **await** 拉取打卡详情并据此填充;展示上只用 **`nutritionStatsLength > 0`** 控制营养卡显示。
|
||||
39
scripts/logs/agent-BUG-008-170907.log
Normal file
39
scripts/logs/agent-BUG-008-170907.log
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
BUG-008 已按你的要求修好,修改总结如下。
|
||||
|
||||
### 1. 阅读结果简述
|
||||
|
||||
- **postData.nutritionStats**:在 `data()` 里初始化为 `[]`,在 `formatPostData` 里只从 `data.nutritionDataJson` 解析并赋值;若后端没给或字段名不同,就会一直是空数组。
|
||||
- **加载逻辑**:`loadPostData` 调 `getCommunityDetail(id)`,用返回的 `data` 调用 `formatPostData(data)`。后端确实会返回 `nutritionDataJson`,但可能为空或字段名不一致(如 snake_case)。
|
||||
|
||||
### 2. 已做修改
|
||||
|
||||
**(1)统一从详情数据里构建营养统计**
|
||||
|
||||
- 新增 **`buildNutritionStatsFromDetailData(data)`**,按优先级从接口数据里生成 `nutritionStats`:
|
||||
- 若存在 **`nutritionStats` / `nutrition_stats`** 数组,直接规范成 `[{label, value}, ...]` 使用。
|
||||
- 否则解析 **`nutritionDataJson` / `nutrition_data_json`**,按原有逻辑生成热量、蛋白质、钾、磷四项。
|
||||
- 否则从 **`dietaryData` / `mealData` / `dietary_data` / `meal_data`** 等对象里取 calories/energy、protein、potassium、phosphorus(及常见别名),生成同样四项。
|
||||
|
||||
**(2)后端没有营养数据时用打卡数据补充**
|
||||
|
||||
- 新增 **`buildNutritionStatsFromCheckinDetail(detail)`**:根据打卡详情里的 `actualEnergy`、`actualProtein` 等生成 `[{label, value}, ...]`,钾/磷无则显示 `-`。
|
||||
- 新增 **`fillNutritionStatsFromCheckin(checkInRecordId)`**:请求 `getCheckinDetail(checkInRecordId)`,用上面方法得到 `nutritionStats` 并赋给 `postData.nutritionStats`。
|
||||
- 在 **`loadPostData`** 里,在 `formatPostData(data)` 之后:若当前 **`postData.nutritionStats.length === 0`** 且 **`data.checkInRecordId`** 存在,则调用 **`fillNutritionStatsFromCheckin(data.checkInRecordId)`**,用打卡数据补全营养统计(不阻塞评论、推荐等加载)。
|
||||
|
||||
**(3)展示条件只依赖数组长度**
|
||||
|
||||
- 营养统计卡片的 **v-if** 已改为只依赖是否有数据:
|
||||
- 原:`v-if="postData.nutritionStats && postData.nutritionStats.length > 0"`
|
||||
- 现:`v-if="postData.nutritionStats.length > 0"`
|
||||
(`postData.nutritionStats` 初始化为 `[]`,不会为 undefined。)
|
||||
|
||||
**(4)接口引用**
|
||||
|
||||
- 在 `@/api/tool.js` 的 import 中增加了 **`getCheckinDetail`**,用于在无详情营养数据时拉取打卡详情并计算营养统计。
|
||||
|
||||
效果总结:
|
||||
|
||||
- 后端有 `nutritionDataJson` 或其它营养相关字段(含不同命名)时,会正确解析并显示。
|
||||
- 后端没有营养数据但有关联打卡记录时,会用打卡详情中的热量、蛋白质等补全并显示。
|
||||
- 卡片是否展示只由 **`postData.nutritionStats.length > 0`** 决定,不再依赖“后端某字段是否存在”。
|
||||
24
scripts/logs/agent-BUG-009-102338.log
Normal file
24
scripts/logs/agent-BUG-009-102338.log
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
已按 BUG-009 要求处理,修改总结如下。
|
||||
|
||||
**1. Template 中的 Tab 与类型标签**
|
||||
|
||||
- **Tab 文案**:四个 Tab 的展示文字已是中文(推荐、最新、关注、热门),无需改。
|
||||
- **Tab 内部值**:`currentTab` 仍为 `recommend` / `latest` / `follow` / `hot`,用于 `switchTab` 和接口参数 `tab: this.currentTab`。按要求不改动接口逻辑,因此这些值保持英文,仅界面显示为中文。
|
||||
- **帖子类型标签**:`.type-tag` 和 `.meal-tag` 的文案都来自 `getMealTypeLabel(item.mealType)`,没有在模板里写死英文。
|
||||
|
||||
**2. 数据中的类型字段与 label 映射**
|
||||
|
||||
- `getMealTypeLabel` 中已有英文 → 中文映射:breakfast→早餐、lunch→午餐、dinner→晚餐、snack→加餐、share→分享、checkin→打卡。
|
||||
- 原先在未知类型时会 `return mealType`,可能把后端英文直接展示出来。
|
||||
- **修改**:未知类型时的 fallback 从 `mealType` 改为 `'分享'`,保证所有展示的 label 都是中文。
|
||||
|
||||
**具体改动(仅一处)**
|
||||
|
||||
- 在 `getMealTypeLabel` 中,将
|
||||
`return map[lower] != null ? map[lower] : mealType`
|
||||
改为
|
||||
`return map[lower] != null ? map[lower] : '分享'`
|
||||
这样任意未在 map 中的 `mealType`(包括英文或其它值)在界面上都会显示为「分享」,不会出现英文。
|
||||
|
||||
路由与接口调用未做任何修改。
|
||||
20
scripts/logs/agent-BUG-009-165426.log
Normal file
20
scripts/logs/agent-BUG-009-165426.log
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
BUG-009 已按你的要求改完,修改总结如下:
|
||||
|
||||
## 1. Template 检查结果
|
||||
|
||||
- **Tab 文案**:四个 Tab 的展示文字早就是中文(推荐、最新、关注、热门),未改。
|
||||
- **Tab 内部值**:`currentTab` 仍为 `recommend` / `latest` / `follow` / `hot`,用于 `switchTab()` 和接口参数 `tab`,按「不改动接口调用等逻辑」保留。
|
||||
- **帖子类型标签**:两处原先直接显示 `{{ item.mealType }}`,若接口返回英文(如 `breakfast`)会显示英文,已改为通过映射显示中文。
|
||||
|
||||
## 2. 具体修改
|
||||
|
||||
1. **类型标签展示改为用“中文 label”**
|
||||
- 有图:`<view class="meal-tag">{{ getMealTypeLabel(item.mealType) }}</view>`
|
||||
- 无图:`<view class="type-tag">{{ getMealTypeLabel(item.mealType) }}</view>`
|
||||
|
||||
2. **新增 `getMealTypeLabel(mealType)` 方法**
|
||||
- 英文 → 中文映射:`breakfast`→早餐、`lunch`→午餐、`dinner`→晚餐、`snack`→加餐、`share`→分享、`checkin`→打卡。
|
||||
- 若 `mealType` 已是中文或未知,则原样返回;空则返回「分享」。
|
||||
|
||||
这样 Tab 展示仍是中文,帖子类型在界面上也统一为中文;`currentTab`、接口入参和请求逻辑均未改动。
|
||||
8
scripts/logs/fix-bugs-20260302_1643.log
Normal file
8
scripts/logs/fix-bugs-20260302_1643.log
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
═══════════════════════════════════════════════
|
||||
[2026-03-02 16:43:17] ▶ 阶段 0 — 基线确认(运行回归测试,记录当前失败情况)
|
||||
═══════════════════════════════════════════════
|
||||
|
||||
Running 10 tests using 1 worker
|
||||
|
||||
✘ 1 [mobile-chrome] › tests/e2e/bug-regression.spec.ts:114:5 › TC-B01a 打卡前积分无提前跳变 (31.5s)
|
||||
1806
scripts/logs/fix-bugs-20260302_1644.log
Normal file
1806
scripts/logs/fix-bugs-20260302_1644.log
Normal file
File diff suppressed because it is too large
Load Diff
2526
scripts/logs/fix-bugs-20260303_1020.log
Normal file
2526
scripts/logs/fix-bugs-20260303_1020.log
Normal file
File diff suppressed because it is too large
Load Diff
0
scripts/logs/launchd-fix-all-error.log
Normal file
0
scripts/logs/launchd-fix-all-error.log
Normal file
5564
scripts/logs/launchd-fix-all.log
Normal file
5564
scripts/logs/launchd-fix-all.log
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user