合同批量推送

作者:董保全v1

批量推送商户合作方案合同签约(随单转推广费、F2妥投100%升级版物流合同、蜂鸟-准时达–全城版特约配送)。通过浏览器自动化操作轩辕系统合作方案页面,支持单店测试和批量执行。触发词:随单转合同推送、随单转推广费、批量签约、合作方案推送、合同推送、F2妥投、升级版签约、物流合同签约、蜂鸟准时达升级、全城送合同推送、全城版签约、特约配送合同、全城送物流合同、F5合同、F5、F5再推送、F5全城版。

下载量
319
点赞
78
价格
免费

技能文档

---
name: contract-batch-push
description: 批量推送商户合作方案合同签约(随单转推广费、F2妥投100%升级版物流合同、蜂鸟-准时达–全城版特约配送)。通过浏览器自动化操作轩辕系统合作方案页面,支持单店测试和批量执行。触发词:随单转合同推送、随单转推广费、批量签约、合作方案推送、合同推送、F2妥投、升级版签约、物流合同签约、蜂鸟准时达升级、全城送合同推送、全城版签约、特约配送合同、全城送物流合同、F5合同、F5、F5再推送、F5全城版。
version: 1.4.0
---

# 合同批量推送(随单转推广费 / F2妥投升级版 / 全城版特约配送)

## 触发场景

- 批量推送随单转推广费签约
- 从Excel名单执行随单转签约
- 合作方案批量添加「随单转推广费」
- F2妥投100%升级版物流合同批量签约
- 蜂鸟准时达升级版签约
- 全城送合同批量推送
- 蜂鸟-准时达–全城版(特约配送)签约
- F5合同批量推送 / F5再推送(**F5 = 蜂鸟-准时达–全城版 的业务别名**,与全城送/全城版同一合同,无需反问确认)

## 前置确认

执行前必须向用户确认:

1. **合同类型**:随单转推广费 / F2妥投升级版 / 全城版(特约配送)
2. **门店列表**:Excel文件路径 或 直接提供门店ID
3. **费率**:随单转默认4%,需确认(全城版无费率参数)
4. **生效日期**:必须用户明确指定,不可擅自决定(全城版为商家确认后次日自动生效)
5. **浏览器登录态**:确保已登录轩辕系统(xy.ele.me)

## 一、随单转推广费签约流程

### 核心URL

```
https://alsc-pc-commercial-contracts.faas.ele.me/?shopId={shopId}&source=xy
```

直接导航到此URL(绕过轩辕SPA路由和iframe限制)。

### 单店操作步骤

**Step 1: 导航至合作方案页**

使用 `tabs_context_mcp` 确保Tab Group就绪,`navigate` 到上述URL。等待页面加载完成(title含"合作方案"或页面出现方案列表)。

**Step 2: 点击「添加合作方案」**

页面加载后(title="合作方案"),点击「添加合作方案」按钮。

优先JS方式(成功率高):
```javascript
var btn = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('添加合作方案'));
if (btn) { btn.click(); console.log('Clicked 添加合作方案'); } else { console.log('No button'); }
```

备选:`read_page` 中该按钮通常显示为 `[ref_4] button "添加合作方案"`,可用 `computer` action=left_click ref=ref_4 点击。坐标备选:约 (1845, 28)(1920宽视口右上角)。

若JS超时(该域名下偶尔发生),直接用坐标点击。

**Step 3: 选择「随单转推广费」**

弹出"添加合作方案"页面,结构为:基础服务(特约配送)→ 商家服务 → **经营助力**(随单转推广费、接单宝、云盒)。

用 `computer` 坐标点击「随单转推广费」卡片(1920x897视口下约 x=200, y=420)。

备选JS:
```javascript
document.querySelectorAll('[class*="card"], [class*="item"], [class*="scheme"]').forEach(el => {
  if (el.textContent.includes('随单转推广费') && !el.textContent.includes('接单宝')) el.click();
});
```

点击后进入签约表单页(URL变为 `/sign-contract?shopId={shopId}&source=xy&tenantType=ELE`)。

表单结构:费率% | 转入账户(门店自己的账户/门店归属连锁层级的账户)| 生效时间 | 有效期 | 特殊说明。

**Step 4: 设置费率(React fiber注入)**

费率输入框是React受控组件,必须通过fiber注入:

```javascript
const inputs = document.querySelectorAll('input');
let rateInput = null;
for (const input of inputs) {
  if (input.type === 'number' && input.placeholder.includes('建议设置')) {
    rateInput = input;
    break;
  }
}
if (rateInput) {
  const fiberKey = Object.keys(rateInput).find(k => k.startsWith('__reactFiber') || k.startsWith('__reactInternalInstance'));
  if (fiberKey) {
    const fiber = rateInput[fiberKey];
    if (fiber && fiber.memoizedProps && fiber.memoizedProps.onChange) {
      rateInput.value = '4';
      fiber.memoizedProps.onChange({ target: rateInput, currentTarget: rateInput });
    }
  }
}
```

**Step 5: 设置生效日期**

日期选择器(Ant Design DatePicker)需要组合操作:

1. 用 `computer` 坐标点击日期输入框打开日历面板
2. 用 `computer` 点击目标日期格子
3. 日历关闭后,用 `computer` action=type 在日期输入框中输入完整日期字符串(如 `2026-05-19`),触发表单验证通过

备选JS方案(直接调用fiber onChange):
```javascript
const dateInput = document.querySelector('input[placeholder="请选择日期"], .ant-picker-input input');
if (dateInput) {
  const fiberKey = Object.keys(dateInput).find(k => k.startsWith('__reactFiber'));
  if (fiberKey && dateInput[fiberKey].memoizedProps.onChange) {
    dateInput.value = '2026-05-19';
    dateInput[fiberKey].memoizedProps.onChange({ target: dateInput, currentTarget: dateInput });
  }
}
```

**Step 6: 点击「立即签约」**

用 `computer` 坐标点击「立即签约」按钮。

**Step 7: 验证结果**

成功标志:URL变为 `/sign-result?...`,页面出现"签约审核提交成功"。

### 关键参数

| 参数 | 值 |
|------|-----|
| goodsId | 291 |
| skuId | 339 |
| salesPlanId | 99066036 |
| 费率 | 0.04 (4%) |
| 转入账户 | SHOP(门店自己) |
| 有效期 | CONTRACT_VALIDITY_AUTO(自动续期) |

## 二、F2妥投100%升级版物流合同签约

### 背景

将门店已有的「蜂鸟准时达 标准版(98%妥投率)」升级为「蜂鸟准时达 升级版(100%承诺妥投率)」。

### 核心URL

```
https://alsc-pc-commercial-contracts.faas.ele.me/?shopId={shopId}&source=xy
```

### 单店操作步骤

1. 导航到合作方案页(同上URL)
2. 用 `get_page_text` 确认当前方案状态(应显示"蜂鸟准时达 平台配送 98%承诺妥投率 标准版")
3. 点击「添加合作方案」按钮
4. 在方案选择页中选择「基础服务」→「蜂鸟准时达」(或「特约配送」)
5. 进入签约表单页(`/sign-contract`),系统会自动识别为升级
6. 确认信息后点击「立即签约」提交
7. 验证:URL变为 `/sign-result`,页面出现"签约审核提交成功"

### 判断是否已升级

`get_page_text` 中若显示"100%承诺妥投率 升级版"则已升级,标记skipped(already)。
若显示"98%承诺妥投率 标准版"则需要升级。

## 三、蜂鸟-准时达–全城版(特约配送)签约

> **别名**:业务口语「F5合同 / F5 / F5再推送 / F5全城版」= 本章节的蜂鸟-准时达–全城版(特约配送),与「全城送 / 全城版」是同一份合同。用户说 F5 时直接走本流程,无需反问确认合同类型。

### 背景

全城送=同城配送范围的蜂鸟准时达合同。签约后状态为「待确认」,需商家在商家端确认后次日生效,按月自动续期。签约不影响门店既有的到店自取、蜂鸟准时达98%标准版等合同。

### 跨域iframe关键发现

轩辕 shop-detail 页(`alsc-shop-manage-pc.faas.ele.me/shop-detail?shopId=X`)的「合作方案」模块嵌套在**跨域 iframe**(`alsc-pc-commercial-contracts.faas.ele.me/?shopId=X&source=xy`)中。由于跨域限制:

- 父页的 `find` 工具**无法定位** iframe 内的按钮/选项
- 父页的坐标点击**可能失效**(iframe 偏移导致坐标不准)
- 父页的 `javascript_tool` **无法穿透**到 iframe 内部 DOM

**解决方案**:直接 `navigate` 到 iframe 源 URL 作为顶层页面操作,此时所有 JS/DOM 操作均正常。

### 核心URL

```
https://alsc-pc-commercial-contracts.faas.ele.me/?shopId={shopId}&source=xy
```

### 单店操作步骤

**Step 1: 直接导航到 contracts 源页**

```
navigate → https://alsc-pc-commercial-contracts.faas.ele.me/?shopId={shopId}&source=xy
```

等待页面加载(title 含"合作方案")。注意该页面加载较慢(约15-30秒),若 navigate 超时则重试一次。

**Step 2: 点击「添加合作方案」(JS leaf-text click)**

在源页顶层,使用 JS 叶子节点文本匹配点击:

```javascript
(() => {
  const els = Array.from(document.querySelectorAll('*')).filter(
    e => e.children.length === 0 && e.textContent.trim() === '添加合作方案'
  );
  if (!els.length) return 'notfound:' + Array.from(document.querySelectorAll('button')).map(b => b.textContent.trim()).slice(0,10).join('|');
  els[0].click();
  return 'clicked:' + els[0].tagName + '.' + els[0].className;
})()
```

点击后进入"添加合作方案"选择页,结构为:基础服务(特约配送/远距离配送)→ 商家服务 → 经营助力。

**Step 3: 选择「蜂鸟-准时达–全城版」(en dash 陷阱)**

⚠️ **关键陷阱**:选项文案为「蜂鸟-准时达–全城版」,其中第二个 dash 是 **en dash(U+2013 –)**,不是普通连字符(U+002D -)。使用 `===` 精确匹配会失败!

**必须使用 `includes('全城版')` 模糊匹配**:

```javascript
(() => {
  const els = Array.from(document.querySelectorAll('*')).filter(
    e => e.children.length === 0 && e.textContent.trim().includes('全城版')
  );
  if (!els.length) return 'notfound';
  els[0].click();
  return 'clicked:' + els[0].tagName + ' txt=' + els[0].textContent.trim();
})()
```

点击后展开配送信息配置区:
- 配送范围:**同城**(默认勾选)
- 配送时效:**智能计算**(默认勾选)
- 合同类型:**普通**(默认勾选)

通常无需修改参数,直接使用默认值。

**Step 4: 点击「立即签约」**

```javascript
(() => {
  const els = Array.from(document.querySelectorAll('button, span')).filter(
    e => e.textContent.trim() === '立即签约'
  );
  if (!els.length) return 'notfound';
  const btn = els.find(e => e.tagName === 'BUTTON') || els[0];
  btn.click();
  return 'clicked:' + btn.tagName;
})()
```

⚠️ **整页刷新会杀 eval(批量执行必须用 setTimeout 安全退出模式)**:点击「立即签约」会触发**整页刷新**(→ sign-result),当前 evaluate 会报 `"Inspected target navigated or closed"`。**关键认知**:签约动作其实已在页面跳转**之前**完成,这个报错只是 eval 被整页刷新打断的**假错误**,并非签约失败。因此批量执行时改为:让点击通过 `setTimeout` 异步发出,使 evaluate 先安全返回,再在**下一轮工具调用**读取 URL 核验:

```javascript
// 本轮:发出点击后立即安全退出
(() => {
  const btn = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === '立即签约');
  if (btn) { setTimeout(() => btn.click(), 100); return 'scheduled'; }
  return 'notfound';
})()
```

```javascript
// 下一轮(等待 3-5 秒后):读 sign-result URL 核验
(async () => {
  await new Promise(r => setTimeout(r, 3000));
  return location.href.includes('sign-result') ? 'SIGNED' : 'PENDING';
})()
```

返回 `SIGNED` 即判定提交成功;返回 `PENDING` 再结合页面 toast 判断(见「五、异常处理」的在途单锁判定)。也可用 `tabs_context_mcp` 直接看 URL 是否含 `/sign-result`。

**Step 5: 关闭评分弹窗**

签约成功后会弹出满意度评分弹窗("请为刚完成的签约流程打分"),遮挡页面操作。用 JS 关闭:

```javascript
(() => {
  const btns = Array.from(document.querySelectorAll('button')).filter(
    b => b.textContent.trim() === '取 消' || b.textContent.trim() === '取消'
  );
  if (btns.length) { btns[0].click(); return 'closed'; }
  const x = document.querySelector('.ant-modal-close');
  if (x) { x.click(); return 'closed-x'; }
  return 'no-dialog';
})()
```

**Step 6: 核验签约结果**

重新导航回列表页验证:

```
navigate → https://alsc-pc-commercial-contracts.faas.ele.me/?shopId={shopId}&source=xy
```

核验口径(三项全部满足=成功):
1. **全部数+1**:合作方案 Tab「全部」计数比签约前多 1
2. **特约配送+1**:Tab「特约配送」计数比签约前多 1
3. **状态=待确认**:新合同卡片显示「蜂鸟-准时达–全城版|同城/智能计算/普通」,状态为橙色「待确认」

补充核验(sign-result 页):签约提交成功后 URL 跳转至 `/sign-result?...`,页面会显示 `orderNo`(签约单号)以及「商家确认 → 合作生效」步骤条(当前停在"商家确认"步骤)。若能看到 orderNo + 步骤条,即使未回列表页也可判定签约已提交。提交后状态为「待确认」,商家确认后次日生效、按月自动续期。

### 判断是否已签约

导航到列表页后,用 JS 检查是否已存在全城版合同:

```javascript
(() => {
  const has = Array.from(document.querySelectorAll('*')).some(
    e => e.children.length === 0 && e.textContent.includes('全城版')
  );
  return has ? 'ALREADY' : 'NOT_FOUND';
})()
```

若返回 ALREADY,标记 skipped(already),继续下一家。

### 关键参数

| 参数 | 值 |
|------|-----|
| 配送范围 | 同城 |
| 配送时效 | 智能计算 |
| 合同类型 | 普通 |
| 生效方式 | 商家确认后次日生效 |
| 续期方式 | 按月自动续期 |
| 签约后状态 | 待确认(商家确认→合作生效) |

## 四、批量执行策略

### Excel名单解析

三层表头结构(header=2):
```python
import pandas as pd
df = pd.read_excel(file_path, header=2)
pending = df[df['随单转是否签约'] == 0]['商户id'].dropna().unique()
```

### 规模预警

| 规模 | 策略 |
|------|------|
| ≤ 50家 | 直接执行,预估15-30分钟 |
| 51-200家 | 分批处理,每批30-50家 |
| > 200家 | 强烈建议分批+断点续传;告知用户可能需数小时 |

### 进度管理

每10-15家保存一次进度到 `batch_progress.json`:
```json
{
  "total": 120,
  "success": ["shopId1", "shopId2"],
  "skipped": [{"id": "shopId3", "reason": "已签约"}],
  "unknown": [{"id": "shopId4", "reason": "tab_timeout"}],
  "pending": ["shopId5", "shopId6"]
}
```

### Tab管理

- **必须单 Tab 串行处理,禁止多 Tab 并行**:本次 112 家实测中 4 路并行直接压垮浏览器扩展,导致所有 Tab 集体 V2 timeout;改回单 Tab 串行后恢复正常。并行不但不会更快,反而会让整批卡死。
- 单 Tab 处理上限约 170 家后 JS 引擎卡死
- **僵死 Tab(连续 2 次 V2 timeout)直接 close 换新 Tab**,不必先绕 baidu.com 恢复;`tabs_create_mcp` 新开 Tab 在同一 MCP 组内保持登录态
- 一般卡死(未僵死)可先导航到 baidu.com 尝试恢复,无效再 close 换新 Tab
- 同MCP组新建Tab保持登录态,跨组会丢失
- 每轮处理30家后主动换新Tab防止累积卡顿

### 并行会话去重

当有另一个会话/Tab 在并行处理同一批名单时(如 112 家批量推送中发现另一会话已完成 1138957670):

1. **本会话只用自己名下的 Tab**,不操作其他会话的 Tab
2. **每店执行前先跑"是否已签约"检查**(JS `includes('全城版')` 判断),返回 ALREADY 则跳过——这是防重复签约的核心守卫
3. 进度表中标注"并行会话完成"以区分来源,不计入本会话成功数
4. 断点清单落盘时包含已跳过的门店 ID + reason(`parallel_session_done`),确保续跑时不重复处理

### 并行会话 tab 劫持处置(cron/重试会话共享 tab 组)

⚠️ 当另一会话(如 9.11 定时重试 cron 任务)与本会话**共享同一 tab 组**时,本会话 `navigate` 到 A 店后,tab 可能被并行会话**中途导航到 B 店**,导致本会话在错误的门店上继续操作。

**识别信号**:navigate 到 `shopId=A` 后回读 URL,却显示 `shopId=B`(非自己导航的门店);或本会话发出的 setTimeout 点击落到了别人切换的页面上。

**处置(不要在被劫持的 tab 上纠缠)**:

1. **立即用 `tabs_create_mcp` 另开一个专属新 tab** 续跑(同 MCP 组保持登录态),后续本会话只认这个新 tab
2. 对被打断的 A 店,**执行前先跑已签守卫**(JS `includes('全城版')`):返回 `ALREADY` 则跳过——A 店可能在劫持前的 setTimeout 点击已生效,或已被并行会话签掉
3. 不试图与并行会话抢同一 tab、不做跨会话协调;靠"专属 tab + 已签守卫幂等去重"自然化解冲突
4. 若发现 tab 被导航走但门店确未签,在专属新 tab 上重新走完整签约流程即可

## 五、异常处理

| 异常 | 处理 |
|------|------|
| "暂无可签约的合作方案" | 标记skipped(no_suidan),继续下一家 |
| "需先完成入驻协议签约" | 标记skipped(prerequisite),继续 |
| "已有生效方案"/ALREADY_SIGNED | 标记skipped(already),继续 |
| toast「原合同正在被处理中」+ URL 停在 sign-contract(PENDING) | **在途单锁,startOrder 已受理,非失败**!标记 `pending_lock(in_transit)`,**不要重复推送**。此时列表页查不到全城版卡片(`NO_QC`)**不等于未提交**——在途单尚未生成卡片。处置:30 分钟后重试;仍锁则走中台查在途单。本次 112 家实测有 7 家命中此模式(1151316186/1164069297/1290173852/1298158290/2047980435/2059244514/2125984938) |
| 页面加载超时/Tab冻结 | 导航baidu.com恢复,失败则换新Tab,标记unknown |
| 登录态失效 | 中断流程,提示用户重新登录 |
| 表单验证失败"请选择生效时间" | 重新用type输入日期字符串 |
| ResizeObserver无限循环 | 立即换新Tab,标记该店unknown |
| 主脚本返回SIGNED_WAIT但验证false\|false,停留sign-contract、无任何toast/报错 | 最多再点1次「立即签约」(合计≤2次);仍无跳转无报错则标记unknown继续。此模式集中出现在历史"入驻协议未签约"失败店(如2088877267/501332772/503000433,2026-07-09实测复现),页面无错误文案,需人工排查门店资质 |
| 父页 find/坐标点击合作方案按钮无响应 | 确认内容在跨域 iframe,直接 navigate 到 iframe 源 URL `alsc-pc-commercial-contracts.faas.ele.me/?shopId=X&source=xy` 作为顶层页面操作 |
| JS 精确匹配选项名失败(en dash U+2013) | 「蜂鸟-准时达–全城版」中第二个 dash 是 en dash,改用 `includes('全城版')` 模糊匹配 |
| 签约后弹出评分弹窗遮挡页面 | JS 点击「取消」按钮或 `.ant-modal-close` 关闭弹窗 |
| 异步 JS 报 "Inspected target navigated or closed" **或 "Detached while handling command"** | 两者同为**整页刷新打断 evaluate 的假错误**(根因一致,只是报错文案不同):签约点击触发页面跳转,实际签约已成功。改用 `setTimeout(() => btn.click(), 100)` 让 evaluate 先安全退出,下一轮再通过 URL 含 `/sign-result` 判断成功;若已报 Detached/navigated,直接下轮读 `location.href.includes('sign-result')` 核验即可,勿重复点击 |
| Tab 连续2次 V2 timeout(僵死) | 用 `tabs_create_mcp` 新开 Tab,在新 Tab 中重新导航继续(同 MCP 组保持登录态) |
| 浏览器扩展/MCP 服务整体断连(`builtin_browser` 从工具列表消失) | 区别于单 Tab 冻结——此时所有浏览器操作均不可用。处置:① 立即落盘断点清单(pending 门店列表)到 `batch_progress.json`,确保已签门店不丢失;② 轮询探测扩展恢复(每 10-15 秒调用一次 `qw_mcp_list` 检查 `builtin_browser` 是否重新出现),**勿盲目重试 JS/navigate**;③ 扩展恢复后从断点清单续跑(本次实测:扩展断连 → 落盘 → 约 2 分钟后恢复 → 从 174100331 续跑成功)。若超过 5 分钟未恢复,中断流程通知用户检查 Chrome 扩展状态 |

## 六、结果报告

批量完成后生成汇总:
- 成功/跳过/未知 数量统计
- 失败门店及原因明细
- 建议重试列表(unknown门店)
- 输出Excel报告文件

### xlsx 报告生成配方(实测:Windows bash 环境)

⚠️ **运行时约束**:本机 bash 环境**只有 `py` launcher**(无 `python` / `python3`,直接调会报 `EXIT=127 command not found`);写含中文的 xlsx **必须 `py -X utf8`**,否则默认 GBK 编码写入中文会抛 `UnicodeEncodeError`。

**Step 1|探测 openpyxl 是否可用**

```bash
py -c "import openpyxl; print('ok')"
```

若报缺库:`py -m pip install openpyxl`(或退回用 xlsx 技能)。

**Step 2|Write 一个 gen_report.py(双 sheet:汇总 + 明细)**

```python
# -*- coding: utf-8 -*-
import openpyxl
from openpyxl.styles import Font, PatternFill

signed  = ["171304880", "174100331"]      # 本会话新签
already = ["1265396248", "2047980435"]     # 已存在/并行会话已签 → skipped(already)
unknown = ["542855116", "542873113"]       # 静默失败/资质类 → 待人工

wb = openpyxl.Workbook()
# 汇总 sheet
ws = wb.active; ws.title = "汇总"
head = Font(bold=True, color="FFFFFF"); fill = PatternFill("solid", fgColor="ED7D31")
rows = [("分类", "数量", "说明"),
        ("已签约(本会话)", len(signed), "sign-result 核验通过"),
        ("已存在/并行已签", len(already), "守卫命中 ALREADY,跳过"),
        ("静默失败 unknown", len(unknown), "两次点击无跳转无toast,资质类待人工/中台"),
        ("合计", len(signed)+len(already)+len(unknown), "")]
for r in rows: ws.append(r)
for c in ws[1]: c.font = head; c.fill = fill

# 明细 sheet
ws2 = wb.create_sheet("明细")
ws2.append(["门店ID", "状态", "备注"])
for c in ws2[1]: c.font = head; c.fill = fill
for s in signed:  ws2.append([s, "已签约", "本会话新签"])
for s in already: ws2.append([s, "已存在", "守卫去重跳过"])
for s in unknown: ws2.append([s, "unknown", "静默失败,待人工排查资质"])

out = r"C:\Users\TBSG\.qoderwork\workspace\<chatId>\outputs\全城版合同批量推送报告.xlsx"
wb.save(out); print("saved:", out)
```

**Step 3|执行并交付**

```bash
py -X utf8 "C:\Users\TBSG\.qoderwork\workspace\<chatId>\gen_report.py"
```

输出到 `outputs/`,用 `file://` 链接交付给用户。状态口径:`signed`(本会话新签)/ `already`(守卫命中跳过,含并行会话已签)/ `unknown`(静默失败待人工)/ `pending_lock`(在途锁,30分钟后重试)分别归类计数,明细 sheet 逐店列 门店ID|状态|备注。

## 关键约束

1. 浏览器操作必须**单 Tab 串行**,不可并行多 Tab 同时签约(多路并行会压垮浏览器扩展,触发集体 V2 timeout,反而拖垮整批)
2. 费率和生效日期必须用户确认,不可擅自决定(全城版无此参数,使用默认值)
3. 每10家保存进度,防止中断丢失
4. 关键步骤(费率设置后、提交前)截图确认
5. 遇到SIGN_VERIFY_FAIL需复查,可能是表单未正确填写
6. 所有合同类型均应直接导航 contracts 源页操作,不要在父页 iframe 中定位
7. 提交后报「原合同正在被处理中」= 在途单锁、已受理,**非失败,禁止重复推送**(30 分钟后重试或走中台查在途单)

## 实战经验(来自1900+店批量执行)

1. **JS vs 坐标**:该域名下 `javascript_tool` 偶尔超时(约5%概率),坐标点击更稳定。优先JS,超时则切坐标。
2. **费率默认值**:表单默认费率=3%,需改为4%。若fiber注入失败,备选方案:先triple_click选中输入框全部内容,再type输入"4"。
3. **日期输入关键**:纯JS设置日期常触发"请选择生效时间"验证错误。最可靠方法:computer点击打开日历→点击目标日期→日历关闭后再type完整日期字符串。
4. **Tab生命周期**:单Tab处理约170家后JS引擎彻底卡死(连baidu.com都timeout),必须换新Tab。建议每30家主动换新。
5. **部分门店页面资源异常**会导致立即卡死(如某些门店的CDN资源404触发无限重试),应标记unknown跳过,不要重试。
6. **登录态保持**:同MCP组内新建Tab保持登录态;跨MCP组切换会丢失。始终在同一Tab Group内操作。
7. **批量节奏**:每家门店约需40-90秒(导航3s + 点击添加3s + 选方案3s + 设费率5s + 设日期10s + 提交5s + 验证3s + 间隔等待)。全城版更快(无费率/日期设置),约30-60秒/家。
8. **get_page_text验证**:成功签约后URL含`/sign-result`,get_page_text会显示"签约审核提交成功请到审批-我提交的-审核中查看"。
9. **跨域 iframe 通用规律**:轩辕 shop-detail 页的合作方案/门店合同等模块均嵌套在 `alsc-pc-commercial-contracts.faas.ele.me` 跨域 iframe 中,所有同类合同推送(随单转/F2/全城版)都应直接导航源页操作,不要试图在父页定位。
10. **JS leaf-text click 最稳**:在 contracts 源页上,`querySelectorAll('*')` + `children.length===0` + textContent 匹配 + `.click()` 比 find/坐标点击成功率高,因为页面元素层级深、ref 定位常返回容器而非按钮本身。
11. **en dash 字符陷阱**:「蜂鸟-准时达–全城版」中第二个 dash 是 U+2013(en dash),非普通连字符 U+002D,所有文本匹配务必用 includes 而非 ===。
12. **setTimeout 安全退出模式**:批量执行时,若 JS 中点击「立即签约」会触发页面跳转导致 evaluate 报错 "Inspected target navigated or closed",改用 `setTimeout(() => btn.click(), 100)` 让 evaluate 先返回,再异步检查 sign-result URL 判断成功。
13. **全城版签约后流程**:签约提交≠生效,状态为「待确认」,需商家在商家端确认后次日生效。批量推送完成后应提醒用户跟进商家确认(可用 batch-store-send-list 技能生成催确认清单)。
14. **扩展断连≠Tab冻结**:Chrome 扩展断连时 `builtin_browser` 整体从 MCP 工具列表消失(所有浏览器操作均不可用),与单 Tab V2 timeout 是两种不同故障。断连时勿重试 JS/navigate(会全部失败),应立即落盘断点清单后进入轮询探测模式(`qw_mcp_list` 检查服务是否恢复),恢复后续跑。112 家批量实测:断连约 2 分钟后自恢复,从断点 174100331 续跑零丢失。
15. **并行会话去重**:当多会话/多 Tab 并行处理同一批名单时(如另一会话已完成 1138957670),核心守卫是每店执行前先跑 `includes('全城版')` 已签检查。返回 ALREADY 则跳过、标注 `parallel_session_done`。不要试图跨会话协调进度——让"幂等检查"自然去重即可。
16. **在途单锁 ≠ 失败(112 家实测沉淀)**:提交后若页面弹 toast「原合同正在被处理中」、URL 停在 sign-contract、返回 `PENDING`,这是 **startOrder 已受理的在途锁**,不是签约失败。判定要点:① 此时列表页查不到全城版卡片(`NO_QC`)**不代表未提交**,在途单尚未生成卡片;② 标记 `pending_lock(in_transit)`,**禁止重复推送**(重复点只会持续撞锁);③ 30 分钟后可重试,仍锁则走中台查在途单。本次 7 家(1151316186 等)命中,已排期 9.11 自动重试。
17. **整页刷新杀 eval → setTimeout 点击 + 下轮读 URL 核验**:点「立即签约」触发整页刷新,签约其实已在跳转前完成,`"Inspected target navigated or closed"` 只是 eval 被刷新打断的假错误。正确管线:本轮用 `setTimeout(() => btn.click(), 100)` 让 eval 先安全返回 `scheduled`;**下一轮工具调用**再跑 `location.href.includes('sign-result') ? 'SIGNED' : 'PENDING'` 核验。配合**单 Tab 串行**(多路并行会压垮扩展导致集体 V2 timeout),僵死 Tab 直接 close 换新,是本次跑通 112 家的核心运行时纪律。
18. **假错误有两种文案,同一根因**:除 `"Inspected target navigated or closed"` 外,整页刷新还会报 `"Detached while handling command"`(104 店 F5 再推送实测复现,如 1317743659)。两者都是 eval 被整页 reload 打断的假错误,签约已成功——不要因文案不同而误判失败或重复点击,直接下一轮读 `sign-result` URL 核验即可。
19. **cron/重试会话共享 tab 组 → tab 劫持**:当另一定时会话(如 9.11 在途锁重试 cron)与本会话共用同一 tab 组时,本会话 navigate 到 A 店后,tab 可能被并行会话中途导航到 B 店(回读 URL 是别人家的 shopId)。处置:立即 `tabs_create_mcp` **另开专属新 tab** 续跑,不在被劫持 tab 上纠缠;对被打断的 A 店执行前先跑已签守卫(`includes('全城版')`),ALREADY 则跳过(劫持前 setTimeout 点击可能已生效或并行会话已签)。靠"专属 tab + 幂等守卫"零冲突化解,不做跨会话协调。
20. **F5 = 全城版别名**:业务口语「F5合同 / F5再推送」就是蜂鸟-准时达–全城版(特约配送),与全城送/全城版同一合同,直接走第三章流程,无需反问确认合同类型。
21. **xlsx 报告用 py -X utf8 + openpyxl**:本机 bash 只有 `py` launcher(无 python/python3),生成含中文的 xlsx 报告必须 `py -X utf8 gen_report.py`,否则 GBK 编码写中文报错。配方见「六、结果报告」:双 sheet(汇总计数 + 明细 门店ID|状态|备注),输出到 outputs/ 用 file:// 交付。

如何安装此技能?

访问技能市场,点击「安装」按钮,按提示将技能包放入 AI 编程助手的 skills 目录即可。

浏览技能市场

支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手