- 添加 Gemini 2.5 Flash 对话接口(流式+非流式) - 添加 NanoBanana 图像生成/编辑接口 - 添加 Sora2 视频生成接口(文生视频、图生视频、去水印) - 移除 models-integration 子项目(功能已迁移至主后端) - 新增测试文档和 Playwright E2E 配置 - 更新前端页面和 API 接口 - 更新后端配置和日志处理
252 lines
14 KiB
Bash
Executable File
252 lines
14 KiB
Bash
Executable File
#!/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 "────────────────────────────────────────────────"
|