# 执行计划：智能定位语义化升级 - 语义化用例生成器

> **文档版本**: v1.0
> **创建日期**: 2026-08-18
> **关联PRD**: `_PRD_智能定位语义化升级_语义化用例生成器.md`
> **预计工期**: 3 个阶段（后端生成 → 前端回填 → 数据配套），每阶段独立交付验证

---

## 一、执行概述

### 1.1 执行目标

把智能定位从"裸选择器提取器"升级为"**语义化用例生成器**"：定位阶段复用执行期的 `semantic_resolver.resolve_step` 解析链，产出 `semantic` 语义目标（type/scope/text/contains/container）+ 条件 `verify`，让智能定位生成的用例**天然走语义化执行机制**，与「新建会议-语义化重写示范」同级别稳定。

1. 语义解析优先定位（反向复用解析链，命中即执行验证）
2. semantic 目标生成规则（type/text/scope/contains/container/nth）
3. 条件 verify 生成（防假通过，不引入假失败）
4. 动态数据 CTX 化（`{__CTX:key__}` + `parameters` 初值）
5. 前端 batchLocate 回填 semantic/verify 并落库
6. 配套数据增强（会议列表 scope 注册、映射表 v2 键对齐）

**硬性约束**：不改动解析链（`semantic_resolver.py`/`playwright_executor.py`/`element_mapping_service.py`/`page_url_service.py` 只消费不修改）；老用例（无 semantic 字段）执行零影响。

### 1.2 改动范围

| 模块 | 文件 | 改动类型 |
|------|------|----------|
| 智能定位服务 | `backend/app/services/smart_locate_service.py` | **增强**（核心：semantic 生成） |
| 智能定位路由 | `backend/app/routers/smart_locate.py` | 增强（schema 加字段） |
| 前端定位 API | `frontend/src/api/elementLocate.ts` | 增强（类型） |
| 前端用例页 | `frontend/src/views/Cases.vue` | 增强（batchLocate 回填） |
| 页面注册表 | `backend/app/data/page_url_mapping.json` | 增强（meeting_list scope，可选） |
| 元素映射表 | `backend/app/data/elements_mapping.json` | 增强（v2 页级键，可选） |

### 1.3 不改动的部分

- `semantic_resolver.py` / `playwright_executor.py` / `element_mapping_service.py` / `page_url_service.py`（解析链已稳定，只消费）
- `keyword_matcher.py` / `selector_extractor.py` / `claude_service.py`（复用现有能力）
- 数据库 schema（无新表/新列）
- 现有 `selectors` / `params.selector` / `locator_type` / `locator_value` 输出格式（双轨兼容）
- 被测系统（5.44/5.69）无改动

---

## 二、任务分解与实施计划

### 阶段 1：后端 semantic 生成（Phase A）

#### 任务 1.1：候选 semantic 目标构造 `_build_candidate_semantic`

**文件**: `backend/app/services/smart_locate_service.py`

**实施步骤**：

1. 新增方法，从步骤名 + action 构造候选 semantic 目标：

```python
def _build_candidate_semantic(self, step: Dict, page) -> Optional[Dict]:
    """
    从步骤名/action 构造候选 semantic 目标（语义解析优先路径用）
    - type: action 映射（fill→input，click→button 缺省）
    - text: 步骤名核心词（剔除动作词、动态值、标点）
    - scope: recognize_current_page 识别结果（识别不到 None）
    - contains: 步骤名"xxx：值"模式中的锚点值
    """
```

2. `text` 提取：复用 `keyword_matcher` 的动作词剥离思路，取核心词（如"确定创建"/"会议名称"/"预定会议"）。**剔除动态值**（`：` 后的值，避免污染语义键）。
3. `type` 缺省推断：`action=="fill"` → `input`；`action=="click"` → `button`（后续 `_infer_semantic_from_element` 再按元素细化）。
4. `scope` 复用 `get_page_url_service().recognize_current_page(page)`；识别不到 → `None`（该字段留空，执行期降级安全）。

**验收标准**：
- 步骤名"点击【确定创建】按钮" → `{type: "button", text: "确定创建"}`
- 步骤名"勾选会议室：北京展厅会议室" → `{type: "button", text: "勾选会议室", contains: "北京展厅会议室"}`
- scope 识别不到时字段留空不抛异常

#### 任务 1.2：语义解析优先 `_try_semantic_execute`

**文件**: `backend/app/services/smart_locate_service.py`

**实施步骤**：

1. 新增方法，构造候选 semantic → `resolve_step` → 命中则执行验证：

```python
def _try_semantic_execute(self, page, step: Dict, scope: Optional[str]) -> Optional[Dict]:
    """
    语义解析优先：构造候选 semantic → resolve_step 命中 chain
    → 复用 _execute_step 执行 → 成功则返回 {semantic, selectors, params}
    失败返回 None（调用方走 keyword 定位路径）
    """
    semantic = self._build_candidate_semantic(step, page)
    if not semantic:
        return None
    ctx = ExecutionContext({})
    chain = self._semantic_resolver.resolve_step(page, step, scope, ctx) or []
    if not chain:
        return None
    # 用解析链构造临时结果并执行验证
    probe = dict(step, params={**step.get("params", {}), "selectors": chain})
    if self._execute_step(probe):
        return {"semantic": semantic, "chain": chain, "selectors": chain}
    return None
```

2. 依赖注入：`__init__` 增加 `self._semantic_resolver = get_semantic_resolver()`、`self._page_url_service = get_page_url_service()`。
3. `_execute_step` 复用现有实现（fill/click/wait/select + 弹窗检测）。

**验收标准**：
- 语义路径命中时返回 `{semantic, chain}`，步骤不进 keyword 打分路径
- 语义路径未命中/执行失败 → 返回 None，调用方回退现有路径，行为不变

#### 任务 1.3：定位成功后反向生成 `_infer_semantic_from_element`

**文件**: `backend/app/services/smart_locate_service.py`

**实施步骤**：

1. 新增方法，从候选元素反推细化 semantic：

```python
def _infer_semantic_from_element(self, step: Dict, element_info: Dict,
                                 container: Optional[Dict]) -> Dict:
    """
    反向生成 semantic（keyword 定位成功后）
    - type: element_info.tag/className/role + action 反推
      input/textarea→input；.el-checkbox/input[type=checkbox] 且容器 table→row_checkbox
      否则 checkbox；.el-tabs__item/role=tab→tab；img/i/icon→icon；button→button；
      tr/.el-table__row→row；其余 button
    - container: 父容器信息 {type, selector}
    - text/contains/scope: 复用 _build_candidate_semantic 结果
    """
```

2. 容器推断：复用 `keyword_matcher._detect_parent_container(page, element)`（返回 `{container: 'dialog'/'table'/...}`）与 `selector_extractor._generate_combined_selectors` 的运行时容器信息，映射为 `{type, selector}`。
3. 返回值含 `type/text/scope/contains/container` 全字段（缺失留空）。

**验收标准**：
- fill 步骤 → `type: "input"`
- 点击 `.el-table` 内 `.el-checkbox` → `type: "row_checkbox"` + `container: {type: "table", selector: ".el-table"}`
- 点击 `.el-tabs__item` → `type: "tab"`

#### 任务 1.4：条件 verify 生成 `_detect_verify_after`

**文件**: `backend/app/services/smart_locate_service.py`

**实施步骤**：

1. 新增方法，定位执行后检测确定状态变化：

```python
def _detect_verify_after(self, step: Dict, page) -> Optional[Dict]:
    """
    观察到确定状态变化才生成 verify（保守策略）
    - 成功提示 .el-message--success → {type: "text_visible", text: 提示文案}
    - 弹窗/抽屉/确认框出现 → {type: "dialog"}（带 title 文本）
    - 特定元素出现（如 .room .user_list）→ {type: "element_visible", selector}
    - 观察不到 → None
    """
```

2. 复用现有验证类步骤的检测逻辑（`is_verification_step` 分支已有 `.el-message--success` 等检测），抽成通用方法。
3. verify 类型对齐前端 `ASSERT_TYPE_OPTIONS`（text_visible / element_visible / dialog）。

**验收标准**：
- 点击"确定创建"后出现"创建成功"提示 → `{type: "text_visible", text: "创建成功"}`
- 观察不到状态变化 → 返回 None（不生成错误断言）

#### 任务 1.5：动态数据 CTX 化 `_ctf_param`

**文件**: `backend/app/services/smart_locate_service.py`

**实施步骤**：

1. 新增方法，识别步骤名动态值：

```python
def _ctf_param(self, step_name: str) -> Tuple[Optional[str], Optional[str]]:
    """
    步骤名含"xxx：值"模式 → (CTX 键名, 初值)；无则 (None, None)
    值识别为动态数据（非纯静态词）时替换为 {__CTX:key__}
    """
```

2. `locate_steps` 收集所有 CTX 键 → 用例级 `parameters`（返回给调用方合并）。
3. 生成的步骤名中动态值替换为 `{__CTX:key__}`（如"勾选会议室：北京展厅会议室"→"勾选会议室：{__CTX:room__}"），初值 `parameters["room"]="北京展厅会议室"`。

**验收标准**：
- "勾选会议室：北京展厅会议室" → 步骤名含 `{__CTX:room__}`，parameters 含 `room: "北京展厅会议室"`
- 静态值步骤（无 `：`）原样保留

#### 任务 1.6：定位流程整合 + schema 扩展

**文件**: `backend/app/services/smart_locate_service.py`, `backend/app/routers/smart_locate.py`

**实施步骤**：

1. `_locate_single_step` 流程整合（在原 keyword 定位之前插入语义优先路径）：

```
定位流程（改造后）：
1. 已有选择器 → 直接使用（现状保留）
2. navigate / 登录步骤 → 现状保留
3. 验证类步骤 → 现状保留
4. 【新增】_try_semantic_execute 命中 → 返回 {selectors, semantic, verify}
5. 【新增】keyword 定位成功 → _infer_semantic_from_element 反向生成 semantic
   + _detect_verify_after 条件生成 verify
6. keyword 定位失败 → 现状（语义推断回退 / 失败标记）
```

2. 返回值增加 `semantic` / `verify` 字段（在 `_locate_single_step` 结果 dict 中）。
3. `locate_steps` 收集 `parameters`（`_ctf_param` 产出）附加到返回结果。
4. `backend/app/routers/smart_locate.py` 的 `SmartLocateResult` schema 增加：

```python
semantic: Optional[Dict[str, Any]] = Field(None, description="语义目标")
verify: Optional[Dict[str, Any]] = Field(None, description="状态验证")
```

`SmartLocateResponse` 增加 `parameters: Dict[str, Any] = Field(default_factory=dict)`。

**验收标准**：
- 定位结果含 `semantic`（命中语义路径或 keyword 成功步骤）
- 老步骤（已有选择器/登录/navigate）结果格式与改造前一致
- API 响应 schema 校验通过

### 阶段 2：前端回填（Phase B）

#### 任务 2.1：elementLocate.ts 类型扩展

**文件**: `frontend/src/api/elementLocate.ts`

**实施步骤**：

1. `SmartLocateResult`（L156-183）增加：

```ts
semantic?: Record<string, any>
verify?: Record<string, any>
```

2. `SmartLocateResponse`（L188-199）增加：

```ts
parameters?: Record<string, any>
```

**验收标准**：`npm run build` 类型检查通过。

#### 任务 2.2：Cases.vue batchLocate 回填 semantic

**文件**: `frontend/src/views/Cases.vue`

**实施步骤**：

1. `batchLocate()`（L1069-1154）步骤回写逻辑（L1110-1134）扩展：

```ts
const updatedSteps = steps.map((s: any) => {
  const r = result.results.find((x: any) => x.order === s.order && x.success)
  if (r) {
    const updatedParams = { ...(s.params || {}), ...(r.params || {}) }
    if (r.selectors?.primary) {
      updatedParams.selector = r.selectors.primary
    }
    return {
      ...s,
      params: updatedParams,
      locator_type: 'css',
      locator_value: r.selectors?.primary || '',
      // 新增：回填 semantic / verify（保留步骤已有值）
      semantic: r.semantic || s.semantic,
      verify: r.verify || s.verify,
    }
  }
  return s
})
```

2. 用例 `parameters` 合并：`result.parameters` 与用例现有 parameters 合并后随 update 提交。
3. 落库后编辑模式自动切 semantic（已有判定 L872-875：任一步有 `semantic.text` 即切，无需改动）。

**验收标准**：
- 智能定位后步骤含 `semantic`/`verify` 并落库
- 编辑弹窗打开自动切语义模式，`CaseStepEditor` 显示 semantic 表单
- 老用例（无 semantic 返回）行为不变

### 阶段 3：配套数据增强（Phase C，可选）

#### 任务 3.1：会议列表 scope 注册

**文件**: `backend/app/data/page_url_mapping.json`

**实施步骤**：

1. 注册 `meeting_list` 页：url_patterns（`meetingV3.*(Message|message)` 或按抓包 URL 校准）+ fingerprint（`.el-table` 会议列表容器，min_count 1）。
2. 参照 `create_meeting` 的 `match_rules`/`skip_steps` 补直达配置（可选）。

**验收标准**：`recognize_current_page` 能识别会议列表页；不影响既有 4 页识别。

#### 任务 3.2：元素映射表 v2 页级键对齐

**文件**: `backend/app/data/elements_mapping.json`

**实施步骤**：

1. 核对 `_page_id_for` 归组结果，把"会议预约"页下会议子页元素（会议列表/会议模板/会议室/个人日程）在键前缀或 tier 上对齐到独立页级 token，使 `lookup_by_key("meeting_list", key)` 能命中。

**验收标准**：`lookup_by_key("meeting_list", "会议列表-表格")` 等命中；语义化执行回归通过。

---

## 三、验收标准

### 3.1 功能验收

| # | 验收项 | 验收标准 |
|---|--------|---------|
| 1 | 语义解析优先 | 命中语义路径的步骤不经 keyword 打分，且实际执行成功 |
| 2 | semantic 生成 | 定位结果含 `semantic`（type/scope/text/contains/container），经 `resolve_step` 命中验证 |
| 3 | 条件 verify | 观察到确定状态变化才生成，观察不到不生成 |
| 4 | 前端回填 | `batchLocate` 后步骤含 semantic/verify 并落库，编辑弹窗自动切语义模式 |
| 5 | 动态数据 CTX | "xxx：值"步骤值转 `{__CTX:key__}`，初值进 `parameters` |

### 3.2 执行验收（关键）

| # | 验收项 | 验收标准 |
|---|--------|---------|
| 1 | 智能定位生成用例 | 「新建会议」相关用例调智能定位 → 生成 semantic 目标 → 落库 |
| 2 | 连跑两次无残留 | 生成用例真实执行连跑两次全绿、零残留 |
| 3 | 回归 | 老用例（无 semantic）执行全部通过，不受影响 |

---

## 四、测试计划

### 4.1 单元测试（后端）

- `_build_candidate_semantic`：步骤名 → semantic 候选（含动态值剔除、scope 留空）
- `_infer_semantic_from_element`：元素信息 → type/container 反推
- `_detect_verify_after`：状态观察 → verify / None
- `_ctf_param`：动态值识别 → (CTX 键, 初值)

运行：`cd backend && pytest tests/ -v --deselect tests/test_api.py`（预存坏用例排除）

### 4.2 构建测试

- `cd frontend && npm run build`

### 4.3 端到端测试

1. 用「新建会议」相关用例步骤调 `POST /api/element/smart-locate`
2. 校验返回的 `semantic`/`verify` 字段
3. 落库 → 真实执行连跑两次 → 校验全绿 + 5.44 会议列表零残留
4. 回归：老用例执行

---

## 五、风险评估

| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| 生成的 semantic.text 过拟合当前 DOM | 中 | 执行漂移 | 强制"resolve_step 命中 + 实际执行成功才返回" |
| verify 生成错误导致执行失败 | 中 | 假失败 | 保守策略：仅生成观察到的确定状态断言 |
| scope 覆盖不全（注册表仅 4 页） | 中 | 部分步骤 scope 留空 | 识别不到时 semantic.scope 留空，执行期语义解析降级安全 |
| 老用例/老范式回归 | 低 | 存量用例受影响 | 新逻辑仅在智能定位流程启用，keyword 路径与执行器零改动 |
| CTX 化误伤静态值 | 低 | 步骤名变化 | 仅"xxx：值"模式 + 值非纯静态词才替换 |

---

## 六、实施记录

| 日期 | 任务 | 状态 | 说明 |
|------|------|------|------|
| 2026-08-18 | PRD 评审通过 | ✅ | 执行计划生成 |
| 2026-08-18 | 阶段 1 后端 semantic 生成 | ✅ | `smart_locate_service.py`：`_build_candidate_semantic` / `_try_semantic_execute`（链首 DOM 校验）/ `_infer_semantic_from_element` / `_infer_semantic_from_pattern`（模式值作 text，动态值 CTX，新增 `_extract_pattern_value` / `_ctxify_if_dynamic`）/ `_validate_semantic_resolves`（反向生成经执行期解析器校验，row_checkbox→row 降级）/ `_ctf_param`（语义优先路径同样收集参数）/ `_execute_step` 全候选点击链 + force 重试 |
| 2026-08-18 | schema 扩展 | ✅ | `routers/smart_locate.py` `SmartLocateResult` 增 `semantic`/`verify` |
| 2026-08-18 | keyword_matcher 兜底 | ✅ | `find_element_by_semantic` 兜底 `return None, []`，修复 tuple 解包崩溃 |
| 2026-08-18 | 阶段 2 前端回填 | ✅ | `elementLocate.ts` 类型扩展 + `Cases.vue` `batchLocate` 回填 semantic/verify；`npm run build` 通过 |
| 2026-08-18 | 阶段 3 配套数据 | ✅ | `page_url_mapping.json` 会议列表 scope 注册（5 页加载正常） |
| 2026-08-18 | 单测 | ✅ | `test_smart_locate_semantic.py` 37 用例全过（新增模式语义生成/校验降级/`_extract_pattern_value`/`_ctxify_if_dynamic`）；全量 `pytest --ignore=test_api.py` 161 过 |
| 2026-08-18 | 端到端验证 | ✅ | `verify_smart_locate_semantic.py` 连跑两次 7/7 全绿；4 个步骤产出 semantic（input×2 + row_checkbox + tab），3 个动态值 CTX 化（param1 会议名/param2 会议室/param3 议题），语义与示范用例 `create_semantic_meeting_case.py` 同构 |

---

## 七、后续工作

- 智能定位自动生成 `finally` api_call 清理步骤（对齐示范用例，本次不实施）
- 自愈合机制（选择器失效自动修复）
- 智能定位生成结果的前端预览（semantic 目标可视化）

---

## 八、附录

### 8.1 关键复用点索引

| 复用点 | 位置 |
|------|------|
| `resolve_step(page, step, scope, ctx)` 解析链入口 | `backend/app/services/semantic_resolver.py` |
| `recognize_current_page(page)` scope 识别 | `backend/app/services/page_url_service.py:262` |
| `ExecutionContext` 上下文变量 | `backend/app/executors/ui_context.py` |
| `match_element_by_keywords` / `get_candidate_details` / `_detect_parent_container` | `backend/app/services/keyword_matcher.py` |
| `extract_element_info` / `_generate_combined_selectors` | `backend/app/services/selector_extractor.py` |
| `/api/debug/resolve` 无侵入语义解析验证接口 | `backend/app/routers/debug.py` |
| semantic 步骤构造模板 | `backend/scripts/create_semantic_meeting_case.py` |
| 执行器 semantic 消费点 | `backend/app/executors/playwright_executor.py:1170-1194` |

### 8.2 相关文档

| 文档 | 路径 |
|------|------|
| 本 PRD | `Docs/PRD/需求文档/用例管理/_PRD_智能定位语义化升级_语义化用例生成器.md` |
| 复杂用例通用执行机制 PRD/计划 | `Docs/PRD/需求文档/用例管理/_PRD_复杂用例通用执行机制_语义化用例执行.md` |
| UI 自动化交接文档 | `HANDOFF_UI自动化.md` |

---

*本文档由 Claude Code 于 2026-08-18 生成，评审通过后按任务分解进入 prd-code 实施。*
