自动发帖软件
标题:
无碍模式auto淘宝千牛自动发货系统
[打印本页]
作者:
发帖软件
时间:
3 小时前
标题:
无碍模式auto淘宝千牛自动发货系统
无碍模式auto淘宝千牛自动发货系统
1.png
(892 KB, 下载次数: 0)
3 小时前
上传
// =============================================================================
// 淘宝千牛自动发货系统 v3.0(精简版)
// 仅支持无碍模式(auto),使用完整商品标题精准匹配
// 功能:24小时监控千牛待发货列表 → 匹配商品标题 → 发送卡密/网盘链接
// 适用:AIWROK 安卓自动化平台,ES5/Rhino 引擎
// =============================================================================
importClass(java.io.File);
importClass(java.io.FileWriter);
importClass(java.io.BufferedReader);
importClass(java.io.InputStreamReader);
importClass(java.io.FileInputStream);
importClass(java.io.FileOutputStream);
importClass(java.io.OutputStreamWriter);
// =============================================================================
// 第一部分:全局配置
// =============================================================================
var CONFIG = {
千牛包名: "com.taobao.qianniu",
轮询间隔: 30, // 检查新订单间隔(秒)
最大重试: 3,
操作延时: 2, // 每步操作后等待(秒)
// 卡密服务器API(留空则用本地文件)
服务器地址: "",
服务器密钥: "",
使用服务器: false,
卡密目录: "/sdcard/卡密仓库/",
发货记录文件: "/sdcard/发货记录.txt",
启用保活: true,
保活间隔: 300,
启用悬浮窗: true,
// debug=只输出节点摘要不发货; test=处理一个真实订单测试; false=正常监控
调试模式: "debug",
};
// =============================================================================
// 第二部分:商品配置(用完整商品标题,精准匹配)
// =============================================================================
/**
* 配置说明:
* 商品标题: 淘宝商品的完整标题,用于在订单列表中精准匹配
* 发货类型: "卡密" / "网盘" / "卡密+网盘"
* 卡密文件: 本地卡密文件路径(每行一个卡密,用过的自动删除)
* 网盘链接: 该商品对应的网盘链接
* 发货话术: 发送给买家的话术,{卡密}和{网盘}自动替换
*/
var 商品配置 = {
"二年级数学必刷题上册人教版口算题卡天天练": {
发货类型: "卡密",
卡密文件: "/sdcard/卡密仓库/二年级数学必刷题.txt",
网盘链接: "",
发货话术: "您好,您购买的【二年级数学必刷题】已发货!\n卡密:{卡密}\n请打开APP输入卡密激活使用,有问题随时联系~"
},
"小学单位换算练习元角分长度单位专项训练": {
发货类型: "网盘",
卡密文件: "",
网盘链接: "https://pan.baidu.com/s/1aBcDeFgH 提取码: x1y2",
发货话术: "您好,您购买的【小学单位换算练习】已发货!\n网盘下载链接:{网盘}\n请复制链接到浏览器下载,有问题随时联系~"
},
"一年级加减口算练习册10以内20以内凑十法": {
发货类型: "卡密+网盘",
卡密文件: "/sdcard/卡密仓库/一年级加减口算.txt",
网盘链接: "https://pan.baidu.com/s/2bCdEfGhI 提取码: a3b4",
发货话术: "您好,您购买的【一年级加减口算】已发货!\n激活卡密:{卡密}\n网盘链接:{网盘}\n请先下载APP,输入卡密激活使用~"
}
// 继续添加商品...把完整的淘宝商品标题填进来即可
};
// =============================================================================
// 第三部分:无碍模式操作封装(仅auto,无模式分支)
// =============================================================================
var ActionAdapter = {
// ================================================================
// 基础操作(直接调用 auto 对象)
// ================================================================
init: function() {
if (typeof auto !== 'undefined') {
logger.log("无碍模式已就绪");
return true;
}
logger.err("auto对象不存在,请开启无障碍服务");
return false;
},
click: function(x, y) {
try {
auto.clickPoint(x, y);
return true;
} catch (e) {
logger.err("点击失败: " + e);
return false;
}
},
clickPercent: function(px, py) {
try {
auto.clickPercent(px, py);
return true;
} catch (e) {
logger.err("百分比点击失败: " + e);
return false;
}
},
swipe: function(x1, y1, x2, y2, duration) {
duration = duration || 500;
try {
auto.swip(x1, y1, x2, y2, duration, 0);
return true;
} catch (e) {
logger.err("滑动失败: " + e);
return false;
}
},
swipePercent: function(px1, py1, px2, py2, duration) {
duration = duration || 500;
var w = screen.getScreenWidth();
var h = screen.getScreenHeight();
return this.swipe(
Math.floor(px1 * w), Math.floor(py1 * h),
Math.floor(px2 * w), Math.floor(py2 * h), duration
);
},
back: function() {
try { auto.back(); return true; } catch (e) { return false; }
},
home: function() {
try { auto.home(); return true; } catch (e) { return false; }
},
// ================================================================
// 核心:auto.getXml() 节点解析
// 千牛很多按钮文字在 desc 属性里,必须同时匹配 text 和 desc
// ================================================================
getXml: function() {
try {
if (typeof auto !== 'undefined' && typeof auto.getXml === 'function') {
return auto.getXml();
}
} catch (e) {
logger.err("getXml失败: " + e);
}
return "";
},
/**
* 从XML中查找包含指定文字的节点(同时匹配 text 和 desc)
*/
findNodes: function(xml, keyword) {
var results = [];
if (!xml || !keyword) return results;
var pattern = /<node\s+([^>]+?)(?:\/>|>)/g;
var match;
while ((match = pattern.exec(xml)) !== null) {
var attrs = match[1];
var textVal = "";
var descVal = "";
var tm = attrs.match(/text="([^"]*)"/);
if (tm) textVal = tm[1];
var dm = attrs.match(/desc="([^"]*)"/);
if (dm) descVal = dm[1];
if (textVal.indexOf(keyword) !== -1 || descVal.indexOf(keyword) !== -1) {
results.push(this._parseNode(attrs, textVal, descVal));
}
}
return results;
},
/**
* 解析XML中所有节点(不过滤关键词,用于调试和父节点查找)
*/
findAllNodes: function(xml) {
var results = [];
if (!xml) return results;
var pattern = /<node\s+([^>]+?)(?:\/>|>)/g;
var match;
while ((match = pattern.exec(xml)) !== null) {
var attrs = match[1];
var tm = attrs.match(/text="([^"]*)"/);
var dm = attrs.match(/desc="([^"]*)"/);
results.push(this._parseNode(attrs, tm ? tm[1] : "", dm ? dm[1] : ""));
}
return results;
},
/**
* 解析单个节点属性(内部方法)
*/
_parseNode: function(attrs, textVal, descVal) {
var cpm = attrs.match(/centerPercent="\[([0-9.]+),([0-9.]+)\]"/);
var cm = attrs.match(/center="\[(\d+),(\d+)\]"/);
var clm = attrs.match(/clickable="([^"]*)"/);
var idm = attrs.match(/id="([^"]*)"/);
var bm = attrs.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
var clsm = attrs.match(/class="([^"]*)"/);
return {
text: textVal,
desc: descVal,
x: cm ? parseInt(cm[1]) : 0,
y: cm ? parseInt(cm[2]) : 0,
px: cpm ? parseFloat(cpm[1]) : 0,
py: cpm ? parseFloat(cpm[2]) : 0,
clickable: clm ? clm[1] : "false",
id: idm ? idm[1] : "",
bounds: bm ? [parseInt(bm[1]), parseInt(bm[2]), parseInt(bm[3]), parseInt(bm[4])] : null,
class: clsm ? clsm[1] : ""
};
},
/**
* 查找不可点击节点的最近可点击父节点
*/
findClickableParent: function(node, xml) {
if (!node || !node.bounds) return null;
var allNodes = this.findAllNodes(xml);
var nodeArea = (node.bounds[2] - node.bounds[0]) * (node.bounds[3] - node.bounds[1]);
var bestParent = null;
var bestArea = 999999999;
for (var i = 0; i < allNodes.length; i++) {
var p = allNodes[i];
if (p.clickable !== "true" || !p.bounds) continue;
// 父节点必须包含目标节点
if (p.bounds[0] <= node.bounds[0] && p.bounds[1] <= node.bounds[1] &&
p.bounds[2] >= node.bounds[2] && p.bounds[3] >= node.bounds[3]) {
var pArea = (p.bounds[2] - p.bounds[0]) * (p.bounds[3] - p.bounds[1]);
// 选面积最小的可点击父节点(最近的)
if (pArea < bestArea && pArea >= nodeArea) {
bestArea = pArea;
bestParent = p;
}
}
}
return bestParent;
},
/**
* 找文字并点击(核心方法)
* 1. 查找包含文字的节点
* 2. 优先点击 clickable=true 的节点
* 3. 不可点击的找父节点点击
*/
findTextAndClick: function(text, timeout) {
timeout = timeout || 3000;
var startTime = new Date().getTime();
while (new Date().getTime() - startTime < timeout) {
var xml = this.getXml();
if (!xml) { sleep.millisecond(毫秒 = 300); continue; }
var result = this._findBestNode(xml, text);
if (result) {
if (result.clickable === "true") {
this.clickPercent(result.px, result.py);
} else {
// 不可点击 → 找最近可点击父节点
var parent = this.findClickableParent(result, xml);
if (parent) {
logger.log("节点不可点击,使用父节点: [" + result.text + "|" + result.desc + "] -> px=" + parent.px + " py=" + parent.py);
this.clickPercent(parent.px, parent.py);
} else {
this.clickPercent(result.px, result.py);
}
}
sleep.millisecond(毫秒 = 500);
logger.log("找到并点击: " + text + " (text=" + result.text + " desc=" + result.desc + ")", true);
return true;
}
sleep.millisecond(毫秒 = 300);
}
logger.warn("未找到文字: " + text);
return false;
},
/**
* 查找最佳节点(优先可点击的)
*/
_findBestNode: function(xml, text) {
var nodes = this.findNodes(xml, text);
if (nodes.length === 0) return null;
// 优先返回 clickable=true
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].clickable === "true") return nodes[i];
}
return nodes[0];
},
/**
* 找文字(返回节点信息,不点击)
*/
findText: function(text) {
var xml = this.getXml();
if (!xml) return null;
return this._findBestNode(xml, text);
},
hasText: function(text) {
return this.findText(text) !== null;
},
hasAnyText: function(texts) {
for (var i = 0; i < texts.length; i++) {
if (this.findText(texts[i])) return true;
}
return false;
},
/**
* 输出当前页面所有有意义节点的摘要(调试用)
*/
dumpPageSummary: function() {
var xml = this.getXml();
if (!xml) { logger.warn("无法获取页面XML"); return; }
var nodes = this.findAllNodes(xml);
var count = 0;
logger.log("====== 页面节点摘要 ======");
for (var i = 0; i < nodes.length; i++) {
var n = nodes[i];
// 过滤掉空白节点
if (n.text === "" && n.desc === "") continue;
logger.log(" [" + (n.clickable === "true" ? "可点击" : " 不可") + "] text=\"" + n.text + "\" desc=\"" + n.desc + "\" px=" + n.px + " py=" + n.py);
count++;
}
logger.log("====== 共 " + count + " 个有意义节点 ======");
},
/**
* 输入文字(通过剪贴板粘贴,兼容中文)
*/
inputText: function(text) {
try {
if (typeof Clipboard !== 'undefined' && Clipboard.copy) {
Clipboard.copy(text);
sleep.millisecond(毫秒 = 300);
}
// 尝试粘贴
try {
var node = auto.nodeSearch(3000).focused(true);
if (node && typeof node.getNode === 'function') {
var n = node.getNode(0);
if (n && typeof n.paste === 'function') {
n.paste();
}
}
} catch (pe) {}
sleep.second(秒 = 1);
logger.log("已输入文字: " + text.substring(0, 20) + (text.length > 20 ? "..." : ""));
return true;
} catch (e) {
logger.err("输入文字失败: " + e);
return false;
}
},
/**
* 等待指定文字出现
*/
backToText: function(text, timeout) {
timeout = timeout || 10000;
var startTime = new Date().getTime();
while (new Date().getTime() - startTime < timeout) {
if (this.hasText(text)) return true;
sleep.millisecond(毫秒 = 500);
}
return false;
}
};
// =============================================================================
// 第四部分:日志系统(悬浮窗 + Toast + print.log/err/warn)
// =============================================================================
var logger = {
悬浮窗实例: null,
标题控件: null,
内容控件: null,
状态控件: null,
日志缓冲: [],
最大行数: 12,
统计: { 轮次: 0, 发货: 0, 错误: 0, 启动时间: null },
init: function() {
this.统计.启动时间 = new Date();
if (!CONFIG.启用悬浮窗) return;
try {
this.悬浮窗实例 = new floatUI();
this.悬浮窗实例.loadXML(
'<LinearLayout orientation="vertical" w="400" h="280" gravity="top" id="log_main" background="#CC000000">' +
' <LinearLayout orientation="horizontal" w="400" h="30" gravity="center_vertical" background="#FF1a1a2e">' +
' <TextView id="log_title" textColor="#FFD700" textSize="13sp" padding="8dp" layout_weight="1" text="📦 淘宝自动发货v3" />' +
' </LinearLayout>' +
' <LinearLayout orientation="horizontal" w="400" h="24" gravity="center_vertical" background="#FF16213e">' +
' <TextView id="log_status" textColor="#00FFFF" textSize="10sp" padding="6dp" layout_weight="1" text="状态: 初始化中..." />' +
' </LinearLayout>' +
' <TextView id="log_content" textColor="#00FF00" textSize="10sp" padding="6dp" layout_weight="1" text="等待启动...\n" />' +
'</LinearLayout>'
);
this.标题控件 = this.悬浮窗实例.findViewById('log_title');
this.状态控件 = this.悬浮窗实例.findViewById('log_status');
this.内容控件 = this.悬浮窗实例.findViewById('log_content');
var self = this;
setTimeout(function() {
if (self.悬浮窗实例) self.悬浮窗实例.setPosition(5, 5);
}, 200);
} catch (e) {}
},
_time: function() {
var now = new Date();
var h = now.getHours(), m = now.getMinutes(), s = now.getSeconds();
return (h < 10 ? "0" : "") + h + ":" + (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s;
},
_更新状态: function() {
if (!this.状态控件) return;
try {
var runtime = "";
if (this.统计.启动时间) {
var diff = Math.floor((new Date() - this.统计.启动时间) / 1000);
var h = Math.floor(diff / 3600);
var m = Math.floor((diff % 3600) / 60);
var s = diff % 60;
runtime = " 运行" + (h > 0 ? h + "h" : "") + m + "m" + s + "s";
}
this.状态控件.setText("轮次:" + this.统计.轮次 + " | 发货:" + this.统计.发货 + " | 错误:" + this.统计.错误 + runtime);
} catch (e) {}
},
_toast: function(msg) {
try {
if (typeof toast !== 'undefined' && toast.show) toast.show("" + msg);
} catch (e) {}
},
_output: function(level, msg, showToast) {
var timeStr = this._time();
var levelTag = "";
if (level === "信息") { levelTag = "ℹ"; }
else if (level === "成功") { levelTag = "✅"; }
else if (level === "警告") { levelTag = "⚠"; }
else if (level === "错误") { levelTag = "❌"; this.统计.错误++; }
var line = timeStr + " " + levelTag + " " + msg;
// 按级别调用 AIWROK 平台原生方法
try {
if (level === "错误" && typeof print !== 'undefined' && print.err) {
print.err(line);
} else if (level === "警告" && typeof print !== 'undefined' && print.warn) {
print.warn(line);
} else if (typeof print !== 'undefined' && print.log) {
print.log(line);
} else if (typeof printl === 'function') {
printl(line);
}
} catch (e) {}
// 悬浮窗
this.日志缓冲.push(line);
if (this.日志缓冲.length > this.最大行数) this.日志缓冲.shift();
if (this.内容控件) {
try { this.内容控件.setText(this.日志缓冲.join("\n")); } catch (e) {}
}
this._更新状态();
if (showToast) this._toast(levelTag + " " + msg);
},
log: function(msg, toast) { this._output("信息", msg, toast); },
warn: function(msg, toast) { this._output("警告", msg, toast); },
err: function(msg, toast) { this._output("错误", msg, toast); },
success: function(msg, toast) { this._output("成功", msg, toast); },
addShip: function() { this.统计.发货++; this._更新状态(); },
addRound: function() { this.统计.轮次++; this._更新状态(); }
};
// =============================================================================
// 第五部分:卡密管理
// =============================================================================
var 卡密管理 = {
取本地卡密: function(文件路径) {
try {
var file = new File(文件路径);
if (!file.exists()) {
logger.err("卡密文件不存在: " + 文件路径);
return null;
}
var reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
var lines = [], line;
while ((line = reader.readLine()) !== null) {
line = line.trim();
if (line !== "" && line.indexOf("#") !== 0) lines.push(line);
}
reader.close();
if (lines.length === 0) {
logger.warn("卡密文件已空: " + 文件路径);
return null;
}
var 卡密 = lines[0];
logger.log("取出卡密: " + 卡密 + " (剩余 " + (lines.length - 1) + " 个)");
var remaining = lines.slice(1);
var writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
for (var i = 0; i < remaining.length; i++) writer.write(remaining[i] + "\n");
writer.close();
return 卡密;
} catch (e) {
logger.err("读取卡密失败: " + e);
return null;
}
},
取服务器卡密: function(商品ID) {
try {
var url = CONFIG.服务器地址 + "?action=get&product=" + 商品ID + "&key=" + CONFIG.服务器密钥;
logger.log("从服务器获取卡密: " + url);
var response = http.get(url);
if (!response) { logger.err("服务器无响应"); return null; }
try {
var json = JSON.parse(response);
if (json.code === 0 && json.data) {
logger.log("服务器返回卡密: " + json.data);
return json.data;
}
logger.err("服务器返回错误: " + (json.msg || json.message || response));
} catch (e) {
if (response && response.length > 0) {
logger.log("服务器返回卡密: " + response);
return response;
}
}
} catch (e) {
logger.err("服务器获取卡密失败: " + e);
}
return null;
},
上报已使用: function(商品ID, 卡密, 订单号) {
try {
var url = CONFIG.服务器地址 + "?action=report&product=" + 商品ID + "&key=" + 卡密 + "&order=" + 订单号;
var response = http.get(url);
logger.log("服务器上报结果: " + response);
} catch (e) {
logger.err("服务器上报失败: " + e);
}
},
取卡密: function(商品) {
if (CONFIG.使用服务器) return this.取服务器卡密(商品.名称 || "");
return this.取本地卡密(商品.卡密文件);
},
检查库存: function(商品) {
if (CONFIG.使用服务器) return -1;
try {
var file = new File(商品.卡密文件);
if (!file.exists()) return 0;
var reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
var count = 0, line;
while ((line = reader.readLine()) !== null) {
line = line.trim();
if (line !== "" && line.indexOf("#") !== 0) count++;
}
reader.close();
return count;
} catch (e) { return -1; }
}
};
// =============================================================================
// 第六部分:发货记录
// =============================================================================
var 发货记录 = {
已发货: function(订单号) {
try {
var file = new File(CONFIG.发货记录文件);
if (!file.exists()) return false;
var reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
var line;
while ((line = reader.readLine()) !== null) {
if (line.indexOf(订单号) !== -1) { reader.close(); return true; }
}
reader.close();
} catch (e) {}
return false;
},
记录: function(订单号, 商品名, 发货内容) {
try {
var writer = new OutputStreamWriter(new FileOutputStream(CONFIG.发货记录文件, true), "UTF-8");
var now = new Date();
var dateStr = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate() + " " + logger._time();
writer.write(dateStr + " | " + 订单号 + " | " + 商品名 + " | " + 发货内容 + "\n");
writer.close();
logger.log("已记录发货: " + 订单号 + " -> " + 商品名);
} catch (e) {
logger.err("记录发货失败: " + e);
}
},
今日数量: function() {
try {
var file = new File(CONFIG.发货记录文件);
if (!file.exists()) return 0;
var reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
var now = new Date();
var today = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
var count = 0, line;
while ((line = reader.readLine()) !== null) {
if (line.indexOf(today) !== -1) count++;
}
reader.close();
return count;
} catch (e) { return 0; }
}
};
// =============================================================================
// 第七部分:千牛自动化操作
// =============================================================================
var 千牛操作 = {
启动千牛: function() {
logger.log("启动千牛...", true);
try {
app.openApp(CONFIG.千牛包名);
for (var i = 8; i > 0; i--) {
sleep.second(秒 = 1);
}
logger.success("千牛已启动");
return true;
} catch (e) {
logger.err("启动千牛失败: " + e);
return false;
}
},
确保运行: function() {
// 无碍模式没有shell,直接用app.openApp确保运行
app.openApp(CONFIG.千牛包名);
sleep.second(秒 = 3);
},
/**
* 检查是否在订单管理页面
*/
在订单管理页: function() {
return ActionAdapter.hasText("待发货") || ActionAdapter.hasText("待付款") ||
ActionAdapter.hasText("已发货") || ActionAdapter.hasText("催发货");
},
/**
* 检查待发货标签是否已选中
*/
待发货已选中: function() {
var xml = ActionAdapter.getXml();
if (!xml) return false;
var nodes = ActionAdapter.findNodes(xml, "待发货");
for (var i = 0; i < nodes.length; i++) {
// selected=true 表示已选中
var pattern = /<node\s+([^>]+?)(?:\/>|>)/g;
var match;
while ((match = pattern.exec(xml)) !== null) {
var attrs = match[1];
if ((attrs.indexOf("待发货") !== -1) && attrs.indexOf('selected="true"') !== -1) {
return true;
}
}
}
return false;
},
/**
* 进入待发货订单列表
* 多条路径:直接找"待发货"标签 → 找"订单管理"入口 → 首页重试
*/
进入待发货列表: function() {
logger.log("进入待发货订单列表...", true);
// 路径1:直接点击"待发货"标签
if (ActionAdapter.findTextAndClick("待发货", 3000)) {
sleep.second(秒 = CONFIG.操作延时);
if (this.在订单管理页()) {
logger.log("已在待发货列表页面");
return true;
}
}
// 路径2:找"订单管理"入口
if (ActionAdapter.findTextAndClick("订单管理", 2000)) {
sleep.second(秒 = CONFIG.操作延时);
if (ActionAdapter.findTextAndClick("待发货", 3000)) {
sleep.second(秒 = CONFIG.操作延时);
if (this.在订单管理页()) return true;
}
}
// 路径3:从首页找订单入口
ActionAdapter.home();
sleep.second(秒 = 2);
if (ActionAdapter.findTextAndClick("订单", 3000)) {
sleep.second(秒 = CONFIG.操作延时);
ActionAdapter.findTextAndClick("待发货", 3000);
sleep.second(秒 = CONFIG.操作延时);
if (this.在订单管理页()) return true;
}
logger.warn("未能进入待发货列表");
return false;
},
/**
* 检查是否有新订单(空状态消失 = 有订单)
*/
有新订单: function() {
// 空状态提示
if (ActionAdapter.hasText("还没有相关订单") || ActionAdapter.hasText("暂无")) {
return false;
}
// 有订单时的特征文字
var 订单特征 = ["立即发货", "去发货", "买家已付款", "联系买家"];
for (var i = 0; i < 订单特征.length; i++) {
if (ActionAdapter.hasText(订单特征[i])) {
logger.log("检测到待发货订单: " + 订单特征[i], true);
return true;
}
}
// 检查是否有订单号格式的数字
var xml = ActionAdapter.getXml();
if (xml) {
var allNodes = ActionAdapter.findAllNodes(xml);
for (var j = 0; j < allNodes.length; j++) {
if (allNodes[j].text && /^\d{15,20}$/.test(allNodes[j].text)) {
logger.log("检测到订单号: " + allNodes[j].text, true);
return true;
}
}
}
return false;
},
/**
* 匹配商品(用完整商品标题精准匹配)
* 遍历商品配置,在页面XML中查找哪个商品标题出现了
* @return {object|null} {名称, 配置, 节点}
*/
匹配商品: function() {
var xml = ActionAdapter.getXml();
if (!xml) xml = "";
for (var 商品标题 in 商品配置) {
// 直接用完整标题去XML里找
var nodes = ActionAdapter.findNodes(xml, 商品标题);
if (nodes.length > 0) {
logger.success("精准匹配到商品: " + 商品标题, true);
logger.log(" 节点: text=[" + nodes[0].text + "] desc=[" + nodes[0].desc + "] px=" + nodes[0].px + " py=" + nodes[0].py);
return {
名称: 商品标题,
配置: 商品配置[商品标题],
节点: nodes[0]
};
}
}
// 如果完整标题没匹配到,尝试模糊匹配(标题前6个字)
for (var 标题 in 商品配置) {
var 短标题 = 标题.substring(0, 6);
var nodes2 = ActionAdapter.findNodes(xml, 短标题);
if (nodes2.length > 0) {
logger.log("模糊匹配到商品: " + 标题 + " (关键词: " + 短标题 + ")", true);
return {
名称: 标题,
配置: 商品配置[标题],
节点: nodes2[0]
};
}
}
logger.warn("未匹配到任何商品");
return null;
},
/**
* 获取当前订单号
*/
获取订单号: function() {
var xml = ActionAdapter.getXml();
if (xml) {
var patterns = [
/订单号[::]\s*(\d{10,20})/,
/订单编号[::]\s*(\d{10,20})/,
/"(\d{15,20})"/
];
for (var i = 0; i < patterns.length; i++) {
var m = xml.match(patterns[i]);
if (m && m[1]) {
logger.log("提取到订单号: " + m[1]);
return m[1];
}
}
}
var 临时号 = "TEMP" + new Date().getTime();
logger.warn("未能提取订单号,使用临时号: " + 临时号);
return 临时号;
},
/**
* 点击订单进入详情页
*/
点击进入订单: function(商品节点) {
if (!商品节点) {
ActionAdapter.clickPercent(0.5, 0.4);
sleep.second(秒 = CONFIG.操作延时);
} else {
var node = 商品节点.节点 || 商品节点;
if (node.px > 0 && node.py > 0) {
ActionAdapter.clickPercent(node.px, node.py);
} else {
ActionAdapter.clickPercent(0.5, 0.4);
}
sleep.second(秒 = CONFIG.操作延时);
}
// 验证是否进入订单详情
if (ActionAdapter.hasText("订单详情") || ActionAdapter.hasText("订单号") ||
ActionAdapter.hasText("联系买家") || ActionAdapter.hasText("发货") ||
ActionAdapter.hasText("阿里旺旺") || ActionAdapter.hasText("旺旺")) {
logger.success("已进入订单详情");
return true;
}
if (ActionAdapter.hasText("确认发货") || ActionAdapter.hasText("物流")) {
logger.success("已进入发货页面");
return true;
}
logger.warn("未能进入订单详情");
return false;
},
/**
* 进入买家聊天界面(点阿里旺旺)
*/
进入聊天: function() {
logger.log("进入买家聊天界面...");
var 按钮文字 = ["阿里旺旺", "旺旺", "联系买家", "发消息", "联系", "留言"];
for (var i = 0; i < 按钮文字.length; i++) {
if (ActionAdapter.findTextAndClick(按钮文字[i], 2000)) {
sleep.second(秒 = CONFIG.操作延时);
logger.success("已进入聊天界面: " + 按钮文字[i]);
return true;
}
}
logger.warn("未能进入聊天界面");
return false;
},
/**
* 在聊天界面发送消息
*/
发送消息: function(消息内容) {
logger.log("准备发送消息...", true);
// 步骤1:点击聊天输入框
ActionAdapter.clickPercent(0.5, 0.92);
sleep.second(秒 = 1);
// 步骤2:通过剪贴板粘贴
ActionAdapter.inputText(消息内容);
sleep.second(秒 = 1);
// 步骤3:点击发送按钮
var 发送按钮文字 = ["发送", "Send", "发送消息"];
var 发送成功 = false;
for (var i = 0; i < 发送按钮文字.length; i++) {
if (ActionAdapter.findTextAndClick(发送按钮文字[i], 2000)) {
sleep.second(秒 = 1);
发送成功 = true;
break;
}
}
// 百分比点击发送按钮(通常在右下角)
if (!发送成功) {
ActionAdapter.clickPercent(0.95, 0.92);
sleep.second(秒 = 1);
发送成功 = true;
}
if (发送成功) logger.success("消息已发送", true);
return 发送成功;
},
/**
* 返回待发货订单列表
*/
返回列表: function() {
logger.log("返回订单列表...");
ActionAdapter.back();
sleep.second(秒 = CONFIG.操作延时);
ActionAdapter.back();
sleep.second(秒 = CONFIG.操作延时);
if (!this.在订单管理页()) {
sleep.second(秒 = 1);
if (!this.在订单管理页()) {
logger.warn("返回后不在订单管理页,重新进入");
this.进入待发货列表();
}
}
},
/**
* 执行发货(完整流程)
* 在订单详情页点击"发货" → 进入发货页面 → 选"无需物流" → 填写发货留言 → 确认发货
* @param {object} 发货内容 - {消息, 摘要, 卡密}
* @return {boolean} 是否发货成功
*/
执行发货: function(发货内容) {
logger.log("===== 开始执行发货操作 =====", true);
// 步骤1:在订单详情页点击"发货"按钮
var 发货按钮 = ["立即发货", "去发货", "发货"];
var 点击成功 = false;
for (var i = 0; i < 发货按钮.length; i++) {
if (ActionAdapter.findTextAndClick(发货按钮[i], 3000)) {
sleep.second(秒 = CONFIG.操作延时);
logger.log("已点击发货按钮: " + 发货按钮[i]);
点击成功 = true;
break;
}
}
if (!点击成功) {
// 可能已经在发货页面了
if (ActionAdapter.hasText("确认发货") || ActionAdapter.hasText("无需物流")) {
logger.log("已在发货页面");
点击成功 = true;
} else {
logger.err("未找到发货按钮");
return false;
}
}
// 步骤2:等待发货页面加载,检查页面特征
sleep.second(秒 = 2);
var 在发货页 = ActionAdapter.hasText("确认发货") ||
ActionAdapter.hasText("无需物流") ||
ActionAdapter.hasText("物流公司") ||
ActionAdapter.hasText("发货方式");
if (!在发货页) {
logger.log("发货页面未加载,再等一下...");
sleep.second(秒 = 2);
在发货页 = ActionAdapter.hasText("确认发货") ||
ActionAdapter.hasText("无需物流") ||
ActionAdapter.hasText("物流公司");
}
if (在发货页) {
logger.log("已进入发货页面");
ActionAdapter.dumpPageSummary();
}
// 步骤3:选择"无需物流"(虚拟商品不需要快递)
var 物流选项 = ["无需物流", "自己联系物流", "虚拟商品", "电子凭证", "不需要物流"];
var 选了物流 = false;
for (var j = 0; j < 物流选项.length; j++) {
if (ActionAdapter.findTextAndClick(物流选项[j], 2000)) {
sleep.second(秒 = 1);
logger.log("已选择: " + 物流选项[j]);
选了物流 = true;
break;
}
}
if (!选了物流) {
logger.log("未找到'无需物流'选项,可能默认已选或页面不同");
// 输出页面节点帮助排查
ActionAdapter.dumpPageSummary();
}
// 步骤4:填写发货留言/备注(把卡密/网盘信息填进去)
var 留言字段 = ["发货留言", "卖家发货备注", "发货备注", "留言", "备注", "给买家留言"];
var 填了留言 = false;
for (var k = 0; k < 留言字段.length; k++) {
if (ActionAdapter.findTextAndClick(留言字段[k], 1500)) {
sleep.second(秒 = 1);
// 点击后可能出现输入框,填入发货内容
ActionAdapter.inputText(发货内容.消息);
sleep.second(秒 = 1);
logger.log("已填写发货留言: " + 留言字段[k]);
填了留言 = true;
break;
}
}
if (!填了留言) {
// 尝试找输入框直接填写
logger.log("未找到留言字段,尝试直接找输入框...");
// 发货页面的输入框通常在中部
ActionAdapter.clickPercent(0.5, 0.5);
sleep.second(秒 = 1);
ActionAdapter.inputText(发货内容.消息);
sleep.second(秒 = 1);
}
// 步骤5:点击"确认发货"按钮
logger.log("寻找确认发货按钮...");
var 确认按钮 = ["确认发货", "确定发货", "提交", "确定"];
var 确认成功 = false;
for (var m = 0; m < 确认按钮.length; m++) {
if (ActionAdapter.findTextAndClick(确认按钮[m], 3000)) {
sleep.second(秒 = CONFIG.操作延时);
logger.log("已点击: " + 确认按钮[m]);
确认成功 = true;
break;
}
}
if (!确认成功) {
// 尝试点击右下角的确认按钮(常见位置)
logger.log("未找到确认按钮文字,尝试点击右下角...");
ActionAdapter.clickPercent(0.85, 0.9);
sleep.second(秒 = CONFIG.操作延时);
}
// 步骤6:验证发货是否成功
sleep.second(秒 = 2);
var 发货成功 = ActionAdapter.hasText("发货成功") ||
ActionAdapter.hasText("已发货") ||
ActionAdapter.hasText("发货完成") ||
ActionAdapter.hasText("提交成功");
// 如果没有明确的成功提示,检查是否回到了订单详情或列表
if (!发货成功) {
if (ActionAdapter.hasText("订单详情") || ActionAdapter.hasText("待发货") ||
ActionAdapter.hasText("已发货") || ActionAdapter.hasText("催发货")) {
logger.log("已返回订单页面,推断发货成功");
发货成功 = true;
}
}
// 处理可能的二次确认弹窗
if (ActionAdapter.hasText("确定") || ActionAdapter.hasText("确认")) {
var 弹窗按钮 = ["确定", "确认", "是"];
for (var n = 0; n < 弹窗按钮.length; n++) {
if (ActionAdapter.findTextAndClick(弹窗按钮[n], 1500)) {
sleep.second(秒 = 1);
logger.log("已确认弹窗: " + 弹窗按钮[n]);
break;
}
}
sleep.second(秒 = 2);
// 再次检查
if (!发货成功) {
发货成功 = ActionAdapter.hasText("发货成功") ||
ActionAdapter.hasText("已发货") ||
ActionAdapter.hasText("发货完成");
}
}
if (发货成功) {
logger.success("发货操作完成!", true);
} else {
logger.warn("未能确认发货是否成功,请手动检查");
ActionAdapter.dumpPageSummary();
}
return 发货成功;
},
/**
* 标记发货(旧方法保留,仅作为后备)
*/
标记发货: function() {
logger.log("尝试标记订单发货...");
var 发货按钮 = ["发货", "确认发货", "一键发货"];
for (var i = 0; i < 发货按钮.length; i++) {
if (ActionAdapter.findTextAndClick(发货按钮[i], 2000)) {
sleep.second(秒 = CONFIG.操作延时);
logger.success("已标记发货");
return true;
}
}
logger.warn("未找到发货按钮");
return false;
}
};
// =============================================================================
// 第八部分:发货核心流程
// =============================================================================
var 发货流程 = {
/**
* 处理一个订单的完整流程
* 匹配商品 → 进详情 → 执行发货(选无需物流+确认) → 点旺旺 → 发消息 → 返回列表
*/
处理订单: function() {
logger.log("========== 开始处理订单 ==========");
// 步骤1:匹配商品
var 商品 = 千牛操作.匹配商品();
if (!商品) {
logger.warn("未匹配到商品,跳过");
return false;
}
// 步骤2:获取订单号
var 订单号 = 千牛操作.获取订单号();
// 步骤3:检查是否已发货
if (发货记录.已发货(订单号)) {
logger.log("订单 " + 订单号 + " 已发过货,跳过");
ActionAdapter.swipePercent(0.5, 0.6, 0.5, 0.3, 500);
sleep.second(秒 = 1);
return false;
}
// 步骤4:准备发货内容
var 发货内容 = this.准备发货内容(商品);
if (!发货内容) {
logger.err("准备发货内容失败");
return false;
}
// 步骤5:点击订单进入详情
if (!千牛操作.点击进入订单(商品.节点)) {
logger.err("进入订单详情失败");
return false;
}
// 步骤6:执行发货(点发货 → 选无需物流 → 填留言 → 确认发货)
var 发货结果 = 千牛操作.执行发货(发货内容);
if (发货结果) {
logger.success("订单已发货: " + 订单号, true);
} else {
logger.warn("发货操作未能确认成功,继续发旺旺消息");
}
// 步骤7:进入聊天界面(点阿里旺旺,给买家发卡密/网盘信息)
// 此时可能需要返回到订单详情页
if (!ActionAdapter.hasText("订单详情") && !ActionAdapter.hasText("阿里旺旺")) {
// 如果发货后不在订单详情,尝试返回
ActionAdapter.back();
sleep.second(秒 = CONFIG.操作延时);
}
if (千牛操作.进入聊天()) {
// 步骤8:发送消息
if (千牛操作.发送消息(发货内容.消息)) {
logger.success("旺旺消息已发送", true);
// 步骤9:返回订单详情
ActionAdapter.back();
sleep.second(秒 = CONFIG.操作延时);
} else {
logger.err("发送旺旺消息失败");
}
} else {
logger.warn("未能进入旺旺聊天(发货已完成,消息发送失败)");
}
// 步骤10:记录发货
发货记录.记录(订单号, 商品.名称, 发货内容.摘要);
// 步骤11:上报服务器
if (CONFIG.使用服务器 && 发货内容.卡密) {
卡密管理.上报已使用(商品.名称, 发货内容.卡密, 订单号);
}
logger.success("订单 " + 订单号 + " 处理完成: " + 商品.名称, true);
logger.success("今日已发货: " + 发货记录.今日数量() + " 单");
// 步骤12:返回列表
千牛操作.返回列表();
return true;
},
准备发货内容: function(商品) {
var 配置 = 商品.配置;
var 话术 = 配置.发货话术;
var 卡密 = "";
var 网盘 = 配置.网盘链接 || "";
var 摘要 = "";
if (配置.发货类型 === "卡密") {
卡密 = 卡密管理.取卡密(配置);
if (!卡密) { logger.err("无可用卡密!商品: " + 商品.名称); return null; }
话术 = 话术.replace("{卡密}", 卡密).replace("{网盘}", 网盘);
摘要 = "卡密:" + 卡密;
} else if (配置.发货类型 === "网盘") {
话术 = 话术.replace("{网盘}", 网盘).replace("{卡密}", "");
摘要 = "网盘:" + 网盘.substring(0, 20);
} else if (配置.发货类型 === "卡密+网盘") {
卡密 = 卡密管理.取卡密(配置);
if (!卡密) { logger.err("无可用卡密!商品: " + 商品.名称); return null; }
话术 = 话术.replace("{卡密}", 卡密).replace("{网盘}", 网盘);
摘要 = "卡密:" + 卡密 + " 网盘:" + 网盘.substring(0, 15);
}
return { 消息: 话术, 摘要: 摘要, 卡密: 卡密 };
},
/**
* 处理当前所有可见的待发货订单
*/
处理当前订单: function() {
var 处理数量 = 0;
var 连续无订单 = 0;
for (var i = 0; i < 50; i++) {
if (!千牛操作.有新订单()) {
连续无订单++;
if (连续无订单 >= 2) {
logger.log("没有更多待发货订单");
break;
}
ActionAdapter.swipePercent(0.5, 0.6, 0.5, 0.3, 500);
sleep.second(秒 = 1);
continue;
}
连续无订单 = 0;
logger.log("--- 处理第 " + (i + 1) + " 个订单 ---");
if (this.处理订单()) 处理数量++;
sleep.second(秒 = 1);
}
logger.success("本轮处理完成,共发货 " + 处理数量 + " 单", true);
return 处理数量;
}
};
// =============================================================================
// 第九部分:保活心跳(无碍版,不用shell)
// =============================================================================
var 保活系统 = {
线程: null,
运行中: false,
start: function() {
if (!CONFIG.启用保活) return;
this.运行中 = true;
this.线程 = new thread().runJsCode(function() {
while (保活系统.运行中) {
try {
// 无碍模式没有shell,用getXml检查千牛是否在前台
var xml = ActionAdapter.getXml();
if (!xml || xml === "") {
logger.warn("千牛可能未运行,尝试重启...");
app.openApp(CONFIG.千牛包名);
sleep.second(秒 = 8);
}
logger.log("保活心跳: 今日发货 " + 发货记录.今日数量() + " 单");
} catch (e) {}
sleep.second(秒 = CONFIG.保活间隔);
}
});
logger.log("保活线程已启动");
},
stop: function() {
this.运行中 = false;
logger.log("保活线程已停止");
}
};
// =============================================================================
// 第十部分:库存预警
// =============================================================================
var 库存预警 = {
检查全部: function() {
var 预警商品 = [];
for (var 商品名 in 商品配置) {
var 配置 = 商品配置[商品名];
if (配置.发货类型 === "卡密" || 配置.发货类型 === "卡密+网盘") {
var 库存 = 卡密管理.检查库存(配置);
if (库存 >= 0 && 库存 < 5) {
预警商品.push(商品名 + " (剩余" + 库存 + "个)");
logger.warn("库存预警: " + 商品名 + " 仅剩 " + 库存 + " 个卡密!");
}
}
}
return 预警商品;
}
};
// =============================================================================
// 第十一部分:主控制流程(持续监控模式)
// =============================================================================
var 主控 = {
运行中: false,
统计: { 总轮次: 0, 总发货: 0, 开始时间: null, 最后检查: null },
初始化: function() {
logger.log("========================================");
logger.log(" 淘宝千牛自动发货系统 v3.0");
logger.log(" 精简版 · 仅无碍模式 · 完整标题匹配");
logger.log("========================================");
logger.init();
if (!ActionAdapter.init()) {
logger.err("无碍模式初始化失败,系统退出");
return false;
}
try {
var dir = new File(CONFIG.卡密目录);
if (!dir.exists()) dir.mkdirs();
} catch (e) {}
var 预警 = 库存预警.检查全部();
if (预警.length > 0) logger.warn("库存预警: " + 预警.join(", "));
logger.log("商品数量: " + Object.keys(商品配置).length);
logger.log("监控间隔: " + CONFIG.轮询间隔 + "秒");
this.统计.开始时间 = new Date();
logger.success("系统初始化完成", true);
return true;
},
进入监控状态: function() {
千牛操作.确保运行();
sleep.second(秒 = 2);
if (!千牛操作.进入待发货列表()) {
logger.err("进入待发货列表失败!", true);
return false;
}
if (!千牛操作.待发货已选中()) {
ActionAdapter.findTextAndClick("待发货", 3000);
sleep.second(秒 = CONFIG.操作延时);
}
logger.success("已进入待发货列表,开始持续监控", true);
return true;
},
监控一轮: function() {
this.统计.总轮次++;
logger.addRound();
try {
if (!千牛操作.在订单管理页()) {
logger.warn("不在订单管理页面,重新进入");
this.进入监控状态();
return;
}
if (千牛操作.有新订单()) {
logger.success("检测到新订单!开始处理...", true);
var 发货数 = 发货流程.处理当前订单();
this.统计.总发货 += 发货数;
for (var i = 0; i < 发货数; i++) logger.addShip();
if (发货数 > 0) {
logger.success("本轮发货 " + 发货数 + " 单,累计 " + this.统计.总发货 + " 单", true);
}
if (!千牛操作.在订单管理页()) this.进入监控状态();
} else {
if (this.统计.总轮次 % 10 === 0) {
logger.log("监控中... 暂无新订单 (轮次:" + this.统计.总轮次 + ")");
}
if (this.统计.总轮次 % 20 === 0) 库存预警.检查全部();
}
} catch (e) {
logger.err("监控异常: " + e, true);
logger.log("异常恢复:重新进入待发货列表...", true);
this.进入监控状态();
}
this.统计.最后检查 = new Date();
},
主循环: function() {
this.运行中 = true;
logger.success("系统进入持续监控模式", true);
logger.log("停在待发货列表页面,有人下单自动发货", true);
while (this.运行中) {
try { this.监控一轮(); } catch (e) { logger.err("主循环异常: " + e, true); }
var 等待秒数 = CONFIG.轮询间隔;
for (var i = 等待秒数; i > 0; i--) {
if (!this.运行中) break;
if (i % 10 === 0 || i <= 3) { try { logger._更新状态(); } catch (e2) {} }
sleep.second(秒 = 1);
}
}
},
start: function() {
if (!this.初始化()) return;
保活系统.start();
if (!this.进入监控状态()) {
logger.err("无法进入监控状态,5秒后重试...", true);
sleep.second(秒 = 5);
if (!this.进入监控状态()) {
logger.err("重试失败,系统退出", true);
return;
}
}
this.主循环();
},
stop: function() {
this.运行中 = false;
保活系统.stop();
logger.log("系统已停止");
}
};
// =============================================================================
// 第十二部分:启动入口
// =============================================================================
function 确保目录存在(路径) {
try {
var dir = new File(路径);
if (!dir.exists()) dir.mkdirs();
} catch (e) {}
}
function 创建卡密示例() {
try {
for (var 商品名 in 商品配置) {
var 配置 = 商品配置[商品名];
if (配置.卡密文件 && 配置.卡密文件 !== "") {
var file = new File(配置.卡密文件);
if (!file.exists()) {
var writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
writer.write("# " + 商品名 + " 卡密文件\n");
writer.write("# 每行一个卡密,用过的自动删除\n\n");
writer.write("Q5J3HHT8-NJMF\n");
writer.write("KA8CPLJP-DNCM\n");
writer.write("FYYEGC6D-KPCA\n");
writer.close();
logger.log("已创建卡密示例文件: " + 配置.卡密文件);
}
}
}
} catch (e) {
logger.err("创建卡密示例失败: " + e);
}
}
// =============================================================================
// 启动
// =============================================================================
确保目录存在(CONFIG.卡密目录);
确保目录存在("/sdcard/");
创建卡密示例();
if (CONFIG.调试模式 === "debug") {
// ===== 调试模式:输出页面节点,验证XML解析 =====
logger.init();
logger.log("========================================");
logger.log(" 调试模式:验证XML解析");
logger.log("========================================");
if (!ActionAdapter.init()) {
logger.err("无碍模式初始化失败");
} else {
千牛操作.启动千牛();
sleep.second(秒 = 3);
logger.log("===== 当前页面节点摘要 =====");
ActionAdapter.dumpPageSummary();
logger.log("===== 测试查找'待发货'节点 =====");
var xml = ActionAdapter.getXml();
var nodes = ActionAdapter.findNodes(xml, "待发货");
logger.log("查找'待发货'结果: " + nodes.length + " 个节点");
for (var i = 0; i < nodes.length; i++) {
logger.log(" 节点" + i + ": text=[" + nodes[i].text + "] desc=[" + nodes[i].desc + "] px=" + nodes[i].px + " py=" + nodes[i].py + " clickable=" + nodes[i].clickable);
if (nodes[i].clickable === "false") {
var parent = ActionAdapter.findClickableParent(nodes[i], xml);
if (parent) {
logger.log(" -> 父节点: px=" + parent.px + " py=" + parent.py + " clickable=" + parent.clickable);
}
}
}
logger.log("===== 测试商品标题匹配 =====");
var 商品结果 = 千牛操作.匹配商品();
if (商品结果) {
logger.success("匹配到商品: " + 商品结果.名称);
} else {
logger.log("当前页面未匹配到商品(正常,列表为空时无商品)");
}
logger.success("调试完成!", true);
logger.log("如需测试真实发货,请将 CONFIG.调试模式 设为 'test'");
logger.log("如需正常监控,请将 CONFIG.调试模式 设为 false");
}
} else if (CONFIG.调试模式 === "test") {
// ===== 测试模式:处理一个真实订单,验证完整发货流程 =====
logger.init();
logger.log("========================================");
logger.log(" 测试模式:处理一个真实订单");
logger.log("========================================");
if (!ActionAdapter.init()) {
logger.err("无碍模式初始化失败");
} else {
// 启动千牛
千牛操作.启动千牛();
sleep.second(秒 = 3);
// 进入待发货列表
if (!千牛操作.进入待发货列表()) {
logger.err("进入待发货列表失败!", true);
} else {
logger.log("===== 检查是否有待发货订单 =====");
if (千牛操作.有新订单()) {
logger.success("检测到订单!开始处理...", true);
// 输出页面节点,看看订单列表长什么样
logger.log("===== 订单列表节点摘要 =====");
ActionAdapter.dumpPageSummary();
// 尝试匹配商品
logger.log("===== 尝试匹配商品 =====");
var 商品 = 千牛操作.匹配商品();
if (商品) {
logger.success("匹配到商品: " + 商品.名称, true);
// 处理这个订单
logger.log("===== 开始处理订单 =====");
var 结果 = 发货流程.处理订单();
if (结果) {
logger.success("测试发货成功!", true);
} else {
logger.err("测试发货失败,请检查日志", true);
}
} else {
logger.warn("未匹配到商品");
logger.log("请检查商品配置中的标题是否与淘宝订单中的商品标题一致");
logger.log("===== 当前页面所有节点 =====");
ActionAdapter.dumpPageSummary();
}
} else {
logger.log("当前没有待发货订单,请先在淘宝下一单测试");
logger.log("===== 当前页面节点 =====");
ActionAdapter.dumpPageSummary();
}
}
logger.log("========================================");
logger.log("测试完成!");
logger.log("如需正常监控,请将 CONFIG.调试模式 设为 false");
logger.log("========================================");
}
} else {
// ===== 正常模式:24小时持续监控 =====
主控.start();
}
复制代码
欢迎光临 自动发帖软件 (http://www.fatiegongju.com/)
Powered by Discuz! X3.2