提交 46a566f2 authored 作者: 陈泽健's avatar 陈泽健

feat(element-locate): 元素定位功能优化 - API增强 + 配置面板

Phase 1: 后端 API 增强
- 新增 BatchLocateRequest 参数: page_load_timeout, extra_wait_time, wait_for_selector, retry_on_empty, max_retries
- 新增 BatchLocateResponse 字段: elements_extracted, retries, page_load_time
- 增强 _do_locate_with_executor 支持配置参数和重试机制

Phase 2: 微前端元素提取增强
- 优化 extract_interactive_elements 函数,增强元素去重
- 扩展 Element UI/Vuetify/Ant Design 组件支持
- 提取更多元素属性(data-*, title, alt, role 等)

Phase 3: 前端配置面板
- 新增获取定位配置弹窗(支持配置等待时间、重试等参数)
- 新增预览页面按钮
- 优化定位结果显示(元素数量、耗时、重试次数)
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 885b901c
...@@ -300,31 +300,43 @@ function extractInteractiveElements() { ...@@ -300,31 +300,43 @@ function extractInteractiveElements() {
### 8.1 Phase 1 执行记录 ### 8.1 Phase 1 执行记录
**开始时间**: **开始时间**: 2026-08-03
**结束时间**: **结束时间**: 2026-08-03
**执行人**: **执行人**: Claude Code
**完成情况**: **完成情况**: ✅ 已完成
- 更新 BatchLocateRequest/BatchLocateResponse schema
- 增强 _do_locate_with_executor 支持配置参数和重试机制
- 记录元素数量、重试次数、页面加载耗时
### 8.2 Phase 2 执行记录 ### 8.2 Phase 2 执行记录
**开始时间**: **开始时间**: 2026-08-03
**结束时间**: **结束时间**: 2026-08-03
**执行人**: **执行人**: Claude Code
**完成情况**: **完成情况**: ✅ 已完成
- 优化 extract_interactive_elements 函数
- 增强元素去重逻辑(多重属性组合 key)
- 扩展 Element UI/Vuetify/Ant Design 组件支持
- 提取更多元素属性(data-*, title, alt, role 等)
### 8.3 Phase 3 执行记录 ### 8.3 Phase 3 执行记录
**开始时间**: **开始时间**: 2026-08-03
**结束时间**: **结束时间**: 2026-08-03
**执行人**: **执行人**: Claude Code
**完成情况**: **完成情况**: ✅ 已完成
- 新增获取定位配置弹窗
- 支持配置页面加载超时、额外等待时间、等待特定元素
- 新增预览页面按钮
- 优化定位结果显示(元素数量、耗时、重试次数)
- 前端构建验证通过
### 8.4 Phase 4 执行记录 ### 8.4 Phase 4 执行记录
**开始时间**: **开始时间**: 待执行
**结束时间**: **结束时间**:
**执行人**: **执行人**:
**完成情况**: **完成情况**: ⏳ 待部署验证
--- ---
......
...@@ -2,10 +2,16 @@ ...@@ -2,10 +2,16 @@
> **生成时间**: 2026-08-03 > **生成时间**: 2026-08-03
> **当前分支**: `platform-auto-test` > **当前分支**: `platform-auto-test`
> **最近提交**: `82c6f778` fix(element-locate): 修复批量定位数据库更新问题,延长超时时间 > **最近提交**: `待提交` feat(element-locate): 元素定位功能优化 - API增强 + 配置面板
> **状态**: ✅ 元素定位功能完成 + 始终使用 Claude CLI + 前端步骤表格显示优化 > **状态**: ✅ 元素定位功能优化完成(Phase 1-3)
> >
> **本次会话完成**: > **本次会话完成**:
> - ✅ Phase 1: 后端 API 增强 — 新增 5 个配置参数 + 3 个响应字段 + 重试机制
> - ✅ Phase 2: 微前端元素提取增强 — 扩展 Element UI/Vuetify/Ant Design 组件支持
> - ✅ Phase 3: 前端配置面板 — 获取定位配置弹窗 + 预览页面功能
> - ✅ 前端构建验证通过
>
> **上次会话完成**:
> - ✅ 修复步骤表格不显示定位信息问题(新增"定位类型"和"定位值"列) > - ✅ 修复步骤表格不显示定位信息问题(新增"定位类型"和"定位值"列)
> - ✅ 去掉置信度判断,始终调用 Claude CLI 进行元素匹配 > - ✅ 去掉置信度判断,始终调用 Claude CLI 进行元素匹配
> - ✅ 修复批量定位数据库更新失败问题 > - ✅ 修复批量定位数据库更新失败问题
...@@ -13,8 +19,6 @@ ...@@ -13,8 +19,6 @@
> - ✅ 优化微前端元素提取(支持 shadow DOM + Element UI 组件) > - ✅ 优化微前端元素提取(支持 shadow DOM + Element UI 组件)
> - ✅ 优化 Claude CLI 调用(直接传递元素列表,不再让宿主机重新访问页面) > - ✅ 优化 Claude CLI 调用(直接传递元素列表,不再让宿主机重新访问页面)
> - ✅ 创建测试用例验证闭环(登录成功 8/8,会议列表 2/7) > - ✅ 创建测试用例验证闭环(登录成功 8/8,会议列表 2/7)
> - ✅ 生成优化需求文档和计划执行文档
> - ✅ 代码提交并推送到远程仓库
--- ---
...@@ -197,7 +201,12 @@ ...@@ -197,7 +201,12 @@
{ {
"case_id": "case_xxx", "case_id": "case_xxx",
"page_url": "https://192.168.5.44/", "page_url": "https://192.168.5.44/",
"auto_login": true "auto_login": true,
"page_load_timeout": 10000, // 可选:页面加载超时(毫秒)
"extra_wait_time": 5000, // 可选:额外等待时间(毫秒)
"wait_for_selector": "", // 可选:等待特定元素(CSS选择器)
"retry_on_empty": true, // 可选:元素为空时重试
"max_retries": 2 // 可选:最大重试次数
} }
``` ```
...@@ -219,7 +228,10 @@ ...@@ -219,7 +228,10 @@
"message": "置信度 95%" "message": "置信度 95%"
} }
], ],
"message": "成功定位 5/6 个步骤" "message": "成功定位 5/6 个步骤",
"elements_extracted": 42, // 新增:提取到的元素总数
"retries": 0, // 新增:实际重试次数
"page_load_time": 12.5 // 新增:页面加载耗时(秒)
} }
``` ```
...@@ -240,7 +252,7 @@ ...@@ -240,7 +252,7 @@
| 优先级 | 任务 | 说明 | | 优先级 | 任务 | 说明 |
|--------|------|------| |--------|------|------|
| 🔴 **P0** | 元素定位功能优化 | 按已生成的 PRD 和计划执行文档实施优化 | | 🔴 **P0** | 部署到服务器 | 前端已构建,需上传到 192.168.5.60 并验证 |
| 🟡 **P1** | 设备模拟模块联调 | MQTT 环境配置与联调待验证 | | 🟡 **P1** | 设备模拟模块联调 | MQTT 环境配置与联调待验证 |
| 🟢 **P2** | 清理临时脚本 | 根目录大量探索脚本和部署脚本待清理 | | 🟢 **P2** | 清理临时脚本 | 根目录大量探索脚本和部署脚本待清理 |
| 🟢 **P2** | Phase 5 剩余 | Pinia 状态管理、单元测试 | | 🟢 **P2** | Phase 5 剩余 | Pinia 状态管理、单元测试 |
......
...@@ -64,6 +64,16 @@ export interface BatchLocateRequest { ...@@ -64,6 +64,16 @@ export interface BatchLocateRequest {
page_url?: string page_url?: string
/** 是否自动登录(默认 true) */ /** 是否自动登录(默认 true) */
auto_login?: boolean auto_login?: boolean
/** 页面加载超时时间(毫秒,默认 10000) */
page_load_timeout?: number
/** 页面加载后额外等待时间(毫秒,默认 5000) */
extra_wait_time?: number
/** 等待特定元素出现(CSS选择器) */
wait_for_selector?: string
/** 元素为空时是否重试(默认 true) */
retry_on_empty?: boolean
/** 最大重试次数(默认 2) */
max_retries?: number
} }
/** /**
...@@ -102,6 +112,12 @@ export interface BatchLocateResponse { ...@@ -102,6 +112,12 @@ export interface BatchLocateResponse {
results: StepLocateResult[] results: StepLocateResult[]
/** 消息 */ /** 消息 */
message: string message: string
/** 提取到的元素总数 */
elements_extracted?: number
/** 实际重试次数 */
retries?: number
/** 页面加载耗时(秒) */
page_load_time?: number
} }
/** /**
......
...@@ -188,7 +188,7 @@ ...@@ -188,7 +188,7 @@
size="small" size="small"
type="success" type="success"
link link
@click="batchLocate(row)" @click="showLocateConfig(row)"
:loading="locatingCaseId === row.id" :loading="locatingCaseId === row.id"
:disabled="row.caseType !== 'ui'" :disabled="row.caseType !== 'ui'"
> >
...@@ -217,6 +217,67 @@ ...@@ -217,6 +217,67 @@
</div> </div>
</el-card> </el-card>
<!-- 获取定位配置弹窗 -->
<el-dialog
v-model="locateConfigVisible"
title="批量获取定位"
width="500px"
destroy-on-close
>
<el-form label-width="120px">
<el-form-item label="用例名称">
<el-input :value="locateConfigCaseName" disabled />
</el-form-item>
<el-divider content-position="left">高级配置</el-divider>
<el-form-item label="页面加载超时">
<el-input-number
v-model="locateConfig.page_load_timeout"
:min="5000"
:max="60000"
:step="5000"
style="width: 150px"
/>
<span style="margin-left: 10px; color: #999">毫秒</span>
</el-form-item>
<el-form-item label="额外等待时间">
<el-input-number
v-model="locateConfig.extra_wait_time"
:min="0"
:max="30000"
:step="1000"
style="width: 150px"
/>
<span style="margin-left: 10px; color: #999">毫秒</span>
</el-form-item>
<el-form-item label="等待特定元素">
<el-input
v-model="locateConfig.wait_for_selector"
placeholder="CSS 选择器(可选)"
style="width: 300px"
/>
</el-form-item>
<el-form-item label="自动重试">
<el-switch v-model="locateConfig.retry_on_empty" />
<span style="margin-left: 10px; color: #999">元素为空时自动重试</span>
</el-form-item>
<el-form-item v-if="locateConfig.retry_on_empty" label="最大重试次数">
<el-input-number
v-model="locateConfig.max_retries"
:min="1"
:max="5"
style="width: 100px"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="previewPage">预览页面</el-button>
<el-button @click="locateConfigVisible = false">取消</el-button>
<el-button type="primary" @click="batchLocate" :loading="locatingCaseId !== ''">
开始获取
</el-button>
</template>
</el-dialog>
<!-- 创建/编辑用例弹窗 --> <!-- 创建/编辑用例弹窗 -->
<el-dialog <el-dialog
v-model="editDialogVisible" v-model="editDialogVisible"
...@@ -884,6 +945,34 @@ const deleteCase = async (row: any) => { ...@@ -884,6 +945,34 @@ const deleteCase = async (row: any) => {
/** 当前正在获取定位的用例 ID */ /** 当前正在获取定位的用例 ID */
const locatingCaseId = ref('') const locatingCaseId = ref('')
/** 配置面板相关状态 */
const locateConfigVisible = ref(false)
const locateConfigCaseId = ref('')
const locateConfigCaseName = ref('')
const locateConfig = ref({
page_load_timeout: 10000,
extra_wait_time: 5000,
wait_for_selector: '',
retry_on_empty: true,
max_retries: 2,
})
/**
* 显示获取定位配置面板
*/
const showLocateConfig = (row: any) => {
locateConfigCaseId.value = row.id
locateConfigCaseName.value = row.name
locateConfigVisible.value = true
}
/**
* 预览页面(在新窗口打开已登录的目标页面)
*/
const previewPage = () => {
window.open('https://192.168.5.44/', '_blank')
}
/** /**
* 一键获取用例所有步骤的元素定位 * 一键获取用例所有步骤的元素定位
* *
...@@ -893,29 +982,35 @@ const locatingCaseId = ref('') ...@@ -893,29 +982,35 @@ const locatingCaseId = ref('')
* 3. 为每个步骤匹配定位器并更新到数据库 * 3. 为每个步骤匹配定位器并更新到数据库
* 4. 前端显示结果 * 4. 前端显示结果
*/ */
const batchLocate = async (row: any) => { const batchLocate = async () => {
try { locateConfigVisible.value = false
await ElMessageBox.confirm( locatingCaseId.value = locateConfigCaseId.value
`将为用例「${row.name}」的所有步骤自动获取元素定位,是否继续?`,
'批量获取定位',
{ type: 'info', confirmButtonText: '开始获取', cancelButtonText: '取消' }
)
} catch {
return
}
locatingCaseId.value = row.id
try { try {
ElMessage.info('正在启动浏览器获取定位,请稍候...') ElMessage.info('正在启动浏览器获取定位,请稍候...')
const result = await elementLocateApi.locateBatch({ const result = await elementLocateApi.locateBatch({
case_id: row.id, case_id: locateConfigCaseId.value,
page_url: 'https://192.168.5.44/', page_url: 'https://192.168.5.44/',
auto_login: true, auto_login: true,
page_load_timeout: locateConfig.value.page_load_timeout,
extra_wait_time: locateConfig.value.extra_wait_time,
wait_for_selector: locateConfig.value.wait_for_selector || undefined,
retry_on_empty: locateConfig.value.retry_on_empty,
max_retries: locateConfig.value.max_retries,
}) })
if (result.success) { if (result.success) {
const msg = `定位完成:成功 ${result.located_steps}/${result.total_steps} 个步骤` let msg = `定位完成:成功 ${result.located_steps}/${result.total_steps} 个步骤`
if (result.elements_extracted) {
msg += `,提取 ${result.elements_extracted} 个元素`
}
if (result.page_load_time) {
msg += `,耗时 ${result.page_load_time.toFixed(1)}s`
}
if (result.retries) {
msg += `,重试 ${result.retries} 次`
}
ElMessage.success(msg) ElMessage.success(msg)
// 刷新用例列表 // 刷新用例列表
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论