合
合同批量推送
作者:董保全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:// 交付。支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手