# 资产分类下拉框选择方案

## 问题背景

在 https://asset.2spread.com 的资产管理系统中，新增资产弹窗包含"资产分类"和"状态"两个下拉选择框。这些下拉框使用 Element UI 的 `el-select` 组件实现，需要正确触发点击和选择操作。

## 遇到的问题

### 问题1：下拉框定位错误
**现象**：最初使用 `.el-dialog .el-select .el-input__wrapper` 选择器无法找到下拉框。

**原因**：Element UI 新版本的下拉框结构变化，选择器类名改为 `.el-select__wrapper`。

**解决方案**：更新选择器为 `.el-select__wrapper`。

### 问题2：点击被拦截
**现象**：点击下拉框时报错 `el-overlay-dialog subtree intercepts pointer events`。

**原因**：弹窗使用 `.el-overlay-dialog` 容器，直接在全局定位会被遮挡层拦截。

**解决方案**：先定位到 `.el-overlay-dialog`，再在其内部查找下拉框：
```python
dialog = page.locator(".el-overlay-dialog")
selects = dialog.locator(".el-select__wrapper")
```

### 问题3：选项不可见
**现象**：下拉框打开后，使用 Playwright 的 `locator.click()` 点击选项时超时，报错 `element is not visible`。

**原因**：DOM 中存在两组重复的选项列表：
- 第一组：隐藏的缓存列表（`rect` 全为 0，不可见）
- 第二组：当前打开的下拉框（有实际坐标，可见）

Playwright 的 `querySelectorAll` 会找到第一组不可见的元素，导致点击失败。

**解决方案**：使用 JavaScript 直接操作 DOM，通过 `getBoundingClientRect()` 判断元素是否有实际坐标（`width > 0`），只点击可见的选项。

## 最终解决方案

### 完整代码

```python
def _set_select_value(self, page, text, select_index=0):
    """点击弹窗内第select_index个下拉框，选择匹配text的选项"""
    try:
        # 步骤1：在弹窗内定位下拉框
        dialog = page.locator(".el-overlay-dialog")
        selects = dialog.locator(".el-select__wrapper")
        
        if selects.count() <= select_index:
            print(f"    [X] 找不到第{select_index}个下拉框", flush=True)
            return

        # 步骤2：点击下拉框打开选项列表
        selects.nth(select_index).click()
        page.wait_for_timeout(800)

        # 步骤3：用JavaScript点击有实际坐标的可见选项
        result = page.evaluate("""(text) => {
            const items = document.querySelectorAll('.el-select-dropdown__list li');
            for (const item of items) {
                const rect = item.getBoundingClientRect();
                // 只点击有实际坐标的可见元素
                if (item.textContent.trim() === text && rect.width > 0) {
                    item.dispatchEvent(new MouseEvent('click', {bubbles: true}));
                    return true;
                }
            }
            return false;
        }""", text)
        
        if result:
            print(f"    [OK] 已选择: {text}", flush=True)
        else:
            print(f"    [X] 未找到选项: {text}", flush=True)
        page.wait_for_timeout(300)

    except Exception as e:
        print(f"    [X] 选择失败: {e}", flush=True)
        page.keyboard.press("Escape")
        page.wait_for_timeout(300)
```

### 调用方式

```python
# 选择资产分类（第0个下拉框）
self._set_select_value(page, "打印机", 0)

# 选择状态（第1个下拉框）
self._set_select_value(page, "在用", 1)
```

## 技术要点

### 1. 弹窗内定位
```python
dialog = page.locator(".el-overlay-dialog")
selects = dialog.locator(".el-select__wrapper")
```
- 先定位弹窗容器，避免点击被遮挡层拦截
- 在弹窗内部查找下拉框

### 2. 区分可见/不可见元素
```javascript
const rect = item.getBoundingClientRect();
if (rect.width > 0) {
    // 这是可见的元素
}
```
- 使用 `getBoundingClientRect()` 获取元素实际坐标
- `width > 0` 表示元素有实际渲染尺寸，是可见的

### 3. 触发 Vue 响应
```javascript
item.dispatchEvent(new MouseEvent('click', {bubbles: true}));
```
- 使用 `dispatchEvent` 触发真实的鼠标点击事件
- `bubbles: true` 确保事件冒泡，触发 Vue 的事件监听器

## 调试技巧

### 查看下拉框结构
```python
# 点击下拉框后，获取所有选项的状态
items = page.evaluate("""() => {
    const items = document.querySelectorAll('.el-select-dropdown__list li');
    return Array.from(items).map(li => ({
        text: li.textContent.trim(),
        visible: li.offsetParent !== null,
        rect: li.getBoundingClientRect()
    }));
}""")
```

### 截图调试
```python
page.screenshot(path="dropdown.png")
```

## 系统中的可选项

### 资产分类（9个选项）
- 办公桌
- 办公家具
- 台式电脑
- 办公椅
- 电子设备
- 交通工具
- 笔记本电脑
- 打印机
- 网络设备

### 状态（4个选项）
- 在用
- 闲置
- 维修中
- 报废

## 总结

解决 Element UI 下拉框选择的关键是：
1. 正确定位弹窗内的下拉框元素
2. 区分 DOM 中的可见/不可见重复元素
3. 使用 JavaScript 直接操作 DOM 绕过 Playwright 的可见性检查
4. 触发真实的鼠标事件以激活 Vue 的响应式更新
